@snap/camera-kit 0.7.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 (554) hide show
  1. package/LICENSE.md +6247 -0
  2. package/README.md +166 -0
  3. package/docs/html/.nojekyll +1 -0
  4. package/docs/html/assets/highlight.css +106 -0
  5. package/docs/html/assets/main.js +54 -0
  6. package/docs/html/assets/search.js +1 -0
  7. package/docs/html/assets/style.css +1225 -0
  8. package/docs/html/assets/widgets.png +0 -0
  9. package/docs/html/assets/widgets@2x.png +0 -0
  10. package/docs/html/classes/CameraKit.html +121 -0
  11. package/docs/html/classes/CameraKitSession.html +347 -0
  12. package/docs/html/classes/CameraKitSource.html +152 -0
  13. package/docs/html/classes/LensPerformanceMeasurement.html +115 -0
  14. package/docs/html/classes/LensPerformanceMetrics.html +76 -0
  15. package/docs/html/classes/LensRepository.html +171 -0
  16. package/docs/html/classes/LensSources.html +82 -0
  17. package/docs/html/classes/Transform2D.html +99 -0
  18. package/docs/html/classes/TypedCustomEvent.html +109 -0
  19. package/docs/html/classes/TypedEventTarget.html +146 -0
  20. package/docs/html/functions/Injectable.html +193 -0
  21. package/docs/html/functions/bootstrapCameraKit.html +158 -0
  22. package/docs/html/functions/createExtension.html +127 -0
  23. package/docs/html/functions/createImageSource.html +123 -0
  24. package/docs/html/functions/createMediaStreamSource.html +123 -0
  25. package/docs/html/functions/createUserMediaSource.html +127 -0
  26. package/docs/html/functions/createVideoSource.html +124 -0
  27. package/docs/html/functions/estimateLensPerformance.html +116 -0
  28. package/docs/html/functions/getRequiredBootstrapURLs.html +124 -0
  29. package/docs/html/functions/lensSourcesFactory.html +116 -0
  30. package/docs/html/functions/uriHandlersFactory.html +118 -0
  31. package/docs/html/index.html +208 -0
  32. package/docs/html/interfaces/CameraKitBootstrapConfiguration.html +132 -0
  33. package/docs/html/interfaces/CameraKitSourceSubscriber.html +121 -0
  34. package/docs/html/interfaces/ComputedFrameMetrics.html +70 -0
  35. package/docs/html/interfaces/CreateSessionOptions.html +77 -0
  36. package/docs/html/interfaces/EstimatedLensPerformance.html +78 -0
  37. package/docs/html/interfaces/Lens.html +115 -0
  38. package/docs/html/interfaces/LensSource.html +113 -0
  39. package/docs/html/interfaces/MediaStreamSourceOptions.html +65 -0
  40. package/docs/html/interfaces/UriCancelRequest.html +65 -0
  41. package/docs/html/interfaces/UriHandler.html +128 -0
  42. package/docs/html/interfaces/UriRequest.html +80 -0
  43. package/docs/html/interfaces/UriResponse.html +80 -0
  44. package/docs/html/interfaces/VideoSourceOptions.html +60 -0
  45. package/docs/html/modules.html +198 -0
  46. package/docs/html/types/AssetLoader.html +126 -0
  47. package/docs/html/types/AssetTiming.html +116 -0
  48. package/docs/html/types/BenchmarkError.html +107 -0
  49. package/docs/html/types/BootstrapError.html +110 -0
  50. package/docs/html/types/CacheKeyNotFoundError.html +107 -0
  51. package/docs/html/types/CameraKitDeviceInfo.html +114 -0
  52. package/docs/html/types/CameraKitSessionEventListener.html +109 -0
  53. package/docs/html/types/CameraKitSessionEvents.html +118 -0
  54. package/docs/html/types/CameraKitSourceError.html +107 -0
  55. package/docs/html/types/CameraKitSourceInfo.html +107 -0
  56. package/docs/html/types/CameraKitSourceOptions.html +113 -0
  57. package/docs/html/types/ConfigurationError.html +109 -0
  58. package/docs/html/types/Keyboard.html +196 -0
  59. package/docs/html/types/KeyboardEvents.html +109 -0
  60. package/docs/html/types/LegalError.html +107 -0
  61. package/docs/html/types/LensAssetError.html +109 -0
  62. package/docs/html/types/LensContentValidationError.html +107 -0
  63. package/docs/html/types/LensError.html +107 -0
  64. package/docs/html/types/LensExecutionError.html +114 -0
  65. package/docs/html/types/LensImagePickerError.html +110 -0
  66. package/docs/html/types/LensLaunchParams.html +109 -0
  67. package/docs/html/types/LensMetricsEvents.html +110 -0
  68. package/docs/html/types/LensPerformanceCluster.html +107 -0
  69. package/docs/html/types/LensView.html +119 -0
  70. package/docs/html/types/LensWait.html +111 -0
  71. package/docs/html/types/PersistentStoreError.html +109 -0
  72. package/docs/html/types/PlatformNotSupportedError.html +110 -0
  73. package/docs/html/types/PublicContainer.html +110 -0
  74. package/docs/html/types/RenderTarget.html +111 -0
  75. package/docs/html/types/Uri.html +107 -0
  76. package/docs/html/types/UriHandlers.html +109 -0
  77. package/docs/html/types/WebGLError.html +107 -0
  78. package/docs/html/variables/extensionRequestContext.html +109 -0
  79. package/docs/md/.nojekyll +1 -0
  80. package/docs/md/README.md +168 -0
  81. package/docs/md/classes/CameraKit.md +94 -0
  82. package/docs/md/classes/CameraKitSession.md +359 -0
  83. package/docs/md/classes/CameraKitSource.md +110 -0
  84. package/docs/md/classes/LensPerformanceMeasurement.md +77 -0
  85. package/docs/md/classes/LensPerformanceMetrics.md +37 -0
  86. package/docs/md/classes/LensRepository.md +145 -0
  87. package/docs/md/classes/LensSources.md +29 -0
  88. package/docs/md/classes/Transform2D.md +55 -0
  89. package/docs/md/classes/TypedCustomEvent.md +65 -0
  90. package/docs/md/classes/TypedEventTarget.md +103 -0
  91. package/docs/md/interfaces/CameraKitBootstrapConfiguration.md +106 -0
  92. package/docs/md/interfaces/CameraKitSourceSubscriber.md +55 -0
  93. package/docs/md/interfaces/ComputedFrameMetrics.md +29 -0
  94. package/docs/md/interfaces/CreateSessionOptions.md +35 -0
  95. package/docs/md/interfaces/EstimatedLensPerformance.md +38 -0
  96. package/docs/md/interfaces/Lens.md +84 -0
  97. package/docs/md/interfaces/LensSource.md +68 -0
  98. package/docs/md/interfaces/MediaStreamSourceOptions.md +22 -0
  99. package/docs/md/interfaces/UriCancelRequest.md +22 -0
  100. package/docs/md/interfaces/UriHandler.md +63 -0
  101. package/docs/md/interfaces/UriRequest.md +43 -0
  102. package/docs/md/interfaces/UriResponse.md +43 -0
  103. package/docs/md/interfaces/VideoSourceOptions.md +15 -0
  104. package/docs/md/modules.md +827 -0
  105. package/lib/CameraKit.d.ts +170 -0
  106. package/lib/CameraKit.js +145 -0
  107. package/lib/CameraKit.js.map +1 -0
  108. package/lib/__tests__/data.d.ts +9 -0
  109. package/lib/__tests__/data.js +50 -0
  110. package/lib/__tests__/data.js.map +1 -0
  111. package/lib/__tests__/deferred.d.ts +16 -0
  112. package/lib/__tests__/deferred.js +29 -0
  113. package/lib/__tests__/deferred.js.map +1 -0
  114. package/lib/__tests__/jest.matchers.d.ts +17 -0
  115. package/lib/__tests__/jest.matchers.js +67 -0
  116. package/lib/__tests__/jest.matchers.js.map +1 -0
  117. package/lib/assertPlatformSupported.d.ts +4 -0
  118. package/lib/assertPlatformSupported.js +10 -0
  119. package/lib/assertPlatformSupported.js.map +1 -0
  120. package/lib/benchmark/benchmarkGflops.d.ts +16 -0
  121. package/lib/benchmark/benchmarkGflops.js +129 -0
  122. package/lib/benchmark/benchmarkGflops.js.map +1 -0
  123. package/lib/benchmark/estimateLensPerformanceCluster.d.ts +33 -0
  124. package/lib/benchmark/estimateLensPerformanceCluster.js +48 -0
  125. package/lib/benchmark/estimateLensPerformanceCluster.js.map +1 -0
  126. package/lib/benchmark/webglUtils.d.ts +7 -0
  127. package/lib/benchmark/webglUtils.js +87 -0
  128. package/lib/benchmark/webglUtils.js.map +1 -0
  129. package/lib/bootstrapCameraKit.d.ts +96 -0
  130. package/lib/bootstrapCameraKit.js +204 -0
  131. package/lib/bootstrapCameraKit.js.map +1 -0
  132. package/lib/common/__mocks__/loadScript.d.ts +1 -0
  133. package/lib/common/__mocks__/loadScript.js +10 -0
  134. package/lib/common/__mocks__/loadScript.js.map +1 -0
  135. package/lib/common/assertions.d.ts +27 -0
  136. package/lib/common/assertions.js +39 -0
  137. package/lib/common/assertions.js.map +1 -0
  138. package/lib/common/cameraKitUserAgent.d.ts +34 -0
  139. package/lib/common/cameraKitUserAgent.js +216 -0
  140. package/lib/common/cameraKitUserAgent.js.map +1 -0
  141. package/lib/common/copyDefinedProperties.d.ts +13 -0
  142. package/lib/common/copyDefinedProperties.js +16 -0
  143. package/lib/common/copyDefinedProperties.js.map +1 -0
  144. package/lib/common/entries.d.ts +3 -0
  145. package/lib/common/entries.js +3 -0
  146. package/lib/common/entries.js.map +1 -0
  147. package/lib/common/errorHelpers.d.ts +10 -0
  148. package/lib/common/errorHelpers.js +24 -0
  149. package/lib/common/errorHelpers.js.map +1 -0
  150. package/lib/common/getFilename.d.ts +1 -0
  151. package/lib/common/getFilename.js +4 -0
  152. package/lib/common/getFilename.js.map +1 -0
  153. package/lib/common/index.d.ts +2 -0
  154. package/lib/common/index.js +3 -0
  155. package/lib/common/index.js.map +1 -0
  156. package/lib/common/loadScript.d.ts +1 -0
  157. package/lib/common/loadScript.js +11 -0
  158. package/lib/common/loadScript.js.map +1 -0
  159. package/lib/common/locale.d.ts +2 -0
  160. package/lib/common/locale.js +11 -0
  161. package/lib/common/locale.js.map +1 -0
  162. package/lib/common/localization.d.ts +43 -0
  163. package/lib/common/localization.js +43 -0
  164. package/lib/common/localization.js.map +1 -0
  165. package/lib/common/memoize.d.ts +8 -0
  166. package/lib/common/memoize.js +15 -0
  167. package/lib/common/memoize.js.map +1 -0
  168. package/lib/common/pageVisibility.d.ts +20 -0
  169. package/lib/common/pageVisibility.js +62 -0
  170. package/lib/common/pageVisibility.js.map +1 -0
  171. package/lib/common/time.d.ts +1 -0
  172. package/lib/common/time.js +2 -0
  173. package/lib/common/time.js.map +1 -0
  174. package/lib/common/typeguards.d.ts +53 -0
  175. package/lib/common/typeguards.js +92 -0
  176. package/lib/common/typeguards.js.map +1 -0
  177. package/lib/common/types.d.ts +10 -0
  178. package/lib/common/types.js +2 -0
  179. package/lib/common/types.js.map +1 -0
  180. package/lib/common/validate.d.ts +14 -0
  181. package/lib/common/validate.js +104 -0
  182. package/lib/common/validate.js.map +1 -0
  183. package/lib/configuration.d.ts +92 -0
  184. package/lib/configuration.js +36 -0
  185. package/lib/configuration.js.map +1 -0
  186. package/lib/configurationOverrides.d.ts +12 -0
  187. package/lib/configurationOverrides.js +41 -0
  188. package/lib/configurationOverrides.js.map +1 -0
  189. package/lib/dependency-injection/Container.d.ts +177 -0
  190. package/lib/dependency-injection/Container.js +160 -0
  191. package/lib/dependency-injection/Container.js.map +1 -0
  192. package/lib/dependency-injection/Injectable.d.ts +39 -0
  193. package/lib/dependency-injection/Injectable.js +18 -0
  194. package/lib/dependency-injection/Injectable.js.map +1 -0
  195. package/lib/dependency-injection/PartialContainer.d.ts +81 -0
  196. package/lib/dependency-injection/PartialContainer.js +85 -0
  197. package/lib/dependency-injection/PartialContainer.js.map +1 -0
  198. package/lib/dependency-injection/RootServices.d.ts +62 -0
  199. package/lib/dependency-injection/RootServices.js +2 -0
  200. package/lib/dependency-injection/RootServices.js.map +1 -0
  201. package/lib/dependency-injection/types.d.ts +56 -0
  202. package/lib/dependency-injection/types.js +2 -0
  203. package/lib/dependency-injection/types.js.map +1 -0
  204. package/lib/environment.json +1 -0
  205. package/lib/events/TypedCustomEvent.d.ts +10 -0
  206. package/lib/events/TypedCustomEvent.js +11 -0
  207. package/lib/events/TypedCustomEvent.js.map +1 -0
  208. package/lib/events/TypedEventTarget.d.ts +25 -0
  209. package/lib/events/TypedEventTarget.js +57 -0
  210. package/lib/events/TypedEventTarget.js.map +1 -0
  211. package/lib/events/scan.d.ts +15 -0
  212. package/lib/events/scan.js +46 -0
  213. package/lib/events/scan.js.map +1 -0
  214. package/lib/extensions/LensSources.d.ts +58 -0
  215. package/lib/extensions/LensSources.js +50 -0
  216. package/lib/extensions/LensSources.js.map +1 -0
  217. package/lib/extensions/UriHandlers.d.ts +54 -0
  218. package/lib/extensions/UriHandlers.js +93 -0
  219. package/lib/extensions/UriHandlers.js.map +1 -0
  220. package/lib/extensions/extensionRequestContext.d.ts +4 -0
  221. package/lib/extensions/extensionRequestContext.js +14 -0
  222. package/lib/extensions/extensionRequestContext.js.map +1 -0
  223. package/lib/generated-proto/blizzard/cameraKitEvents.d.ts +5603 -0
  224. package/lib/generated-proto/blizzard/cameraKitEvents.js +522 -0
  225. package/lib/generated-proto/blizzard/cameraKitEvents.js.map +1 -0
  226. package/lib/generated-proto/pb_schema/camera_kit/v3/business_events.d.ts +98 -0
  227. package/lib/generated-proto/pb_schema/camera_kit/v3/business_events.js +260 -0
  228. package/lib/generated-proto/pb_schema/camera_kit/v3/business_events.js.map +1 -0
  229. package/lib/generated-proto/pb_schema/camera_kit/v3/export.d.ts +543 -0
  230. package/lib/generated-proto/pb_schema/camera_kit/v3/export.js +429 -0
  231. package/lib/generated-proto/pb_schema/camera_kit/v3/export.js.map +1 -0
  232. package/lib/generated-proto/pb_schema/camera_kit/v3/legal_prompt.d.ts +100 -0
  233. package/lib/generated-proto/pb_schema/camera_kit/v3/legal_prompt.js +164 -0
  234. package/lib/generated-proto/pb_schema/camera_kit/v3/legal_prompt.js.map +1 -0
  235. package/lib/generated-proto/pb_schema/camera_kit/v3/lens.d.ts +395 -0
  236. package/lib/generated-proto/pb_schema/camera_kit/v3/lens.js +644 -0
  237. package/lib/generated-proto/pb_schema/camera_kit/v3/lens.js.map +1 -0
  238. package/lib/generated-proto/pb_schema/camera_kit/v3/operational_metrics.d.ts +185 -0
  239. package/lib/generated-proto/pb_schema/camera_kit/v3/operational_metrics.js +172 -0
  240. package/lib/generated-proto/pb_schema/camera_kit/v3/operational_metrics.js.map +1 -0
  241. package/lib/generated-proto/pb_schema/camera_kit/v3/ranking.d.ts +86 -0
  242. package/lib/generated-proto/pb_schema/camera_kit/v3/ranking.js +234 -0
  243. package/lib/generated-proto/pb_schema/camera_kit/v3/ranking.js.map +1 -0
  244. package/lib/generated-proto/pb_schema/camera_kit/v3/service.d.ts +854 -0
  245. package/lib/generated-proto/pb_schema/camera_kit/v3/service.js +629 -0
  246. package/lib/generated-proto/pb_schema/camera_kit/v3/service.js.map +1 -0
  247. package/lib/generated-proto/pb_schema/cdp/cof/benchmark.d.ts +86 -0
  248. package/lib/generated-proto/pb_schema/cdp/cof/benchmark.js +185 -0
  249. package/lib/generated-proto/pb_schema/cdp/cof/benchmark.js.map +1 -0
  250. package/lib/generated-proto/pb_schema/cdp/cof/benchmark_name.d.ts +95 -0
  251. package/lib/generated-proto/pb_schema/cdp/cof/benchmark_name.js +104 -0
  252. package/lib/generated-proto/pb_schema/cdp/cof/benchmark_name.js.map +1 -0
  253. package/lib/generated-proto/pb_schema/cdp/cof/circumstance_service.d.ts +10212 -0
  254. package/lib/generated-proto/pb_schema/cdp/cof/circumstance_service.js +1300 -0
  255. package/lib/generated-proto/pb_schema/cdp/cof/circumstance_service.js.map +1 -0
  256. package/lib/generated-proto/pb_schema/cdp/cof/config_request.d.ts +401 -0
  257. package/lib/generated-proto/pb_schema/cdp/cof/config_request.js +525 -0
  258. package/lib/generated-proto/pb_schema/cdp/cof/config_request.js.map +1 -0
  259. package/lib/generated-proto/pb_schema/cdp/cof/config_response.d.ts +1287 -0
  260. package/lib/generated-proto/pb_schema/cdp/cof/config_response.js +135 -0
  261. package/lib/generated-proto/pb_schema/cdp/cof/config_response.js.map +1 -0
  262. package/lib/generated-proto/pb_schema/cdp/cof/config_result.d.ts +4208 -0
  263. package/lib/generated-proto/pb_schema/cdp/cof/config_result.js +1053 -0
  264. package/lib/generated-proto/pb_schema/cdp/cof/config_result.js.map +1 -0
  265. package/lib/generated-proto/pb_schema/cdp/cof/debug_info.d.ts +102 -0
  266. package/lib/generated-proto/pb_schema/cdp/cof/debug_info.js +165 -0
  267. package/lib/generated-proto/pb_schema/cdp/cof/debug_info.js.map +1 -0
  268. package/lib/generated-proto/pb_schema/cdp/cof/namespace.d.ts +8 -0
  269. package/lib/generated-proto/pb_schema/cdp/cof/namespace.js +17 -0
  270. package/lib/generated-proto/pb_schema/cdp/cof/namespace.js.map +1 -0
  271. package/lib/generated-proto/pb_schema/common/ruid.d.ts +75 -0
  272. package/lib/generated-proto/pb_schema/common/ruid.js +96 -0
  273. package/lib/generated-proto/pb_schema/common/ruid.js.map +1 -0
  274. package/lib/generated-proto/pb_schema/common/value.d.ts +131 -0
  275. package/lib/generated-proto/pb_schema/common/value.js +204 -0
  276. package/lib/generated-proto/pb_schema/common/value.js.map +1 -0
  277. package/lib/generated-proto/pb_schema/google/api/annotations.d.ts +1 -0
  278. package/lib/generated-proto/pb_schema/google/api/annotations.js +9 -0
  279. package/lib/generated-proto/pb_schema/google/api/annotations.js.map +1 -0
  280. package/lib/generated-proto/pb_schema/google/api/http.d.ts +3636 -0
  281. package/lib/generated-proto/pb_schema/google/api/http.js +271 -0
  282. package/lib/generated-proto/pb_schema/google/api/http.js.map +1 -0
  283. package/lib/generated-proto/pb_schema/google/protobuf/any.d.ts +139 -0
  284. package/lib/generated-proto/pb_schema/google/protobuf/any.js +94 -0
  285. package/lib/generated-proto/pb_schema/google/protobuf/any.js.map +1 -0
  286. package/lib/generated-proto/pb_schema/google/protobuf/descriptor.d.ts +50968 -0
  287. package/lib/generated-proto/pb_schema/google/protobuf/descriptor.js +2962 -0
  288. package/lib/generated-proto/pb_schema/google/protobuf/descriptor.js.map +1 -0
  289. package/lib/generated-proto/pb_schema/google/protobuf/timestamp.d.ts +98 -0
  290. package/lib/generated-proto/pb_schema/google/protobuf/timestamp.js +82 -0
  291. package/lib/generated-proto/pb_schema/google/protobuf/timestamp.js.map +1 -0
  292. package/lib/generated-proto/pb_schema/google/protobuf/wrappers.d.ts +173 -0
  293. package/lib/generated-proto/pb_schema/google/protobuf/wrappers.js +332 -0
  294. package/lib/generated-proto/pb_schema/google/protobuf/wrappers.js.map +1 -0
  295. package/lib/generated-proto/pb_schema/lenses/geocircle.d.ts +42 -0
  296. package/lib/generated-proto/pb_schema/lenses/geocircle.js +52 -0
  297. package/lib/generated-proto/pb_schema/lenses/geocircle.js.map +1 -0
  298. package/lib/generated-proto/pb_schema/lenses/geopoint.d.ts +32 -0
  299. package/lib/generated-proto/pb_schema/lenses/geopoint.js +50 -0
  300. package/lib/generated-proto/pb_schema/lenses/geopoint.js.map +1 -0
  301. package/lib/generated-proto/pb_schema/lenses/launch_params.d.ts +29 -0
  302. package/lib/generated-proto/pb_schema/lenses/launch_params.js +43 -0
  303. package/lib/generated-proto/pb_schema/lenses/launch_params.js.map +1 -0
  304. package/lib/generated-proto/pb_schema/lenses/launchdata.d.ts +365 -0
  305. package/lib/generated-proto/pb_schema/lenses/launchdata.js +216 -0
  306. package/lib/generated-proto/pb_schema/lenses/launchdata.js.map +1 -0
  307. package/lib/generated-proto/pb_schema/lenses/lures.d.ts +113 -0
  308. package/lib/generated-proto/pb_schema/lenses/lures.js +64 -0
  309. package/lib/generated-proto/pb_schema/lenses/lures.js.map +1 -0
  310. package/lib/generated-proto/pb_schema/lenses/persistent_store.d.ts +29 -0
  311. package/lib/generated-proto/pb_schema/lenses/persistent_store.js +43 -0
  312. package/lib/generated-proto/pb_schema/lenses/persistent_store.js.map +1 -0
  313. package/lib/generated-proto/pb_schema/lenses/snappable.d.ts +921 -0
  314. package/lib/generated-proto/pb_schema/lenses/snappable.js +954 -0
  315. package/lib/generated-proto/pb_schema/lenses/snappable.js.map +1 -0
  316. package/lib/generated-proto/pb_schema/lenses/user_data.d.ts +247 -0
  317. package/lib/generated-proto/pb_schema/lenses/user_data.js +362 -0
  318. package/lib/generated-proto/pb_schema/lenses/user_data.js.map +1 -0
  319. package/lib/handlers/HandlerChainBuilder.d.ts +95 -0
  320. package/lib/handlers/HandlerChainBuilder.js +187 -0
  321. package/lib/handlers/HandlerChainBuilder.js.map +1 -0
  322. package/lib/handlers/arrayBufferParsingHandler.d.ts +10 -0
  323. package/lib/handlers/arrayBufferParsingHandler.js +18 -0
  324. package/lib/handlers/arrayBufferParsingHandler.js.map +1 -0
  325. package/lib/handlers/batchingHandler.d.ts +25 -0
  326. package/lib/handlers/batchingHandler.js +79 -0
  327. package/lib/handlers/batchingHandler.js.map +1 -0
  328. package/lib/handlers/cameraKitServiceFetchHandlerFactory.d.ts +12 -0
  329. package/lib/handlers/cameraKitServiceFetchHandlerFactory.js +19 -0
  330. package/lib/handlers/cameraKitServiceFetchHandlerFactory.js.map +1 -0
  331. package/lib/handlers/debugHandler.d.ts +8 -0
  332. package/lib/handlers/debugHandler.js +27 -0
  333. package/lib/handlers/debugHandler.js.map +1 -0
  334. package/lib/handlers/defaultFetchHandler.d.ts +15 -0
  335. package/lib/handlers/defaultFetchHandler.js +29 -0
  336. package/lib/handlers/defaultFetchHandler.js.map +1 -0
  337. package/lib/handlers/headersModifyingFetchHandler.d.ts +8 -0
  338. package/lib/handlers/headersModifyingFetchHandler.js +13 -0
  339. package/lib/handlers/headersModifyingFetchHandler.js.map +1 -0
  340. package/lib/handlers/index.d.ts +2 -0
  341. package/lib/handlers/index.js +3 -0
  342. package/lib/handlers/index.js.map +1 -0
  343. package/lib/handlers/mappingHandler.d.ts +15 -0
  344. package/lib/handlers/mappingHandler.js +65 -0
  345. package/lib/handlers/mappingHandler.js.map +1 -0
  346. package/lib/handlers/noCorsRetryingFetchHandler.d.ts +48 -0
  347. package/lib/handlers/noCorsRetryingFetchHandler.js +94 -0
  348. package/lib/handlers/noCorsRetryingFetchHandler.js.map +1 -0
  349. package/lib/handlers/persistingHandler.d.ts +14 -0
  350. package/lib/handlers/persistingHandler.js +71 -0
  351. package/lib/handlers/persistingHandler.js.map +1 -0
  352. package/lib/handlers/rateLimitingHandler.d.ts +20 -0
  353. package/lib/handlers/rateLimitingHandler.js +43 -0
  354. package/lib/handlers/rateLimitingHandler.js.map +1 -0
  355. package/lib/handlers/requestStateEmittingHandler.d.ts +29 -0
  356. package/lib/handlers/requestStateEmittingHandler.js +43 -0
  357. package/lib/handlers/requestStateEmittingHandler.js.map +1 -0
  358. package/lib/handlers/responseCachingHandler.d.ts +27 -0
  359. package/lib/handlers/responseCachingHandler.js +94 -0
  360. package/lib/handlers/responseCachingHandler.js.map +1 -0
  361. package/lib/handlers/retryingHandler.d.ts +37 -0
  362. package/lib/handlers/retryingHandler.js +73 -0
  363. package/lib/handlers/retryingHandler.js.map +1 -0
  364. package/lib/handlers/timeoutHandler.d.ts +18 -0
  365. package/lib/handlers/timeoutHandler.js +30 -0
  366. package/lib/handlers/timeoutHandler.js.map +1 -0
  367. package/lib/index.d.ts +33 -0
  368. package/lib/index.js +32 -0
  369. package/lib/index.js.map +1 -0
  370. package/lib/legal/legalPrompt.d.ts +17 -0
  371. package/lib/legal/legalPrompt.js +144 -0
  372. package/lib/legal/legalPrompt.js.map +1 -0
  373. package/lib/legal/legalState.d.ts +50 -0
  374. package/lib/legal/legalState.js +149 -0
  375. package/lib/legal/legalState.js.map +1 -0
  376. package/lib/lens/Lens.d.ts +71 -0
  377. package/lib/lens/Lens.js +63 -0
  378. package/lib/lens/Lens.js.map +1 -0
  379. package/lib/lens/LensLaunchParams.d.ts +19 -0
  380. package/lib/lens/LensLaunchParams.js +38 -0
  381. package/lib/lens/LensLaunchParams.js.map +1 -0
  382. package/lib/lens/LensPersistenceStore.d.ts +7 -0
  383. package/lib/lens/LensPersistenceStore.js +20 -0
  384. package/lib/lens/LensPersistenceStore.js.map +1 -0
  385. package/lib/lens/LensRepository.d.ts +134 -0
  386. package/lib/lens/LensRepository.js +239 -0
  387. package/lib/lens/LensRepository.js.map +1 -0
  388. package/lib/lens/assets/LensAssetRepository.d.ts +66 -0
  389. package/lib/lens/assets/LensAssetRepository.js +179 -0
  390. package/lib/lens/assets/LensAssetRepository.js.map +1 -0
  391. package/lib/lens/assets/LensAssetsProvider.d.ts +21 -0
  392. package/lib/lens/assets/LensAssetsProvider.js +41 -0
  393. package/lib/lens/assets/LensAssetsProvider.js.map +1 -0
  394. package/lib/lens/assets/deviceDependentAssetLoader.d.ts +11 -0
  395. package/lib/lens/assets/deviceDependentAssetLoader.js +58 -0
  396. package/lib/lens/assets/deviceDependentAssetLoader.js.map +1 -0
  397. package/lib/lens/assets/remoteMediaAssetLoaderFactory.d.ts +10 -0
  398. package/lib/lens/assets/remoteMediaAssetLoaderFactory.js +26 -0
  399. package/lib/lens/assets/remoteMediaAssetLoaderFactory.js.map +1 -0
  400. package/lib/lens/assets/staticAssetLoader.d.ts +10 -0
  401. package/lib/lens/assets/staticAssetLoader.js +24 -0
  402. package/lib/lens/assets/staticAssetLoader.js.map +1 -0
  403. package/lib/lens/index.d.ts +7 -0
  404. package/lib/lens/index.js +7 -0
  405. package/lib/lens/index.js.map +1 -0
  406. package/lib/lens/lensEnvelopeUtil.d.ts +5 -0
  407. package/lib/lens/lensEnvelopeUtil.js +19 -0
  408. package/lib/lens/lensEnvelopeUtil.js.map +1 -0
  409. package/lib/lens/lensHttpUtil.d.ts +4 -0
  410. package/lib/lens/lensHttpUtil.js +30 -0
  411. package/lib/lens/lensHttpUtil.js.map +1 -0
  412. package/lib/lens-client-interface/exif.d.ts +20 -0
  413. package/lib/lens-client-interface/exif.js +61 -0
  414. package/lib/lens-client-interface/exif.js.map +1 -0
  415. package/lib/lens-client-interface/imagePicker.d.ts +7 -0
  416. package/lib/lens-client-interface/imagePicker.js +128 -0
  417. package/lib/lens-client-interface/imagePicker.js.map +1 -0
  418. package/lib/lens-client-interface/lensClientInterface.d.ts +13 -0
  419. package/lib/lens-client-interface/lensClientInterface.js +30 -0
  420. package/lib/lens-client-interface/lensClientInterface.js.map +1 -0
  421. package/lib/lens-core-module/generated-types.d.ts +426 -0
  422. package/lib/lens-core-module/generated-types.js +2 -0
  423. package/lib/lens-core-module/generated-types.js.map +1 -0
  424. package/lib/lens-core-module/index.d.ts +2 -0
  425. package/lib/lens-core-module/index.js +3 -0
  426. package/lib/lens-core-module/index.js.map +1 -0
  427. package/lib/lens-core-module/loader/index.d.ts +1 -0
  428. package/lib/lens-core-module/loader/index.js +2 -0
  429. package/lib/lens-core-module/loader/index.js.map +1 -0
  430. package/lib/lens-core-module/loader/lensCoreFactory.d.ts +30 -0
  431. package/lib/lens-core-module/loader/lensCoreFactory.js +121 -0
  432. package/lib/lens-core-module/loader/lensCoreFactory.js.map +1 -0
  433. package/lib/lensCoreWasmVersions.json +5 -0
  434. package/lib/logger/errorLoggingDecorator.d.ts +9 -0
  435. package/lib/logger/errorLoggingDecorator.js +32 -0
  436. package/lib/logger/errorLoggingDecorator.js.map +1 -0
  437. package/lib/logger/logEntries.d.ts +15 -0
  438. package/lib/logger/logEntries.js +14 -0
  439. package/lib/logger/logEntries.js.map +1 -0
  440. package/lib/logger/logger.d.ts +35 -0
  441. package/lib/logger/logger.js +48 -0
  442. package/lib/logger/logger.js.map +1 -0
  443. package/lib/logger/registerLogEntriesSubscriber.d.ts +14 -0
  444. package/lib/logger/registerLogEntriesSubscriber.js +23 -0
  445. package/lib/logger/registerLogEntriesSubscriber.js.map +1 -0
  446. package/lib/media-sources/CameraKitSource.d.ts +88 -0
  447. package/lib/media-sources/CameraKitSource.js +140 -0
  448. package/lib/media-sources/CameraKitSource.js.map +1 -0
  449. package/lib/media-sources/FunctionSource.d.ts +30 -0
  450. package/lib/media-sources/FunctionSource.js +132 -0
  451. package/lib/media-sources/FunctionSource.js.map +1 -0
  452. package/lib/media-sources/ImageSource.d.ts +13 -0
  453. package/lib/media-sources/ImageSource.js +28 -0
  454. package/lib/media-sources/ImageSource.js.map +1 -0
  455. package/lib/media-sources/MediaStreamSource.d.ts +41 -0
  456. package/lib/media-sources/MediaStreamSource.js +146 -0
  457. package/lib/media-sources/MediaStreamSource.js.map +1 -0
  458. package/lib/media-sources/VideoSource.d.ts +21 -0
  459. package/lib/media-sources/VideoSource.js +38 -0
  460. package/lib/media-sources/VideoSource.js.map +1 -0
  461. package/lib/metrics/businessEventsReporter.d.ts +37 -0
  462. package/lib/metrics/businessEventsReporter.js +160 -0
  463. package/lib/metrics/businessEventsReporter.js.map +1 -0
  464. package/lib/metrics/metricsEventTarget.d.ts +41 -0
  465. package/lib/metrics/metricsEventTarget.js +11 -0
  466. package/lib/metrics/metricsEventTarget.js.map +1 -0
  467. package/lib/metrics/metricsHandler.d.ts +9 -0
  468. package/lib/metrics/metricsHandler.js +13 -0
  469. package/lib/metrics/metricsHandler.js.map +1 -0
  470. package/lib/metrics/operationalMetricsReporter.d.ts +52 -0
  471. package/lib/metrics/operationalMetricsReporter.js +108 -0
  472. package/lib/metrics/operationalMetricsReporter.js.map +1 -0
  473. package/lib/metrics/reporters/reportBenchmarks.d.ts +10 -0
  474. package/lib/metrics/reporters/reportBenchmarks.js +29 -0
  475. package/lib/metrics/reporters/reportBenchmarks.js.map +1 -0
  476. package/lib/metrics/reporters/reportGlobalException.d.ts +19 -0
  477. package/lib/metrics/reporters/reportGlobalException.js +68 -0
  478. package/lib/metrics/reporters/reportGlobalException.js.map +1 -0
  479. package/lib/metrics/reporters/reportHttpMetrics.d.ts +17 -0
  480. package/lib/metrics/reporters/reportHttpMetrics.js +92 -0
  481. package/lib/metrics/reporters/reportHttpMetrics.js.map +1 -0
  482. package/lib/metrics/reporters/reportLegalState.d.ts +15 -0
  483. package/lib/metrics/reporters/reportLegalState.js +34 -0
  484. package/lib/metrics/reporters/reportLegalState.js.map +1 -0
  485. package/lib/metrics/reporters/reportLensAndAssetDownload.d.ts +38 -0
  486. package/lib/metrics/reporters/reportLensAndAssetDownload.js +88 -0
  487. package/lib/metrics/reporters/reportLensAndAssetDownload.js.map +1 -0
  488. package/lib/metrics/reporters/reportLensValidationFailed.d.ts +20 -0
  489. package/lib/metrics/reporters/reportLensValidationFailed.js +24 -0
  490. package/lib/metrics/reporters/reportLensValidationFailed.js.map +1 -0
  491. package/lib/metrics/reporters/reportLensView.d.ts +36 -0
  492. package/lib/metrics/reporters/reportLensView.js +101 -0
  493. package/lib/metrics/reporters/reportLensView.js.map +1 -0
  494. package/lib/metrics/reporters/reportLensWait.d.ts +33 -0
  495. package/lib/metrics/reporters/reportLensWait.js +56 -0
  496. package/lib/metrics/reporters/reportLensWait.js.map +1 -0
  497. package/lib/metrics/reporters/reportSessionException.d.ts +17 -0
  498. package/lib/metrics/reporters/reportSessionException.js +12 -0
  499. package/lib/metrics/reporters/reportSessionException.js.map +1 -0
  500. package/lib/metrics/reporters/reportUserSession.d.ts +14 -0
  501. package/lib/metrics/reporters/reportUserSession.js +67 -0
  502. package/lib/metrics/reporters/reportUserSession.js.map +1 -0
  503. package/lib/metrics/reporters/reporters.d.ts +44 -0
  504. package/lib/metrics/reporters/reporters.js +33 -0
  505. package/lib/metrics/reporters/reporters.js.map +1 -0
  506. package/lib/namedErrors.d.ts +107 -0
  507. package/lib/namedErrors.js +56 -0
  508. package/lib/namedErrors.js.map +1 -0
  509. package/lib/persistence/ExpiringPersistence.d.ts +20 -0
  510. package/lib/persistence/ExpiringPersistence.js +58 -0
  511. package/lib/persistence/ExpiringPersistence.js.map +1 -0
  512. package/lib/persistence/IndexedDBPersistence.d.ts +47 -0
  513. package/lib/persistence/IndexedDBPersistence.js +180 -0
  514. package/lib/persistence/IndexedDBPersistence.js.map +1 -0
  515. package/lib/persistence/Persistence.d.ts +25 -0
  516. package/lib/persistence/Persistence.js +10 -0
  517. package/lib/persistence/Persistence.js.map +1 -0
  518. package/lib/remote-configuration/cofHandler.d.ts +21 -0
  519. package/lib/remote-configuration/cofHandler.js +75 -0
  520. package/lib/remote-configuration/cofHandler.js.map +1 -0
  521. package/lib/remote-configuration/remoteConfiguration.d.ts +13 -0
  522. package/lib/remote-configuration/remoteConfiguration.js +43 -0
  523. package/lib/remote-configuration/remoteConfiguration.js.map +1 -0
  524. package/lib/session/CameraKitSession.d.ts +252 -0
  525. package/lib/session/CameraKitSession.js +439 -0
  526. package/lib/session/CameraKitSession.js.map +1 -0
  527. package/lib/session/CameraKitSessionEvents.d.ts +33 -0
  528. package/lib/session/CameraKitSessionEvents.js +21 -0
  529. package/lib/session/CameraKitSessionEvents.js.map +1 -0
  530. package/lib/session/LensKeyboard.d.ts +89 -0
  531. package/lib/session/LensKeyboard.js +95 -0
  532. package/lib/session/LensKeyboard.js.map +1 -0
  533. package/lib/session/LensPerformanceMeasurement.d.ts +55 -0
  534. package/lib/session/LensPerformanceMeasurement.js +91 -0
  535. package/lib/session/LensPerformanceMeasurement.js.map +1 -0
  536. package/lib/session/LensPerformanceMetrics.d.ts +31 -0
  537. package/lib/session/LensPerformanceMetrics.js +58 -0
  538. package/lib/session/LensPerformanceMetrics.js.map +1 -0
  539. package/lib/session/index.d.ts +1 -0
  540. package/lib/session/index.js +2 -0
  541. package/lib/session/index.js.map +1 -0
  542. package/lib/session/lensState.d.ts +29 -0
  543. package/lib/session/lensState.js +160 -0
  544. package/lib/session/lensState.js.map +1 -0
  545. package/lib/session/sessionState.d.ts +10 -0
  546. package/lib/session/sessionState.js +12 -0
  547. package/lib/session/sessionState.js.map +1 -0
  548. package/lib/transforms/Transform2D.d.ts +17 -0
  549. package/lib/transforms/Transform2D.js +18 -0
  550. package/lib/transforms/Transform2D.js.map +1 -0
  551. package/lib/transforms/index.d.ts +1 -0
  552. package/lib/transforms/index.js +2 -0
  553. package/lib/transforms/index.js.map +1 -0
  554. package/package.json +62 -0
