@snap/camera-kit 0.14.0 → 0.15.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 (265) hide show
  1. package/LICENSE.md +5921 -1485
  2. package/README.md +1 -1
  3. package/docs/html/assets/search.js +1 -1
  4. package/docs/html/classes/CameraKit.html +7 -7
  5. package/docs/html/classes/CameraKitSession.html +17 -25
  6. package/docs/html/classes/CameraKitSource.html +15 -10
  7. package/docs/html/classes/LensPerformanceMeasurement.html +7 -7
  8. package/docs/html/classes/LensPerformanceMetrics.html +7 -7
  9. package/docs/html/classes/LensRepository.html +7 -7
  10. package/docs/html/classes/Transform2D.html +7 -7
  11. package/docs/html/classes/TypedCustomEvent.html +7 -7
  12. package/docs/html/classes/TypedEventTarget.html +7 -7
  13. package/docs/html/functions/ConcatInjectable.html +202 -0
  14. package/docs/html/functions/Injectable.html +15 -16
  15. package/docs/html/functions/bootstrapCameraKit.html +7 -7
  16. package/docs/html/functions/createExtension.html +7 -7
  17. package/docs/html/functions/createImageSource.html +7 -7
  18. package/docs/html/functions/createMediaStreamSource.html +7 -7
  19. package/docs/html/functions/createUserMediaSource.html +7 -7
  20. package/docs/html/functions/createVideoSource.html +7 -7
  21. package/docs/html/functions/estimateLensPerformance.html +7 -7
  22. package/docs/html/functions/getRequiredBootstrapURLs.html +7 -7
  23. package/docs/html/functions/lensSourcesFactory.html +17 -9
  24. package/docs/html/functions/remoteApiServicesFactory.html +7 -7
  25. package/docs/html/index.html +9 -9
  26. package/docs/html/interfaces/CameraKitBootstrapConfiguration.html +7 -7
  27. package/docs/html/interfaces/CameraKitSourceSubscriber.html +7 -7
  28. package/docs/html/interfaces/ComputedFrameMetrics.html +7 -7
  29. package/docs/html/interfaces/CreateSessionOptions.html +7 -7
  30. package/docs/html/interfaces/EstimatedLensPerformance.html +7 -7
  31. package/docs/html/interfaces/Lens.html +7 -7
  32. package/docs/html/interfaces/LensLaunchData.html +183 -0
  33. package/docs/html/interfaces/LensSource.html +28 -46
  34. package/docs/html/interfaces/MediaStreamSourceOptions.html +7 -7
  35. package/docs/html/interfaces/Preview.html +7 -7
  36. package/docs/html/interfaces/RemoteApiRequest.html +7 -7
  37. package/docs/html/interfaces/RemoteApiResponse.html +7 -7
  38. package/docs/html/interfaces/RemoteApiService.html +7 -7
  39. package/docs/html/interfaces/Snapcode.html +7 -7
  40. package/docs/html/interfaces/UriCancelRequest.html +7 -7
  41. package/docs/html/interfaces/UriRequest.html +7 -7
  42. package/docs/html/interfaces/UriResponse.html +7 -7
  43. package/docs/html/interfaces/VideoSourceOptions.html +7 -7
  44. package/docs/html/modules.html +12 -12
  45. package/docs/html/types/AssetLoader.html +7 -7
  46. package/docs/html/types/AssetTiming.html +7 -7
  47. package/docs/html/types/BenchmarkError.html +7 -7
  48. package/docs/html/types/BootstrapError.html +7 -7
  49. package/docs/html/types/CacheKeyNotFoundError.html +7 -7
  50. package/docs/html/types/CameraKitDeviceInfo.html +7 -7
  51. package/docs/html/types/CameraKitDeviceOptions.html +7 -7
  52. package/docs/html/types/CameraKitSessionEventListener.html +7 -7
  53. package/docs/html/types/CameraKitSessionEvents.html +7 -7
  54. package/docs/html/types/CameraKitSourceError.html +7 -7
  55. package/docs/html/types/CameraKitSourceInfo.html +7 -7
  56. package/docs/html/types/CameraKitSourceOptions.html +7 -7
  57. package/docs/html/types/ConfigurationError.html +7 -7
  58. package/docs/html/types/Keyboard.html +7 -7
  59. package/docs/html/types/KeyboardEvents.html +7 -7
  60. package/docs/html/types/LegalError.html +7 -7
  61. package/docs/html/types/LensAbortError.html +7 -7
  62. package/docs/html/types/LensAssetError.html +7 -7
  63. package/docs/html/types/LensContentValidationError.html +7 -7
  64. package/docs/html/types/LensError.html +7 -7
  65. package/docs/html/types/LensExecutionError.html +7 -7
  66. package/docs/html/types/LensImagePickerError.html +7 -7
  67. package/docs/html/types/LensMetricsEvents.html +7 -7
  68. package/docs/html/types/LensPerformanceCluster.html +7 -7
  69. package/docs/html/types/LensView.html +7 -7
  70. package/docs/html/types/LensWait.html +7 -7
  71. package/docs/html/types/PersistentStoreError.html +7 -7
  72. package/docs/html/types/PlatformNotSupportedError.html +7 -7
  73. package/docs/html/types/PublicContainer.html +7 -7
  74. package/docs/html/types/RemoteApiRequestHandler.html +7 -7
  75. package/docs/html/types/RemoteApiServices.html +7 -7
  76. package/docs/html/types/RemoteApiStatus.html +7 -7
  77. package/docs/html/types/RenderTarget.html +7 -7
  78. package/docs/html/types/Uri.html +7 -7
  79. package/docs/html/types/WebGLError.html +7 -7
  80. package/docs/html/variables/extensionRequestContext.html +7 -7
  81. package/docs/md/README.md +1 -1
  82. package/docs/md/classes/CameraKit.md +1 -1
  83. package/docs/md/classes/CameraKitSession.md +11 -22
  84. package/docs/md/classes/CameraKitSource.md +11 -5
  85. package/docs/md/classes/LensPerformanceMeasurement.md +1 -1
  86. package/docs/md/classes/LensPerformanceMetrics.md +1 -1
  87. package/docs/md/classes/LensRepository.md +1 -1
  88. package/docs/md/classes/Transform2D.md +1 -1
  89. package/docs/md/classes/TypedCustomEvent.md +1 -1
  90. package/docs/md/classes/TypedEventTarget.md +1 -1
  91. package/docs/md/interfaces/CameraKitBootstrapConfiguration.md +1 -1
  92. package/docs/md/interfaces/CameraKitSourceSubscriber.md +1 -1
  93. package/docs/md/interfaces/ComputedFrameMetrics.md +1 -1
  94. package/docs/md/interfaces/CreateSessionOptions.md +1 -1
  95. package/docs/md/interfaces/EstimatedLensPerformance.md +1 -1
  96. package/docs/md/interfaces/Lens.md +1 -1
  97. package/docs/md/interfaces/LensLaunchData.md +53 -0
  98. package/docs/md/interfaces/LensSource.md +23 -25
  99. package/docs/md/interfaces/MediaStreamSourceOptions.md +1 -1
  100. package/docs/md/interfaces/Preview.md +1 -1
  101. package/docs/md/interfaces/RemoteApiRequest.md +1 -1
  102. package/docs/md/interfaces/RemoteApiResponse.md +1 -1
  103. package/docs/md/interfaces/RemoteApiService.md +1 -1
  104. package/docs/md/interfaces/Snapcode.md +1 -1
  105. package/docs/md/interfaces/UriCancelRequest.md +1 -1
  106. package/docs/md/interfaces/UriRequest.md +1 -1
  107. package/docs/md/interfaces/UriResponse.md +1 -1
  108. package/docs/md/interfaces/VideoSourceOptions.md +1 -1
  109. package/docs/md/modules.md +125 -28
  110. package/lib/CameraKit.d.ts +14 -6
  111. package/lib/__tests__/data.d.ts +2 -2
  112. package/lib/__tests__/data.js +2 -2
  113. package/lib/__tests__/data.js.map +1 -1
  114. package/lib/bootstrapCameraKit.js +12 -3
  115. package/lib/bootstrapCameraKit.js.map +1 -1
  116. package/lib/clients/createTsProtoClient.d.ts +47 -0
  117. package/lib/clients/createTsProtoClient.js +53 -0
  118. package/lib/clients/createTsProtoClient.js.map +1 -0
  119. package/lib/clients/grpcHandler.d.ts +23 -0
  120. package/lib/clients/grpcHandler.js +87 -0
  121. package/lib/clients/grpcHandler.js.map +1 -0
  122. package/lib/clients/lensesClient.d.ts +9 -0
  123. package/lib/clients/lensesClient.js +6 -0
  124. package/lib/clients/lensesClient.js.map +1 -0
  125. package/lib/common/entries.d.ts +1 -0
  126. package/lib/common/entries.js +2 -0
  127. package/lib/common/entries.js.map +1 -1
  128. package/lib/common/result.d.ts +36 -0
  129. package/lib/common/result.js +40 -0
  130. package/lib/common/result.js.map +1 -0
  131. package/lib/common/unionBy.d.ts +28 -0
  132. package/lib/common/unionBy.js +46 -0
  133. package/lib/common/unionBy.js.map +1 -0
  134. package/lib/configuration.js +14 -1
  135. package/lib/configuration.js.map +1 -1
  136. package/lib/dependency-injection/Injectable.d.ts +67 -11
  137. package/lib/dependency-injection/Injectable.js +21 -2
  138. package/lib/dependency-injection/Injectable.js.map +1 -1
  139. package/lib/dependency-injection/RootServices.d.ts +5 -1
  140. package/lib/dependency-injection/RootServices.js.map +1 -1
  141. package/lib/environment.json +1 -1
  142. package/lib/extensions/RemoteApiServices.d.ts +1 -1
  143. package/lib/extensions/RemoteApiServices.js +7 -7
  144. package/lib/extensions/RemoteApiServices.js.map +1 -1
  145. package/lib/extensions/uriHandlersRegister.d.ts +6 -6
  146. package/lib/extensions/uriHandlersRegister.js +1 -1
  147. package/lib/extensions/uriHandlersRegister.js.map +1 -1
  148. package/lib/generated-proto/blizzard/cameraKitEvents.js.map +1 -1
  149. package/lib/generated-proto/pb_schema/camera_kit/v3/business_events.d.ts +15 -17
  150. package/lib/generated-proto/pb_schema/camera_kit/v3/business_events.js +62 -69
  151. package/lib/generated-proto/pb_schema/camera_kit/v3/business_events.js.map +1 -1
  152. package/lib/generated-proto/pb_schema/camera_kit/v3/export.d.ts +6 -0
  153. package/lib/generated-proto/pb_schema/camera_kit/v3/export.js +68 -0
  154. package/lib/generated-proto/pb_schema/camera_kit/v3/export.js.map +1 -1
  155. package/lib/generated-proto/pb_schema/camera_kit/v3/legal_prompt.d.ts +5 -6
  156. package/lib/generated-proto/pb_schema/camera_kit/v3/legal_prompt.js +11 -25
  157. package/lib/generated-proto/pb_schema/camera_kit/v3/legal_prompt.js.map +1 -1
  158. package/lib/generated-proto/pb_schema/camera_kit/v3/lens.d.ts +19 -14
  159. package/lib/generated-proto/pb_schema/camera_kit/v3/lens.js +145 -64
  160. package/lib/generated-proto/pb_schema/camera_kit/v3/lens.js.map +1 -1
  161. package/lib/generated-proto/pb_schema/camera_kit/v3/operational_metrics.d.ts +2 -0
  162. package/lib/generated-proto/pb_schema/camera_kit/v3/operational_metrics.js +30 -0
  163. package/lib/generated-proto/pb_schema/camera_kit/v3/operational_metrics.js.map +1 -1
  164. package/lib/generated-proto/pb_schema/camera_kit/v3/ranking.d.ts +15 -16
  165. package/lib/generated-proto/pb_schema/camera_kit/v3/ranking.js +36 -62
  166. package/lib/generated-proto/pb_schema/camera_kit/v3/ranking.js.map +1 -1
  167. package/lib/generated-proto/pb_schema/camera_kit/v3/service.d.ts +1294 -12
  168. package/lib/generated-proto/pb_schema/camera_kit/v3/service.js +200 -0
  169. package/lib/generated-proto/pb_schema/camera_kit/v3/service.js.map +1 -1
  170. package/lib/generated-proto/pb_schema/cdp/cof/config_result.d.ts +4 -0
  171. package/lib/generated-proto/pb_schema/cdp/cof/config_result.js +4 -0
  172. package/lib/generated-proto/pb_schema/cdp/cof/config_result.js.map +1 -1
  173. package/lib/generated-proto/pb_schema/google/protobuf/descriptor.d.ts +39 -45
  174. package/lib/generated-proto/pb_schema/google/protobuf/descriptor.js +74 -192
  175. package/lib/generated-proto/pb_schema/google/protobuf/descriptor.js.map +1 -1
  176. package/lib/handlers/defaultFetchHandler.js +1 -5
  177. package/lib/handlers/defaultFetchHandler.js.map +1 -1
  178. package/lib/index.d.ts +3 -3
  179. package/lib/index.js +2 -6
  180. package/lib/index.js.map +1 -1
  181. package/lib/lens/Lens.d.ts +2 -12
  182. package/lib/lens/Lens.js +2 -2
  183. package/lib/lens/Lens.js.map +1 -1
  184. package/lib/lens/LensLaunchData.d.ts +37 -0
  185. package/lib/lens/LensLaunchData.js +35 -0
  186. package/lib/lens/LensLaunchData.js.map +1 -0
  187. package/lib/lens/LensRepository.d.ts +4 -7
  188. package/lib/lens/LensRepository.js +24 -35
  189. package/lib/lens/LensRepository.js.map +1 -1
  190. package/lib/lens/LensSource.d.ts +43 -0
  191. package/lib/lens/LensSource.js +42 -0
  192. package/lib/lens/LensSource.js.map +1 -0
  193. package/lib/lens/assets/LensAssetRepository.js +2 -4
  194. package/lib/lens/assets/LensAssetRepository.js.map +1 -1
  195. package/lib/lens/assets/LensAssetsProvider.d.ts +1 -1
  196. package/lib/lens/cameraKitLensSource.d.ts +16 -0
  197. package/lib/lens/cameraKitLensSource.js +59 -0
  198. package/lib/lens/cameraKitLensSource.js.map +1 -0
  199. package/lib/lens-core-module/lensCore.d.ts +2 -1
  200. package/lib/lens-core-module/lensCore.js +6 -1
  201. package/lib/lens-core-module/lensCore.js.map +1 -1
  202. package/lib/lens-core-module/lensCoreError.js +1 -1
  203. package/lib/lens-core-module/lensCoreError.js.map +1 -1
  204. package/lib/lensCoreWasmVersions.json +3 -3
  205. package/lib/media-sources/CameraKitSource.d.ts +10 -4
  206. package/lib/media-sources/CameraKitSource.js +11 -4
  207. package/lib/media-sources/CameraKitSource.js.map +1 -1
  208. package/lib/media-sources/ImageSource.js +1 -11
  209. package/lib/media-sources/ImageSource.js.map +1 -1
  210. package/lib/media-sources/MediaStreamSource.js +1 -5
  211. package/lib/media-sources/MediaStreamSource.js.map +1 -1
  212. package/lib/media-sources/VideoSource.js +1 -11
  213. package/lib/media-sources/VideoSource.js.map +1 -1
  214. package/lib/metrics/businessEventsReporter.js +1 -1
  215. package/lib/metrics/businessEventsReporter.js.map +1 -1
  216. package/lib/metrics/reporters/reportGlobalException.d.ts +7 -0
  217. package/lib/metrics/reporters/reportGlobalException.js +22 -4
  218. package/lib/metrics/reporters/reportGlobalException.js.map +1 -1
  219. package/lib/metrics/reporters/reportHttpMetrics.js +14 -0
  220. package/lib/metrics/reporters/reportHttpMetrics.js.map +1 -1
  221. package/lib/metrics/reporters/reportLensValidationFailed.d.ts +1 -1
  222. package/lib/metrics/reporters/reportLensView.d.ts +1 -1
  223. package/lib/metrics/reporters/reportLensWait.d.ts +1 -1
  224. package/lib/metrics/reporters/reportSessionException.d.ts +1 -1
  225. package/lib/metrics/reporters/reporters.d.ts +1 -1
  226. package/lib/persistence/ExpiringPersistence.js +3 -4
  227. package/lib/persistence/ExpiringPersistence.js.map +1 -1
  228. package/lib/platform/platformCapabilities.js +2 -1
  229. package/lib/platform/platformCapabilities.js.map +1 -1
  230. package/lib/platform/platformInfo.js +1 -1
  231. package/lib/platform/platformInfo.js.map +1 -1
  232. package/lib/remote-configuration/cofHandler.d.ts +1 -0
  233. package/lib/remote-configuration/cofHandler.js +61 -50
  234. package/lib/remote-configuration/cofHandler.js.map +1 -1
  235. package/lib/session/CameraKitSession.d.ts +9 -11
  236. package/lib/session/CameraKitSession.js +22 -18
  237. package/lib/session/CameraKitSession.js.map +1 -1
  238. package/lib/session/CameraKitSessionEvents.d.ts +1 -1
  239. package/lib/session/CameraKitSessionEvents.js.map +1 -1
  240. package/lib/session/LensKeyboard.d.ts +7 -1
  241. package/lib/session/lensState.d.ts +3 -3
  242. package/lib/session/lensState.js +40 -15
  243. package/lib/session/lensState.js.map +1 -1
  244. package/package.json +1 -1
  245. package/docs/html/classes/LensSources.html +0 -160
  246. package/docs/html/types/LensLaunchParams.html +0 -115
  247. package/docs/md/classes/LensSources.md +0 -29
  248. package/lib/common/any.d.ts +0 -19
  249. package/lib/common/any.js +0 -53
  250. package/lib/common/any.js.map +0 -1
  251. package/lib/extensions/LensSources.d.ts +0 -58
  252. package/lib/extensions/LensSources.js +0 -54
  253. package/lib/extensions/LensSources.js.map +0 -1
  254. package/lib/lens/LensLaunchParams.d.ts +0 -19
  255. package/lib/lens/LensLaunchParams.js +0 -40
  256. package/lib/lens/LensLaunchParams.js.map +0 -1
  257. package/lib/lens/index.d.ts +0 -7
  258. package/lib/lens/index.js +0 -7
  259. package/lib/lens/index.js.map +0 -1
  260. package/lib/lens/lensEnvelopeUtil.d.ts +0 -5
  261. package/lib/lens/lensEnvelopeUtil.js +0 -19
  262. package/lib/lens/lensEnvelopeUtil.js.map +0 -1
  263. package/lib/lens/lensHttpUtil.d.ts +0 -5
  264. package/lib/lens/lensHttpUtil.js +0 -52
  265. package/lib/lens/lensHttpUtil.js.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"platformCapabilities.js","sourceRoot":"","sources":["../../src/platform/platformCapabilities.ts"],"names":[],"mappings":"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","sourcesContent":["import { exceptions, simd } from \"wasm-feature-detect\";\nimport { memoize } from \"../common/memoize\";\nimport { XrCapabilities } from \"../lens-core-module\";\nimport { platformNotSupportedError } from \"../namedErrors\";\nimport { getPlatformInfo } from \"./platformInfo\";\n\n/** @internal */\nexport type SupportedCapability<T> = T & { supported: true };\n/** @internal */\nexport type UnsupportedCapability = { supported: false; error: Error };\n/** @internal */\nexport type Capability<T = void> = SupportedCapability<T> | UnsupportedCapability;\n\n//-----------\n// WebGL\n//-----------\n\ntype WebGlCapability = Capability<{ maxTextureSize: number }>;\n\n// This required minimum max texture size is based on data from\n// https://web3dsurvey.com/webgl/parameters/MAX_TEXTURE_SIZE. Checking for a reasonable minimum MAX_TEXTURE_SIZE avoids\n// attempting to run lenses on platforms that will not support them -- most commonly, we've seen some platforms that\n// report 0 MAX_TEXTURE_SIZE, which will cause errors for all lenses.\nconst minRequiredMaxTextureSize = 1024;\n\n/**\n * @returns An object with fields describing support for various WebGL features.\n *\n * @internal\n */\nfunction getWebGlSupport(): WebGlCapability {\n const ctx = document.createElement(\"canvas\").getContext(\"webgl2\");\n if (!ctx)\n return {\n supported: false,\n error: platformNotSupportedError(\"CameraKit requires WebGL2, but this browser does not support WebGL2.\"),\n };\n const maxTextureSize = ctx.getParameter(ctx.MAX_TEXTURE_SIZE);\n const supported = maxTextureSize >= minRequiredMaxTextureSize;\n return supported\n ? { supported, maxTextureSize }\n : {\n supported,\n error: platformNotSupportedError(\n `CameraKit requires WebGL's MAX_TEXTURE_SIZE exceed a minimum value of ` +\n `${minRequiredMaxTextureSize}, but the browser's reported MAX_TEXTURE_SIZE is ${maxTextureSize}.`\n ),\n };\n}\n\n//-----------\n// WASM\n//-----------\n\ntype WasmCapability = Capability<{ wasmFeatures: number }>;\n\n/**\n * Because there may be a large number of WASM-related capabilities, and because these may correspond to various builds\n * of LensCore, we encode the various WASM capabilities into a single number by bitwise OR-ing together the numbers\n * corresponding to each capability.\n *\n * Since each combindation of capabilities is represented by a single number, we can easily map between that number and\n * the corresponding LensCore build name that makes use of those capabilities.\n *\n * @internal\n */\nexport enum WasmFeatures {\n Default = 0b00000000,\n SIMD = 0b00000001,\n ExceptionHandling = 0b00000010,\n}\n\n/**\n * @returns A non-negative integer representing the combination of supported WebAssembly features, or -1 if WebAssembly\n * is not supported at all.\n *\n * @internal\n */\nasync function getWebAssemblyCapabilities(): Promise<WasmCapability> {\n if (globalThis.WebAssembly === undefined)\n return {\n supported: false,\n error: platformNotSupportedError(\n \"CameraKit requires WebAssembly, but this browser does not support WebAssembly.\"\n ),\n };\n return {\n supported: true,\n wasmFeatures: (\n await Promise.all([\n simd().then((supported) => {\n // Although Safari 16.4 reports SIMD support, LensCore encounters rendering bugs when using\n // SIMD in Safari 16.4. We will disable SIMD for now until Safari stabilizes the feature.\n if (getPlatformInfo().browser.brand === \"Safari\") return WasmFeatures.Default;\n return supported ? WasmFeatures.SIMD : WasmFeatures.Default;\n }),\n exceptions().then((supported) => (supported ? WasmFeatures.ExceptionHandling : WasmFeatures.Default)),\n ])\n ).reduce((features, feature) => features | feature, WasmFeatures.Default),\n };\n}\n\n//-----------\n// WebXR\n//-----------\n\ntype WebXrCapability = Capability<XrCapabilities>;\n\n/**\n * @returns A Promise containing an object with fields describing the support of various WebXR features. This object's\n * type is defined by LensCore, as they consume these capabilities and adjust behavior accordingly.\n *\n * @internal\n */\nasync function getWebXrCapabilities(): Promise<WebXrCapability> {\n const notSupported: WebXrCapability = {\n supported: false,\n error: platformNotSupportedError(\n `Use of this feature requires WebXR support for immersive AR sessions, but ` +\n `this browser does not support immersive AR sessions.`\n ),\n };\n if (!isSecureContext) return notSupported;\n if (!navigator.xr) return notSupported;\n const isImmersiveArSupported = await navigator.xr.isSessionSupported(\"immersive-ar\");\n return isImmersiveArSupported\n ? {\n supported: true,\n sixDofSupported: true,\n sceneDepthSupported: true,\n }\n : notSupported;\n}\n\n/** @internal */\nexport interface PlatformCapabilities {\n webgl: WebGlCapability;\n wasm: WasmCapability;\n webxr: WebXrCapability;\n}\n\n/**\n * Get information about the current platform capabilities, including:\n * - WebGL support and various WebGL parameters.\n * - WASM support and support for various WASM features.\n * - WebXR support and support for various WebXR features.\n *\n * @internal\n */\nexport const getPlatformCapabilities = memoize(async function getPlatformCapabilities(): Promise<PlatformCapabilities> {\n return {\n webgl: getWebGlSupport(),\n wasm: await getWebAssemblyCapabilities(),\n webxr: await getWebXrCapabilities(),\n };\n});\n"]}
1
+ {"version":3,"file":"platformCapabilities.js","sourceRoot":"","sources":["../../src/platform/platformCapabilities.ts"],"names":[],"mappings":"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","sourcesContent":["import { exceptions, simd } from \"wasm-feature-detect\";\nimport { memoize } from \"../common/memoize\";\nimport { XrCapabilities } from \"../lens-core-module\";\nimport { platformNotSupportedError } from \"../namedErrors\";\nimport { getPlatformInfo } from \"./platformInfo\";\n\n/** @internal */\nexport type SupportedCapability<T> = T & { supported: true };\n/** @internal */\nexport type UnsupportedCapability = { supported: false; error: Error };\n/** @internal */\nexport type Capability<T = void> = SupportedCapability<T> | UnsupportedCapability;\n\n//-----------\n// WebGL\n//-----------\n\ntype WebGlCapability = Capability<{ maxTextureSize: number }>;\n\n// This required minimum max texture size is based on data from\n// https://web3dsurvey.com/webgl/parameters/MAX_TEXTURE_SIZE. Checking for a reasonable minimum MAX_TEXTURE_SIZE avoids\n// attempting to run lenses on platforms that will not support them -- most commonly, we've seen some platforms that\n// report 0 MAX_TEXTURE_SIZE, which will cause errors for all lenses.\nconst minRequiredMaxTextureSize = 1024;\n\n/**\n * @returns An object with fields describing support for various WebGL features.\n *\n * @internal\n */\nfunction getWebGlSupport(): WebGlCapability {\n const ctx = globalThis.document?.createElement(\"canvas\").getContext(\"webgl2\");\n if (!ctx)\n return {\n supported: false,\n error: platformNotSupportedError(\"CameraKit requires WebGL2, but this browser does not support WebGL2.\"),\n };\n const maxTextureSize = ctx.getParameter(ctx.MAX_TEXTURE_SIZE);\n const supported = maxTextureSize >= minRequiredMaxTextureSize;\n return supported\n ? { supported, maxTextureSize }\n : {\n supported,\n error: platformNotSupportedError(\n `CameraKit requires WebGL's MAX_TEXTURE_SIZE exceed a minimum value of ` +\n `${minRequiredMaxTextureSize}, but the browser's reported MAX_TEXTURE_SIZE is ${maxTextureSize}.`\n ),\n };\n}\n\n//-----------\n// WASM\n//-----------\n\ntype WasmCapability = Capability<{ wasmFeatures: number }>;\n\n/**\n * Because there may be a large number of WASM-related capabilities, and because these may correspond to various builds\n * of LensCore, we encode the various WASM capabilities into a single number by bitwise OR-ing together the numbers\n * corresponding to each capability.\n *\n * Since each combindation of capabilities is represented by a single number, we can easily map between that number and\n * the corresponding LensCore build name that makes use of those capabilities.\n *\n * @internal\n */\nexport enum WasmFeatures {\n Default = 0b00000000,\n SIMD = 0b00000001,\n ExceptionHandling = 0b00000010,\n}\n\n/**\n * @returns A non-negative integer representing the combination of supported WebAssembly features, or -1 if WebAssembly\n * is not supported at all.\n *\n * @internal\n */\nasync function getWebAssemblyCapabilities(): Promise<WasmCapability> {\n if (globalThis.WebAssembly === undefined)\n return {\n supported: false,\n error: platformNotSupportedError(\n \"CameraKit requires WebAssembly, but this browser does not support WebAssembly.\"\n ),\n };\n return {\n supported: true,\n wasmFeatures: (\n await Promise.all([\n simd().then((supported) => {\n // Although Safari 16.4 reports SIMD support, LensCore encounters rendering bugs when using\n // SIMD in Safari 16.4. We will disable SIMD for now until Safari stabilizes the feature.\n if (getPlatformInfo().browser.brand === \"Safari\") return WasmFeatures.Default;\n return supported ? WasmFeatures.SIMD : WasmFeatures.Default;\n }),\n exceptions().then((supported) => (supported ? WasmFeatures.ExceptionHandling : WasmFeatures.Default)),\n ])\n ).reduce((features, feature) => features | feature, WasmFeatures.Default),\n };\n}\n\n//-----------\n// WebXR\n//-----------\n\ntype WebXrCapability = Capability<XrCapabilities>;\n\n/**\n * @returns A Promise containing an object with fields describing the support of various WebXR features. This object's\n * type is defined by LensCore, as they consume these capabilities and adjust behavior accordingly.\n *\n * @internal\n */\nasync function getWebXrCapabilities(): Promise<WebXrCapability> {\n const notSupported: WebXrCapability = {\n supported: false,\n error: platformNotSupportedError(\n `Use of this feature requires WebXR support for immersive AR sessions, but ` +\n `this browser does not support immersive AR sessions.`\n ),\n };\n if (!isSecureContext) return notSupported;\n if (!navigator.xr) return notSupported;\n const isImmersiveArSupported = await navigator.xr.isSessionSupported(\"immersive-ar\");\n return isImmersiveArSupported\n ? {\n supported: true,\n sixDofSupported: true,\n sceneDepthSupported: true,\n }\n : notSupported;\n}\n\n/** @internal */\nexport interface PlatformCapabilities {\n webgl: WebGlCapability;\n wasm: WasmCapability;\n webxr: WebXrCapability;\n}\n\n/**\n * Get information about the current platform capabilities, including:\n * - WebGL support and various WebGL parameters.\n * - WASM support and support for various WASM features.\n * - WebXR support and support for various WebXR features.\n *\n * @internal\n */\nexport const getPlatformCapabilities = memoize(async function getPlatformCapabilities(): Promise<PlatformCapabilities> {\n return {\n webgl: getWebGlSupport(),\n wasm: await getWebAssemblyCapabilities(),\n webxr: await getWebXrCapabilities(),\n };\n});\n"]}
@@ -25,7 +25,7 @@ function parseDeviceModel(userAgent) {
25
25
  if (userAgentWithModel) {
26
26
  return userAgentWithModel[1].trim();
27
27
  }
28
- // from user agent like "... (iPad; CPU OS 15_1 like Mac OS X) ..." extract "IPad"
28
+ // from user agent like "... (iPad; CPU OS 15_1 like Mac OS X) ..." extract "iPad"
29
29
  const userAgentWithModel2 = userAgent.match(/\(([^;]+);/);
30
30
  if (userAgentWithModel2) {
31
31
  return userAgentWithModel2[1].trim();
@@ -1 +1 @@
1
- {"version":3,"file":"platformInfo.js","sourceRoot":"","sources":["../../src/platform/platformInfo.ts"],"names":[],"mappings":"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","sourcesContent":["import { memoize } from \"../common/memoize\";\nimport { isRecord } from \"../common/typeguards\";\nimport environment from \"../environment.json\";\nimport lensCoreWasm from \"../lensCoreWasmVersions.json\";\n\ntype BrandArray = Array<{ brand: string; version: string }>;\n\ninterface NavigatorUAData {\n brands: BrandArray;\n mobile: boolean;\n platform: string;\n}\n\nexport type ConnectionType = \"bluetooth\" | \"cellular\" | \"ethernet\" | \"none\" | \"wifi\" | \"wimax\" | \"other\" | \"unknown\";\n\ndeclare global {\n interface Navigator {\n userAgentData?: NavigatorUAData;\n connection?: {\n // This currently has extremely limited support in browsers.\n // https://wicg.github.io/netinfo/#dom-networkinformation-type\n type?: ConnectionType;\n };\n }\n}\n\n/**\n * Some user agents may not properly implement the NavigatorUAData interface, so we have to do our own validation here\n * to make sure we're dealing with a well-formed value.\n */\nfunction isNavigatorUAData(value: unknown): value is NavigatorUAData {\n return (\n isRecord(value) &&\n Array.isArray(value[\"brands\"]) &&\n value[\"brands\"].every((brand) => {\n return isRecord(brand) && typeof brand[\"brand\"] === \"string\" && typeof brand[\"version\"] === \"string\";\n }) &&\n typeof value[\"mobile\"] === \"boolean\" &&\n typeof value[\"platform\"] === \"string\"\n );\n}\n\n/**\n * In the future, we may invest in more robust device-detection (e.g. a UA string database), but for now this will give\n * us some sense of device usage.\n */\nfunction parseDeviceModel(userAgent: string) {\n // from user agent like \"(Linux; Android 11; Pixel 2)\" extact \"Pixel 2\"\n const userAgentWithModel = userAgent.match(/;[^;]+?;([^\\)]+?)\\)/);\n\n if (userAgentWithModel) {\n return userAgentWithModel[1].trim();\n }\n\n // from user agent like \"... (iPad; CPU OS 15_1 like Mac OS X) ...\" extract \"IPad\"\n const userAgentWithModel2 = userAgent.match(/\\(([^;]+);/);\n\n if (userAgentWithModel2) {\n return userAgentWithModel2[1].trim();\n }\n\n return \"unknown\";\n}\n\n/**\n * The origin may be useful to identify the running application (e.g. to attribute metrics).\n *\n * We need to handle cases in which we run inside a child browsing context (e.g. an iframe), which may not have a\n * hostname – in this case we'll check each ancestor context until we find a valid hostname.\n */\nfunction parseOrigin(): string {\n if (location.hostname !== \"\") return location.hostname;\n\n // Firefox does not implement ancestorOrigins, so we need a fallback.\n // Context here: https://github.com/whatwg/html/issues/1918\n const possibleOrigins =\n location.ancestorOrigins === undefined && typeof window !== \"undefined\"\n ? [window.parent.origin, window.top?.origin ?? \"\"]\n : location.ancestorOrigins ?? [];\n\n for (let origin of possibleOrigins) {\n try {\n origin = new URL(origin).hostname;\n if (origin) return origin;\n } catch (_) {}\n }\n\n return \"unknown\";\n}\n\n/* eslint-disable max-len */\n/**\n * The backend defines the allowed list of known OSes which will pass their RegEx test when found in our custom\n * CameraKitWeb userAgent string.\n *\n * See https://github.sc-corp.net/Snapchat/useragent/blob/9333afe7cc6ac00503ad46cb234bcf94006dff98/java/useragent/src/main/java/snapchat/client/UserAgent.java#L124\n */\n/* eslint-enable */\ntype KnownPlatform = \"macos\" | \"windows\" | \"linux\" | \"android\" | \"ios\" | \"ipados\" | \"unknown\";\nfunction parseOSName(userAgent: string): KnownPlatform {\n const knownPlatforms = new Map<string, KnownPlatform>([\n [\"android\", \"android\"],\n [\"linux\", \"linux\"],\n [\"iphone os\", \"ios\"],\n [\"ipad\", \"ipados\"],\n [\"mac os\", \"macos\"],\n [\"macos\", \"macos\"],\n [\"windows\", \"windows\"],\n ]);\n\n const normalizedUserAgent = userAgent.toLowerCase();\n for (const [match, platform] of knownPlatforms.entries()) {\n if (normalizedUserAgent.includes(match)) return platform;\n }\n return \"unknown\";\n}\n\n/**\n * Parse the OS (a.k.a. platform) version.\n *\n * From limited testing, this seems to often produce incorrect results – the userAgent string does not typically include\n * the actual OS version.\n *\n * Better results could be obtained from [NavigatorUAData.getHighEntropyValues]\n * (https://developer.mozilla.org/en-US/docs/Web/API/NavigatorUAData/getHighEntropyValues), but this presents two\n * problems: 1) it's currently only supported on Chrome and 2) browsers may prompt the user for permission to share\n * this information.\n *\n * So, at least for now, we'll be satisfied with the incorrect version number.\n */\nfunction parseOSVersion(userAgent: string) {\n // possible platform version values inside of user agent string\n // \" 11;\"\n // \" 10_15_7)\"\n // \" 13_5_1 \"\n // \" 10.0;\"\n // \" 15_1 \"\n const versionMatch = userAgent.match(/\\s([\\d][\\d_.]*[\\d])(;|\\)|\\s)/);\n\n if (versionMatch != null) {\n return versionMatch[1].replace(/_/g, \".\");\n }\n\n return \"\";\n}\n\n/**\n * Some browsers (e.g. Safari) do not support the `Navigator.userAgentData` API. We'll attempt a sort of polyfill by\n * parsing the data found in [NavigatorUAData](https://developer.mozilla.org/en-US/docs/Web/API/NavigatorUAData) from\n * the raw user agent string.\n */\nfunction parseUserAgentData(userAgent: string): NavigatorUAData {\n let brand: BrandArray[number];\n\n // Parse UA string for Chromium-based browsers (e.g. Chrome, Edge)\n if (/Chrome/.test(userAgent)) {\n const versionMatch = userAgent.match(/Chrome\\/([\\d.]+)/);\n brand = {\n brand: \"Chrome\",\n version: versionMatch !== null ? versionMatch[1] : \"unknown\",\n };\n }\n\n // Parse UA string for Safari (very important for this to only be done if Chrome is not found – Chrome userAgent\n // strings will contain \"Safari\")\n else if (/Safari/.test(userAgent)) {\n let versionMatch = userAgent.match(/Version\\/([\\d.]+)/);\n if (versionMatch === null) versionMatch = userAgent.match(/Safari\\/([\\d.]+)/);\n brand = {\n brand: \"Safari\",\n version: versionMatch !== null ? versionMatch[1] : \"unknown\",\n };\n }\n\n // Parse UA for unknown browser.\n // TODO: will be changed, default value support should be added on a COF server side.\n else {\n brand = {\n brand: \"Firefox\",\n version: \"0\",\n };\n }\n\n // We're not using `mobile` for anything, and we have no consistent way to determine this from the UA string.\n // We'll set it to false, but this should not be used – instead, we'll need to rely on more sophisticated methods\n // (e.g. a userAgent database) to determine actual device.\n const mobile = false;\n const platform = parseOSName(userAgent);\n\n return {\n brands: [brand],\n mobile,\n platform,\n };\n}\n\n/* eslint-disable max-len */\n/**\n * The `brands` array found in [NavigatorUAData](https://developer.mozilla.org/en-US/docs/Web/API/NavigatorUAData) is\n * intentionally designed to discourage standardized processing. This method of extracting brand information will be\n * inherently brittle, and it relies on us matching some well-known brands.\n *\n * For more detail from the spec:\n * See https://wicg.github.io/ua-client-hints/#monkeypatch-html-windoworworkerglobalscope\n * And https://wicg.github.io/ua-client-hints/#grease\n *\n * We also must match the list of known brands allowed by the backend, defined here:\n * https://github.sc-corp.net/Snapchat/useragent/blob/9333afe7cc6ac00503ad46cb234bcf94006dff98/java/useragent/src/main/java/snapchat/client/UserAgent.java#L124\n */\n/* eslint-enable */\ntype KnownBrand = \"Chrome\" | \"Safari\" | \"Firefox\";\nfunction normalizeBrands(brands: BrandArray): BrandArray {\n const knownBrands = new Map<string, KnownBrand>([\n [\"Google Chrome\", \"Chrome\"],\n [\"Chrome\", \"Chrome\"],\n [\"Chromium\", \"Chrome\"],\n [\"Firefox\", \"Firefox\"],\n [\"Microsoft Edge\", \"Chrome\"],\n [\"Safari\", \"Safari\"],\n ]);\n\n const normalizedBrands = brands\n .filter(({ brand }) => knownBrands.has(brand))\n .map((brand) => {\n return {\n // Safety: we've filtered out brands which do not appear as keys in `knownBrands`, so this cannot return\n // undefined.\n brand: knownBrands.get(brand.brand)!,\n version: brand.version,\n };\n });\n\n // TODO: default \"unknown\" value should be added on COF server side. For now we'll use Firefox.\n if (normalizedBrands.length === 0) return [{ brand: \"Firefox\", version: \"0\" }];\n return normalizedBrands;\n}\n\n/* eslint-disable max-len */\n/**\n * We must ensure the data we get from `navigator.userAgentData` is normalized to match what our backend expects to\n * see in our custom CameraKitWeb userAgent string.\n *\n * This string is defined here:\n * https://github.sc-corp.net/Snapchat/useragent/blob/9333afe7cc6ac00503ad46cb234bcf94006dff98/java/useragent/src/main/java/snapchat/client/UserAgent.java#L124\n */\n/* eslint-enable */\nfunction normalizeUserAgentData(userAgentData: NavigatorUAData): NavigatorUAData {\n return {\n brands: normalizeBrands(userAgentData.brands),\n mobile: userAgentData.mobile,\n platform: parseOSName(userAgentData.platform),\n };\n}\n\n/** @internal */\nexport interface PlatformInfo {\n sdkShortVersion: string;\n sdkLongVersion: string;\n lensCore: {\n version: string;\n buildNumber: string;\n baseUrl: string;\n };\n browser: { brand: string; version: string };\n osName: string;\n osVersion: string;\n deviceModel: string;\n locale: string;\n fullLocale: string;\n origin: string;\n connectionType: ConnectionType;\n}\n\n/** @internal */\nexport const getPlatformInfo = memoize(function getPlatformIno(): PlatformInfo {\n // [NavigatorUAData](https://developer.mozilla.org/en-US/docs/Web/API/NavigatorUAData) is currently only\n // available on Chromium-based browsers – it's nice because it gives us clear, well-documented information. But\n // we'll have to fallback to parsing the userAgent string when it's not available.\n const userAgent = navigator.userAgent;\n const userAgentData = isNavigatorUAData(navigator.userAgentData)\n ? normalizeUserAgentData(navigator.userAgentData)\n : parseUserAgentData(userAgent);\n\n const osVersion = parseOSVersion(userAgent);\n const deviceModel = parseDeviceModel(userAgent);\n\n // Remove any `-prerelease` or `+buildmetadata` portions from the semver string.\n const sdkShortVersion = environment.PACKAGE_VERSION.replace(/[-+]\\S+$/, \"\");\n\n const locale = navigator.language;\n // The full locale string includes all the languages with qvalues -- this is needed for some API calls.\n // More on qvalues: https://developer.mozilla.org/en-US/docs/Glossary/Quality_values\n const fullLocale =\n (navigator.languages ?? [])\n .map((lang, index) => {\n const qvalue = Math.max(0, (10 - index) / 10);\n return `${lang};q=${qvalue.toFixed(1)}`;\n })\n .join(\", \") || locale;\n\n return {\n sdkShortVersion,\n sdkLongVersion: environment.PACKAGE_VERSION,\n lensCore: lensCoreWasm,\n // In cases where we've parsed the userAgent string to find the brand, there will only ever be a single brand –\n // in browsers which support NavigatorUAData there could be more than one (e.g. Chrome and Chromium), but they\n // should be equivalent for our purposes -- either way we're okay just picking the first one.\n browser: userAgentData.brands[0],\n osName: userAgentData.platform,\n osVersion,\n deviceModel,\n locale,\n fullLocale,\n origin: parseOrigin(),\n connectionType: navigator.connection?.type ?? \"unknown\",\n };\n});\n"]}
1
+ {"version":3,"file":"platformInfo.js","sourceRoot":"","sources":["../../src/platform/platformInfo.ts"],"names":[],"mappings":"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","sourcesContent":["import { memoize } from \"../common/memoize\";\nimport { isRecord } from \"../common/typeguards\";\nimport environment from \"../environment.json\";\nimport lensCoreWasm from \"../lensCoreWasmVersions.json\";\n\ntype BrandArray = Array<{ brand: string; version: string }>;\n\ninterface NavigatorUAData {\n brands: BrandArray;\n mobile: boolean;\n platform: string;\n}\n\nexport type ConnectionType = \"bluetooth\" | \"cellular\" | \"ethernet\" | \"none\" | \"wifi\" | \"wimax\" | \"other\" | \"unknown\";\n\ndeclare global {\n interface Navigator {\n userAgentData?: NavigatorUAData;\n connection?: {\n // This currently has extremely limited support in browsers.\n // https://wicg.github.io/netinfo/#dom-networkinformation-type\n type?: ConnectionType;\n };\n }\n}\n\n/**\n * Some user agents may not properly implement the NavigatorUAData interface, so we have to do our own validation here\n * to make sure we're dealing with a well-formed value.\n */\nfunction isNavigatorUAData(value: unknown): value is NavigatorUAData {\n return (\n isRecord(value) &&\n Array.isArray(value[\"brands\"]) &&\n value[\"brands\"].every((brand) => {\n return isRecord(brand) && typeof brand[\"brand\"] === \"string\" && typeof brand[\"version\"] === \"string\";\n }) &&\n typeof value[\"mobile\"] === \"boolean\" &&\n typeof value[\"platform\"] === \"string\"\n );\n}\n\n/**\n * In the future, we may invest in more robust device-detection (e.g. a UA string database), but for now this will give\n * us some sense of device usage.\n */\nfunction parseDeviceModel(userAgent: string) {\n // from user agent like \"(Linux; Android 11; Pixel 2)\" extact \"Pixel 2\"\n const userAgentWithModel = userAgent.match(/;[^;]+?;([^\\)]+?)\\)/);\n\n if (userAgentWithModel) {\n return userAgentWithModel[1].trim();\n }\n\n // from user agent like \"... (iPad; CPU OS 15_1 like Mac OS X) ...\" extract \"iPad\"\n const userAgentWithModel2 = userAgent.match(/\\(([^;]+);/);\n\n if (userAgentWithModel2) {\n return userAgentWithModel2[1].trim();\n }\n\n return \"unknown\";\n}\n\n/**\n * The origin may be useful to identify the running application (e.g. to attribute metrics).\n *\n * We need to handle cases in which we run inside a child browsing context (e.g. an iframe), which may not have a\n * hostname – in this case we'll check each ancestor context until we find a valid hostname.\n */\nfunction parseOrigin(): string {\n if (location.hostname !== \"\") return location.hostname;\n\n // Firefox does not implement ancestorOrigins, so we need a fallback.\n // Context here: https://github.com/whatwg/html/issues/1918\n const possibleOrigins =\n location.ancestorOrigins === undefined && typeof window !== \"undefined\"\n ? [window.parent.origin, window.top?.origin ?? \"\"]\n : location.ancestorOrigins ?? [];\n\n for (let origin of possibleOrigins) {\n try {\n origin = new URL(origin).hostname;\n if (origin) return origin;\n } catch (_) {}\n }\n\n return \"unknown\";\n}\n\n/* eslint-disable max-len */\n/**\n * The backend defines the allowed list of known OSes which will pass their RegEx test when found in our custom\n * CameraKitWeb userAgent string.\n *\n * See https://github.sc-corp.net/Snapchat/useragent/blob/9333afe7cc6ac00503ad46cb234bcf94006dff98/java/useragent/src/main/java/snapchat/client/UserAgent.java#L124\n */\n/* eslint-enable */\ntype KnownPlatform = \"macos\" | \"windows\" | \"linux\" | \"android\" | \"ios\" | \"ipados\" | \"unknown\";\nfunction parseOSName(userAgent: string): KnownPlatform {\n const knownPlatforms = new Map<string, KnownPlatform>([\n [\"android\", \"android\"],\n [\"linux\", \"linux\"],\n [\"iphone os\", \"ios\"],\n [\"ipad\", \"ipados\"],\n [\"mac os\", \"macos\"],\n [\"macos\", \"macos\"],\n [\"windows\", \"windows\"],\n ]);\n\n const normalizedUserAgent = userAgent.toLowerCase();\n for (const [match, platform] of knownPlatforms.entries()) {\n if (normalizedUserAgent.includes(match)) return platform;\n }\n return \"unknown\";\n}\n\n/**\n * Parse the OS (a.k.a. platform) version.\n *\n * From limited testing, this seems to often produce incorrect results – the userAgent string does not typically include\n * the actual OS version.\n *\n * Better results could be obtained from [NavigatorUAData.getHighEntropyValues]\n * (https://developer.mozilla.org/en-US/docs/Web/API/NavigatorUAData/getHighEntropyValues), but this presents two\n * problems: 1) it's currently only supported on Chrome and 2) browsers may prompt the user for permission to share\n * this information.\n *\n * So, at least for now, we'll be satisfied with the incorrect version number.\n */\nfunction parseOSVersion(userAgent: string) {\n // possible platform version values inside of user agent string\n // \" 11;\"\n // \" 10_15_7)\"\n // \" 13_5_1 \"\n // \" 10.0;\"\n // \" 15_1 \"\n const versionMatch = userAgent.match(/\\s([\\d][\\d_.]*[\\d])(;|\\)|\\s)/);\n\n if (versionMatch != null) {\n return versionMatch[1].replace(/_/g, \".\");\n }\n\n return \"\";\n}\n\n/**\n * Some browsers (e.g. Safari) do not support the `Navigator.userAgentData` API. We'll attempt a sort of polyfill by\n * parsing the data found in [NavigatorUAData](https://developer.mozilla.org/en-US/docs/Web/API/NavigatorUAData) from\n * the raw user agent string.\n */\nfunction parseUserAgentData(userAgent: string): NavigatorUAData {\n let brand: BrandArray[number];\n\n // Parse UA string for Chromium-based browsers (e.g. Chrome, Edge)\n if (/Chrome/.test(userAgent)) {\n const versionMatch = userAgent.match(/Chrome\\/([\\d.]+)/);\n brand = {\n brand: \"Chrome\",\n version: versionMatch !== null ? versionMatch[1] : \"unknown\",\n };\n }\n\n // Parse UA string for Safari (very important for this to only be done if Chrome is not found – Chrome userAgent\n // strings will contain \"Safari\")\n else if (/Safari/.test(userAgent)) {\n let versionMatch = userAgent.match(/Version\\/([\\d.]+)/);\n if (versionMatch === null) versionMatch = userAgent.match(/Safari\\/([\\d.]+)/);\n brand = {\n brand: \"Safari\",\n version: versionMatch !== null ? versionMatch[1] : \"unknown\",\n };\n }\n\n // Parse UA for unknown browser.\n // TODO: will be changed, default value support should be added on a COF server side.\n else {\n brand = {\n brand: \"Firefox\",\n version: \"0\",\n };\n }\n\n // We're not using `mobile` for anything, and we have no consistent way to determine this from the UA string.\n // We'll set it to false, but this should not be used – instead, we'll need to rely on more sophisticated methods\n // (e.g. a userAgent database) to determine actual device.\n const mobile = false;\n const platform = parseOSName(userAgent);\n\n return {\n brands: [brand],\n mobile,\n platform,\n };\n}\n\n/* eslint-disable max-len */\n/**\n * The `brands` array found in [NavigatorUAData](https://developer.mozilla.org/en-US/docs/Web/API/NavigatorUAData) is\n * intentionally designed to discourage standardized processing. This method of extracting brand information will be\n * inherently brittle, and it relies on us matching some well-known brands.\n *\n * For more detail from the spec:\n * See https://wicg.github.io/ua-client-hints/#monkeypatch-html-windoworworkerglobalscope\n * And https://wicg.github.io/ua-client-hints/#grease\n *\n * We also must match the list of known brands allowed by the backend, defined here:\n * https://github.sc-corp.net/Snapchat/useragent/blob/9333afe7cc6ac00503ad46cb234bcf94006dff98/java/useragent/src/main/java/snapchat/client/UserAgent.java#L124\n */\n/* eslint-enable */\ntype KnownBrand = \"Chrome\" | \"Safari\" | \"Firefox\";\nfunction normalizeBrands(brands: BrandArray): BrandArray {\n const knownBrands = new Map<string, KnownBrand>([\n [\"Google Chrome\", \"Chrome\"],\n [\"Chrome\", \"Chrome\"],\n [\"Chromium\", \"Chrome\"],\n [\"Firefox\", \"Firefox\"],\n [\"Microsoft Edge\", \"Chrome\"],\n [\"Safari\", \"Safari\"],\n ]);\n\n const normalizedBrands = brands\n .filter(({ brand }) => knownBrands.has(brand))\n .map((brand) => {\n return {\n // Safety: we've filtered out brands which do not appear as keys in `knownBrands`, so this cannot return\n // undefined.\n brand: knownBrands.get(brand.brand)!,\n version: brand.version,\n };\n });\n\n // TODO: default \"unknown\" value should be added on COF server side. For now we'll use Firefox.\n if (normalizedBrands.length === 0) return [{ brand: \"Firefox\", version: \"0\" }];\n return normalizedBrands;\n}\n\n/* eslint-disable max-len */\n/**\n * We must ensure the data we get from `navigator.userAgentData` is normalized to match what our backend expects to\n * see in our custom CameraKitWeb userAgent string.\n *\n * This string is defined here:\n * https://github.sc-corp.net/Snapchat/useragent/blob/9333afe7cc6ac00503ad46cb234bcf94006dff98/java/useragent/src/main/java/snapchat/client/UserAgent.java#L124\n */\n/* eslint-enable */\nfunction normalizeUserAgentData(userAgentData: NavigatorUAData): NavigatorUAData {\n return {\n brands: normalizeBrands(userAgentData.brands),\n mobile: userAgentData.mobile,\n platform: parseOSName(userAgentData.platform),\n };\n}\n\n/** @internal */\nexport interface PlatformInfo {\n sdkShortVersion: string;\n sdkLongVersion: string;\n lensCore: {\n version: string;\n buildNumber: string;\n baseUrl: string;\n };\n browser: { brand: string; version: string };\n osName: string;\n osVersion: string;\n deviceModel: string;\n locale: string;\n fullLocale: string;\n origin: string;\n connectionType: ConnectionType;\n}\n\n/** @internal */\nexport const getPlatformInfo = memoize(function getPlatformIno(): PlatformInfo {\n // [NavigatorUAData](https://developer.mozilla.org/en-US/docs/Web/API/NavigatorUAData) is currently only\n // available on Chromium-based browsers – it's nice because it gives us clear, well-documented information. But\n // we'll have to fallback to parsing the userAgent string when it's not available.\n const userAgent = navigator.userAgent;\n const userAgentData = isNavigatorUAData(navigator.userAgentData)\n ? normalizeUserAgentData(navigator.userAgentData)\n : parseUserAgentData(userAgent);\n\n const osVersion = parseOSVersion(userAgent);\n const deviceModel = parseDeviceModel(userAgent);\n\n // Remove any `-prerelease` or `+buildmetadata` portions from the semver string.\n const sdkShortVersion = environment.PACKAGE_VERSION.replace(/[-+]\\S+$/, \"\");\n\n const locale = navigator.language;\n // The full locale string includes all the languages with qvalues -- this is needed for some API calls.\n // More on qvalues: https://developer.mozilla.org/en-US/docs/Glossary/Quality_values\n const fullLocale =\n (navigator.languages ?? [])\n .map((lang, index) => {\n const qvalue = Math.max(0, (10 - index) / 10);\n return `${lang};q=${qvalue.toFixed(1)}`;\n })\n .join(\", \") || locale;\n\n return {\n sdkShortVersion,\n sdkLongVersion: environment.PACKAGE_VERSION,\n lensCore: lensCoreWasm,\n // In cases where we've parsed the userAgent string to find the brand, there will only ever be a single brand –\n // in browsers which support NavigatorUAData there could be more than one (e.g. Chrome and Chromium), but they\n // should be equivalent for our purposes -- either way we're okay just picking the first one.\n browser: userAgentData.brands[0],\n osName: userAgentData.platform,\n osVersion,\n deviceModel,\n locale,\n fullLocale,\n origin: parseOrigin(),\n connectionType: navigator.connection?.type ?? \"unknown\",\n };\n});\n"]}
@@ -9,6 +9,7 @@ export interface Metadata {
9
9
  export declare const COF_REQUEST_TYPE = "cof";
10
10
  export type CofDimensions = {
11
11
  requestType: typeof COF_REQUEST_TYPE;
12
+ delta: string;
12
13
  };
13
14
  /**
14
15
  * Handler chain used to make COF requests. Uses the COF client to perform the
@@ -1,20 +1,24 @@
1
1
  import { __awaiter, __rest } from "tslib";
2
+ /* eslint-disable max-len */
2
3
  import { BrowserHeaders } from "browser-headers";
3
4
  import { getCameraKitUserAgent } from "../platform/cameraKitUserAgent";
4
5
  import { ensureError } from "../common/errorHelpers";
6
+ import { unionBy } from "../common/unionBy";
5
7
  import { CircumstancesServiceClientImpl, GrpcWebImpl } from "../generated-proto/pb_schema/cdp/cof/circumstance_service";
6
8
  import { HandlerChainBuilder } from "../handlers/HandlerChainBuilder";
7
9
  import { dispatchRequestCompleted, dispatchRequestErrored, dispatchRequestStarted, requestStateEventTargetFactory, } from "../handlers/requestStateEmittingHandler";
8
10
  import { createResponseCachingHandler, staleWhileRevalidateStrategy } from "../handlers/responseCachingHandler";
9
11
  import { createRetryingHandler } from "../handlers/retryingHandler";
10
12
  import { createTimeoutHandler } from "../handlers/timeoutHandler";
11
- import { ExpiringPersistence } from "../persistence/ExpiringPersistence";
12
13
  import { IndexedDBPersistence } from "../persistence/IndexedDBPersistence";
13
14
  import { operationalMetricReporterFactory, } from "../metrics/operational/operationalMetricsReporter";
14
15
  import { configurationToken } from "../configuration";
15
16
  import { Injectable } from "../dependency-injection/Injectable";
16
- const id = (h) => h;
17
+ import { getLogger } from "../logger/logger";
18
+ import { ExpiringPersistence } from "../persistence/ExpiringPersistence";
19
+ import { convertDaysToSeconds } from "../common/time";
17
20
  export const COF_REQUEST_TYPE = "cof";
21
+ const logger = getLogger("cofHandler");
18
22
  /**
19
23
  * Handler chain used to make COF requests. Uses the COF client to perform the
20
24
  * requests, with retries, timeout, and caching.
@@ -24,6 +28,8 @@ export const COF_REQUEST_TYPE = "cof";
24
28
  * will retry (with exponential backoff + jitter) for 5 seconds before returning an error to the caller.
25
29
  */
26
30
  export const cofHandlerFactory = Injectable("cofHandler", [configurationToken, requestStateEventTargetFactory.token, operationalMetricReporterFactory.token], (config, requestStateEventTarget, reporter) => {
31
+ const cofCache = new ExpiringPersistence(() => convertDaysToSeconds(365), new IndexedDBPersistence({ databaseName: "COFCache" }));
32
+ const getCacheKey = (r) => JSON.stringify(r);
27
33
  // We need to wrap `targetingQuery` to create a usable Handler – the main issue is that HandlerChainBuilder
28
34
  // always adds a `signal` property to the metadata argument (second argument of the Handler), but
29
35
  // `targetingQuery` expects the second argument to only contain headers.
@@ -31,72 +37,77 @@ export const cofHandlerFactory = Injectable("cofHandler", [configurationToken, r
31
37
  var { signal, isSideEffect: _ } = _a, metadata = __rest(_a, ["signal", "isSideEffect"]);
32
38
  const rpc = new GrpcWebImpl(`https://${config.apiHostname}`, {});
33
39
  const client = new CircumstancesServiceClientImpl(rpc);
34
- return new Promise((resolve, reject) => {
40
+ return new Promise((resolve, reject) => __awaiter(void 0, void 0, void 0, function* () {
41
+ var _b;
35
42
  if (signal) {
36
43
  signal.addEventListener("abort", () => reject(new Error("COF request aborted by handler chain.")));
37
44
  }
38
- client
39
- .targetingQuery(request, new BrowserHeaders(Object.assign({ authorization: `Bearer ${config.apiToken}`, "x-snap-client-user-agent": getCameraKitUserAgent() }, metadata)))
40
- .then((response) => {
41
- // NOTE: in order for cache persistance to work, we need to make the object cloneable,
42
- // i.e. with no methods (it appears targetingQuery() attaches toObject() to response
43
- // object). Safety: We have to cast response object to a type that has toObject
44
- // defined, because that is indeed what generated code has:
45
+ const cachedResponse = yield cofCache.retrieve(getCacheKey(request)).catch((e) => {
46
+ logger.warn("Unable to get COF response from cache.", e);
47
+ return {
48
+ configResultsEtag: undefined,
49
+ configResults: [],
50
+ };
51
+ });
52
+ const dimensions = {
53
+ requestType: COF_REQUEST_TYPE,
54
+ delta: `${!!(cachedResponse === null || cachedResponse === void 0 ? void 0 : cachedResponse.configResultsEtag)}`,
55
+ };
56
+ const { requestId } = dispatchRequestStarted(requestStateEventTarget, { dimensions });
57
+ try {
58
+ const response = yield client.targetingQuery(Object.assign(Object.assign({}, request), { configResultsEtag: cachedResponse === null || cachedResponse === void 0 ? void 0 : cachedResponse.configResultsEtag, deltaSync: !!(cachedResponse === null || cachedResponse === void 0 ? void 0 : cachedResponse.configResultsEtag) }), new BrowserHeaders(Object.assign({ authorization: `Bearer ${config.apiToken}`, "x-snap-client-user-agent": getCameraKitUserAgent() }, metadata)));
59
+ // NOTE: in order for cache persistance to work, we need to make the
60
+ // object cloneable i.e. with no methods (it appears targetingQuery()
61
+ // attaches toObject() to response object). Safety: We have to cast response
62
+ // object to a type that has toObject defined, because that is indeed
63
+ // what generated code has:
45
64
  // eslint-disable-next-line max-len
46
65
  // https://github.sc-corp.net/Snapchat/camera-kit-web-sdk/blob/8d6b4e8bfa3717b376ab197a49972a1e410851f7/packages/web-sdk/src/generated-proto/pb_schema/cdp/cof/circumstance_service.ts#L1459
47
66
  delete response.toObject;
48
- resolve(response);
49
- })
50
- .catch(reject);
51
- });
52
- }))
53
- .map(id((next) => (request, metadata) => __awaiter(void 0, void 0, void 0, function* () {
54
- const dimensions = { requestType: COF_REQUEST_TYPE };
55
- const { requestId } = dispatchRequestStarted(requestStateEventTarget, { dimensions });
56
- try {
57
- const response = yield next(request, metadata);
58
- // TODO: We hardcode status code and sizeByte values because we do not have access to
59
- // underlying transport of configs-web.
60
- // When this ticket is done https://jira.sc-corp.net/browse/CAMKIT-2840,
61
- // we will remove this handler and benefit from existing ones.
62
- const status = 200;
63
- let sizeByte = 0;
64
- try {
65
- sizeByte = new TextEncoder().encode(JSON.stringify(response)).byteLength;
67
+ // Merge the cached configs into the just-returned configs, making sure to remove any configs that are marked as deleted -- this will then get cached by
68
+ // the responseCachingHandler as we return up the handler chain.
69
+ const configResults = unionBy("configId", (_b = cachedResponse === null || cachedResponse === void 0 ? void 0 : cachedResponse.configResults) !== null && _b !== void 0 ? _b : [], response.configResults).filter((config) => !config.delete);
70
+ // TODO: We hardcode status code and sizeByte values because we do not have access to
71
+ // underlying transport of configs-web.
72
+ // When this ticket is done https://jira.sc-corp.net/browse/CAMKIT-2840,
73
+ // we will remove this handler and benefit from existing ones.
74
+ const status = 200;
75
+ let sizeByte = 0;
76
+ try {
77
+ sizeByte = new TextEncoder().encode(JSON.stringify(response)).byteLength;
78
+ }
79
+ finally {
80
+ dispatchRequestCompleted(requestStateEventTarget, {
81
+ requestId,
82
+ dimensions,
83
+ status,
84
+ sizeByte,
85
+ });
86
+ }
87
+ resolve(Object.assign(Object.assign({}, response), { configResults }));
66
88
  }
67
- finally {
68
- dispatchRequestCompleted(requestStateEventTarget, {
89
+ catch (error) {
90
+ dispatchRequestErrored(requestStateEventTarget, {
69
91
  requestId,
70
92
  dimensions,
71
- status,
72
- sizeByte,
93
+ error: ensureError(error),
73
94
  });
74
- return response;
95
+ reject(error);
75
96
  }
76
- }
77
- catch (error) {
78
- dispatchRequestErrored(requestStateEventTarget, {
79
- requestId,
80
- dimensions,
81
- error: ensureError(error),
82
- });
83
- throw error;
84
- }
85
- })))
97
+ }));
98
+ }))
86
99
  // targetingQuery() always converts failed responses into errors (unlike fetch()), so we need a custom
87
100
  // retryPredicate that retries all errors. We'll keep retrying (with backoff) for 20 seconds total
88
101
  // elapsed time before we return an error back up the chain.
89
102
  .map(createRetryingHandler({ retryPredicate: (r) => r instanceof Error }))
90
103
  // API gateway has 15 seconds timeout, so we rely on that first
91
104
  .map(createTimeoutHandler({ timeout: 20 * 1000 }))
92
- .map(createResponseCachingHandler(
93
- // COF responses will be removed from cache after 1 week. Keep in mind that the
94
- // staleWhileRevalidate strategy will update the cache each time COF is requested
95
- // – this expiration comes into play only if e.g. a user doesn't load the page
96
- // for more than a week.
97
- new ExpiringPersistence(() => 7 * 24 * 60 * 60, new IndexedDBPersistence({ databaseName: "COFCache" })), (r) => JSON.stringify(r),
105
+ .map(createResponseCachingHandler(cofCache, getCacheKey,
98
106
  // If we have a matching response already in cache,
99
107
  // we'll return it immediately and then update the cache in the background.
100
- staleWhileRevalidateStrategy({ requestType: "cof", reporter }))).handler);
108
+ staleWhileRevalidateStrategy({
109
+ requestType: "cof",
110
+ reporter,
111
+ }))).handler);
101
112
  });
102
113
  //# sourceMappingURL=cofHandler.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"cofHandler.js","sourceRoot":"","sources":["../../src/remote-configuration/cofHandler.ts"],"names":[],"mappings":"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","sourcesContent":["import { BrowserHeaders } from \"browser-headers\";\nimport { getCameraKitUserAgent } from \"../platform/cameraKitUserAgent\";\nimport { ensureError } from \"../common/errorHelpers\";\nimport { CircumstancesServiceClientImpl, GrpcWebImpl } from \"../generated-proto/pb_schema/cdp/cof/circumstance_service\";\nimport { ConfigTargetingRequest } from \"../generated-proto/pb_schema/cdp/cof/config_request\";\nimport { ConfigTargetingResponse } from \"../generated-proto/pb_schema/cdp/cof/config_response\";\nimport { ChainableHandler, HandlerChainBuilder, RequestMetadata } from \"../handlers/HandlerChainBuilder\";\nimport {\n RequestStateEventTarget,\n dispatchRequestCompleted,\n dispatchRequestErrored,\n dispatchRequestStarted,\n requestStateEventTargetFactory,\n} from \"../handlers/requestStateEmittingHandler\";\nimport { createResponseCachingHandler, staleWhileRevalidateStrategy } from \"../handlers/responseCachingHandler\";\nimport { createRetryingHandler } from \"../handlers/retryingHandler\";\nimport { createTimeoutHandler } from \"../handlers/timeoutHandler\";\nimport { ExpiringPersistence } from \"../persistence/ExpiringPersistence\";\nimport { IndexedDBPersistence } from \"../persistence/IndexedDBPersistence\";\nimport {\n OperationalMetricsReporter,\n operationalMetricReporterFactory,\n} from \"../metrics/operational/operationalMetricsReporter\";\nimport { CameraKitConfiguration, configurationToken } from \"../configuration\";\nimport { Injectable } from \"../dependency-injection/Injectable\";\n\nexport interface Metadata {\n [key: string]: string;\n}\n\nconst id = <Req, Res, Meta extends RequestMetadata>(h: ChainableHandler<Req, Res, Req, Res, Meta>) => h;\n\nexport const COF_REQUEST_TYPE = \"cof\";\n\nexport type CofDimensions = { requestType: typeof COF_REQUEST_TYPE };\n\n/**\n * Handler chain used to make COF requests. Uses the COF client to perform the\n * requests, with retries, timeout, and caching.\n *\n * The handler will first attempt to retrieve the COF response from cache. If it is found, the result is returned\n * immediately and the cache is updated in the background. If no response is found, a COF request is made. This request\n * will retry (with exponential backoff + jitter) for 5 seconds before returning an error to the caller.\n */\nexport const cofHandlerFactory = Injectable(\n \"cofHandler\",\n [configurationToken, requestStateEventTargetFactory.token, operationalMetricReporterFactory.token] as const,\n (\n config: CameraKitConfiguration,\n requestStateEventTarget: RequestStateEventTarget,\n reporter: OperationalMetricsReporter\n ) => {\n // We need to wrap `targetingQuery` to create a usable Handler – the main issue is that HandlerChainBuilder\n // always adds a `signal` property to the metadata argument (second argument of the Handler), but\n // `targetingQuery` expects the second argument to only contain headers.\n return (\n new HandlerChainBuilder(\n async (\n request: Partial<ConfigTargetingRequest>,\n { signal, isSideEffect: _, ...metadata }: Metadata & RequestMetadata\n ) => {\n const rpc = new GrpcWebImpl(`https://${config.apiHostname}`, {});\n const client = new CircumstancesServiceClientImpl(rpc);\n return new Promise<ConfigTargetingResponse>((resolve, reject) => {\n if (signal) {\n signal.addEventListener(\"abort\", () =>\n reject(new Error(\"COF request aborted by handler chain.\"))\n );\n }\n client\n .targetingQuery(\n request,\n new BrowserHeaders({\n authorization: `Bearer ${config.apiToken}`,\n \"x-snap-client-user-agent\": getCameraKitUserAgent(),\n ...metadata,\n })\n )\n .then((response) => {\n // NOTE: in order for cache persistance to work, we need to make the object cloneable,\n // i.e. with no methods (it appears targetingQuery() attaches toObject() to response\n // object). Safety: We have to cast response object to a type that has toObject\n // defined, because that is indeed what generated code has:\n // eslint-disable-next-line max-len\n // https://github.sc-corp.net/Snapchat/camera-kit-web-sdk/blob/8d6b4e8bfa3717b376ab197a49972a1e410851f7/packages/web-sdk/src/generated-proto/pb_schema/cdp/cof/circumstance_service.ts#L1459\n delete (response as any).toObject;\n resolve(response);\n })\n .catch(reject);\n });\n }\n )\n .map(\n id((next) => async (request, metadata) => {\n const dimensions: CofDimensions = { requestType: COF_REQUEST_TYPE };\n const { requestId } = dispatchRequestStarted(requestStateEventTarget, { dimensions });\n try {\n const response = await next(request, metadata);\n // TODO: We hardcode status code and sizeByte values because we do not have access to\n // underlying transport of configs-web.\n // When this ticket is done https://jira.sc-corp.net/browse/CAMKIT-2840,\n // we will remove this handler and benefit from existing ones.\n const status = 200;\n let sizeByte = 0;\n try {\n sizeByte = new TextEncoder().encode(JSON.stringify(response)).byteLength;\n } finally {\n dispatchRequestCompleted(requestStateEventTarget, {\n requestId,\n dimensions,\n status,\n sizeByte,\n });\n return response;\n }\n } catch (error) {\n dispatchRequestErrored(requestStateEventTarget, {\n requestId,\n dimensions,\n error: ensureError(error),\n });\n throw error;\n }\n })\n )\n // targetingQuery() always converts failed responses into errors (unlike fetch()), so we need a custom\n // retryPredicate that retries all errors. We'll keep retrying (with backoff) for 20 seconds total\n // elapsed time before we return an error back up the chain.\n .map(createRetryingHandler({ retryPredicate: (r) => r instanceof Error }))\n // API gateway has 15 seconds timeout, so we rely on that first\n .map(createTimeoutHandler({ timeout: 20 * 1000 }))\n .map(\n createResponseCachingHandler(\n // COF responses will be removed from cache after 1 week. Keep in mind that the\n // staleWhileRevalidate strategy will update the cache each time COF is requested\n // – this expiration comes into play only if e.g. a user doesn't load the page\n // for more than a week.\n new ExpiringPersistence<ConfigTargetingResponse>(\n () => 7 * 24 * 60 * 60,\n new IndexedDBPersistence({ databaseName: \"COFCache\" })\n ),\n (r: Partial<ConfigTargetingRequest>) => JSON.stringify(r),\n\n // If we have a matching response already in cache,\n // we'll return it immediately and then update the cache in the background.\n staleWhileRevalidateStrategy({ requestType: \"cof\", reporter })\n )\n ).handler\n );\n }\n);\n"]}
1
+ {"version":3,"file":"cofHandler.js","sourceRoot":"","sources":["../../src/remote-configuration/cofHandler.ts"],"names":[],"mappings":"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","sourcesContent":["/* eslint-disable max-len */\nimport { BrowserHeaders } from \"browser-headers\";\nimport { getCameraKitUserAgent } from \"../platform/cameraKitUserAgent\";\nimport { ensureError } from \"../common/errorHelpers\";\nimport { unionBy } from \"../common/unionBy\";\nimport { CircumstancesServiceClientImpl, GrpcWebImpl } from \"../generated-proto/pb_schema/cdp/cof/circumstance_service\";\nimport { ConfigTargetingRequest } from \"../generated-proto/pb_schema/cdp/cof/config_request\";\nimport { ConfigTargetingResponse } from \"../generated-proto/pb_schema/cdp/cof/config_response\";\nimport { HandlerChainBuilder, RequestMetadata } from \"../handlers/HandlerChainBuilder\";\nimport {\n RequestStateEventTarget,\n dispatchRequestCompleted,\n dispatchRequestErrored,\n dispatchRequestStarted,\n requestStateEventTargetFactory,\n} from \"../handlers/requestStateEmittingHandler\";\nimport { createResponseCachingHandler, staleWhileRevalidateStrategy } from \"../handlers/responseCachingHandler\";\nimport { createRetryingHandler } from \"../handlers/retryingHandler\";\nimport { createTimeoutHandler } from \"../handlers/timeoutHandler\";\nimport { IndexedDBPersistence } from \"../persistence/IndexedDBPersistence\";\nimport {\n OperationalMetricsReporter,\n operationalMetricReporterFactory,\n} from \"../metrics/operational/operationalMetricsReporter\";\nimport { CameraKitConfiguration, configurationToken } from \"../configuration\";\nimport { Injectable } from \"../dependency-injection/Injectable\";\nimport { getLogger } from \"../logger/logger\";\nimport { ExpiringPersistence } from \"../persistence/ExpiringPersistence\";\nimport { convertDaysToSeconds } from \"../common/time\";\n\nexport interface Metadata {\n [key: string]: string;\n}\n\nexport const COF_REQUEST_TYPE = \"cof\";\n\nexport type CofDimensions = { requestType: typeof COF_REQUEST_TYPE; delta: string };\n\nconst logger = getLogger(\"cofHandler\");\n\n/**\n * Handler chain used to make COF requests. Uses the COF client to perform the\n * requests, with retries, timeout, and caching.\n *\n * The handler will first attempt to retrieve the COF response from cache. If it is found, the result is returned\n * immediately and the cache is updated in the background. If no response is found, a COF request is made. This request\n * will retry (with exponential backoff + jitter) for 5 seconds before returning an error to the caller.\n */\nexport const cofHandlerFactory = Injectable(\n \"cofHandler\",\n [configurationToken, requestStateEventTargetFactory.token, operationalMetricReporterFactory.token] as const,\n (\n config: CameraKitConfiguration,\n requestStateEventTarget: RequestStateEventTarget,\n reporter: OperationalMetricsReporter\n ) => {\n const cofCache = new ExpiringPersistence<ConfigTargetingResponse>(\n () => convertDaysToSeconds(365),\n new IndexedDBPersistence({ databaseName: \"COFCache\" })\n );\n const getCacheKey = (r: Partial<ConfigTargetingRequest>) => JSON.stringify(r);\n // We need to wrap `targetingQuery` to create a usable Handler – the main issue is that HandlerChainBuilder\n // always adds a `signal` property to the metadata argument (second argument of the Handler), but\n // `targetingQuery` expects the second argument to only contain headers.\n return (\n new HandlerChainBuilder(\n async (\n request: Partial<ConfigTargetingRequest>,\n { signal, isSideEffect: _, ...metadata }: Metadata & RequestMetadata\n ) => {\n const rpc = new GrpcWebImpl(`https://${config.apiHostname}`, {});\n const client = new CircumstancesServiceClientImpl(rpc);\n return new Promise<ConfigTargetingResponse>(async (resolve, reject) => {\n if (signal) {\n signal.addEventListener(\"abort\", () =>\n reject(new Error(\"COF request aborted by handler chain.\"))\n );\n }\n\n const cachedResponse = await cofCache.retrieve(getCacheKey(request)).catch((e) => {\n logger.warn(\"Unable to get COF response from cache.\", e);\n return {\n configResultsEtag: undefined,\n configResults: [],\n };\n });\n const dimensions: CofDimensions = {\n requestType: COF_REQUEST_TYPE,\n delta: `${!!cachedResponse?.configResultsEtag}`,\n };\n const { requestId } = dispatchRequestStarted(requestStateEventTarget, { dimensions });\n\n try {\n const response = await client.targetingQuery(\n {\n ...request,\n configResultsEtag: cachedResponse?.configResultsEtag,\n deltaSync: !!cachedResponse?.configResultsEtag,\n },\n new BrowserHeaders({\n authorization: `Bearer ${config.apiToken}`,\n \"x-snap-client-user-agent\": getCameraKitUserAgent(),\n ...metadata,\n })\n );\n\n // NOTE: in order for cache persistance to work, we need to make the\n // object cloneable i.e. with no methods (it appears targetingQuery()\n // attaches toObject() to response object). Safety: We have to cast response\n // object to a type that has toObject defined, because that is indeed\n // what generated code has:\n // eslint-disable-next-line max-len\n // https://github.sc-corp.net/Snapchat/camera-kit-web-sdk/blob/8d6b4e8bfa3717b376ab197a49972a1e410851f7/packages/web-sdk/src/generated-proto/pb_schema/cdp/cof/circumstance_service.ts#L1459\n delete (response as any).toObject;\n\n // Merge the cached configs into the just-returned configs, making sure to remove any configs that are marked as deleted -- this will then get cached by\n // the responseCachingHandler as we return up the handler chain.\n const configResults = unionBy(\n \"configId\",\n cachedResponse?.configResults ?? [],\n response.configResults\n ).filter((config) => !config.delete);\n\n // TODO: We hardcode status code and sizeByte values because we do not have access to\n // underlying transport of configs-web.\n // When this ticket is done https://jira.sc-corp.net/browse/CAMKIT-2840,\n // we will remove this handler and benefit from existing ones.\n const status = 200;\n let sizeByte = 0;\n try {\n sizeByte = new TextEncoder().encode(JSON.stringify(response)).byteLength;\n } finally {\n dispatchRequestCompleted(requestStateEventTarget, {\n requestId,\n dimensions,\n status,\n sizeByte,\n });\n }\n\n resolve({\n ...response,\n configResults,\n });\n } catch (error) {\n dispatchRequestErrored(requestStateEventTarget, {\n requestId,\n dimensions,\n error: ensureError(error),\n });\n reject(error);\n }\n });\n }\n )\n // targetingQuery() always converts failed responses into errors (unlike fetch()), so we need a custom\n // retryPredicate that retries all errors. We'll keep retrying (with backoff) for 20 seconds total\n // elapsed time before we return an error back up the chain.\n .map(createRetryingHandler({ retryPredicate: (r) => r instanceof Error }))\n // API gateway has 15 seconds timeout, so we rely on that first\n .map(createTimeoutHandler({ timeout: 20 * 1000 }))\n .map(\n createResponseCachingHandler(\n cofCache,\n getCacheKey,\n // If we have a matching response already in cache,\n // we'll return it immediately and then update the cache in the background.\n staleWhileRevalidateStrategy({\n requestType: \"cof\",\n reporter,\n })\n )\n ).handler\n );\n }\n);\n"]}
@@ -1,9 +1,9 @@
1
1
  import { Observable } from "rxjs";
2
- import { Lens } from "../lens";
2
+ import { Lens } from "../lens/Lens";
3
3
  import { LensCore } from "../lens-core-module";
4
- import { LensLaunchParams } from "../lens/LensLaunchParams";
4
+ import { LensLaunchData } from "../lens/LensLaunchData";
5
5
  import { TypedEventTarget } from "../events/TypedEventTarget";
6
- import { CameraKitDeviceInfo, CameraKitDeviceOptions, CameraKitSource } from "../media-sources/CameraKitSource";
6
+ import { CameraKitDeviceOptions, CameraKitSource } from "../media-sources/CameraKitSource";
7
7
  import { LogEntry } from "../logger/logger";
8
8
  import { PageVisibility } from "../common/pageVisibility";
9
9
  import { LensPerformanceMetrics } from "./LensPerformanceMetrics";
@@ -66,7 +66,10 @@ export declare class CameraKitSession {
66
66
  * Indicates whether or not the session is currently rendering. If `false`, rendering is stopped. Otherwise the
67
67
  * value indicates which output is being rendered.
68
68
  */
69
- playing: false | RenderTarget;
69
+ playing: {
70
+ live: boolean;
71
+ capture: boolean;
72
+ };
70
73
  /**
71
74
  * Add event listeners here to handle events which occur during the CameraKitSession.
72
75
  *
@@ -135,7 +138,7 @@ export declare class CameraKitSession {
135
138
  * - Lens content download fails, or the download of any required lens assets fails.
136
139
  * - An internal failure occurs in the Lens rendering engine when attempting to apply the lens.
137
140
  */
138
- applyLens(lens: Lens, launchParams?: LensLaunchParams): Promise<boolean>;
141
+ applyLens(lens: Lens, launchData?: LensLaunchData): Promise<boolean>;
139
142
  /**
140
143
  * Remove a Lens from this session.
141
144
  *
@@ -212,11 +215,6 @@ export declare class CameraKitSession {
212
215
  * the {@link CameraKitSource} object attached to the session.
213
216
  */
214
217
  setSource(source: CameraKitSource): Promise<CameraKitSource>;
215
- /** Deprecated: Support for CameraKitDeviceInfo will be removed in future releases.
216
- * Please use CameraKitDeviceOptions instead which accepts the "environment" and "user" cameraType
217
- * @deprecated
218
- */
219
- setSource(source: MediaStream | HTMLVideoElement, options?: Partial<CameraKitDeviceInfo>): Promise<CameraKitSource>;
220
218
  setSource(source: MediaStream | HTMLVideoElement, options?: Partial<CameraKitDeviceOptions>): Promise<CameraKitSource>;
221
219
  /**
222
220
  * Set an FPS limit.
@@ -247,7 +245,7 @@ export declare class CameraKitSession {
247
245
  export declare const cameraKitSessionFactory: {
248
246
  (args_0: LensCore, args_1: Observable<LogEntry>, args_2: LensKeyboard, args_3: import("@snap/state-management").StateMachine<import("@snap/state-management").Action<"suspend", CameraKitSession> | import("@snap/state-management").Action<"resume", CameraKitSession> | import("@snap/state-management").Action<"destroy", undefined>, import("@snap/state-management").State<"inactive", undefined> | import("@snap/state-management").State<"active", CameraKitSession> | import("@snap/state-management").State<"destroyed", undefined>>, args_4: import("@snap/state-management").StateMachine<import("@snap/state-management").Action<"applyLens", {
249
247
  lens: Lens;
250
- launchParams?: LensLaunchParams | undefined;
248
+ launchData?: LensLaunchData | undefined;
251
249
  }> | import("@snap/state-management").Action<"downloadComplete", Lens> | import("@snap/state-management").Action<"turnedOn", Lens> | import("@snap/state-management").Action<"resourcesLoaded", Lens> | import("@snap/state-management").Action<"firstFrameProcessed", Lens> | import("@snap/state-management").Action<"applyLensComplete", Lens> | import("@snap/state-management").Action<"applyLensFailed", {
252
250
  error: import("./lensState").LensErrors;
253
251
  lens: Lens;
@@ -2,7 +2,7 @@ import { __awaiter, __decorate, __metadata, __param } from "tslib";
2
2
  /* eslint-disable @typescript-eslint/member-ordering */
3
3
  import { filter, firstValueFrom, map, of, takeUntil, tap } from "rxjs";
4
4
  import { dispatch, forActions, inStates, isAction, isState } from "@snap/state-management";
5
- import { isLens } from "../lens";
5
+ import { isLens } from "../lens/Lens";
6
6
  import { Injectable } from "../dependency-injection/Injectable";
7
7
  import { lensCoreFactory } from "../lens-core-module/loader/lensCoreFactory";
8
8
  import { getTypeName, guard, validate } from "../common/validate";
@@ -78,7 +78,10 @@ export class CameraKitSession {
78
78
  live: outputs[this.lensCore.CanvasType.Preview.value],
79
79
  capture: outputs[this.lensCore.CanvasType.Capture.value],
80
80
  };
81
- this.playing = false;
81
+ this.playing = {
82
+ live: false,
83
+ capture: false,
84
+ };
82
85
  this.metrics = new LensPerformanceMetrics(this.lensCore);
83
86
  const removeOnHidden = pageVisibility.onPageHidden(() => this.sessionState.dispatch("suspend", this));
84
87
  const removeOnVisible = pageVisibility.onPageVisible(() => this.sessionState.dispatch("resume", this));
@@ -105,9 +108,7 @@ export class CameraKitSession {
105
108
  }
106
109
  else {
107
110
  // NOTE: at this point the error is already reported, so we can just log a warning
108
- logger.warn(new Error("Lens error occurred even though there is no active lens.", {
109
- cause: error,
110
- }));
111
+ logger.warn("Lens error occurred even though there is no active lens.", error);
111
112
  }
112
113
  }),
113
114
  ];