@@ -0,0 +1,65 @@
1
+ import { __awaiter } from "tslib";
2
+ import { onPageHidden } from "../common/pageVisibility";
3
+ /**
4
+ * Map from one request type to another, potentially asynchronously.
5
+ *
6
+ * **NOTE:** If `maxMapConcurrency` is set to some finite number, and more requests are handled than are allowed to
7
+ * be concurrently mapped, the waiting requests will be placed into a unbounded buffer. If, for example, requests are
8
+ * handled with high frequency, `maxMapConcurrency` is low, and the `map` function returns a long-running Promise, this
9
+ * buffer could use a large amount of memory. Keep this in mind when using this handler.
10
+ *
11
+ * @param map Transform each request, may be sync or async.
12
+ * @param maxMapConcurrency If the `map` function is async, it will be invoked at most this number of times
13
+ * concurrently. Setting this to 1 could be useful if it's important for `map` to be called in serial.
14
+ * @returns {@link ChainableHandler}, suitable for use in {@link HandlerChainBuilder.map}
15
+ */
16
+ export const createMappingHandler = (map, maxMapConcurrency = Number.POSITIVE_INFINITY, flushOnPageHidden = true) => {
17
+ const buffer = [];
18
+ let mapConcurrency = 0;
19
+ const processRequest = (request) => __awaiter(void 0, void 0, void 0, function* () {
20
+ try {
21
+ mapConcurrency++;
22
+ const mapped = request.map();
23
+ // We want to make sure that if the mapping operation is not async, we don't introduce asynchronicity here
24
+ // (which unfortunately happens even if you `await` a non-Promise value). This is important so that e.g.
25
+ // handlers which run when the page is terminated can send requests synchronously, since the browser may
26
+ // not pick up any async handlers registered to run on the following event loop.
27
+ if (mapped instanceof Promise)
28
+ request.next(yield mapped);
29
+ else if (mapped)
30
+ request.next(mapped);
31
+ }
32
+ catch (error) {
33
+ request.reject(error);
34
+ }
35
+ finally {
36
+ mapConcurrency--;
37
+ }
38
+ while (buffer.length > 0 && mapConcurrency < maxMapConcurrency) {
39
+ // Safety: we just checked for `buffer.length > 0`, so the shifted value will never be undefined.
40
+ processRequest(buffer.shift());
41
+ }
42
+ });
43
+ // This may indicate that the page is being unloaded, in which case we may want to flush any buffered requests
44
+ // regardless of our max concurrency – otherwise those requests will be lost when the page terminates.
45
+ if (flushOnPageHidden) {
46
+ onPageHidden(() => {
47
+ while (buffer.length > 0)
48
+ processRequest(buffer.shift());
49
+ });
50
+ }
51
+ return (next) => (request, metadata) => {
52
+ return new Promise((resolve, reject) => {
53
+ const mappableRequest = {
54
+ map: () => map(request),
55
+ next: (mappedRequest) => next(mappedRequest, metadata).then(resolve).catch(reject),
56
+ reject,
57
+ };
58
+ if (mapConcurrency < maxMapConcurrency)
59
+ processRequest(mappableRequest);
60
+ else
61
+ buffer.push(mappableRequest);
62
+ });
63
+ };
64
+ };
65
+ //# sourceMappingURL=mappingHandler.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mappingHandler.js","sourceRoot":"","sources":["../../src/handlers/mappingHandler.ts"],"names":[],"mappings":";AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAC;AASxD;;;;;;;;;;;;GAYG;AACH,MAAM,CAAC,MAAM,oBAAoB,GAAG,CAChC,GAAqD,EACrD,oBAA4B,MAAM,CAAC,iBAAiB,EACpD,iBAAiB,GAAG,IAAI,EACwB,EAAE;IAClD,MAAM,MAAM,GAAiC,EAAE,CAAC;IAChD,IAAI,cAAc,GAAG,CAAC,CAAC;IAEvB,MAAM,cAAc,GAAG,CAAO,OAAmC,EAAE,EAAE;QACjE,IAAI;YACA,cAAc,EAAE,CAAC;YACjB,MAAM,MAAM,GAAG,OAAO,CAAC,GAAG,EAAE,CAAC;YAC7B,0GAA0G;YAC1G,wGAAwG;YACxG,wGAAwG;YACxG,gFAAgF;YAChF,IAAI,MAAM,YAAY,OAAO;gBAAE,OAAO,CAAC,IAAI,CAAC,MAAM,MAAM,CAAC,CAAC;iBACrD,IAAI,MAAM;gBAAE,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;SACzC;QAAC,OAAO,KAAK,EAAE;YACZ,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;SACzB;gBAAS;YACN,cAAc,EAAE,CAAC;SACpB;QACD,OAAO,MAAM,CAAC,MAAM,GAAG,CAAC,IAAI,cAAc,GAAG,iBAAiB,EAAE;YAC5D,iGAAiG;YACjG,cAAc,CAAC,MAAM,CAAC,KAAK,EAAG,CAAC,CAAC;SACnC;IACL,CAAC,CAAA,CAAC;IAEF,8GAA8G;IAC9G,sGAAsG;IACtG,IAAI,iBAAiB,EAAE;QACnB,YAAY,CAAC,GAAG,EAAE;YACd,OAAO,MAAM,CAAC,MAAM,GAAG,CAAC;gBAAE,cAAc,CAAC,MAAM,CAAC,KAAK,EAAG,CAAC,CAAC;QAC9D,CAAC,CAAC,CAAC;KACN;IAED,OAAO,CAAC,IAAmC,EAAE,EAAE,CAAC,CAAC,OAAY,EAAE,QAAe,EAAE,EAAE;QAC9E,OAAO,IAAI,OAAO,CAAM,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;YACxC,MAAM,eAAe,GAA+B;gBAChD,GAAG,EAAE,GAAG,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC;gBACvB,IAAI,EAAE,CAAC,aAAa,EAAE,EAAE,CAAC,IAAI,CAAC,aAAa,EAAE,QAAQ,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC;gBAClF,MAAM;aACT,CAAC;YACF,IAAI,cAAc,GAAG,iBAAiB;gBAAE,cAAc,CAAC,eAAe,CAAC,CAAC;;gBACnE,MAAM,CAAC,IAAI,CAAC,eAAe,CAAC,CAAC;QACtC,CAAC,CAAC,CAAC;IACP,CAAC,CAAC;AACN,CAAC,CAAC","sourcesContent":["import { onPageHidden } from \"../common/pageVisibility\";\nimport { ChainableHandler, Handler, RequestMetadata } from \"./HandlerChainBuilder\";\n\ninterface MappableRequest<T> {\n map: () => T | Promise<T>;\n next: (request: T) => Promise<void>;\n reject: (reason: unknown) => void;\n}\n\n/**\n * Map from one request type to another, potentially asynchronously.\n *\n * **NOTE:** If `maxMapConcurrency` is set to some finite number, and more requests are handled than are allowed to\n * be concurrently mapped, the waiting requests will be placed into a unbounded buffer. If, for example, requests are\n * handled with high frequency, `maxMapConcurrency` is low, and the `map` function returns a long-running Promise, this\n * buffer could use a large amount of memory. Keep this in mind when using this handler.\n *\n * @param map Transform each request, may be sync or async.\n * @param maxMapConcurrency If the `map` function is async, it will be invoked at most this number of times\n * concurrently. Setting this to 1 could be useful if it's important for `map` to be called in serial.\n * @returns {@link ChainableHandler}, suitable for use in {@link HandlerChainBuilder.map}\n */\nexport const createMappingHandler = <Req, MappedReq, Res, Meta extends RequestMetadata>(\n map: (request: Req) => MappedReq | Promise<MappedReq>,\n maxMapConcurrency: number = Number.POSITIVE_INFINITY,\n flushOnPageHidden = true\n): ChainableHandler<Req, Res, MappedReq, Res, Meta> => {\n const buffer: MappableRequest<MappedReq>[] = [];\n let mapConcurrency = 0;\n\n const processRequest = async (request: MappableRequest<MappedReq>) => {\n try {\n mapConcurrency++;\n const mapped = request.map();\n // We want to make sure that if the mapping operation is not async, we don't introduce asynchronicity here\n // (which unfortunately happens even if you `await` a non-Promise value). This is important so that e.g.\n // handlers which run when the page is terminated can send requests synchronously, since the browser may\n // not pick up any async handlers registered to run on the following event loop.\n if (mapped instanceof Promise) request.next(await mapped);\n else if (mapped) request.next(mapped);\n } catch (error) {\n request.reject(error);\n } finally {\n mapConcurrency--;\n }\n while (buffer.length > 0 && mapConcurrency < maxMapConcurrency) {\n // Safety: we just checked for `buffer.length > 0`, so the shifted value will never be undefined.\n processRequest(buffer.shift()!);\n }\n };\n\n // This may indicate that the page is being unloaded, in which case we may want to flush any buffered requests\n // regardless of our max concurrency – otherwise those requests will be lost when the page terminates.\n if (flushOnPageHidden) {\n onPageHidden(() => {\n while (buffer.length > 0) processRequest(buffer.shift()!);\n });\n }\n\n return (next: Handler<MappedReq, Res, Meta>) => (request: Req, metadata?: Meta) => {\n return new Promise<Res>((resolve, reject) => {\n const mappableRequest: MappableRequest<MappedReq> = {\n map: () => map(request),\n next: (mappedRequest) => next(mappedRequest, metadata).then(resolve).catch(reject),\n reject,\n };\n if (mapConcurrency < maxMapConcurrency) processRequest(mappableRequest);\n else buffer.push(mappableRequest);\n });\n };\n};\n"]}
@@ -0,0 +1,48 @@
1
+ import { ChainableHandler } from "./HandlerChainBuilder";
2
+ /**
3
+ * Some requests may require a no-cors pre-flight (which are allowed to follow redirects) before they can be
4
+ * successful.
5
+ *
6
+ * An example is a federated identity authentication flow, like OpenID Connect or OAuth. In many such schemes,
7
+ * an unauthenticated request will not include CORs headers. Instead, a redirect to an Identity Provider will be
8
+ * returned. In order follow this redirect, the Fetch request must be made with "no-cors" mode.
9
+ *
10
+ * Once the "no-cors" request is made, redirects are followed resulting in authentication cookies being set on the
11
+ * original domain. Then, the original request can be retried and the server will authenticate the request and set
12
+ * proper CORs headers on the response.
13
+ *
14
+ * Here's an example request flow, in which the page already has cookies for IdentityProvider.com (if that wasn't
15
+ * the case, IdentityProvider.com would prompt the user for credentials and the rest of the flow would be the same):
16
+ *
17
+ * ```
18
+ * WebPage a.com MyServer b.com IdentityProvider c.com
19
+ * | | |
20
+ * Original request, | |
21
+ * unauthenticated: | |
22
+ * |------------------------>| |
23
+ * |<--302: c.com, no CORs---| |
24
+ * | | |
25
+ * | | |
26
+ * No CORs headers in | |
27
+ * response. Retry in | |
28
+ * "no-cors" mode: | |
29
+ * |-----"no-cors" mode----->| |
30
+ * |<--302: c.com, no CORs---| |
31
+ * | | |
32
+ * | | |
33
+ * |------------------IdP cookies------------->|
34
+ * |<----------302: b.com?token=foo------------|
35
+ * | |
36
+ * | | |
37
+ * |----b.com?token=foo----->| |
38
+ * |<-302: b.com, set cookie-| |
39
+ * | | |
40
+ * | | |
41
+ * Retry original request, | |
42
+ * now authenticated: | |
43
+ * |-----------cookie------->| |
44
+ * |<-----------200----------| |
45
+ * | |
46
+ * ```
47
+ */
48
+ export declare const createNoCorsRetryingFetchHandler: <Res>() => ChainableHandler<RequestInfo, Res, RequestInfo, Res, RequestInit | undefined>;
@@ -0,0 +1,94 @@
1
+ import { __awaiter } from "tslib";
2
+ import { getLogger } from "../logger/logger";
3
+ const logger = getLogger("noCorsRetryingFetchHandler");
4
+ const logRetry = (error) => {
5
+ logger.warn(`NoCorsRetrying handler got failed response:`, error, `Retrying request with {mode: "no-cors"}.`);
6
+ };
7
+ /**
8
+ * Some requests may require a no-cors pre-flight (which are allowed to follow redirects) before they can be
9
+ * successful.
10
+ *
11
+ * An example is a federated identity authentication flow, like OpenID Connect or OAuth. In many such schemes,
12
+ * an unauthenticated request will not include CORs headers. Instead, a redirect to an Identity Provider will be
13
+ * returned. In order follow this redirect, the Fetch request must be made with "no-cors" mode.
14
+ *
15
+ * Once the "no-cors" request is made, redirects are followed resulting in authentication cookies being set on the
16
+ * original domain. Then, the original request can be retried and the server will authenticate the request and set
17
+ * proper CORs headers on the response.
18
+ *
19
+ * Here's an example request flow, in which the page already has cookies for IdentityProvider.com (if that wasn't
20
+ * the case, IdentityProvider.com would prompt the user for credentials and the rest of the flow would be the same):
21
+ *
22
+ * ```
23
+ * WebPage a.com MyServer b.com IdentityProvider c.com
24
+ * | | |
25
+ * Original request, | |
26
+ * unauthenticated: | |
27
+ * |------------------------>| |
28
+ * |<--302: c.com, no CORs---| |
29
+ * | | |
30
+ * | | |
31
+ * No CORs headers in | |
32
+ * response. Retry in | |
33
+ * "no-cors" mode: | |
34
+ * |-----"no-cors" mode----->| |
35
+ * |<--302: c.com, no CORs---| |
36
+ * | | |
37
+ * | | |
38
+ * |------------------IdP cookies------------->|
39
+ * |<----------302: b.com?token=foo------------|
40
+ * | |
41
+ * | | |
42
+ * |----b.com?token=foo----->| |
43
+ * |<-302: b.com, set cookie-| |
44
+ * | | |
45
+ * | | |
46
+ * Retry original request, | |
47
+ * now authenticated: | |
48
+ * |-----------cookie------->| |
49
+ * |<-----------200----------| |
50
+ * | |
51
+ * ```
52
+ */
53
+ export const createNoCorsRetryingFetchHandler = () => {
54
+ // If concurrent requests are made to the same domain, we only want to perform one "no-cors" request. We assume
55
+ // requests to the same domain will set the same authentication cookies. To support this, we'll store any
56
+ // in-flight "no-cors" retries and re-use them for concurrent requests.
57
+ const noCorsRequests = new Map();
58
+ return (next) => (input, init = {}) => __awaiter(void 0, void 0, void 0, function* () {
59
+ var _a;
60
+ // `host` includes domain:port, so works for local development. If the input is a relative path, we'll
61
+ // use `location.origin` to resolve into a fully qualified URL (although of course we don't actually
62
+ // anticipate any CORs issues in that case -- but this is cleaner than special-casing).
63
+ let requestKey = typeof input === "string" ? input : input.url;
64
+ try {
65
+ requestKey = new URL(requestKey, location.origin).host;
66
+ }
67
+ catch (_) {
68
+ /* no-op, use the full input URL as the requestKey */
69
+ }
70
+ try {
71
+ // By always attempting the request first, we avoid needing to maintain any state about the validity
72
+ // of the request (e.g. the expiration time for a credential). We just make the request, and if it
73
+ // fails, this tells us we've made an invalid request. This does result in one additional request, but
74
+ // it makes this much more flexible and avoids having to maintain state (which can be a source of bugs).
75
+ return yield next(input, init);
76
+ }
77
+ catch (error) {
78
+ // If the request fails because it was aborted, we assume this was done intentionally and we can stop.
79
+ if (error instanceof Error && error.name === "AbortError")
80
+ throw error;
81
+ // Otherwise we don't actually care what error occurred – we know this will be an error thrown by
82
+ // `fetch` itself (rather than some error encountered on the server, which wouldn't cause `next` to
83
+ // throw), and we'll just assume it's a CORs error. If it's not, we'll perform a "no-cors" retry anyway,
84
+ // which will presumably also fail, and that failure will be returned to the caller.
85
+ logRetry(error);
86
+ const noCorsRequest = (_a = noCorsRequests.get(requestKey)) !== null && _a !== void 0 ? _a : next(input, Object.assign(Object.assign({}, init), { mode: "no-cors" }));
87
+ noCorsRequests.set(requestKey, noCorsRequest);
88
+ yield noCorsRequest;
89
+ noCorsRequests.delete(requestKey);
90
+ return next(input, init);
91
+ }
92
+ });
93
+ };
94
+ //# sourceMappingURL=noCorsRetryingFetchHandler.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"noCorsRetryingFetchHandler.js","sourceRoot":"","sources":["../../src/handlers/noCorsRetryingFetchHandler.ts"],"names":[],"mappings":";AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAG7C,MAAM,MAAM,GAAG,SAAS,CAAC,4BAA4B,CAAC,CAAC;AAEvD,MAAM,QAAQ,GAAG,CAAC,KAAU,EAAE,EAAE;IAC5B,MAAM,CAAC,IAAI,CAAC,6CAA6C,EAAE,KAAK,EAAE,0CAA0C,CAAC,CAAC;AAClH,CAAC,CAAC;AAEF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6CG;AACH,MAAM,CAAC,MAAM,gCAAgC,GAAG,GAM9C,EAAE;IACA,+GAA+G;IAC/G,yGAAyG;IACzG,uEAAuE;IACvE,MAAM,cAAc,GAAG,IAAI,GAAG,EAAwB,CAAC;IAEvD,OAAO,CAAC,IAAI,EAAE,EAAE,CAAC,CAAO,KAAK,EAAE,IAAI,GAAG,EAAE,EAAE,EAAE;;QACxC,sGAAsG;QACtG,oGAAoG;QACpG,uFAAuF;QACvF,IAAI,UAAU,GAAG,OAAO,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC;QAC/D,IAAI;YACA,UAAU,GAAG,IAAI,GAAG,CAAC,UAAU,EAAE,QAAQ,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC;SAC1D;QAAC,OAAO,CAAC,EAAE;YACR,qDAAqD;SACxD;QAED,IAAI;YACA,oGAAoG;YACpG,kGAAkG;YAClG,sGAAsG;YACtG,wGAAwG;YACxG,OAAO,MAAM,IAAI,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC;SAClC;QAAC,OAAO,KAAK,EAAE;YACZ,sGAAsG;YACtG,IAAI,KAAK,YAAY,KAAK,IAAI,KAAK,CAAC,IAAI,KAAK,YAAY;gBAAE,MAAM,KAAK,CAAC;YAEvE,iGAAiG;YACjG,mGAAmG;YACnG,wGAAwG;YACxG,oFAAoF;YACpF,QAAQ,CAAC,KAAK,CAAC,CAAC;YAChB,MAAM,aAAa,GAAG,MAAA,cAAc,CAAC,GAAG,CAAC,UAAU,CAAC,mCAAI,IAAI,CAAC,KAAK,kCAAO,IAAI,KAAE,IAAI,EAAE,SAAS,IAAG,CAAC;YAClG,cAAc,CAAC,GAAG,CAAC,UAAU,EAAE,aAAa,CAAC,CAAC;YAC9C,MAAM,aAAa,CAAC;YACpB,cAAc,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC;YAClC,OAAO,IAAI,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC;SAC5B;IACL,CAAC,CAAA,CAAC;AACN,CAAC,CAAC","sourcesContent":["import { getLogger } from \"../logger/logger\";\nimport { ChainableHandler } from \"./HandlerChainBuilder\";\n\nconst logger = getLogger(\"noCorsRetryingFetchHandler\");\n\nconst logRetry = (error: any) => {\n logger.warn(`NoCorsRetrying handler got failed response:`, error, `Retrying request with {mode: \"no-cors\"}.`);\n};\n\n/**\n * Some requests may require a no-cors pre-flight (which are allowed to follow redirects) before they can be\n * successful.\n *\n * An example is a federated identity authentication flow, like OpenID Connect or OAuth. In many such schemes,\n * an unauthenticated request will not include CORs headers. Instead, a redirect to an Identity Provider will be\n * returned. In order follow this redirect, the Fetch request must be made with \"no-cors\" mode.\n *\n * Once the \"no-cors\" request is made, redirects are followed resulting in authentication cookies being set on the\n * original domain. Then, the original request can be retried and the server will authenticate the request and set\n * proper CORs headers on the response.\n *\n * Here's an example request flow, in which the page already has cookies for IdentityProvider.com (if that wasn't\n * the case, IdentityProvider.com would prompt the user for credentials and the rest of the flow would be the same):\n *\n * ```\n * WebPage a.com MyServer b.com IdentityProvider c.com\n * | | |\n * Original request, | |\n * unauthenticated: | |\n * |------------------------>| |\n * |<--302: c.com, no CORs---| |\n * | | |\n * | | |\n * No CORs headers in | |\n * response. Retry in | |\n * \"no-cors\" mode: | |\n * |-----\"no-cors\" mode----->| |\n * |<--302: c.com, no CORs---| |\n * | | |\n * | | |\n * |------------------IdP cookies------------->|\n * |<----------302: b.com?token=foo------------|\n * | |\n * | | |\n * |----b.com?token=foo----->| |\n * |<-302: b.com, set cookie-| |\n * | | |\n * | | |\n * Retry original request, | |\n * now authenticated: | |\n * |-----------cookie------->| |\n * |<-----------200----------| |\n * | |\n * ```\n */\nexport const createNoCorsRetryingFetchHandler = <Res>(): ChainableHandler<\n RequestInfo,\n Res,\n RequestInfo,\n Res,\n RequestInit | undefined\n> => {\n // If concurrent requests are made to the same domain, we only want to perform one \"no-cors\" request. We assume\n // requests to the same domain will set the same authentication cookies. To support this, we'll store any\n // in-flight \"no-cors\" retries and re-use them for concurrent requests.\n const noCorsRequests = new Map<string, Promise<Res>>();\n\n return (next) => async (input, init = {}) => {\n // `host` includes domain:port, so works for local development. If the input is a relative path, we'll\n // use `location.origin` to resolve into a fully qualified URL (although of course we don't actually\n // anticipate any CORs issues in that case -- but this is cleaner than special-casing).\n let requestKey = typeof input === \"string\" ? input : input.url;\n try {\n requestKey = new URL(requestKey, location.origin).host;\n } catch (_) {\n /* no-op, use the full input URL as the requestKey */\n }\n\n try {\n // By always attempting the request first, we avoid needing to maintain any state about the validity\n // of the request (e.g. the expiration time for a credential). We just make the request, and if it\n // fails, this tells us we've made an invalid request. This does result in one additional request, but\n // it makes this much more flexible and avoids having to maintain state (which can be a source of bugs).\n return await next(input, init);\n } catch (error) {\n // If the request fails because it was aborted, we assume this was done intentionally and we can stop.\n if (error instanceof Error && error.name === \"AbortError\") throw error;\n\n // Otherwise we don't actually care what error occurred – we know this will be an error thrown by\n // `fetch` itself (rather than some error encountered on the server, which wouldn't cause `next` to\n // throw), and we'll just assume it's a CORs error. If it's not, we'll perform a \"no-cors\" retry anyway,\n // which will presumably also fail, and that failure will be returned to the caller.\n logRetry(error);\n const noCorsRequest = noCorsRequests.get(requestKey) ?? next(input, { ...init, mode: \"no-cors\" });\n noCorsRequests.set(requestKey, noCorsRequest);\n await noCorsRequest;\n noCorsRequests.delete(requestKey);\n return next(input, init);\n }\n };\n};\n"]}
@@ -0,0 +1,14 @@
1
+ import { Persistence } from "../persistence/Persistence";
2
+ import { ChainableHandler, RequestMetadata } from "./HandlerChainBuilder";
3
+ /**
4
+ * This handler persists in-flight requests locally, so that if there is an unexpected termination of the process (e.g.
5
+ * the browser tab crashes or is closed) those requests can be recovered and retried on the next page load.
6
+ *
7
+ * Keep in mind, using this handler means some *successful* requests may be repeated (e.g. if the request made it to a
8
+ * server, which responded, but the response didn't reach the browser before the tab closed). Any handler chain making
9
+ * use of this handler should only handle idempotent requests.
10
+ *
11
+ * @param persistence Requests will be temporarily stored here while they are in-flight.
12
+ * @returns {@link ChainableHandler}, suitable for use in {@link HandlerChainBuilder.map}
13
+ */
14
+ export declare const createPersistingHandler: <Req, Res, Meta extends RequestMetadata>(persistence: Persistence<[Req, Meta | undefined]>) => ChainableHandler<Req, Res, Req, Res, Meta>;
@@ -0,0 +1,71 @@
1
+ import { __awaiter } from "tslib";
2
+ import { getLogger } from "../logger/logger";
3
+ const logger = getLogger("persistingHandler");
4
+ /**
5
+ * This handler persists in-flight requests locally, so that if there is an unexpected termination of the process (e.g.
6
+ * the browser tab crashes or is closed) those requests can be recovered and retried on the next page load.
7
+ *
8
+ * Keep in mind, using this handler means some *successful* requests may be repeated (e.g. if the request made it to a
9
+ * server, which responded, but the response didn't reach the browser before the tab closed). Any handler chain making
10
+ * use of this handler should only handle idempotent requests.
11
+ *
12
+ * @param persistence Requests will be temporarily stored here while they are in-flight.
13
+ * @returns {@link ChainableHandler}, suitable for use in {@link HandlerChainBuilder.map}
14
+ */
15
+ export const createPersistingHandler = (persistence) => {
16
+ let needsRecovery = true;
17
+ const maybePerformRecovery = (next) => __awaiter(void 0, void 0, void 0, function* () {
18
+ if (!needsRecovery)
19
+ return;
20
+ needsRecovery = false;
21
+ try {
22
+ const requests = yield persistence.removeAll();
23
+ if (requests.length === 0)
24
+ return;
25
+ // If a recovered request fails, we'll report the error and prevent it from disrupting other requests. We
26
+ // won't re-persist to avoid a poison-pill request that remains in storage forever.
27
+ requests.forEach(([request, metadata]) => performRequest(next)(request, metadata).catch((error) => {
28
+ logger.error(error);
29
+ }));
30
+ // If we fail to retrieve, we have no option but to report the error and proceed. Since we can't tell here
31
+ // if there were any requests to recover, we cannot say if an error here will actually result in data loss.
32
+ }
33
+ catch (error) {
34
+ // TODO: we will also want to report persistence size (either here or elsewhere) to detect scenarious that
35
+ // could result in unbounded DB growth.
36
+ logger.error(error);
37
+ }
38
+ });
39
+ const performRequest = (next) => (req, metadata) => __awaiter(void 0, void 0, void 0, function* () {
40
+ // If there are requests to be recovered (e.g. a prior session crashed while requests were in-flight), they will
41
+ // be passed to the next handler in the chain. This will happen at most once per page load.
42
+ maybePerformRecovery(next);
43
+ // Whether the persistence succeeds or fails, we always want to make the request – so we don't need to wait for
44
+ // the request to be stored before passing it to the `next` handler. This is why we're not awaiting the store
45
+ // call here. We'll also swallow any errors, simply returning `null` for the key – persistence and recovery are
46
+ // always best-effort, and failure should not disrupt other application behavior.
47
+ const keyPromise = persistence.store([req, metadata]).catch((error) => {
48
+ logger.error(error);
49
+ return null;
50
+ });
51
+ try {
52
+ return yield next(req, metadata);
53
+ }
54
+ finally {
55
+ // We don't care if the request was successful or not, either way once it is completed we will remove
56
+ // the request from the persistent store.
57
+ keyPromise
58
+ .then((key) => {
59
+ if (key !== null)
60
+ return persistence.remove(key);
61
+ return;
62
+ })
63
+ // If removal fails, we will recover and re-send the request – failure could occur if the OS cannot
64
+ // complete the DB transaction (e.g. power loss), or potentially in other exceptional scenarios.
65
+ // Therefore it's important that requests handled by this handler be idempotent.
66
+ .catch((error) => logger.error(error));
67
+ }
68
+ });
69
+ return performRequest;
70
+ };
71
+ //# sourceMappingURL=persistingHandler.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"persistingHandler.js","sourceRoot":"","sources":["../../src/handlers/persistingHandler.ts"],"names":[],"mappings":";AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAI7C,MAAM,MAAM,GAAG,SAAS,CAAC,mBAAmB,CAAC,CAAC;AAE9C;;;;;;;;;;GAUG;AACH,MAAM,CAAC,MAAM,uBAAuB,GAAG,CACnC,WAAiD,EACP,EAAE;IAC5C,IAAI,aAAa,GAAG,IAAI,CAAC;IACzB,MAAM,oBAAoB,GAAG,CAAO,IAA6B,EAAE,EAAE;QACjE,IAAI,CAAC,aAAa;YAAE,OAAO;QAC3B,aAAa,GAAG,KAAK,CAAC;QACtB,IAAI;YACA,MAAM,QAAQ,GAAG,MAAM,WAAW,CAAC,SAAS,EAAE,CAAC;YAC/C,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC;gBAAE,OAAO;YAClC,yGAAyG;YACzG,mFAAmF;YACnF,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC,OAAO,EAAE,QAAQ,CAAC,EAAE,EAAE,CACrC,cAAc,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC,KAAK,CAAC,CAAC,KAAK,EAAE,EAAE;gBACpD,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;YACxB,CAAC,CAAC,CACL,CAAC;YAEF,0GAA0G;YAC1G,2GAA2G;SAC9G;QAAC,OAAO,KAAK,EAAE;YACZ,0GAA0G;YAC1G,uCAAuC;YACvC,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;SACvB;IACL,CAAC,CAAA,CAAC;IAEF,MAAM,cAAc,GAAG,CAAC,IAA6B,EAAE,EAAE,CAAC,CAAO,GAAQ,EAAE,QAAe,EAAE,EAAE;QAC1F,gHAAgH;QAChH,2FAA2F;QAC3F,oBAAoB,CAAC,IAAI,CAAC,CAAC;QAE3B,+GAA+G;QAC/G,6GAA6G;QAC7G,+GAA+G;QAC/G,iFAAiF;QACjF,MAAM,UAAU,GAAG,WAAW,CAAC,KAAK,CAAC,CAAC,GAAG,EAAE,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,KAAK,EAAE,EAAE;YAClE,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;YACpB,OAAO,IAAI,CAAC;QAChB,CAAC,CAAC,CAAC;QACH,IAAI;YACA,OAAO,MAAM,IAAI,CAAC,GAAG,EAAE,QAAQ,CAAC,CAAC;SACpC;gBAAS;YACN,qGAAqG;YACrG,yCAAyC;YACzC,UAAU;iBACL,IAAI,CAAC,CAAC,GAAG,EAAE,EAAE;gBACV,IAAI,GAAG,KAAK,IAAI;oBAAE,OAAO,WAAW,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;gBACjD,OAAO;YACX,CAAC,CAAC;gBACF,mGAAmG;gBACnG,gGAAgG;gBAChG,gFAAgF;iBAC/E,KAAK,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC;SAC9C;IACL,CAAC,CAAA,CAAC;IACF,OAAO,cAAc,CAAC;AAC1B,CAAC,CAAC","sourcesContent":["import { getLogger } from \"../logger/logger\";\nimport { Persistence } from \"../persistence/Persistence\";\nimport { ChainableHandler, Handler, RequestMetadata } from \"./HandlerChainBuilder\";\n\nconst logger = getLogger(\"persistingHandler\");\n\n/**\n * This handler persists in-flight requests locally, so that if there is an unexpected termination of the process (e.g.\n * the browser tab crashes or is closed) those requests can be recovered and retried on the next page load.\n *\n * Keep in mind, using this handler means some *successful* requests may be repeated (e.g. if the request made it to a\n * server, which responded, but the response didn't reach the browser before the tab closed). Any handler chain making\n * use of this handler should only handle idempotent requests.\n *\n * @param persistence Requests will be temporarily stored here while they are in-flight.\n * @returns {@link ChainableHandler}, suitable for use in {@link HandlerChainBuilder.map}\n */\nexport const createPersistingHandler = <Req, Res, Meta extends RequestMetadata>(\n persistence: Persistence<[Req, Meta | undefined]>\n): ChainableHandler<Req, Res, Req, Res, Meta> => {\n let needsRecovery = true;\n const maybePerformRecovery = async (next: Handler<Req, Res, Meta>) => {\n if (!needsRecovery) return;\n needsRecovery = false;\n try {\n const requests = await persistence.removeAll();\n if (requests.length === 0) return;\n // If a recovered request fails, we'll report the error and prevent it from disrupting other requests. We\n // won't re-persist to avoid a poison-pill request that remains in storage forever.\n requests.forEach(([request, metadata]) =>\n performRequest(next)(request, metadata).catch((error) => {\n logger.error(error);\n })\n );\n\n // If we fail to retrieve, we have no option but to report the error and proceed. Since we can't tell here\n // if there were any requests to recover, we cannot say if an error here will actually result in data loss.\n } catch (error) {\n // TODO: we will also want to report persistence size (either here or elsewhere) to detect scenarious that\n // could result in unbounded DB growth.\n logger.error(error);\n }\n };\n\n const performRequest = (next: Handler<Req, Res, Meta>) => async (req: Req, metadata?: Meta) => {\n // If there are requests to be recovered (e.g. a prior session crashed while requests were in-flight), they will\n // be passed to the next handler in the chain. This will happen at most once per page load.\n maybePerformRecovery(next);\n\n // Whether the persistence succeeds or fails, we always want to make the request – so we don't need to wait for\n // the request to be stored before passing it to the `next` handler. This is why we're not awaiting the store\n // call here. We'll also swallow any errors, simply returning `null` for the key – persistence and recovery are\n // always best-effort, and failure should not disrupt other application behavior.\n const keyPromise = persistence.store([req, metadata]).catch((error) => {\n logger.error(error);\n return null;\n });\n try {\n return await next(req, metadata);\n } finally {\n // We don't care if the request was successful or not, either way once it is completed we will remove\n // the request from the persistent store.\n keyPromise\n .then((key) => {\n if (key !== null) return persistence.remove(key);\n return;\n })\n // If removal fails, we will recover and re-send the request – failure could occur if the OS cannot\n // complete the DB transaction (e.g. power loss), or potentially in other exceptional scenarios.\n // Therefore it's important that requests handled by this handler be idempotent.\n .catch((error) => logger.error(error));\n }\n };\n return performRequest;\n};\n"]}
@@ -0,0 +1,20 @@
1
+ import { ChainableHandler, RequestMetadata } from "./HandlerChainBuilder";
2
+ /**
3
+ * Limit the rate at which requests are passed to the next handler in the chain.
4
+ *
5
+ * During any page transitions to "hidden" – possibly indicating the page is about to terminate – requests will not be
6
+ * rate limited, to ensure that they are not lost.
7
+ *
8
+ * TODO: If there are requests in the queue waiting to be sent when the page transitions to "hidden," these will not
9
+ * be immediately sent. This means there still is an edge case in which a request may be lost on page termination. This
10
+ * can be fixed with changes to `createMappingHandler`.
11
+ *
12
+ * **NOTE:** Under the hood, requests that come in faster than the set `duration` are placed in an unbounded buffer.
13
+ * If many requests are made quickly and `duration` is long, this could result in high memory usage. Keep this in mind
14
+ * when using this handler.
15
+ *
16
+ * @param duration In milliseconds. Requests will be passed to the next handler in the chain no faster than this. That
17
+ * is, if `duration` is `1000`, the next handler will be called at most once per second.
18
+ * @returns {@link ChainableHandler}, suitable for use in {@link HandlerChainBuilder.map}
19
+ */
20
+ export declare const createRateLimitingHandler: <Req, Res, Meta extends RequestMetadata>(duration: number, flushOnPageHidden?: boolean) => ChainableHandler<Req, Res, Req, Res, Meta>;
@@ -0,0 +1,43 @@
1
+ import { __awaiter } from "tslib";
2
+ import { isDuringVisibilityTransition } from "../common/pageVisibility";
3
+ import { createMappingHandler } from "./mappingHandler";
4
+ const delay = (duration) => new Promise((resolve) => setTimeout(resolve, duration));
5
+ /**
6
+ * Limit the rate at which requests are passed to the next handler in the chain.
7
+ *
8
+ * During any page transitions to "hidden" – possibly indicating the page is about to terminate – requests will not be
9
+ * rate limited, to ensure that they are not lost.
10
+ *
11
+ * TODO: If there are requests in the queue waiting to be sent when the page transitions to "hidden," these will not
12
+ * be immediately sent. This means there still is an edge case in which a request may be lost on page termination. This
13
+ * can be fixed with changes to `createMappingHandler`.
14
+ *
15
+ * **NOTE:** Under the hood, requests that come in faster than the set `duration` are placed in an unbounded buffer.
16
+ * If many requests are made quickly and `duration` is long, this could result in high memory usage. Keep this in mind
17
+ * when using this handler.
18
+ *
19
+ * @param duration In milliseconds. Requests will be passed to the next handler in the chain no faster than this. That
20
+ * is, if `duration` is `1000`, the next handler will be called at most once per second.
21
+ * @returns {@link ChainableHandler}, suitable for use in {@link HandlerChainBuilder.map}
22
+ */
23
+ export const createRateLimitingHandler = (duration, flushOnPageHidden = true) => {
24
+ let mostRecentSendTime = undefined;
25
+ const mappingHandler = createMappingHandler((request) => __awaiter(void 0, void 0, void 0, function* () {
26
+ if (mostRecentSendTime !== undefined) {
27
+ const millisUntilNextSend = duration - (Date.now() - mostRecentSendTime);
28
+ if (millisUntilNextSend > 0)
29
+ yield delay(millisUntilNextSend);
30
+ }
31
+ mostRecentSendTime = Date.now();
32
+ return request;
33
+ }), 1, flushOnPageHidden);
34
+ return (next) => (request, metadata) => {
35
+ // Requests may be made while the page is transitioning to hidden – for example, the page is being unloaded and
36
+ // we're reporting final metrics. In this case, we need to skip rate limiting and synchronously call `next`
37
+ // so that the request is not lost.
38
+ if (isDuringVisibilityTransition("hidden") && flushOnPageHidden)
39
+ return next(request, metadata);
40
+ return mappingHandler(next)(request, metadata);
41
+ };
42
+ };
43
+ //# sourceMappingURL=rateLimitingHandler.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rateLimitingHandler.js","sourceRoot":"","sources":["../../src/handlers/rateLimitingHandler.ts"],"names":[],"mappings":";AAAA,OAAO,EAAE,4BAA4B,EAAE,MAAM,0BAA0B,CAAC;AAExE,OAAO,EAAE,oBAAoB,EAAE,MAAM,kBAAkB,CAAC;AAExD,MAAM,KAAK,GAAG,CAAC,QAAgB,EAAE,EAAE,CAAC,IAAI,OAAO,CAAO,CAAC,OAAO,EAAE,EAAE,CAAC,UAAU,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC,CAAC;AAElG;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAM,CAAC,MAAM,yBAAyB,GAAG,CACrC,QAAgB,EAChB,iBAAiB,GAAG,IAAI,EACkB,EAAE;IAC5C,IAAI,kBAAkB,GAAuB,SAAS,CAAC;IAEvD,MAAM,cAAc,GAAG,oBAAoB,CACvC,CAAO,OAAO,EAAE,EAAE;QACd,IAAI,kBAAkB,KAAK,SAAS,EAAE;YAClC,MAAM,mBAAmB,GAAG,QAAQ,GAAG,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,kBAAkB,CAAC,CAAC;YACzE,IAAI,mBAAmB,GAAG,CAAC;gBAAE,MAAM,KAAK,CAAC,mBAAmB,CAAC,CAAC;SACjE;QACD,kBAAkB,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QAChC,OAAO,OAAO,CAAC;IACnB,CAAC,CAAA,EACD,CAAC,EACD,iBAAiB,CACpB,CAAC;IAEF,OAAO,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,OAAO,EAAE,QAAQ,EAAE,EAAE;QACnC,+GAA+G;QAC/G,2GAA2G;QAC3G,mCAAmC;QACnC,IAAI,4BAA4B,CAAC,QAAQ,CAAC,IAAI,iBAAiB;YAAE,OAAO,IAAI,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC;QAChG,OAAO,cAAc,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC;IACnD,CAAC,CAAC;AACN,CAAC,CAAC","sourcesContent":["import { isDuringVisibilityTransition } from \"../common/pageVisibility\";\nimport { ChainableHandler, RequestMetadata } from \"./HandlerChainBuilder\";\nimport { createMappingHandler } from \"./mappingHandler\";\n\nconst delay = (duration: number) => new Promise<void>((resolve) => setTimeout(resolve, duration));\n\n/**\n * Limit the rate at which requests are passed to the next handler in the chain.\n *\n * During any page transitions to \"hidden\" – possibly indicating the page is about to terminate – requests will not be\n * rate limited, to ensure that they are not lost.\n *\n * TODO: If there are requests in the queue waiting to be sent when the page transitions to \"hidden,\" these will not\n * be immediately sent. This means there still is an edge case in which a request may be lost on page termination. This\n * can be fixed with changes to `createMappingHandler`.\n *\n * **NOTE:** Under the hood, requests that come in faster than the set `duration` are placed in an unbounded buffer.\n * If many requests are made quickly and `duration` is long, this could result in high memory usage. Keep this in mind\n * when using this handler.\n *\n * @param duration In milliseconds. Requests will be passed to the next handler in the chain no faster than this. That\n * is, if `duration` is `1000`, the next handler will be called at most once per second.\n * @returns {@link ChainableHandler}, suitable for use in {@link HandlerChainBuilder.map}\n */\nexport const createRateLimitingHandler = <Req, Res, Meta extends RequestMetadata>(\n duration: number,\n flushOnPageHidden = true\n): ChainableHandler<Req, Res, Req, Res, Meta> => {\n let mostRecentSendTime: number | undefined = undefined;\n\n const mappingHandler = createMappingHandler<Req, Req, Res, Meta>(\n async (request) => {\n if (mostRecentSendTime !== undefined) {\n const millisUntilNextSend = duration - (Date.now() - mostRecentSendTime);\n if (millisUntilNextSend > 0) await delay(millisUntilNextSend);\n }\n mostRecentSendTime = Date.now();\n return request;\n },\n 1,\n flushOnPageHidden\n );\n\n return (next) => (request, metadata) => {\n // Requests may be made while the page is transitioning to hidden – for example, the page is being unloaded and\n // we're reporting final metrics. In this case, we need to skip rate limiting and synchronously call `next`\n // so that the request is not lost.\n if (isDuringVisibilityTransition(\"hidden\") && flushOnPageHidden) return next(request, metadata);\n return mappingHandler(next)(request, metadata);\n };\n};\n"]}
@@ -0,0 +1,29 @@
1
+ import { TypedCustomEvent } from "../events/TypedCustomEvent";
2
+ import { TypedEventTarget } from "../events/TypedEventTarget";
3
+ import { ChainableHandler, RequestMetadata } from "./HandlerChainBuilder";
4
+ interface Started {
5
+ requestId: number;
6
+ timeMs: number;
7
+ dimensions: Dimensions;
8
+ }
9
+ interface Completed {
10
+ requestId: number;
11
+ timeMs: number;
12
+ dimensions: Dimensions;
13
+ status: number;
14
+ sizeByte: number;
15
+ }
16
+ interface Errored {
17
+ requestId: number;
18
+ timeMs: number;
19
+ dimensions: Dimensions;
20
+ error: Error;
21
+ }
22
+ export declare type Dimensions = Record<string, string | undefined>;
23
+ export declare type RequestStateEvents = TypedCustomEvent<"started", Started> | TypedCustomEvent<"completed", Completed> | TypedCustomEvent<"errored", Errored>;
24
+ export declare const requestStateEventTarget: TypedEventTarget<RequestStateEvents>;
25
+ export declare const dispatchRequestStarted: (data: Omit<Started, "requestId" | "timeMs">) => Started;
26
+ export declare const dispatchRequestCompleted: (data: Omit<Completed, "timeMs">) => Completed;
27
+ export declare const dispatchRequestErrored: (data: Omit<Errored, "timeMs">) => Errored;
28
+ export declare const createRequestStateEmittingHandler: <D extends Dimensions = Dimensions>() => ChainableHandler<[RequestInfo, D], Response, RequestInfo, Response, RequestMetadata>;
29
+ export {};
@@ -0,0 +1,43 @@
1
+ import { __awaiter } from "tslib";
2
+ import { ensureError } from "../common/errorHelpers";
3
+ import { getTimeMs } from "../common/time";
4
+ import { TypedCustomEvent } from "../events/TypedCustomEvent";
5
+ import { TypedEventTarget } from "../events/TypedEventTarget";
6
+ let requestId = 0;
7
+ const safeParseInt = (str) => {
8
+ if (str == null)
9
+ return 0;
10
+ const maybeInt = parseInt(str);
11
+ return isNaN(maybeInt) ? 0 : maybeInt;
12
+ };
13
+ export const requestStateEventTarget = new TypedEventTarget();
14
+ export const dispatchRequestStarted = (data) => {
15
+ const started = Object.assign(Object.assign({}, data), { requestId: requestId++, timeMs: getTimeMs() });
16
+ requestStateEventTarget.dispatchEvent(new TypedCustomEvent("started", started));
17
+ return started;
18
+ };
19
+ export const dispatchRequestCompleted = (data) => {
20
+ const completed = Object.assign(Object.assign({}, data), { timeMs: getTimeMs() });
21
+ requestStateEventTarget.dispatchEvent(new TypedCustomEvent("completed", completed));
22
+ return completed;
23
+ };
24
+ export const dispatchRequestErrored = (data) => {
25
+ const errored = Object.assign(Object.assign({}, data), { timeMs: getTimeMs() });
26
+ requestStateEventTarget.dispatchEvent(new TypedCustomEvent("errored", errored));
27
+ return errored;
28
+ };
29
+ export const createRequestStateEmittingHandler = () => (next) => ([request, dimensions], metadata) => __awaiter(void 0, void 0, void 0, function* () {
30
+ const { requestId } = dispatchRequestStarted({ dimensions });
31
+ try {
32
+ const response = yield next(request, metadata);
33
+ const status = response.status;
34
+ const sizeByte = safeParseInt(response.headers.get("content-length"));
35
+ dispatchRequestCompleted({ requestId, dimensions, status, sizeByte });
36
+ return response;
37
+ }
38
+ catch (error) {
39
+ dispatchRequestErrored({ requestId, dimensions, error: ensureError(error) });
40
+ throw error;
41
+ }
42
+ });
43
+ //# sourceMappingURL=requestStateEmittingHandler.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"requestStateEmittingHandler.js","sourceRoot":"","sources":["../../src/handlers/requestStateEmittingHandler.ts"],"names":[],"mappings":";AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAC;AACrD,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAC3C,OAAO,EAAE,gBAAgB,EAAE,MAAM,4BAA4B,CAAC;AAC9D,OAAO,EAAE,gBAAgB,EAAE,MAAM,4BAA4B,CAAC;AAG9D,IAAI,SAAS,GAAG,CAAC,CAAC;AAClB,MAAM,YAAY,GAAG,CAAC,GAAkB,EAAE,EAAE;IACxC,IAAI,GAAG,IAAI,IAAI;QAAE,OAAO,CAAC,CAAC;IAC1B,MAAM,QAAQ,GAAG,QAAQ,CAAC,GAAG,CAAC,CAAC;IAC/B,OAAO,KAAK,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC;AAC1C,CAAC,CAAC;AA8BF,MAAM,CAAC,MAAM,uBAAuB,GAAG,IAAI,gBAAgB,EAAsB,CAAC;AAElF,MAAM,CAAC,MAAM,sBAAsB,GAAG,CAAC,IAA2C,EAAW,EAAE;IAC3F,MAAM,OAAO,mCAAiB,IAAI,KAAE,SAAS,EAAE,SAAS,EAAE,EAAE,MAAM,EAAE,SAAS,EAAE,GAAE,CAAC;IAClF,uBAAuB,CAAC,aAAa,CAAC,IAAI,gBAAgB,CAAC,SAAS,EAAE,OAAO,CAAC,CAAC,CAAC;IAChF,OAAO,OAAO,CAAC;AACnB,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,wBAAwB,GAAG,CAAC,IAA+B,EAAa,EAAE;IACnF,MAAM,SAAS,mCAAmB,IAAI,KAAE,MAAM,EAAE,SAAS,EAAE,GAAE,CAAC;IAC9D,uBAAuB,CAAC,aAAa,CAAC,IAAI,gBAAgB,CAAC,WAAW,EAAE,SAAS,CAAC,CAAC,CAAC;IACpF,OAAO,SAAS,CAAC;AACrB,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,sBAAsB,GAAG,CAAC,IAA6B,EAAW,EAAE;IAC7E,MAAM,OAAO,mCAAiB,IAAI,KAAE,MAAM,EAAE,SAAS,EAAE,GAAE,CAAC;IAC1D,uBAAuB,CAAC,aAAa,CAAC,IAAI,gBAAgB,CAAC,SAAS,EAAE,OAAO,CAAC,CAAC,CAAC;IAChF,OAAO,OAAO,CAAC;AACnB,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,iCAAiC,GAAG,GAM/C,EAAE,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAO,CAAC,OAAO,EAAE,UAAU,CAAC,EAAE,QAAQ,EAAE,EAAE;IACrD,MAAM,EAAE,SAAS,EAAE,GAAG,sBAAsB,CAAC,EAAE,UAAU,EAAE,CAAC,CAAC;IAC7D,IAAI;QACA,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC;QAC/C,MAAM,MAAM,GAAG,QAAQ,CAAC,MAAM,CAAC;QAC/B,MAAM,QAAQ,GAAG,YAAY,CAAC,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,gBAAgB,CAAC,CAAC,CAAC;QACtE,wBAAwB,CAAC,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC,CAAC;QACtE,OAAO,QAAQ,CAAC;KACnB;IAAC,OAAO,KAAK,EAAE;QACZ,sBAAsB,CAAC,EAAE,SAAS,EAAE,UAAU,EAAE,KAAK,EAAE,WAAW,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;QAC7E,MAAM,KAAK,CAAC;KACf;AACL,CAAC,CAAA,CAAC","sourcesContent":["import { ensureError } from \"../common/errorHelpers\";\nimport { getTimeMs } from \"../common/time\";\nimport { TypedCustomEvent } from \"../events/TypedCustomEvent\";\nimport { TypedEventTarget } from \"../events/TypedEventTarget\";\nimport { ChainableHandler, RequestMetadata } from \"./HandlerChainBuilder\";\n\nlet requestId = 0;\nconst safeParseInt = (str: string | null) => {\n if (str == null) return 0;\n const maybeInt = parseInt(str);\n return isNaN(maybeInt) ? 0 : maybeInt;\n};\n\ninterface Started {\n requestId: number;\n timeMs: number;\n dimensions: Dimensions;\n}\n\ninterface Completed {\n requestId: number;\n timeMs: number;\n dimensions: Dimensions;\n status: number;\n sizeByte: number;\n}\n\ninterface Errored {\n requestId: number;\n timeMs: number;\n dimensions: Dimensions;\n error: Error;\n}\n\nexport type Dimensions = Record<string, string | undefined>;\n\nexport type RequestStateEvents =\n | TypedCustomEvent<\"started\", Started>\n | TypedCustomEvent<\"completed\", Completed>\n | TypedCustomEvent<\"errored\", Errored>;\n\nexport const requestStateEventTarget = new TypedEventTarget<RequestStateEvents>();\n\nexport const dispatchRequestStarted = (data: Omit<Started, \"requestId\" | \"timeMs\">): Started => {\n const started: Started = { ...data, requestId: requestId++, timeMs: getTimeMs() };\n requestStateEventTarget.dispatchEvent(new TypedCustomEvent(\"started\", started));\n return started;\n};\n\nexport const dispatchRequestCompleted = (data: Omit<Completed, \"timeMs\">): Completed => {\n const completed: Completed = { ...data, timeMs: getTimeMs() };\n requestStateEventTarget.dispatchEvent(new TypedCustomEvent(\"completed\", completed));\n return completed;\n};\n\nexport const dispatchRequestErrored = (data: Omit<Errored, \"timeMs\">): Errored => {\n const errored: Errored = { ...data, timeMs: getTimeMs() };\n requestStateEventTarget.dispatchEvent(new TypedCustomEvent(\"errored\", errored));\n return errored;\n};\n\nexport const createRequestStateEmittingHandler = <D extends Dimensions = Dimensions>(): ChainableHandler<\n [RequestInfo, D],\n Response,\n RequestInfo,\n Response,\n RequestMetadata\n> => (next) => async ([request, dimensions], metadata) => {\n const { requestId } = dispatchRequestStarted({ dimensions });\n try {\n const response = await next(request, metadata);\n const status = response.status;\n const sizeByte = safeParseInt(response.headers.get(\"content-length\"));\n dispatchRequestCompleted({ requestId, dimensions, status, sizeByte });\n return response;\n } catch (error) {\n dispatchRequestErrored({ requestId, dimensions, error: ensureError(error) });\n throw error;\n }\n};\n"]}
@@ -0,0 +1,27 @@
1
+ import { Persistence, ValidKey } from "../persistence/Persistence";
2
+ import { ChainableHandler, RequestMetadata } from "./HandlerChainBuilder";
3
+ export declare type CachingStrategy<T> = (key: ValidKey, cache: Persistence<T>, network: () => Promise<T>) => Promise<T>;
4
+ /**
5
+ * Create a CachingStrategy that first makes a request to the network, falling back to cache if the network request
6
+ * fails. If the network request fails and a prior response has not been cached, an error is returned to the caller.
7
+ */
8
+ export declare const staleIfErrorStrategy: <T>() => CachingStrategy<T>;
9
+ /**
10
+ * Create a CachingStrategy that first does a cache lookup – if the response is found in cache, it is returned and the
11
+ * entry is updated with a request to the network in the background. If no cached response is found, the network request
12
+ * is made, the result cached and returned to the caller.
13
+ */
14
+ export declare const staleWhileRevalidateStrategy: <T>() => CachingStrategy<T>;
15
+ /**
16
+ * Create a Handler capable of caching responses using various caching strategies.
17
+ *
18
+ * More than one caching strategy can be provided, and they will be composed into a single strategy. For example, an
19
+ * expiringStrategy could be composed with a staleIfErrorStrategy so that responses
20
+ *
21
+ * @param cache A Persistence instance capable of storing responses.
22
+ * @param resolveKey This function is called once for each request, and must return a valid persistence key
23
+ * corresponding uniquely to that request.
24
+ * @param strategy A CachingStrategy used to determine when to retrieve from cache vs. request from the network.
25
+ * @returns
26
+ */
27
+ export declare const createResponseCachingHandler: <Req, Res, Meta extends RequestMetadata>(cache: Persistence<Res>, resolveKey: (request: Req, metadata?: Meta | undefined) => ValidKey, strategy: CachingStrategy<Res>) => ChainableHandler<Req, Res, Req, Res, Meta>;
@@ -0,0 +1,94 @@
1
+ import { __awaiter } from "tslib";
2
+ import { ensureError } from "../common/errorHelpers";
3
+ import { cacheKeyNotFoundError } from "../namedErrors";
4
+ import { getLogger } from "../logger/logger";
5
+ const logger = getLogger("responseCachingHandler");
6
+ const notFound = (key) => cacheKeyNotFoundError(`Response for key ${key} not found in cache.`);
7
+ const strategyFailed = (key, cause) => new Error(`Network request and cache lookup for ${key} both failed.`, { cause });
8
+ /**
9
+ * Create a CachingStrategy that first makes a request to the network, falling back to cache if the network request
10
+ * fails. If the network request fails and a prior response has not been cached, an error is returned to the caller.
11
+ */
12
+ export const staleIfErrorStrategy = () => (key, cache, network) => __awaiter(void 0, void 0, void 0, function* () {
13
+ try {
14
+ const response = yield network();
15
+ cache.store(key, response).catch((error) => {
16
+ logger.warn(`staleIfErrorStrategy failed to store key ${key}.`, error);
17
+ });
18
+ return response;
19
+ }
20
+ catch (networkError) {
21
+ try {
22
+ const cachedResponse = yield cache.retrieve(key);
23
+ if (!cachedResponse)
24
+ throw notFound(key);
25
+ logger.debug(`staleIfErrorStrategy successfully fell back to cache for key ${key} after network error.`, networkError);
26
+ return cachedResponse;
27
+ }
28
+ catch (cacheError) {
29
+ const error = ensureError(cacheError);
30
+ error.cause = networkError;
31
+ throw strategyFailed(key, error);
32
+ }
33
+ }
34
+ });
35
+ /**
36
+ * Create a CachingStrategy that first does a cache lookup – if the response is found in cache, it is returned and the
37
+ * entry is updated with a request to the network in the background. If no cached response is found, the network request
38
+ * is made, the result cached and returned to the caller.
39
+ */
40
+ export const staleWhileRevalidateStrategy = () => (key, cache, network) => __awaiter(void 0, void 0, void 0, function* () {
41
+ try {
42
+ const cachedResponse = yield cache.retrieve(key);
43
+ if (!cachedResponse)
44
+ throw notFound(key);
45
+ network()
46
+ .then((response) => cache.store(key, response))
47
+ .catch((error) => {
48
+ logger.warn(`staleWhileRevalidateStrategy failed to retrieve and store key ${key}.`, error);
49
+ });
50
+ return cachedResponse;
51
+ }
52
+ catch (cacheError) {
53
+ try {
54
+ const response = yield network();
55
+ cache.store(key, response).catch((error) => {
56
+ logger.warn(`staleWhileRevalidateStrategy failed to store key ${key}.`, error);
57
+ });
58
+ logger.debug(`staleWhileRevalidateStrategy successfully fell back to network for key ${key} after cache error.`, cacheError);
59
+ return response;
60
+ }
61
+ catch (networkError) {
62
+ const error = ensureError(networkError);
63
+ error.cause = cacheError;
64
+ throw strategyFailed(key, error);
65
+ }
66
+ }
67
+ });
68
+ /**
69
+ * Create a Handler capable of caching responses using various caching strategies.
70
+ *
71
+ * More than one caching strategy can be provided, and they will be composed into a single strategy. For example, an
72
+ * expiringStrategy could be composed with a staleIfErrorStrategy so that responses
73
+ *
74
+ * @param cache A Persistence instance capable of storing responses.
75
+ * @param resolveKey This function is called once for each request, and must return a valid persistence key
76
+ * corresponding uniquely to that request.
77
+ * @param strategy A CachingStrategy used to determine when to retrieve from cache vs. request from the network.
78
+ * @returns
79
+ */
80
+ export const createResponseCachingHandler = (cache, resolveKey, strategy) => {
81
+ return (next) => (request, metadata) => __awaiter(void 0, void 0, void 0, function* () {
82
+ const network = () => next(request, metadata);
83
+ let key;
84
+ try {
85
+ key = resolveKey(request, metadata);
86
+ }
87
+ catch (error) {
88
+ logger.warn("Cache lookup failed because the cache key could not be resolved.", error);
89
+ return network();
90
+ }
91
+ return strategy(key, cache, network);
92
+ });
93
+ };
94
+ //# sourceMappingURL=responseCachingHandler.js.map