@@ -148,9 +149,9 @@ export class CameraKitSession {
148
149
  * - Lens content download fails, or the download of any required lens assets fails.
149
150
  * - An internal failure occurs in the Lens rendering engine when attempting to apply the lens.
150
151
  */
151
- applyLens(lens, launchParams) {
152
+ applyLens(lens, launchData) {
152
153
  return __awaiter(this, void 0, void 0, function* () {
153
- const action = this.lensState.actions.applyLens({ lens, launchParams });
154
+ const action = this.lensState.actions.applyLens({ lens, launchData });
154
155
  return firstValueFrom(of(action).pipe(dispatch(this.lensState),
155
156
  // If another applyLens occurs while we're waiting, resolve this applyLens promise early – we're no
156
157
  // longer waiting for the requested lens to be applied.
@@ -218,12 +219,12 @@ export class CameraKitSession {
218
219
  */
219
220
  play(target = "live") {
220
221
  return __awaiter(this, void 0, void 0, function* () {
221
- if (this.playing)
222
+ if (this.playing[target])
222
223
  return;
223
- this.playing = target;
224
+ this.playing[target] = true;
224
225
  const type = this.renderTargetToCanvasType(target);
225
226
  return this.lensCore.playCanvas({ type }).catch((error) => {
226
- this.playing = false;
227
+ this.playing[target] = false;
227
228
  throw error;
228
229
  });
229
230
  });
@@ -237,13 +238,12 @@ export class CameraKitSession {
237
238
  */
238
239
  pause(target = "live") {
239
240
  return __awaiter(this, void 0, void 0, function* () {
240
- if (!this.playing)
241
+ if (this.playing[target] === false)
241
242
  return;
242
- const priorPlayingState = this.playing;
243
- this.playing = false;
243
+ this.playing[target] = false;
244
244
  const type = this.renderTargetToCanvasType(target);
245
245
  return this.lensCore.pauseCanvas({ type }).catch((error) => {
246
- this.playing = priorPlayingState;
246
+ this.playing[target] = true;
247
247
  throw error;
248
248
  });
249
249
  });
@@ -281,7 +281,10 @@ export class CameraKitSession {
281
281
  ? createVideoSource(source, options)
282
282
  : source;
283
283
  const priorPlayingState = this.playing;
284
- this.playing = false;
284
+ this.playing = {
285
+ live: false,
286
+ capture: false,
287
+ };
285
288
  // The source will provide its data to LensCore, and use other LensCore APIs (e.g. setRenderSize,
286
289
  // setInputTransform) to render the source correctly.
287
290
  yield cameraKitSource.attach(this.lensCore, (error) => {
@@ -290,9 +293,10 @@ export class CameraKitSession {
290
293
  // If attachment is successful, we'll update our source so that we can detach it later.
291
294
  this.source = cameraKitSource;
292
295
  // Finally we'll resume playback, if appropriate.
293
- if (priorPlayingState) {
294
- yield this.play(priorPlayingState);
295
- }
296
+ if (priorPlayingState.live)
297
+ yield this.play("live");
298
+ if (priorPlayingState.capture)
299
+ yield this.play("capture");
296
300
  return cameraKitSource;
297
301
  });
298
302
  }