@snap/camera-kit 0.13.2 → 0.14.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.
- package/docs/html/assets/search.js +1 -1
- package/docs/html/classes/CameraKit.html +4 -3
- package/docs/html/classes/CameraKitSession.html +4 -3
- package/docs/html/classes/CameraKitSource.html +4 -3
- package/docs/html/classes/LensPerformanceMeasurement.html +4 -3
- package/docs/html/classes/LensPerformanceMetrics.html +4 -3
- package/docs/html/classes/LensRepository.html +6 -5
- package/docs/html/classes/LensSources.html +4 -3
- package/docs/html/classes/Transform2D.html +4 -3
- package/docs/html/classes/TypedCustomEvent.html +4 -3
- package/docs/html/classes/TypedEventTarget.html +4 -3
- package/docs/html/functions/Injectable.html +4 -3
- package/docs/html/functions/bootstrapCameraKit.html +4 -3
- package/docs/html/functions/createExtension.html +4 -3
- package/docs/html/functions/createImageSource.html +4 -3
- package/docs/html/functions/createMediaStreamSource.html +4 -3
- package/docs/html/functions/createUserMediaSource.html +4 -3
- package/docs/html/functions/createVideoSource.html +4 -3
- package/docs/html/functions/estimateLensPerformance.html +4 -3
- package/docs/html/functions/getRequiredBootstrapURLs.html +4 -3
- package/docs/html/functions/lensSourcesFactory.html +4 -3
- package/docs/html/functions/remoteApiServicesFactory.html +4 -3
- package/docs/html/index.html +5 -4
- package/docs/html/interfaces/CameraKitBootstrapConfiguration.html +16 -5
- package/docs/html/interfaces/CameraKitSourceSubscriber.html +5 -4
- package/docs/html/interfaces/ComputedFrameMetrics.html +4 -3
- package/docs/html/interfaces/CreateSessionOptions.html +4 -3
- package/docs/html/interfaces/EstimatedLensPerformance.html +4 -3
- package/docs/html/interfaces/Lens.html +13 -3
- package/docs/html/interfaces/LensSource.html +4 -3
- package/docs/html/interfaces/MediaStreamSourceOptions.html +4 -3
- package/docs/html/interfaces/Preview.html +4 -3
- package/docs/html/interfaces/RemoteApiRequest.html +4 -3
- package/docs/html/interfaces/RemoteApiResponse.html +4 -3
- package/docs/html/interfaces/RemoteApiService.html +4 -3
- package/docs/html/interfaces/Snapcode.html +4 -3
- package/docs/html/interfaces/UriCancelRequest.html +4 -3
- package/docs/html/interfaces/UriRequest.html +4 -3
- package/docs/html/interfaces/UriResponse.html +4 -3
- package/docs/html/interfaces/VideoSourceOptions.html +4 -3
- package/docs/html/modules.html +6 -4
- package/docs/html/types/AssetLoader.html +4 -3
- package/docs/html/types/AssetTiming.html +4 -3
- package/docs/html/types/BenchmarkError.html +4 -3
- package/docs/html/types/BootstrapError.html +4 -3
- package/docs/html/types/CacheKeyNotFoundError.html +4 -3
- package/docs/html/types/CameraKitDeviceInfo.html +4 -3
- package/docs/html/types/CameraKitDeviceOptions.html +4 -3
- package/docs/html/types/CameraKitSessionEventListener.html +4 -3
- package/docs/html/types/CameraKitSessionEvents.html +6 -5
- package/docs/html/types/CameraKitSourceError.html +4 -3
- package/docs/html/types/CameraKitSourceInfo.html +4 -3
- package/docs/html/types/CameraKitSourceOptions.html +4 -3
- package/docs/html/types/ConfigurationError.html +4 -3
- package/docs/html/types/Keyboard.html +4 -3
- package/docs/html/types/KeyboardEvents.html +4 -3
- package/docs/html/types/LegalError.html +4 -3
- package/docs/html/types/LensAbortError.html +119 -0
- package/docs/html/types/LensAssetError.html +4 -3
- package/docs/html/types/LensContentValidationError.html +4 -3
- package/docs/html/types/LensError.html +4 -3
- package/docs/html/types/LensExecutionError.html +4 -3
- package/docs/html/types/LensImagePickerError.html +4 -3
- package/docs/html/types/LensLaunchParams.html +4 -3
- package/docs/html/types/LensMetricsEvents.html +4 -3
- package/docs/html/types/LensPerformanceCluster.html +4 -3
- package/docs/html/types/LensView.html +4 -3
- package/docs/html/types/LensWait.html +4 -3
- package/docs/html/types/PersistentStoreError.html +4 -3
- package/docs/html/types/PlatformNotSupportedError.html +4 -3
- package/docs/html/types/PublicContainer.html +4 -3
- package/docs/html/types/RemoteApiRequestHandler.html +4 -3
- package/docs/html/types/RemoteApiServices.html +4 -3
- package/docs/html/types/RemoteApiStatus.html +4 -3
- package/docs/html/types/RenderTarget.html +4 -3
- package/docs/html/types/Uri.html +4 -3
- package/docs/html/types/WebGLError.html +4 -3
- package/docs/html/variables/extensionRequestContext.html +4 -3
- package/docs/md/classes/CameraKit.md +1 -1
- package/docs/md/classes/CameraKitSession.md +1 -1
- package/docs/md/classes/CameraKitSource.md +1 -1
- package/docs/md/classes/LensPerformanceMeasurement.md +1 -1
- package/docs/md/classes/LensPerformanceMetrics.md +1 -1
- package/docs/md/classes/LensRepository.md +3 -3
- package/docs/md/classes/LensSources.md +1 -1
- package/docs/md/classes/Transform2D.md +1 -1
- package/docs/md/classes/TypedCustomEvent.md +1 -1
- package/docs/md/classes/TypedEventTarget.md +1 -1
- package/docs/md/interfaces/CameraKitBootstrapConfiguration.md +13 -2
- package/docs/md/interfaces/CameraKitSourceSubscriber.md +3 -3
- package/docs/md/interfaces/ComputedFrameMetrics.md +1 -1
- package/docs/md/interfaces/CreateSessionOptions.md +1 -1
- package/docs/md/interfaces/EstimatedLensPerformance.md +1 -1
- package/docs/md/interfaces/Lens.md +11 -1
- package/docs/md/interfaces/LensSource.md +1 -1
- package/docs/md/interfaces/MediaStreamSourceOptions.md +1 -1
- package/docs/md/interfaces/Preview.md +1 -1
- package/docs/md/interfaces/RemoteApiRequest.md +1 -1
- package/docs/md/interfaces/RemoteApiResponse.md +1 -1
- package/docs/md/interfaces/RemoteApiService.md +1 -1
- package/docs/md/interfaces/Snapcode.md +1 -1
- package/docs/md/interfaces/UriCancelRequest.md +1 -1
- package/docs/md/interfaces/UriRequest.md +1 -1
- package/docs/md/interfaces/UriResponse.md +1 -1
- package/docs/md/interfaces/VideoSourceOptions.md +1 -1
- package/docs/md/modules.md +24 -4
- package/lib/CameraKit.d.ts +139 -7
- package/lib/CameraKit.js +19 -19
- package/lib/CameraKit.js.map +1 -1
- package/lib/__tests__/data.d.ts +9 -4
- package/lib/__tests__/data.js +19 -9
- package/lib/__tests__/data.js.map +1 -1
- package/lib/bootstrapCameraKit.js +2 -2
- package/lib/bootstrapCameraKit.js.map +1 -1
- package/lib/common/localization.js +7 -31
- package/lib/common/localization.js.map +1 -1
- package/lib/configuration.d.ts +7 -0
- package/lib/configuration.js +1 -0
- package/lib/configuration.js.map +1 -1
- package/lib/configurationOverrides.d.ts +2 -2
- package/lib/configurationOverrides.js +11 -6
- package/lib/configurationOverrides.js.map +1 -1
- package/lib/dependency-injection/RootServices.d.ts +2 -2
- package/lib/dependency-injection/RootServices.js.map +1 -1
- package/lib/environment.json +1 -1
- package/lib/extensions/extensionRequestContext.js +4 -4
- package/lib/extensions/extensionRequestContext.js.map +1 -1
- package/lib/extensions/uriHandlersRegister.d.ts +2 -2
- package/lib/extensions/uriHandlersRegister.js.map +1 -1
- package/lib/generated-proto/blizzard/cameraKitEvents.d.ts +272 -0
- package/lib/generated-proto/blizzard/cameraKitEvents.js +38 -24
- package/lib/generated-proto/blizzard/cameraKitEvents.js.map +1 -1
- package/lib/handlers/cameraKitServiceFetchHandlerFactory.js +2 -2
- package/lib/handlers/cameraKitServiceFetchHandlerFactory.js.map +1 -1
- package/lib/index.d.ts +2 -1
- package/lib/index.js +2 -1
- package/lib/index.js.map +1 -1
- package/lib/lens/Lens.d.ts +9 -1
- package/lib/lens/Lens.js +2 -1
- package/lib/lens/Lens.js.map +1 -1
- package/lib/lens/LensPersistenceStore.d.ts +2 -2
- package/lib/lens/LensPersistenceStore.js.map +1 -1
- package/lib/lens/LensRepository.d.ts +2 -2
- package/lib/lens/LensRepository.js +5 -4
- package/lib/lens/LensRepository.js.map +1 -1
- package/lib/lens/assets/LensAssetRepository.d.ts +4 -4
- package/lib/lens/assets/LensAssetRepository.js +1 -3
- package/lib/lens/assets/LensAssetRepository.js.map +1 -1
- package/lib/lens/assets/LensAssetsProvider.d.ts +9 -3
- package/lib/lens/assets/LensAssetsProvider.js +12 -5
- package/lib/lens/assets/LensAssetsProvider.js.map +1 -1
- package/lib/lens-client-interface/imagePicker.d.ts +2 -2
- package/lib/lens-client-interface/imagePicker.js.map +1 -1
- package/lib/lens-client-interface/lensClientInterface.d.ts +2 -2
- package/lib/lens-client-interface/lensClientInterface.js.map +1 -1
- package/lib/lens-core-module/generated-types.d.ts +4 -2
- package/lib/lens-core-module/generated-types.js.map +1 -1
- package/lib/lens-core-module/index.d.ts +1 -0
- package/lib/lens-core-module/index.js +1 -0
- package/lib/lens-core-module/index.js.map +1 -1
- package/lib/lens-core-module/lensCore.d.ts +41 -0
- package/lib/lens-core-module/lensCore.js +54 -0
- package/lib/lens-core-module/lensCore.js.map +1 -0
- package/lib/lens-core-module/lensCoreError.d.ts +15 -0
- package/lib/lens-core-module/lensCoreError.js +43 -0
- package/lib/lens-core-module/lensCoreError.js.map +1 -0
- package/lib/lens-core-module/loader/lensCoreFactory.d.ts +1 -2
- package/lib/lens-core-module/loader/lensCoreFactory.js +24 -26
- package/lib/lens-core-module/loader/lensCoreFactory.js.map +1 -1
- package/lib/lensCoreWasmVersions.json +3 -3
- package/lib/logger/registerLogEntriesSubscriber.js +2 -2
- package/lib/logger/registerLogEntriesSubscriber.js.map +1 -1
- package/lib/media-sources/CameraKitSource.d.ts +3 -3
- package/lib/media-sources/CameraKitSource.js +22 -31
- package/lib/media-sources/CameraKitSource.js.map +1 -1
- package/lib/media-sources/FunctionSource.js +33 -36
- package/lib/media-sources/FunctionSource.js.map +1 -1
- package/lib/media-sources/MediaStreamSource.js +11 -15
- package/lib/media-sources/MediaStreamSource.js.map +1 -1
- package/lib/metrics/businessEventsReporter.js +114 -108
- package/lib/metrics/businessEventsReporter.js.map +1 -1
- package/lib/metrics/reporters/reportGlobalException.js +25 -7
- package/lib/metrics/reporters/reportGlobalException.js.map +1 -1
- package/lib/metrics/reporters/reportHttpMetrics.js +2 -2
- package/lib/metrics/reporters/reportHttpMetrics.js.map +1 -1
- package/lib/metrics/reporters/reportLensView.js +5 -3
- package/lib/metrics/reporters/reportLensView.js.map +1 -1
- package/lib/metrics/reporters/reportLensWait.js +8 -2
- package/lib/metrics/reporters/reportLensWait.js.map +1 -1
- package/lib/metrics/reporters/reportPlatformCapabilities.d.ts +12 -0
- package/lib/metrics/reporters/reportPlatformCapabilities.js +18 -0
- package/lib/metrics/reporters/reportPlatformCapabilities.js.map +1 -0
- package/lib/metrics/reporters/reporters.d.ts +2 -1
- package/lib/metrics/reporters/reporters.js +3 -1
- package/lib/metrics/reporters/reporters.js.map +1 -1
- package/lib/namedErrors.d.ts +17 -0
- package/lib/namedErrors.js +2 -0
- package/lib/namedErrors.js.map +1 -1
- package/lib/platform/assertPlatformSupported.d.ts +4 -0
- package/lib/platform/assertPlatformSupported.js +15 -0
- package/lib/platform/assertPlatformSupported.js.map +1 -0
- package/lib/platform/cameraKitUserAgent.d.ts +2 -0
- package/lib/platform/cameraKitUserAgent.js +20 -0
- package/lib/platform/cameraKitUserAgent.js.map +1 -0
- package/lib/platform/platformCapabilities.d.ts +50 -0
- package/lib/platform/platformCapabilities.js +121 -0
- package/lib/platform/platformCapabilities.js.map +1 -0
- package/lib/{common/cameraKitUserAgent.d.ts → platform/platformInfo.d.ts} +13 -10
- package/lib/{common/cameraKitUserAgent.js → platform/platformInfo.js} +94 -100
- package/lib/platform/platformInfo.js.map +1 -0
- package/lib/remote-configuration/cofHandler.js +2 -2
- package/lib/remote-configuration/cofHandler.js.map +1 -1
- package/lib/remote-configuration/preloadConfiguration.d.ts +2 -2
- package/lib/remote-configuration/preloadConfiguration.js.map +1 -1
- package/lib/session/CameraKitSession.d.ts +3 -3
- package/lib/session/CameraKitSession.js +23 -30
- package/lib/session/CameraKitSession.js.map +1 -1
- package/lib/session/CameraKitSessionEvents.d.ts +7 -3
- package/lib/session/CameraKitSessionEvents.js +17 -0
- package/lib/session/CameraKitSessionEvents.js.map +1 -1
- package/lib/session/LensPerformanceMetrics.d.ts +2 -2
- package/lib/session/LensPerformanceMetrics.js +4 -3
- package/lib/session/LensPerformanceMetrics.js.map +1 -1
- package/lib/session/lensState.d.ts +2 -2
- package/lib/session/lensState.js +36 -37
- package/lib/session/lensState.js.map +1 -1
- package/package.json +2 -2
- package/lib/assertPlatformSupported.d.ts +0 -6
- package/lib/assertPlatformSupported.js +0 -21
- package/lib/assertPlatformSupported.js.map +0 -1
- package/lib/common/cameraKitUserAgent.js.map +0 -1
- package/lib/common/locale.d.ts +0 -2
- package/lib/common/locale.js +0 -11
- package/lib/common/locale.js.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"businessEventsReporter.js","sourceRoot":"","sources":["../../src/metrics/businessEventsReporter.ts"],"names":[],"mappings":"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","sourcesContent":["import { v4 } from \"uuid\";\nimport { catchError, from, of, switchMap, take } from \"rxjs\";\nimport { ConnectionType, cameraKitUserAgent as userAgent } from \"../common/cameraKitUserAgent\";\nimport { entries } from \"../common/entries\";\nimport { Injectable } from \"../dependency-injection/Injectable\";\nimport { EventOfType } from \"../events/TypedCustomEvent\";\nimport { EventsFromTarget } from \"../events/TypedEventTarget\";\nimport { FetchHandler } from \"../handlers/defaultFetchHandler\";\nimport { createBatchingHandler } from \"../handlers/batchingHandler\";\nimport { HandlerChainBuilder } from \"../handlers/HandlerChainBuilder\";\nimport { createMappingHandler } from \"../handlers/mappingHandler\";\nimport * as blizzard from \"../generated-proto/blizzard/cameraKitEvents\";\nimport { getLogger } from \"../logger/logger\";\nimport { PageVisibility, pageVisibilityFactory } from \"../common/pageVisibility\";\nimport { CameraKitApiHostname, CameraKitConfiguration, configurationToken } from \"../configuration\";\nimport { remoteConfigurationFactory, RemoteConfiguration } from \"../remote-configuration/remoteConfiguration\";\nimport { IndexedDBPersistence } from \"../persistence/IndexedDBPersistence\";\nimport { ExpiringPersistence } from \"../persistence/ExpiringPersistence\";\nimport { convertDaysToSeconds } from \"../common/time\";\nimport { metricsHandlerFactory } from \"./metricsHandler\";\nimport { MetricsEventTarget, metricsEventTargetFactory } from \"./metricsEventTarget\";\n\nconst logger = getLogger(\"BusinessEventsReporter\");\n\ntype Nullables<T> = { [K in keyof T]-?: undefined extends T[K] ? K : never }[keyof T];\ntype UndefinedToOptional<T> = Partial<Pick<T, Nullables<T>>> & Omit<T, Nullables<T>>;\n\ntype CameraKitBusinessEvents = EventsFromTarget<MetricsEventTarget>[\"detail\"];\n\ntype MakeBlizzardEvent<E> = Omit<E, \"name\"> & { cameraKitEventBase: blizzard.CameraKitEventBase };\n\ntype CreateEventData<EventType extends EventsFromTarget<MetricsEventTarget>[\"type\"]> = (\n event: MakeBlizzardEvent<EventOfType<EventType, EventsFromTarget<MetricsEventTarget>>[\"detail\"]>\n) => [string, UndefinedToOptional<blizzard.ServerEventData>];\n\ntype EventHandlers = {\n [EventType in EventsFromTarget<MetricsEventTarget>[\"type\"]]: CreateEventData<EventType>;\n};\n\n/**\n * Translate between an external metric name, which is exposed to SDK users, and an internal Blizzard event name,\n * property name, and constructor.\n *\n * It is very important that we do this, since the naming of these internal business events are unintuitive and will\n * not make sense to SDK users.\n *\n * For a full list of business events (using their internal names), see:\n * https://docs.google.com/document/d/1-kSzFWCWw9Qo3D08FR1_cqeHTsUtk9p3p3uOptzWDTY/\n */\ntype CameraKitBusinessEventMap = {\n assetDownload: MakeBusinessEvent<blizzard.CameraKitAssetDownload>;\n assetValidationFailed: MakeBusinessEvent<blizzard.CameraKitAssetValidationFailed>;\n benchmarkComplete: MakeBusinessEvent<blizzard.CameraKitWebBenchmarkComplete>;\n exception: MakeBusinessEvent<blizzard.CameraKitException>;\n legalPrompt: MakeBusinessEvent<blizzard.CameraKitLegalPrompt>;\n lensDownload: MakeBusinessEvent<blizzard.CameraKitLensDownload>;\n lensView: MakeBusinessEvent<blizzard.CameraKitWebLensSwipe>;\n lensWait: MakeBusinessEvent<blizzard.CameraKitLensSpin>;\n lensContentValidationFailed: MakeBusinessEvent<blizzard.CameraKitLensContentValidationFailed>;\n session: MakeBusinessEvent<blizzard.CameraKitSession>;\n};\n\n/**\n * This interface is defined in the CameraKit pb_schema proto definition – but the generated TypeScript does not handle\n * the `Any` type properly. It does not conform to the Proto3 canonical JSON mapping scheme, as defined here:\n * https://developers.google.com/protocol-buffers/docs/proto3#json\n *\n * To solve this (since we only need one message from the CameraKit schema), we'll just manually define the correct\n * interface here.\n */\ninterface SetBusinessEventsRequest {\n batchEvents: {\n \"@type\": \"com.snapchat.analytics.blizzard.ServerEventBatch\";\n serverEvents: blizzard.ServerEvent[];\n };\n}\n\n// CameraKit's prod metrics endpoint.\n// See: https://github.sc-corp.net/Snapchat/pb_schema/blob/2a966db/proto/camera_kit/v3/service.proto#L133\nconst relativePath = \"/com.snap.camerakit.v3.Metrics/metrics/business_events\";\n\n// It is rather cumbersome to check the actual final size of a batch, but we can easily limit the number of events we\n// include in each batch -- looking at historical data, typical events average ~1.3kb per event. But there are some\n// events (like CAMERA_KIT_EXCEPTION, which includes a stack trace) that can be much larger.\n//\n// To prevent us running over the 64kibibyte limit imposed by browsers on `keep-alive` requests, we'll set quite a low\n// limit to ensure we don't lose events which are larger in size than we expect.\nconst BUSINESS_EVENT_BATCH_MAX_SIZE = 10;\nconst BUSINESS_EVENT_BATCH_MAX_AGE_MS = 5000;\n\nconst connectivityTypeMapping: Partial<Record<ConnectionType, blizzard.CameraKitConnectivityType>> = {\n cellular: blizzard.CameraKitConnectivityType.CAMERA_KIT_CONNECTIVITY_TYPE_MOBILE,\n bluetooth: blizzard.CameraKitConnectivityType.CAMERA_KIT_CONNECTIVITY_TYPE_BLUETOOTH,\n wifi: blizzard.CameraKitConnectivityType.CAMERA_KIT_CONNECTIVITY_TYPE_WIFI,\n unknown: blizzard.CameraKitConnectivityType.CAMERA_KIT_CONNECTIVITY_TYPE_UNKNOWN,\n none: blizzard.CameraKitConnectivityType.CAMERA_KIT_CONNECTIVITY_TYPE_UNREACHABLE,\n};\n\nconst vendorUuidKey = \"vendorUuid\";\nconst vendorUuidExpiry = convertDaysToSeconds(60);\n\n/**\n * Retrieves or generates a vendor UUID (Universally Unique Identifier).\n *\n * @param persistence - The persistence storage interface where UUID is stored.\n * @returns {Promise<string | undefined>} - A Promise that resolves to the vendor UUID or undefined,\n * if any failure occurs or opt-in is not enabled.\n */\nconst getOrGenerateVendorUuid = async (persistence: ExpiringPersistence<string>): Promise<string | undefined> => {\n try {\n const storedUuid = await persistence.retrieve(vendorUuidKey);\n if (storedUuid) {\n return storedUuid;\n }\n\n const newUuid = v4();\n await persistence.store(vendorUuidKey, newUuid);\n\n return newUuid;\n } catch (error) {\n throw new Error(\"Failed to generate vendor UUID\");\n }\n};\n\nfunction listenAndReport(\n metricsEventTarget: MetricsEventTarget,\n metricsHandler: FetchHandler,\n pageVisibility: PageVisibility,\n eventHandlers: EventHandlers,\n apiHostname: CameraKitApiHostname,\n appVendorUuid: string | undefined\n): void {\n const sessionId = v4();\n logger.log(`Session ID: ${sessionId}`);\n\n // Blizzard convention is to start the sequenceId at 1.\n let sequenceId = 1;\n\n const handler = new HandlerChainBuilder(metricsHandler)\n .map(\n createMappingHandler((events: blizzard.ServerEvent[]) => {\n const body: SetBusinessEventsRequest = {\n batchEvents: {\n \"@type\": \"com.snapchat.analytics.blizzard.ServerEventBatch\",\n serverEvents: events,\n },\n };\n\n return new Request(`https://${apiHostname}${relativePath}`, {\n method: \"POST\",\n body: JSON.stringify(body),\n credentials: \"include\",\n\n // When this is true it makes fetch behave like `Navigator.sendBeacon` – that is, the request\n // will still be made even if the page terminates.\n // https://developer.mozilla.org/en-US/docs/Web/API/fetch\n keepalive: pageVisibility.isDuringVisibilityTransition(\"hidden\"),\n });\n }, pageVisibility)\n )\n .map(\n createBatchingHandler({\n batchReduce: (\n previousBundle: blizzard.ServerEvent[] | undefined,\n businessEvent: blizzard.ServerEvent\n ) => {\n const bundle = previousBundle ?? [];\n bundle.push(businessEvent);\n return bundle;\n },\n isBatchComplete: (bundle) => bundle.length >= BUSINESS_EVENT_BATCH_MAX_SIZE,\n maxBatchAge: BUSINESS_EVENT_BATCH_MAX_AGE_MS,\n pageVisibility,\n })\n ).handler;\n\n const makeBlizzardEvent = <E extends CameraKitBusinessEvents>(event: E): MakeBlizzardEvent<E> => {\n const deviceConnectivity =\n connectivityTypeMapping[userAgent.connectionType!] ??\n blizzard.CameraKitConnectivityType.CAMERA_KIT_CONNECTIVITY_TYPE_UNKNOWN;\n\n return {\n ...event,\n cameraKitEventBase: blizzard.CameraKitEventBase.fromPartial({\n kitEventBase: blizzard.KitEventBase.fromPartial({\n locale: userAgent.locale,\n kitVariant: blizzard.KitType.CAMERA_KIT_WEB,\n kitVariantVersion: userAgent.sdkShortVersion,\n kitClientTimestampMillis: Date.now(),\n }),\n deviceCluster: 0,\n cameraKitVersion: userAgent.sdkLongVersion,\n lensCoreVersion: userAgent.lensCoreVersion,\n deviceModel: userAgent.deviceModel,\n cameraKitVariant: blizzard.CameraKitVariant.CAMERA_KIT_VARIANT_PARTNER,\n cameraKitFlavor: blizzard.CameraKitFlavor.CAMERA_KIT_FLAVOR_DEBUG,\n // We overload appId, using the origin instead because it's nice and human-readable (our backed adds\n // the true appId as oauth_client_id before forwarding events to Blizzard).\n appId: userAgent.origin,\n deviceConnectivity,\n sessionId: sessionId,\n appVendorUuid,\n }),\n };\n };\n\n const sendServerEvent = (\n eventName: string,\n eventData: UndefinedToOptional<blizzard.ServerEventData>\n ): Promise<void> => {\n return handler(\n blizzard.ServerEvent.fromPartial({\n eventName,\n osType: userAgent.osType,\n osVersion: userAgent.osVersion,\n maxSequenceIdOnInstance: 0,\n sequenceId: sequenceId++,\n eventData,\n })\n );\n };\n\n entries(eventHandlers).forEach(([eventType, createEventData]) => {\n metricsEventTarget.addEventListener(eventType, ({ detail }) => {\n // Safety: When iterating over object keys in a mapped type, we lose the association between the key type\n // and the value type – at each iteration, the key type is a union of all possible keys and the value type\n // is a union of all possible values. When the value is a function with an argument, and that argument\n // depends on the key type (which is a union), the contravariance of the argument type means that the union\n // becomes an intersection. In our case here, this means the compiler expects each argument to contain all\n // properties from all event types. The cast is safe because the mapped `EventHandlers` type ensures that\n // `createEventData` takes an argument of the type corresponding its key's `eventType`'s event detail.\n const [eventName, eventData] = createEventData(makeBlizzardEvent(detail) as any);\n sendServerEvent(eventName, eventData);\n });\n });\n}\n\nexport type MakeBusinessEvent<E> = Omit<\n {\n [K in keyof E]: Exclude<E[K], undefined> extends Record<keyof any, any>\n ? MakeBusinessEvent<Exclude<E[K], undefined>>\n : E[K];\n },\n \"cameraKitEventBase\"\n>;\n\nexport type MakeTaggedBusinessEvent<K extends keyof CameraKitBusinessEventMap> = {\n name: K;\n} & CameraKitBusinessEventMap[K];\n\nexport const businessEventsReporterFactory = Injectable(\n \"businessEventsReporter\",\n [\n metricsEventTargetFactory.token,\n metricsHandlerFactory.token,\n pageVisibilityFactory.token,\n configurationToken,\n remoteConfigurationFactory.token,\n ] as const,\n (\n metricsEventTarget: MetricsEventTarget,\n metricsHandler: FetchHandler,\n pageVisibility: PageVisibility,\n configuration: CameraKitConfiguration,\n remoteConfiguration: RemoteConfiguration\n ) => {\n const vendorAnalyticsPersistence = new ExpiringPersistence<string>(\n () => vendorUuidExpiry,\n new IndexedDBPersistence({ databaseName: \"SessionHistory\" })\n );\n\n remoteConfiguration\n .getInitializationConfig()\n .pipe(\n take(1),\n switchMap(({ appVendorUuidOptIn }) => {\n if (appVendorUuidOptIn) {\n return from(getOrGenerateVendorUuid(vendorAnalyticsPersistence));\n }\n return of(undefined);\n }),\n catchError((error) => {\n logger.warn(`Failed to retrieve or generate vendor UUID.`, error);\n return of(undefined);\n })\n )\n .subscribe({\n next: (appVendorUuid) => {\n /**\n * This defines a mapping from a business event's external name (the name we document in public\n * API docs), to its internal representation as a Blizzard ServerEvent.\n *\n * It is important that we do this, since the naming of these internal business events are\n * unintuitive and will not make sense to SDK users.\n *\n * To specify the internal event, we must give the ServerEvent's eventName, the specific property\n * name which contains the event data (this is a \"oneof\" property on ServerEvent), and use the\n * correct event type's `fromPartial` method (this is generated from the ServerEvent protobuf).\n *\n * These events are documented here:\n * https://docs.google.com/document/d/1-kSzFWCWw9Qo3D08FR1_cqeHTsUtk9p3p3uOptzWDTY/\n *\n * They are defined in code here:\n * https://github.sc-corp.net/Snapchat/snapchat/tree/master/blizzard/schema/blizzard-schema/\n * codeGen/src/main/java/com/snapchat/analytics/schema/events/cameraKit\n */\n listenAndReport(\n metricsEventTarget,\n metricsHandler,\n pageVisibility,\n {\n assetDownload: (event) => [\n \"CAMERA_KIT_ASSET_DOWNLOAD\",\n { cameraKitAssetDownload: blizzard.CameraKitAssetDownload.fromPartial(event) },\n ],\n assetValidationFailed: (event) => [\n \"CAMERA_KIT_ASSET_VALIDATION_FAILED\",\n {\n cameraKitAssetValidationFailed:\n blizzard.CameraKitAssetValidationFailed.fromPartial(event),\n },\n ],\n benchmarkComplete: (event) => [\n \"CAMERA_KIT_WEB_BENCHMARK_COMPLETE\",\n {\n cameraKitWebBenchmarkComplete:\n blizzard.CameraKitWebBenchmarkComplete.fromPartial(event),\n },\n ],\n exception: (event) => [\n \"CAMERA_KIT_EXCEPTION\",\n { cameraKitException: blizzard.CameraKitException.fromPartial(event) },\n ],\n legalPrompt: (event) => [\n \"CAMERA_KIT_LEGAL_PROMPT\",\n { cameraKitLegalPrompt: blizzard.CameraKitLegalPrompt.fromPartial(event) },\n ],\n lensDownload: (event) => [\n \"CAMERA_KIT_LENS_DOWNLOAD\",\n { cameraKitLensDownload: blizzard.CameraKitLensDownload.fromPartial(event) },\n ],\n lensView: (event) => [\n \"CAMERA_KIT_WEB_LENS_SWIPE\",\n { cameraKitWebLensSwipe: blizzard.CameraKitWebLensSwipe.fromPartial(event) },\n ],\n lensWait: (event) => [\n \"CAMERA_KIT_LENS_SPIN\",\n { cameraKitLensSpin: blizzard.CameraKitLensSpin.fromPartial(event) },\n ],\n lensContentValidationFailed: (event) => [\n \"CAMERA_KIT_LENS_CONTENT_VALIDATION_FAILED\",\n {\n cameraKitLensContentValidationFailed:\n blizzard.CameraKitLensContentValidationFailed.fromPartial(event),\n },\n ],\n session: (event) => [\n \"CAMERA_KIT_SESSION\",\n { cameraKitSession: blizzard.CameraKitSession.fromPartial(event) },\n ],\n },\n configuration.apiHostname,\n appVendorUuid\n );\n },\n });\n }\n);\n"]}
|
|
1
|
+
{"version":3,"file":"businessEventsReporter.js","sourceRoot":"","sources":["../../src/metrics/businessEventsReporter.ts"],"names":[],"mappings":"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","sourcesContent":["import { v4 } from \"uuid\";\nimport { Observable, catchError, combineLatestWith, from, fromEvent, map, merge, of, switchMap, take } from \"rxjs\";\nimport { entries } from \"../common/entries\";\nimport { Injectable } from \"../dependency-injection/Injectable\";\nimport { EventOfType } from \"../events/TypedCustomEvent\";\nimport { EventsFromTarget } from \"../events/TypedEventTarget\";\nimport { FetchHandler } from \"../handlers/defaultFetchHandler\";\nimport { createBatchingHandler } from \"../handlers/batchingHandler\";\nimport { HandlerChainBuilder } from \"../handlers/HandlerChainBuilder\";\nimport { createMappingHandler } from \"../handlers/mappingHandler\";\nimport * as blizzard from \"../generated-proto/blizzard/cameraKitEvents\";\nimport { getLogger } from \"../logger/logger\";\nimport { PageVisibility, pageVisibilityFactory } from \"../common/pageVisibility\";\nimport { CameraKitApiHostname, CameraKitConfiguration, configurationToken } from \"../configuration\";\nimport { remoteConfigurationFactory, RemoteConfiguration } from \"../remote-configuration/remoteConfiguration\";\nimport { IndexedDBPersistence } from \"../persistence/IndexedDBPersistence\";\nimport { ExpiringPersistence } from \"../persistence/ExpiringPersistence\";\nimport { convertDaysToSeconds } from \"../common/time\";\nimport { ConnectionType, getPlatformInfo } from \"../platform/platformInfo\";\nimport { metricsHandlerFactory } from \"./metricsHandler\";\nimport { MetricsEventTarget, metricsEventTargetFactory } from \"./metricsEventTarget\";\n\nconst logger = getLogger(\"BusinessEventsReporter\");\n\ntype Nullables<T> = { [K in keyof T]-?: undefined extends T[K] ? K : never }[keyof T];\ntype UndefinedToOptional<T> = Partial<Pick<T, Nullables<T>>> & Omit<T, Nullables<T>>;\n\ntype CameraKitBusinessEvents = EventsFromTarget<MetricsEventTarget>[\"detail\"];\n\ntype MakeBlizzardEvent<E> = Omit<E, \"name\"> & { cameraKitEventBase: blizzard.CameraKitEventBase };\n\ntype CreateEventData<EventType extends EventsFromTarget<MetricsEventTarget>[\"type\"]> = (\n event: MakeBlizzardEvent<EventOfType<EventType, EventsFromTarget<MetricsEventTarget>>[\"detail\"]>\n) => [string, UndefinedToOptional<blizzard.ServerEventData>];\n\ntype EventHandlers = {\n [EventType in EventsFromTarget<MetricsEventTarget>[\"type\"]]: CreateEventData<EventType>;\n};\n\n/**\n * Translate between an external metric name, which is exposed to SDK users, and an internal Blizzard event name,\n * property name, and constructor.\n *\n * It is very important that we do this, since the naming of these internal business events are unintuitive and will\n * not make sense to SDK users.\n *\n * For a full list of business events (using their internal names), see:\n * https://docs.google.com/document/d/1-kSzFWCWw9Qo3D08FR1_cqeHTsUtk9p3p3uOptzWDTY/\n */\ntype CameraKitBusinessEventMap = {\n assetDownload: MakeBusinessEvent<blizzard.CameraKitAssetDownload>;\n assetValidationFailed: MakeBusinessEvent<blizzard.CameraKitAssetValidationFailed>;\n benchmarkComplete: MakeBusinessEvent<blizzard.CameraKitWebBenchmarkComplete>;\n exception: MakeBusinessEvent<blizzard.CameraKitException>;\n legalPrompt: MakeBusinessEvent<blizzard.CameraKitLegalPrompt>;\n lensDownload: MakeBusinessEvent<blizzard.CameraKitLensDownload>;\n lensView: MakeBusinessEvent<blizzard.CameraKitWebLensSwipe>;\n lensWait: MakeBusinessEvent<blizzard.CameraKitLensSpin>;\n lensContentValidationFailed: MakeBusinessEvent<blizzard.CameraKitLensContentValidationFailed>;\n session: MakeBusinessEvent<blizzard.CameraKitSession>;\n};\n\n/**\n * This interface is defined in the CameraKit pb_schema proto definition – but the generated TypeScript does not handle\n * the `Any` type properly. It does not conform to the Proto3 canonical JSON mapping scheme, as defined here:\n * https://developers.google.com/protocol-buffers/docs/proto3#json\n *\n * To solve this (since we only need one message from the CameraKit schema), we'll just manually define the correct\n * interface here.\n */\ninterface SetBusinessEventsRequest {\n batchEvents: {\n \"@type\": \"com.snapchat.analytics.blizzard.ServerEventBatch\";\n serverEvents: blizzard.ServerEvent[];\n };\n}\n\ninterface AppVendorAndPartnerUuid {\n appVendorUuid: string | undefined;\n partnerUuid: string | undefined;\n}\n\n// CameraKit's prod metrics endpoint.\n// See: https://github.sc-corp.net/Snapchat/pb_schema/blob/2a966db/proto/camera_kit/v3/service.proto#L133\nconst relativePath = \"/com.snap.camerakit.v3.Metrics/metrics/business_events\";\n\n// It is rather cumbersome to check the actual final size of a batch, but we can easily limit the number of events we\n// include in each batch -- looking at historical data, typical events average ~1.3kb per event. But there are some\n// events (like CAMERA_KIT_EXCEPTION, which includes a stack trace) that can be much larger.\n//\n// To prevent us running over the 64kibibyte limit imposed by browsers on `keep-alive` requests, we'll set quite a low\n// limit to ensure we don't lose events which are larger in size than we expect.\nconst BUSINESS_EVENT_BATCH_MAX_SIZE = 10;\nconst BUSINESS_EVENT_BATCH_MAX_AGE_MS = 5000;\n\nconst connectivityTypeMapping: Partial<Record<ConnectionType, blizzard.CameraKitConnectivityType>> = {\n cellular: blizzard.CameraKitConnectivityType.CAMERA_KIT_CONNECTIVITY_TYPE_MOBILE,\n bluetooth: blizzard.CameraKitConnectivityType.CAMERA_KIT_CONNECTIVITY_TYPE_BLUETOOTH,\n wifi: blizzard.CameraKitConnectivityType.CAMERA_KIT_CONNECTIVITY_TYPE_WIFI,\n unknown: blizzard.CameraKitConnectivityType.CAMERA_KIT_CONNECTIVITY_TYPE_UNKNOWN,\n none: blizzard.CameraKitConnectivityType.CAMERA_KIT_CONNECTIVITY_TYPE_UNREACHABLE,\n};\n\nconst vendorUuidKey = \"vendorUuid\";\nconst vendorUuidExpiry = convertDaysToSeconds(60);\n\n/**\n * Retrieves or generates a vendor UUID (Universally Unique Identifier).\n *\n * @param persistence - The persistence storage interface where UUID is stored.\n * @returns {Promise<string | undefined>} - A Promise that resolves to the vendor UUID or undefined,\n * if any failure occurs or opt-in is not enabled.\n */\nconst getOrGenerateVendorUuid = async (persistence: ExpiringPersistence<string>): Promise<string | undefined> => {\n try {\n const storedUuid = await persistence.retrieve(vendorUuidKey);\n if (storedUuid) {\n return storedUuid;\n }\n\n const newUuid = v4();\n await persistence.store(vendorUuidKey, newUuid);\n\n return newUuid;\n } catch (error) {\n throw new Error(\"Failed to generate vendor UUID\");\n }\n};\n\nfunction listenAndReport(\n metricsEventTarget: MetricsEventTarget,\n metricsHandler: FetchHandler,\n pageVisibility: PageVisibility,\n eventHandlers: EventHandlers,\n apiHostname: CameraKitApiHostname,\n appVendorAndPartnerUuid: Observable<AppVendorAndPartnerUuid>\n): void {\n const sessionId = v4();\n logger.log(`Session ID: ${sessionId}`);\n\n // Blizzard convention is to start the sequenceId at 1.\n let sequenceId = 1;\n\n const handler = new HandlerChainBuilder(metricsHandler)\n .map(\n createMappingHandler((events: blizzard.ServerEvent[]) => {\n const body: SetBusinessEventsRequest = {\n batchEvents: {\n \"@type\": \"com.snapchat.analytics.blizzard.ServerEventBatch\",\n serverEvents: events,\n },\n };\n\n return new Request(`https://${apiHostname}${relativePath}`, {\n method: \"POST\",\n body: JSON.stringify(body),\n credentials: \"include\",\n\n // When this is true it makes fetch behave like `Navigator.sendBeacon` – that is, the request\n // will still be made even if the page terminates.\n // https://developer.mozilla.org/en-US/docs/Web/API/fetch\n keepalive: pageVisibility.isDuringVisibilityTransition(\"hidden\"),\n });\n }, pageVisibility)\n )\n .map(\n createBatchingHandler({\n batchReduce: (\n previousBundle: blizzard.ServerEvent[] | undefined,\n businessEvent: blizzard.ServerEvent\n ) => {\n const bundle = previousBundle ?? [];\n bundle.push(businessEvent);\n return bundle;\n },\n isBatchComplete: (bundle) => bundle.length >= BUSINESS_EVENT_BATCH_MAX_SIZE,\n maxBatchAge: BUSINESS_EVENT_BATCH_MAX_AGE_MS,\n pageVisibility,\n })\n ).handler;\n\n const makeBlizzardEvent = <E extends CameraKitBusinessEvents>(\n event: E,\n appVendorUuid: string | undefined,\n partnerUuid: string | undefined\n ): MakeBlizzardEvent<E> => {\n const { sdkShortVersion, sdkLongVersion, lensCore, locale, origin, deviceModel, connectionType } =\n getPlatformInfo();\n\n const deviceConnectivity =\n connectivityTypeMapping[connectionType!] ??\n blizzard.CameraKitConnectivityType.CAMERA_KIT_CONNECTIVITY_TYPE_UNKNOWN;\n\n return {\n ...event,\n cameraKitEventBase: blizzard.CameraKitEventBase.fromPartial({\n kitEventBase: blizzard.KitEventBase.fromPartial({\n locale,\n kitVariant: blizzard.KitType.CAMERA_KIT_WEB,\n kitVariantVersion: sdkShortVersion,\n kitClientTimestampMillis: Date.now(),\n }),\n deviceCluster: 0,\n cameraKitVersion: sdkLongVersion,\n lensCoreVersion: lensCore.version,\n deviceModel,\n cameraKitVariant: blizzard.CameraKitVariant.CAMERA_KIT_VARIANT_PARTNER,\n cameraKitFlavor: blizzard.CameraKitFlavor.CAMERA_KIT_FLAVOR_DEBUG,\n // We overload appId, using the origin instead because it's nice and human-readable (our backed adds\n // the true appId as oauth_client_id before forwarding events to Blizzard).\n appId: origin,\n deviceConnectivity,\n sessionId,\n appVendorUuid,\n partnerUuid,\n }),\n };\n };\n\n const sendServerEvent = (\n eventName: string,\n eventData: UndefinedToOptional<blizzard.ServerEventData>\n ): Promise<void> => {\n const { osName: osType, osVersion } = getPlatformInfo();\n return handler(\n blizzard.ServerEvent.fromPartial({\n eventName,\n osType,\n osVersion,\n maxSequenceIdOnInstance: 0,\n sequenceId: sequenceId++,\n eventData,\n })\n );\n };\n\n // Add event listeners for each event type and turn those listeners into Observables\n const metricsEvents = entries(eventHandlers).map(([eventType, createEventData]) =>\n fromEvent(metricsEventTarget, eventType).pipe(map((event) => ({ event, createEventData })))\n );\n\n // Subscribe to all the metrics events and combine them with the app/partner IDs obtained\n // from remote configuration -- this means we'll queue up any metrics events that occur\n // before remote config is downloaded, and send them once that config is available.\n merge(...metricsEvents)\n .pipe(combineLatestWith(appVendorAndPartnerUuid))\n .subscribe(([{ event, createEventData }, { appVendorUuid, partnerUuid }]) => {\n // Safety: When iterating over object keys in a mapped type, we lose the association between the key type\n // and the value type – at each iteration, the key type is a union of all possible keys and the value type\n // is a union of all possible values. When the value is a function with an argument, and that argument\n // depends on the key type (which is a union), the contravariance of the argument type means that the union\n // becomes an intersection. In our case here, this means the compiler expects each argument to contain all\n // properties from all event types. The cast is safe because the mapped `EventHandlers` type ensures that\n // `createEventData` takes an argument of the type corresponding its key's `eventType`'s event detail.\n const [eventName, eventData] = createEventData(\n makeBlizzardEvent(event.detail, appVendorUuid, partnerUuid) as any\n );\n sendServerEvent(eventName, eventData);\n });\n}\n\nexport type MakeBusinessEvent<E> = Omit<\n {\n [K in keyof E]: Exclude<E[K], undefined> extends Record<keyof any, any>\n ? MakeBusinessEvent<Exclude<E[K], undefined>>\n : E[K];\n },\n \"cameraKitEventBase\"\n>;\n\nfunction getAppVendorAndPartnerUuid(\n configuration: CameraKitConfiguration,\n remoteConfiguration: RemoteConfiguration\n): Observable<AppVendorAndPartnerUuid> {\n const vendorAnalyticsPersistence = new ExpiringPersistence<string>(\n () => vendorUuidExpiry,\n new IndexedDBPersistence({ databaseName: \"SessionHistory\" })\n );\n\n return remoteConfiguration.getInitializationConfig().pipe(\n take(1),\n\n switchMap(({ appVendorUuidOptIn }) => {\n const partnerUuid = configuration.analyticsId;\n if (appVendorUuidOptIn) {\n return from(getOrGenerateVendorUuid(vendorAnalyticsPersistence)).pipe(\n map((appVendorUuid) => ({ appVendorUuid, partnerUuid }))\n );\n }\n return of({ appVendorUuid: undefined, partnerUuid });\n }),\n\n catchError((error) => {\n logger.warn(`Failed to retrieve or generate vendor UUID.`, error);\n return of({ appVendorUuid: undefined, partnerUuid: configuration.analyticsId });\n })\n );\n}\n\nexport type MakeTaggedBusinessEvent<K extends keyof CameraKitBusinessEventMap> = {\n name: K;\n} & CameraKitBusinessEventMap[K];\n\nexport const businessEventsReporterFactory = Injectable(\n \"businessEventsReporter\",\n [\n metricsEventTargetFactory.token,\n metricsHandlerFactory.token,\n pageVisibilityFactory.token,\n configurationToken,\n remoteConfigurationFactory.token,\n ] as const,\n (\n metricsEventTarget: MetricsEventTarget,\n metricsHandler: FetchHandler,\n pageVisibility: PageVisibility,\n configuration: CameraKitConfiguration,\n remoteConfiguration: RemoteConfiguration\n ) => {\n const appVendorAndPartnerUuid = getAppVendorAndPartnerUuid(configuration, remoteConfiguration);\n\n /**\n * This defines a mapping from a business event's external name (the name we document in public\n * API docs), to its internal representation as a Blizzard ServerEvent.\n *\n * It is important that we do this, since the naming of these internal business events are\n * unintuitive and will not make sense to SDK users.\n *\n * To specify the internal event, we must give the ServerEvent's eventName, the specific property\n * name which contains the event data (this is a \"oneof\" property on ServerEvent), and use the\n * correct event type's `fromPartial` method (this is generated from the ServerEvent protobuf).\n *\n * These events are documented here:\n * https://docs.google.com/document/d/1-kSzFWCWw9Qo3D08FR1_cqeHTsUtk9p3p3uOptzWDTY/\n *\n * They are defined in code here:\n * https://github.sc-corp.net/Snapchat/snapchat/tree/master/blizzard/schema/blizzard-schema/\n * codeGen/src/main/java/com/snapchat/analytics/schema/events/cameraKit\n */\n listenAndReport(\n metricsEventTarget,\n metricsHandler,\n pageVisibility,\n {\n assetDownload: (event) => [\n \"CAMERA_KIT_ASSET_DOWNLOAD\",\n { cameraKitAssetDownload: blizzard.CameraKitAssetDownload.fromPartial(event) },\n ],\n assetValidationFailed: (event) => [\n \"CAMERA_KIT_ASSET_VALIDATION_FAILED\",\n {\n cameraKitAssetValidationFailed: blizzard.CameraKitAssetValidationFailed.fromPartial(event),\n },\n ],\n benchmarkComplete: (event) => [\n \"CAMERA_KIT_WEB_BENCHMARK_COMPLETE\",\n {\n cameraKitWebBenchmarkComplete: blizzard.CameraKitWebBenchmarkComplete.fromPartial(event),\n },\n ],\n exception: (event) => [\n \"CAMERA_KIT_EXCEPTION\",\n { cameraKitException: blizzard.CameraKitException.fromPartial(event) },\n ],\n legalPrompt: (event) => [\n \"CAMERA_KIT_LEGAL_PROMPT\",\n { cameraKitLegalPrompt: blizzard.CameraKitLegalPrompt.fromPartial(event) },\n ],\n lensDownload: (event) => [\n \"CAMERA_KIT_LENS_DOWNLOAD\",\n { cameraKitLensDownload: blizzard.CameraKitLensDownload.fromPartial(event) },\n ],\n lensView: (event) => [\n \"CAMERA_KIT_WEB_LENS_SWIPE\",\n { cameraKitWebLensSwipe: blizzard.CameraKitWebLensSwipe.fromPartial(event) },\n ],\n lensWait: (event) => [\n \"CAMERA_KIT_LENS_SPIN\",\n { cameraKitLensSpin: blizzard.CameraKitLensSpin.fromPartial(event) },\n ],\n lensContentValidationFailed: (event) => [\n \"CAMERA_KIT_LENS_CONTENT_VALIDATION_FAILED\",\n {\n cameraKitLensContentValidationFailed:\n blizzard.CameraKitLensContentValidationFailed.fromPartial(event),\n },\n ],\n session: (event) => [\n \"CAMERA_KIT_SESSION\",\n { cameraKitSession: blizzard.CameraKitSession.fromPartial(event) },\n ],\n },\n configuration.apiHostname,\n appVendorAndPartnerUuid\n );\n }\n);\n"]}
|
|
@@ -13,23 +13,41 @@ const logMethods = entries(logLevelMap).map(([level]) => level);
|
|
|
13
13
|
const maxBufferedEntries = 15;
|
|
14
14
|
const contextSeparator = "\n\n----------------- Context -----------------\n\n";
|
|
15
15
|
const methodLength = logMethods.reduce((max, method) => Math.max(max, method.length), 0);
|
|
16
|
-
function getContextString(
|
|
16
|
+
function getContextString(logEntries) {
|
|
17
17
|
const result = [];
|
|
18
|
-
for (const entry of
|
|
18
|
+
for (const { entry, count, lastTime } of logEntries) {
|
|
19
19
|
const time = entry.time.toISOString();
|
|
20
20
|
const method = entry.level.padStart(methodLength);
|
|
21
21
|
// TODO: improve pretty printing
|
|
22
22
|
const messages = entry.messages.map((m) => m + "").join(" ");
|
|
23
|
-
|
|
23
|
+
let dupSuffix = count > 1 ? ` (Repeated ${count} times with the last occurrence at ${lastTime.toISOString()})` : "";
|
|
24
|
+
result.push(`${time} [${entry.module}] ${method}: ${messages}${dupSuffix}`);
|
|
24
25
|
}
|
|
25
26
|
return result.join("\n");
|
|
26
27
|
}
|
|
27
28
|
export function reportExceptionToBlizzard(logEntries, metricsEventTarget, reporter, lensState) {
|
|
28
29
|
logEntries
|
|
29
|
-
.pipe(scan((
|
|
30
|
-
entries
|
|
31
|
-
|
|
32
|
-
|
|
30
|
+
.pipe(scan(({ entries }, newEntry) => {
|
|
31
|
+
const lastEntry = entries[entries.length - 1];
|
|
32
|
+
const isNewEntryRepeated = lastEntry &&
|
|
33
|
+
lastEntry.entry.messages.join() === newEntry.messages.join() &&
|
|
34
|
+
lastEntry.entry.level === newEntry.level;
|
|
35
|
+
if (isNewEntryRepeated) {
|
|
36
|
+
lastEntry.count += 1;
|
|
37
|
+
lastEntry.lastTime = newEntry.time;
|
|
38
|
+
}
|
|
39
|
+
else {
|
|
40
|
+
entries.push({
|
|
41
|
+
entry: newEntry,
|
|
42
|
+
count: 1,
|
|
43
|
+
lastTime: newEntry.time,
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
return {
|
|
47
|
+
entries: entries.slice(-maxBufferedEntries),
|
|
48
|
+
recent: newEntry,
|
|
49
|
+
};
|
|
50
|
+
},
|
|
33
51
|
// Start with a dummy recent entry -- it gets overridden each time we handle a log entry.
|
|
34
52
|
{ entries: [], recent: { time: new Date(), module: "any", level: "debug", messages: [] } }), filter(({ recent }) => recent.level === "error"), map(({ entries, recent }) => ({
|
|
35
53
|
context: entries,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"reportGlobalException.js","sourceRoot":"","sources":["../../../src/metrics/reporters/reportGlobalException.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,wBAAwB,CAAC;AACjD,OAAO,EAAE,MAAM,EAAE,GAAG,EAAc,IAAI,EAAE,OAAO,EAAE,SAAS,EAAE,MAAM,MAAM,CAAC;AACzE,OAAO,EAAE,OAAO,EAAE,MAAM,sBAAsB,CAAC;AAC/C,OAAO,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAC3D,OAAO,EAAE,UAAU,EAAE,MAAM,uCAAuC,CAAC;AACnE,OAAO,EAAE,gBAAgB,EAAE,MAAM,+BAA+B,CAAC;AACjE,OAAO,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAC;AAC5D,OAAO,EAAY,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAE5D,OAAO,EAAsB,yBAAyB,EAAE,MAAM,uBAAuB,CAAC;AACtF,OAAO,EACH,gCAAgC,GAEnC,MAAM,2CAA2C,CAAC;AAEnD,MAAM,UAAU,GAAG,OAAO,CAAC,WAAW,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,KAAK,CAAC,EAAE,EAAE,CAAC,KAAK,CAAC,CAAC;AAEhE,uDAAuD;AACvD,MAAM,kBAAkB,GAAG,EAAE,CAAC;AAC9B,MAAM,gBAAgB,GAAG,qDAAqD,CAAC;AAC/E,MAAM,YAAY,GAAG,UAAU,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,MAAM,EAAE,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,EAAE,MAAM,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,CAAC;
|
|
1
|
+
{"version":3,"file":"reportGlobalException.js","sourceRoot":"","sources":["../../../src/metrics/reporters/reportGlobalException.ts"],"names":[],"mappings":"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","sourcesContent":["import { isState } from \"@snap/state-management\";\nimport { filter, map, Observable, scan, Subject, takeUntil } from \"rxjs\";\nimport { entries } from \"../../common/entries\";\nimport { stringifyError } from \"../../common/errorHelpers\";\nimport { Injectable } from \"../../dependency-injection/Injectable\";\nimport { TypedCustomEvent } from \"../../events/TypedCustomEvent\";\nimport { logEntriesFactory } from \"../../logger/logEntries\";\nimport { LogEntry, logLevelMap } from \"../../logger/logger\";\nimport { LensState } from \"../../session/lensState\";\nimport { MetricsEventTarget, metricsEventTargetFactory } from \"../metricsEventTarget\";\nimport {\n operationalMetricReporterFactory,\n OperationalMetricsReporter,\n} from \"../operational/operationalMetricsReporter\";\n\nconst logMethods = entries(logLevelMap).map(([level]) => level);\n\n// How many log entries to include as the error context\nconst maxBufferedEntries = 15;\nconst contextSeparator = \"\\n\\n----------------- Context -----------------\\n\\n\";\nconst methodLength = logMethods.reduce((max, method) => Math.max(max, method.length), 0);\n\ninterface RepeatableLogEntry {\n entry: LogEntry;\n count: number;\n lastTime: Date;\n}\n\ninterface EntriesBuffer {\n /**\n * LogEntries grouped by their message.\n */\n entries: RepeatableLogEntry[];\n /**\n * The recent log entry.\n */\n recent: LogEntry;\n}\n\nfunction getContextString(logEntries: RepeatableLogEntry[]) {\n const result = [];\n for (const { entry, count, lastTime } of logEntries) {\n const time = entry.time.toISOString();\n const method = entry.level.padStart(methodLength);\n // TODO: improve pretty printing\n const messages = entry.messages.map((m) => m + \"\").join(\" \");\n let dupSuffix =\n count > 1 ? ` (Repeated ${count} times with the last occurrence at ${lastTime.toISOString()})` : \"\";\n\n result.push(`${time} [${entry.module}] ${method}: ${messages}${dupSuffix}`);\n }\n return result.join(\"\\n\");\n}\n\nexport function reportExceptionToBlizzard(\n logEntries: Observable<LogEntry>,\n metricsEventTarget: MetricsEventTarget,\n reporter: OperationalMetricsReporter,\n lensState?: LensState\n) {\n logEntries\n .pipe(\n scan<LogEntry, EntriesBuffer>(\n ({ entries }, newEntry) => {\n const lastEntry = entries[entries.length - 1];\n const isNewEntryRepeated =\n lastEntry &&\n lastEntry.entry.messages.join() === newEntry.messages.join() &&\n lastEntry.entry.level === newEntry.level;\n if (isNewEntryRepeated) {\n lastEntry.count += 1;\n lastEntry.lastTime = newEntry.time;\n } else {\n entries.push({\n entry: newEntry,\n count: 1,\n lastTime: newEntry.time,\n });\n }\n return {\n entries: entries.slice(-maxBufferedEntries),\n recent: newEntry,\n };\n },\n // Start with a dummy recent entry -- it gets overridden each time we handle a log entry.\n { entries: [], recent: { time: new Date(), module: \"any\", level: \"debug\", messages: [] } }\n ),\n filter(({ recent }) => recent.level === \"error\"),\n map(({ entries, recent }) => ({\n context: entries,\n error: recent.messages.find((e) => e instanceof Error) as Error,\n })),\n filter(({ error }) => !!error)\n )\n .subscribe(({ error, context }) => {\n const currentLensState = lensState?.getState();\n const lensId =\n currentLensState && !isState(currentLensState, \"noLensApplied\") ? currentLensState.data.id : \"none\";\n metricsEventTarget.dispatchEvent(\n new TypedCustomEvent(\"exception\", {\n name: \"exception\",\n lensId,\n type: error.name,\n reason: `${stringifyError(error)}${contextSeparator}${getContextString(context)}`,\n })\n );\n\n reporter.count(\"handled_exception\", 1, new Map([[\"type\", error.name]]));\n });\n}\n\nexport interface GlobalExceptionReporter {\n attachLensContext: (lensState: LensState) => void;\n}\n\n/**\n * Reports log entries to Blizzard when there is no CameraKit session yet.\n *\n * @internal\n */\nexport const reportGlobalException = Injectable(\n \"reportGlobalException\",\n [logEntriesFactory.token, metricsEventTargetFactory.token, operationalMetricReporterFactory.token] as const,\n (\n logEntries: Observable<LogEntry>,\n metricsEventTarget: MetricsEventTarget,\n reporter: OperationalMetricsReporter\n ): GlobalExceptionReporter => {\n // Initially we log exceptions without any lens context\n const cancellationSubject = new Subject<void>();\n reportExceptionToBlizzard(logEntries.pipe(takeUntil(cancellationSubject)), metricsEventTarget, reporter);\n\n // Later session scope reporter triggers cancellation of the global one\n // and initiates exception reporting with a lens context\n return {\n attachLensContext: (lensState: LensState) => {\n cancellationSubject.next();\n reportExceptionToBlizzard(logEntries, metricsEventTarget, reporter, lensState);\n },\n };\n }\n);\n"]}
|
|
@@ -4,7 +4,7 @@ import { scan } from "../../events/scan";
|
|
|
4
4
|
import { COF_REQUEST_TYPE } from "../../remote-configuration/cofHandler";
|
|
5
5
|
import { requestStateEventTargetFactory, } from "../../handlers/requestStateEmittingHandler";
|
|
6
6
|
import { operationalMetricReporterFactory, } from "../operational/operationalMetricsReporter";
|
|
7
|
-
import {
|
|
7
|
+
import { getPlatformInfo } from "../../platform/platformInfo";
|
|
8
8
|
import { isLensOrAssetRequest } from "./reportLensAndAssetDownload";
|
|
9
9
|
const getContentType = (dimensions) => {
|
|
10
10
|
switch (dimensions.requestType) {
|
|
@@ -68,7 +68,7 @@ export const reportHttpMetrics = Injectable("reportHttpMetrics", [operationalMet
|
|
|
68
68
|
const status = getStatus(event);
|
|
69
69
|
const operationalDimensions = new Map([
|
|
70
70
|
["content_type", getContentType(dimensions)],
|
|
71
|
-
["network_type", (_a =
|
|
71
|
+
["network_type", (_a = getPlatformInfo().connectionType) !== null && _a !== void 0 ? _a : "unknown"],
|
|
72
72
|
["status", status],
|
|
73
73
|
]);
|
|
74
74
|
return {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"reportHttpMetrics.js","sourceRoot":"","sources":["../../../src/metrics/reporters/reportHttpMetrics.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAC;AAC5D,OAAO,EAAE,UAAU,EAAE,MAAM,uCAAuC,CAAC;AACnE,OAAO,EAAE,IAAI,EAAE,MAAM,mBAAmB,CAAC;AACzC,OAAO,EAAiB,gBAAgB,EAAE,MAAM,uCAAuC,CAAC;AACxF,OAAO,EAIH,8BAA8B,GACjC,MAAM,4CAA4C,CAAC;AACpD,OAAO,EACH,gCAAgC,GAEnC,MAAM,2CAA2C,CAAC;AACnD,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"reportHttpMetrics.js","sourceRoot":"","sources":["../../../src/metrics/reporters/reportHttpMetrics.ts"],"names":[],"mappings":"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","sourcesContent":["import { assertUnreachable } from \"../../common/assertions\";\nimport { Injectable } from \"../../dependency-injection/Injectable\";\nimport { scan } from \"../../events/scan\";\nimport { CofDimensions, COF_REQUEST_TYPE } from \"../../remote-configuration/cofHandler\";\nimport {\n Dimensions,\n RequestStateEventTarget,\n RequestStateEvents,\n requestStateEventTargetFactory,\n} from \"../../handlers/requestStateEmittingHandler\";\nimport {\n operationalMetricReporterFactory,\n OperationalMetricsReporter,\n} from \"../operational/operationalMetricsReporter\";\nimport { getPlatformInfo } from \"../../platform/platformInfo\";\nimport { AssetDownloadDimensions, isLensOrAssetRequest, LensDownloadDimensions } from \"./reportLensAndAssetDownload\";\n\ntype InProgressMap = Map<number, { startTimeMs: number }>;\ninterface InProgress {\n name: \"inProgress\";\n inProgress: InProgressMap;\n}\ninterface Completed {\n name: \"completed\";\n inProgress: InProgressMap;\n dimensions: Map<string, string>;\n downloadTimeMs: number;\n downloadSizeKb: number;\n}\ntype RequestState = InProgress | Completed;\n\nconst getContentType = (dimensions: LensDownloadDimensions | AssetDownloadDimensions | CofDimensions): string => {\n switch (dimensions.requestType) {\n case \"lens_content\":\n return \"lens_content\";\n case \"asset\":\n return dimensions.assetType;\n case COF_REQUEST_TYPE:\n return COF_REQUEST_TYPE;\n default:\n assertUnreachable(dimensions);\n }\n};\n\nconst getSizeKb = (event: RequestStateEvents): number => {\n switch (event.type) {\n case \"started\":\n case \"errored\":\n return 0;\n case \"completed\":\n return event.detail.sizeByte / 1024;\n default:\n assertUnreachable(event);\n }\n};\n\nconst getStatus = (event: RequestStateEvents): string => {\n switch (event.type) {\n case \"started\":\n case \"errored\":\n // We'll use status 0 to indicate that an exception occurred during the request. This is somewhat in keeping\n // with browsers that set the response status to 0 if the request was not able to be made (e.g. CORs\n // preflight failed, or the user canceled the request).\n return \"0\";\n case \"completed\":\n return event.detail.status.toString();\n default:\n assertUnreachable(event);\n }\n};\n\nexport const isRelevantRequest = (\n value: Dimensions\n): value is LensDownloadDimensions | AssetDownloadDimensions | CofDimensions => {\n return isLensOrAssetRequest(value) || value[\"requestType\"] === COF_REQUEST_TYPE;\n};\n\nexport const reportHttpMetrics = Injectable(\n \"reportHttpMetrics\",\n [operationalMetricReporterFactory.token, requestStateEventTargetFactory.token] as const,\n (reporter: OperationalMetricsReporter, requestStateEventTarget: RequestStateEventTarget) => {\n scan<RequestState>({ name: \"inProgress\", inProgress: new Map() })(\n requestStateEventTarget,\n [\"started\", \"completed\", \"errored\"],\n (state, event) => {\n const { inProgress } = state;\n const { dimensions, requestId, timeMs } = event.detail;\n\n if (!isRelevantRequest(dimensions)) return state;\n\n switch (event.type) {\n case \"started\":\n inProgress.set(requestId, { startTimeMs: timeMs });\n return { name: \"inProgress\", inProgress };\n case \"completed\":\n case \"errored\":\n const completedRequest = inProgress.get(requestId);\n if (!completedRequest) return state;\n inProgress.delete(requestId);\n\n const downloadTimeMs = timeMs - completedRequest.startTimeMs;\n const downloadSizeKb = getSizeKb(event);\n const status = getStatus(event);\n const operationalDimensions = new Map<string, string>([\n [\"content_type\", getContentType(dimensions)],\n [\"network_type\", getPlatformInfo().connectionType ?? \"unknown\"],\n [\"status\", status],\n ]);\n\n return {\n name: \"completed\",\n inProgress: state.inProgress,\n dimensions: operationalDimensions,\n downloadSizeKb,\n downloadTimeMs,\n };\n default:\n assertUnreachable(event);\n }\n }\n ).addEventListener(\"state\", ({ detail: state }) => {\n if (state.name !== \"completed\") return;\n\n const { dimensions, downloadTimeMs, downloadSizeKb } = state;\n\n reporter.count(\"download_finished\", 1, dimensions);\n reporter.timer(\"download_latency\", downloadTimeMs, dimensions);\n reporter.histogram(\"download_size_kb\", downloadSizeKb, dimensions);\n });\n }\n);\n"]}
|
|
@@ -74,7 +74,7 @@ export const reportLensView = Injectable("reportLensView", [
|
|
|
74
74
|
// If the session is resumed (e.g. user returns to this tab while a lens is on), we count this as a new
|
|
75
75
|
// LensView (and applyDelaySec will be 0).
|
|
76
76
|
lensState.events.pipe(inStates("lensApplied"), switchMap(([, s]) => sessionState.events.pipe(forActions("resume"), takeUntil(lensState.events.pipe(forActions("removeLens"))), map(() => s.data)))))
|
|
77
|
-
.pipe(map((lens) => [getTimeMs(), lens.id]), mergeMap(([applyLensStartTime, lensId]) => {
|
|
77
|
+
.pipe(map((lens) => [getTimeMs(), lens.id, lens.groupId]), mergeMap(([applyLensStartTime, lensId, lensGroupId]) => {
|
|
78
78
|
const alreadyOn = isState(lensState.getState(), "lensApplied");
|
|
79
79
|
const applyDelay = alreadyOn
|
|
80
80
|
? of(0)
|
|
@@ -98,10 +98,11 @@ export const reportLensView = Injectable("reportLensView", [
|
|
|
98
98
|
// turned on. But just in case that assumption is violated, we'll clean up
|
|
99
99
|
// (and not report) if another lens turns on before our lens is turned off.
|
|
100
100
|
takeUntil(lensState.events.pipe(forActions("turnedOn"), filter(([a]) => a.data.id !== lensId))), take(1), map(([applyDelaySec, viewMetrics, isFirstTimeResults]) => (Object.assign(Object.assign({ applyDelaySec,
|
|
101
|
-
lensId
|
|
101
|
+
lensId,
|
|
102
|
+
lensGroupId }, viewMetrics), isFirstTimeResults))));
|
|
102
103
|
}))
|
|
103
104
|
.subscribe({
|
|
104
|
-
next: ({ applyDelaySec, lensId, viewTimeSec, avgFps, lensFrameProcessingTimeMsAvg, lensFrameProcessingTimeMsStd, lensFrameProcessingTimeMsMedian, lensFrameProcessingN, isLensFirstWithinDay, isLensFirstWithinMonth, }) => __awaiter(void 0, void 0, void 0, function* () {
|
|
105
|
+
next: ({ applyDelaySec, lensId, lensGroupId, viewTimeSec, avgFps, lensFrameProcessingTimeMsAvg, lensFrameProcessingTimeMsStd, lensFrameProcessingTimeMsMedian, lensFrameProcessingN, isLensFirstWithinDay, isLensFirstWithinMonth, }) => __awaiter(void 0, void 0, void 0, function* () {
|
|
105
106
|
if (viewTimeSec < viewTimeThresholdSec)
|
|
106
107
|
return;
|
|
107
108
|
const lensView = {
|
|
@@ -109,6 +110,7 @@ export const reportLensView = Injectable("reportLensView", [
|
|
|
109
110
|
applyDelaySec,
|
|
110
111
|
avgFps,
|
|
111
112
|
lensId,
|
|
113
|
+
lensGroupId,
|
|
112
114
|
lensFrameProcessingTimeMsAvg,
|
|
113
115
|
lensFrameProcessingTimeMsStd,
|
|
114
116
|
// We don't support recording video, but applications may do this without our knowledge.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"reportLensView.js","sourceRoot":"","sources":["../../../src/metrics/reporters/reportLensView.ts"],"names":[],"mappings":"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","sourcesContent":["import { combineLatestWith, filter, from, map, merge, mergeMap, of, raceWith, switchMap, take, takeUntil } from \"rxjs\";\nimport { forActions, inStates, isState } from \"@snap/state-management\";\nimport { Injectable } from \"../../dependency-injection/Injectable\";\nimport { TypedCustomEvent } from \"../../events/TypedCustomEvent\";\nimport { MetricsEventTarget, metricsEventTargetFactory } from \"../metricsEventTarget\";\nimport { CameraKitSession, cameraKitSessionFactory } from \"../../session/CameraKitSession\";\nimport { MakeTaggedBusinessEvent } from \"../businessEventsReporter\";\nimport { getTimeMs } from \"../../common/time\";\nimport {\n operationalMetricReporterFactory,\n OperationalMetricsReporter,\n} from \"../operational/operationalMetricsReporter\";\nimport { CameraKitConfiguration, configurationToken } from \"../../configuration\";\nimport { lensStateFactory, LensState } from \"../../session/lensState\";\nimport { SessionState, sessionStateFactory } from \"../../session/sessionState\";\nimport { Histogram } from \"../operational/Histogram\";\nimport { IndexedDBPersistence } from \"../../persistence/IndexedDBPersistence\";\nimport { ExpiringPersistence } from \"../../persistence/ExpiringPersistence\";\nimport { dayFormatter, monthFormatter } from \"../../common/date\";\n\n// We ignore short-duration lens views.\n//\n// The value is documented here:\n// https://docs.google.com/document/d/1-kSzFWCWw9Qo3D08FR1_cqeHTsUtk9p3p3uOptzWDTY/edit#heading=h.q5liip76r9lt\nconst viewTimeThresholdSec = 0.1;\n\nasync function isFirstTimeWithinPeriods(lensId: string, persistence: ExpiringPersistence<Date>) {\n let isLensFirstWithinDay = false;\n let isLensFirstWithinMonth = false;\n\n try {\n const lensLastViewDate = await persistence.retrieve(lensId);\n const currentDate = new Date();\n\n if (!lensLastViewDate) {\n isLensFirstWithinDay = true;\n isLensFirstWithinMonth = true;\n } else {\n isLensFirstWithinDay = dayFormatter.format(lensLastViewDate) !== dayFormatter.format(currentDate);\n isLensFirstWithinMonth = monthFormatter.format(lensLastViewDate) !== monthFormatter.format(currentDate);\n }\n\n await persistence.store(lensId, currentDate);\n } catch (error) {\n console.error(`Error handling persistence for lensId ${lensId}: ${error}`);\n isLensFirstWithinDay = false;\n isLensFirstWithinMonth = false;\n }\n\n return { isLensFirstWithinDay, isLensFirstWithinMonth };\n}\n\n/**\n * The LensView metric is emitted after a lens has been viewed (for longer than 100ms), when the lens is turned off.\n *\n * It contains information about rendering performance.\n *\n * Notes:\n * - If the page is hidden (e.g. user switches to a different tab, or application, or closes the tab, or closes the\n * browser, navigates to a new page, refreshes, etc.) this metric will be emitted at that time. This is to ensure\n * we don't lose the metric if the page is closed.\n * - If the page is hidden and then made visible again later (e.g. user switches to a different tab, then back), we\n * will begin measuring a new LensView. That is, we will not capture the time when the page is hidden even if the\n * lens is still rendering in the background.\n *\n * @category Lenses\n * @category Metrics\n */\n// This type corresponds to the internal CameraKitLensSwipe event, described here:\n// https://docs.google.com/document/d/1-kSzFWCWw9Qo3D08FR1_cqeHTsUtk9p3p3uOptzWDTY#heading=h.q5liip76r9lt\nexport type LensView = MakeTaggedBusinessEvent<\"lensView\">;\n\n/**\n * @internal\n */\nexport const reportLensView = Injectable(\n \"reportLensView\",\n [\n cameraKitSessionFactory.token,\n lensStateFactory.token,\n sessionStateFactory.token,\n metricsEventTargetFactory.token,\n operationalMetricReporterFactory.token,\n configurationToken,\n ] as const,\n async (\n session: CameraKitSession,\n lensState: LensState,\n sessionState: SessionState,\n metricsEventTarget: MetricsEventTarget,\n operationalMetricsReporter: OperationalMetricsReporter,\n configuration: CameraKitConfiguration\n ): Promise<void> => {\n // We need to do this await up front so that it won't interrupt reporting the metric when the session is\n // suspended -- suspension could happen because the tab is closing, in which case we cannot perform await a\n // Promise, because in the case of a tab close the browser will not schedule any work for future turns of the\n // event loop.\n const { cluster: performanceCluster, webglRendererInfo } = (await configuration.lensPerformance) ?? {\n cluster: 0,\n webglRendererInfo: \"unknown\",\n };\n\n const lensViewPersistence = new ExpiringPersistence<Date>(\n // 60 days expiration\n () => 60 * 24 * 60 * 60,\n new IndexedDBPersistence({ databaseName: \"recentLensViews\" })\n );\n\n merge(\n // Begin measuring LensCore apply time once the lens has finished downloading and we actually add the lens\n // to LensCore (LensWait measures the full download + LensCore apply time i.e. perceived UX latency).\n lensState.events.pipe(\n forActions(\"downloadComplete\"),\n map(([a]) => a.data)\n ),\n\n // If the session is resumed (e.g. user returns to this tab while a lens is on), we count this as a new\n // LensView (and applyDelaySec will be 0).\n lensState.events.pipe(\n inStates(\"lensApplied\"),\n switchMap(([, s]) =>\n sessionState.events.pipe(\n forActions(\"resume\"),\n takeUntil(lensState.events.pipe(forActions(\"removeLens\"))),\n map(() => s.data)\n )\n )\n )\n )\n .pipe(\n map((lens): [number, string] => [getTimeMs(), lens.id]),\n mergeMap(([applyLensStartTime, lensId]) => {\n const alreadyOn = isState(lensState.getState(), \"lensApplied\");\n\n const applyDelay = alreadyOn\n ? of(0)\n : lensState.events.pipe(\n forActions(\"resourcesLoaded\"),\n filter(([a]) => a.data.id === lensId),\n // Applying a new lens may happen before removing the old one, so if we kept taking events\n // we would get the lensResourcesLoaded for the next lens, too.\n take(1),\n map(() => (getTimeMs() - applyLensStartTime) / 1000)\n );\n\n const viewMetrics = (\n alreadyOn\n ? of([getTimeMs(), session.metrics.beginMeasurement()] as const)\n : lensState.events.pipe(\n forActions(\"turnedOn\"),\n filter(([a]) => a.data.id === lensId),\n map(() => [getTimeMs(), session.metrics.beginMeasurement()] as const)\n )\n ).pipe(\n take(1),\n mergeMap(([lensTurnedOnTime, metricsMeasurement]) =>\n lensState.events.pipe(\n forActions(\"turnedOff\"),\n // Applying a new lens may happen before removing the old one, so we'll get a\n // lensTurnedOff for the prior lens (if one was applied), which we must filter out.\n filter(([a]) => a.data.id === lensId),\n // If the session is suspended, we'll count that as the lens turning off.\n raceWith(sessionState.events.pipe(forActions(\"suspend\"))),\n map(() => {\n metricsMeasurement.end();\n return {\n viewTimeSec: (getTimeMs() - lensTurnedOnTime) / 1000,\n ...metricsMeasurement.measure(),\n };\n })\n )\n )\n );\n\n return applyDelay.pipe(\n combineLatestWith(viewMetrics, from(isFirstTimeWithinPeriods(lensId, lensViewPersistence))),\n // This lens should always receive the lensTurnedOff action *before* the next lens is\n // turned on. But just in case that assumption is violated, we'll clean up\n // (and not report) if another lens turns on before our lens is turned off.\n takeUntil(\n lensState.events.pipe(\n forActions(\"turnedOn\"),\n filter(([a]) => a.data.id !== lensId)\n )\n ),\n take(1),\n map(([applyDelaySec, viewMetrics, isFirstTimeResults]) => ({\n applyDelaySec,\n lensId,\n ...viewMetrics,\n ...isFirstTimeResults,\n }))\n );\n })\n )\n .subscribe({\n next: async ({\n applyDelaySec,\n lensId,\n viewTimeSec,\n avgFps,\n lensFrameProcessingTimeMsAvg,\n lensFrameProcessingTimeMsStd,\n lensFrameProcessingTimeMsMedian,\n lensFrameProcessingN,\n isLensFirstWithinDay,\n isLensFirstWithinMonth,\n }) => {\n if (viewTimeSec < viewTimeThresholdSec) return;\n\n const lensView: LensView = {\n name: \"lensView\",\n applyDelaySec,\n avgFps,\n lensId,\n lensFrameProcessingTimeMsAvg,\n lensFrameProcessingTimeMsStd,\n // We don't support recording video, but applications may do this without our knowledge.\n recordingTimeSec: 0,\n viewTimeSec,\n isLensFirstWithinDay,\n isLensFirstWithinMonth,\n performanceCluster,\n webglRendererInfo,\n };\n\n metricsEventTarget.dispatchEvent(new TypedCustomEvent(\"lensView\", lensView));\n operationalMetricsReporter.report(Histogram.level(\"lens_view\", viewTimeSec * 1000));\n\n // The first few frames will typically take much longer to process (as they might involve requesting\n // remote assets to be downloaded, or other high-latency initialization steps) -- so we'll skip\n // reporting views with a very small number of frames.\n if (lensFrameProcessingN >= 30) {\n operationalMetricsReporter.report(\n Histogram.level(\"lens_view_frame-processing-time\", lensFrameProcessingTimeMsMedian, {\n performance_cluster: performanceCluster.toString(),\n })\n );\n }\n },\n });\n }\n);\n"]}
|
|
1
|
+
{"version":3,"file":"reportLensView.js","sourceRoot":"","sources":["../../../src/metrics/reporters/reportLensView.ts"],"names":[],"mappings":"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","sourcesContent":["import { combineLatestWith, filter, from, map, merge, mergeMap, of, raceWith, switchMap, take, takeUntil } from \"rxjs\";\nimport { forActions, inStates, isState } from \"@snap/state-management\";\nimport { Injectable } from \"../../dependency-injection/Injectable\";\nimport { TypedCustomEvent } from \"../../events/TypedCustomEvent\";\nimport { MetricsEventTarget, metricsEventTargetFactory } from \"../metricsEventTarget\";\nimport { CameraKitSession, cameraKitSessionFactory } from \"../../session/CameraKitSession\";\nimport { MakeTaggedBusinessEvent } from \"../businessEventsReporter\";\nimport { getTimeMs } from \"../../common/time\";\nimport {\n operationalMetricReporterFactory,\n OperationalMetricsReporter,\n} from \"../operational/operationalMetricsReporter\";\nimport { CameraKitConfiguration, configurationToken } from \"../../configuration\";\nimport { lensStateFactory, LensState } from \"../../session/lensState\";\nimport { SessionState, sessionStateFactory } from \"../../session/sessionState\";\nimport { Histogram } from \"../operational/Histogram\";\nimport { IndexedDBPersistence } from \"../../persistence/IndexedDBPersistence\";\nimport { ExpiringPersistence } from \"../../persistence/ExpiringPersistence\";\nimport { dayFormatter, monthFormatter } from \"../../common/date\";\n\n// We ignore short-duration lens views.\n//\n// The value is documented here:\n// https://docs.google.com/document/d/1-kSzFWCWw9Qo3D08FR1_cqeHTsUtk9p3p3uOptzWDTY/edit#heading=h.q5liip76r9lt\nconst viewTimeThresholdSec = 0.1;\n\nasync function isFirstTimeWithinPeriods(lensId: string, persistence: ExpiringPersistence<Date>) {\n let isLensFirstWithinDay = false;\n let isLensFirstWithinMonth = false;\n\n try {\n const lensLastViewDate = await persistence.retrieve(lensId);\n const currentDate = new Date();\n\n if (!lensLastViewDate) {\n isLensFirstWithinDay = true;\n isLensFirstWithinMonth = true;\n } else {\n isLensFirstWithinDay = dayFormatter.format(lensLastViewDate) !== dayFormatter.format(currentDate);\n isLensFirstWithinMonth = monthFormatter.format(lensLastViewDate) !== monthFormatter.format(currentDate);\n }\n\n await persistence.store(lensId, currentDate);\n } catch (error) {\n console.error(`Error handling persistence for lensId ${lensId}: ${error}`);\n isLensFirstWithinDay = false;\n isLensFirstWithinMonth = false;\n }\n\n return { isLensFirstWithinDay, isLensFirstWithinMonth };\n}\n\n/**\n * The LensView metric is emitted after a lens has been viewed (for longer than 100ms), when the lens is turned off.\n *\n * It contains information about rendering performance.\n *\n * Notes:\n * - If the page is hidden (e.g. user switches to a different tab, or application, or closes the tab, or closes the\n * browser, navigates to a new page, refreshes, etc.) this metric will be emitted at that time. This is to ensure\n * we don't lose the metric if the page is closed.\n * - If the page is hidden and then made visible again later (e.g. user switches to a different tab, then back), we\n * will begin measuring a new LensView. That is, we will not capture the time when the page is hidden even if the\n * lens is still rendering in the background.\n *\n * @category Lenses\n * @category Metrics\n */\n// This type corresponds to the internal CameraKitLensSwipe event, described here:\n// https://docs.google.com/document/d/1-kSzFWCWw9Qo3D08FR1_cqeHTsUtk9p3p3uOptzWDTY#heading=h.q5liip76r9lt\nexport type LensView = MakeTaggedBusinessEvent<\"lensView\">;\n\n/**\n * @internal\n */\nexport const reportLensView = Injectable(\n \"reportLensView\",\n [\n cameraKitSessionFactory.token,\n lensStateFactory.token,\n sessionStateFactory.token,\n metricsEventTargetFactory.token,\n operationalMetricReporterFactory.token,\n configurationToken,\n ] as const,\n async (\n session: CameraKitSession,\n lensState: LensState,\n sessionState: SessionState,\n metricsEventTarget: MetricsEventTarget,\n operationalMetricsReporter: OperationalMetricsReporter,\n configuration: CameraKitConfiguration\n ): Promise<void> => {\n // We need to do this await up front so that it won't interrupt reporting the metric when the session is\n // suspended -- suspension could happen because the tab is closing, in which case we cannot perform await a\n // Promise, because in the case of a tab close the browser will not schedule any work for future turns of the\n // event loop.\n const { cluster: performanceCluster, webglRendererInfo } = (await configuration.lensPerformance) ?? {\n cluster: 0,\n webglRendererInfo: \"unknown\",\n };\n\n const lensViewPersistence = new ExpiringPersistence<Date>(\n // 60 days expiration\n () => 60 * 24 * 60 * 60,\n new IndexedDBPersistence({ databaseName: \"recentLensViews\" })\n );\n\n merge(\n // Begin measuring LensCore apply time once the lens has finished downloading and we actually add the lens\n // to LensCore (LensWait measures the full download + LensCore apply time i.e. perceived UX latency).\n lensState.events.pipe(\n forActions(\"downloadComplete\"),\n map(([a]) => a.data)\n ),\n\n // If the session is resumed (e.g. user returns to this tab while a lens is on), we count this as a new\n // LensView (and applyDelaySec will be 0).\n lensState.events.pipe(\n inStates(\"lensApplied\"),\n switchMap(([, s]) =>\n sessionState.events.pipe(\n forActions(\"resume\"),\n takeUntil(lensState.events.pipe(forActions(\"removeLens\"))),\n map(() => s.data)\n )\n )\n )\n )\n .pipe(\n map((lens): [number, string, string] => [getTimeMs(), lens.id, lens.groupId]),\n mergeMap(([applyLensStartTime, lensId, lensGroupId]) => {\n const alreadyOn = isState(lensState.getState(), \"lensApplied\");\n\n const applyDelay = alreadyOn\n ? of(0)\n : lensState.events.pipe(\n forActions(\"resourcesLoaded\"),\n filter(([a]) => a.data.id === lensId),\n // Applying a new lens may happen before removing the old one, so if we kept taking events\n // we would get the lensResourcesLoaded for the next lens, too.\n take(1),\n map(() => (getTimeMs() - applyLensStartTime) / 1000)\n );\n\n const viewMetrics = (\n alreadyOn\n ? of([getTimeMs(), session.metrics.beginMeasurement()] as const)\n : lensState.events.pipe(\n forActions(\"turnedOn\"),\n filter(([a]) => a.data.id === lensId),\n map(() => [getTimeMs(), session.metrics.beginMeasurement()] as const)\n )\n ).pipe(\n take(1),\n mergeMap(([lensTurnedOnTime, metricsMeasurement]) =>\n lensState.events.pipe(\n forActions(\"turnedOff\"),\n // Applying a new lens may happen before removing the old one, so we'll get a\n // lensTurnedOff for the prior lens (if one was applied), which we must filter out.\n filter(([a]) => a.data.id === lensId),\n // If the session is suspended, we'll count that as the lens turning off.\n raceWith(sessionState.events.pipe(forActions(\"suspend\"))),\n map(() => {\n metricsMeasurement.end();\n return {\n viewTimeSec: (getTimeMs() - lensTurnedOnTime) / 1000,\n ...metricsMeasurement.measure(),\n };\n })\n )\n )\n );\n\n return applyDelay.pipe(\n combineLatestWith(viewMetrics, from(isFirstTimeWithinPeriods(lensId, lensViewPersistence))),\n // This lens should always receive the lensTurnedOff action *before* the next lens is\n // turned on. But just in case that assumption is violated, we'll clean up\n // (and not report) if another lens turns on before our lens is turned off.\n takeUntil(\n lensState.events.pipe(\n forActions(\"turnedOn\"),\n filter(([a]) => a.data.id !== lensId)\n )\n ),\n take(1),\n map(([applyDelaySec, viewMetrics, isFirstTimeResults]) => ({\n applyDelaySec,\n lensId,\n lensGroupId,\n ...viewMetrics,\n ...isFirstTimeResults,\n }))\n );\n })\n )\n .subscribe({\n next: async ({\n applyDelaySec,\n lensId,\n lensGroupId,\n viewTimeSec,\n avgFps,\n lensFrameProcessingTimeMsAvg,\n lensFrameProcessingTimeMsStd,\n lensFrameProcessingTimeMsMedian,\n lensFrameProcessingN,\n isLensFirstWithinDay,\n isLensFirstWithinMonth,\n }) => {\n if (viewTimeSec < viewTimeThresholdSec) return;\n\n const lensView: LensView = {\n name: \"lensView\",\n applyDelaySec,\n avgFps,\n lensId,\n lensGroupId,\n lensFrameProcessingTimeMsAvg,\n lensFrameProcessingTimeMsStd,\n // We don't support recording video, but applications may do this without our knowledge.\n recordingTimeSec: 0,\n viewTimeSec,\n isLensFirstWithinDay,\n isLensFirstWithinMonth,\n performanceCluster,\n webglRendererInfo,\n };\n\n metricsEventTarget.dispatchEvent(new TypedCustomEvent(\"lensView\", lensView));\n operationalMetricsReporter.report(Histogram.level(\"lens_view\", viewTimeSec * 1000));\n\n // The first few frames will typically take much longer to process (as they might involve requesting\n // remote assets to be downloaded, or other high-latency initialization steps) -- so we'll skip\n // reporting views with a very small number of frames.\n if (lensFrameProcessingN >= 30) {\n operationalMetricsReporter.report(\n Histogram.level(\"lens_view_frame-processing-time\", lensFrameProcessingTimeMsMedian, {\n performance_cluster: performanceCluster.toString(),\n })\n );\n }\n },\n });\n }\n);\n"]}
|
|
@@ -25,6 +25,7 @@ export const reportLensWait = Injectable("reportLensWait", [lensStateFactory.tok
|
|
|
25
25
|
lensState.events
|
|
26
26
|
.pipe(forActions("applyLens"), mergeMap(([a]) => {
|
|
27
27
|
const lensId = a.data.lens.id;
|
|
28
|
+
const lensGroupId = a.data.lens.groupId;
|
|
28
29
|
const applyLensStartTime = getTimeMs();
|
|
29
30
|
return lensState.events.pipe(
|
|
30
31
|
// We'll measure the time until either the requested lens was rendered, or a new applyLens
|
|
@@ -37,16 +38,21 @@ export const reportLensWait = Injectable("reportLensWait", [lensStateFactory.tok
|
|
|
37
38
|
//
|
|
38
39
|
// (This effect can be mitigated by increasing the viewtimeThresholdSec to ignore low-duration
|
|
39
40
|
// waits that are likely caused by user behavior).
|
|
40
|
-
forActions("firstFrameProcessed", "applyLens"), take(1), map(() => [
|
|
41
|
+
forActions("firstFrameProcessed", "applyLens"), take(1), map(() => [
|
|
42
|
+
(getTimeMs() - applyLensStartTime) / 1000,
|
|
43
|
+
lensId,
|
|
44
|
+
lensGroupId,
|
|
45
|
+
]));
|
|
41
46
|
}))
|
|
42
47
|
.subscribe({
|
|
43
|
-
next: ([viewTimeSec, lensId]) => {
|
|
48
|
+
next: ([viewTimeSec, lensId, lensGroupId]) => {
|
|
44
49
|
if (viewTimeSec < viewTimeThresholdSec)
|
|
45
50
|
return;
|
|
46
51
|
const lensWait = {
|
|
47
52
|
name: "lensWait",
|
|
48
53
|
lensId,
|
|
49
54
|
viewTimeSec,
|
|
55
|
+
lensGroupId,
|
|
50
56
|
};
|
|
51
57
|
metricsEventTarget.dispatchEvent(new TypedCustomEvent("lensWait", lensWait));
|
|
52
58
|
reporter.timer("lens.apply_lens_latency", viewTimeSec * 1000);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"reportLensWait.js","sourceRoot":"","sources":["../../../src/metrics/reporters/reportLensWait.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAC;AACpD,OAAO,EAAE,GAAG,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAC3C,OAAO,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAC;AAC9C,OAAO,EAAE,UAAU,EAAE,MAAM,uCAAuC,CAAC;AACnE,OAAO,EAAE,gBAAgB,EAAE,MAAM,+BAA+B,CAAC;AACjE,OAAO,EAAE,gBAAgB,EAAa,MAAM,yBAAyB,CAAC;AAEtE,OAAO,EAAsB,yBAAyB,EAAE,MAAM,uBAAuB,CAAC;AACtF,OAAO,EACH,gCAAgC,GAEnC,MAAM,2CAA2C,CAAC;AAEnD,uCAAuC;AACvC,EAAE;AACF,gCAAgC;AAChC,8GAA8G;AAC9G,MAAM,oBAAoB,GAAG,GAAG,CAAC;AAcjC;;;;;;;;;GASG;AACH,MAAM,CAAC,MAAM,cAAc,GAAG,UAAU,CACpC,gBAAgB,EAChB,CAAC,gBAAgB,CAAC,KAAK,EAAE,yBAAyB,CAAC,KAAK,EAAE,gCAAgC,CAAC,KAAK,CAAU,EAC1G,CAAC,SAAoB,EAAE,kBAAsC,EAAE,QAAoC,EAAE,EAAE;IACnG,SAAS,CAAC,MAAM;SACX,IAAI,CACD,UAAU,CAAC,WAAW,CAAC,EACvB,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,EAAE;QACb,MAAM,MAAM,GAAG,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;QAC9B,MAAM,kBAAkB,GAAG,SAAS,EAAE,CAAC;QACvC,OAAO,SAAS,CAAC,MAAM,CAAC,IAAI;QACxB,0FAA0F;QAC1F,sEAAsE;QACtE,EAAE;QACF,8FAA8F;QAC9F,gGAAgG;QAChG,6FAA6F;QAC7F,kDAAkD;QAClD,EAAE;QACF,8FAA8F;QAC9F,kDAAkD;QAClD,UAAU,CAAC,qBAAqB,EAAE,WAAW,CAAC,EAC9C,IAAI,CAAC,CAAC,CAAC,EACP,GAAG,CAAC,
|
|
1
|
+
{"version":3,"file":"reportLensWait.js","sourceRoot":"","sources":["../../../src/metrics/reporters/reportLensWait.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAC;AACpD,OAAO,EAAE,GAAG,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAC3C,OAAO,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAC;AAC9C,OAAO,EAAE,UAAU,EAAE,MAAM,uCAAuC,CAAC;AACnE,OAAO,EAAE,gBAAgB,EAAE,MAAM,+BAA+B,CAAC;AACjE,OAAO,EAAE,gBAAgB,EAAa,MAAM,yBAAyB,CAAC;AAEtE,OAAO,EAAsB,yBAAyB,EAAE,MAAM,uBAAuB,CAAC;AACtF,OAAO,EACH,gCAAgC,GAEnC,MAAM,2CAA2C,CAAC;AAEnD,uCAAuC;AACvC,EAAE;AACF,gCAAgC;AAChC,8GAA8G;AAC9G,MAAM,oBAAoB,GAAG,GAAG,CAAC;AAcjC;;;;;;;;;GASG;AACH,MAAM,CAAC,MAAM,cAAc,GAAG,UAAU,CACpC,gBAAgB,EAChB,CAAC,gBAAgB,CAAC,KAAK,EAAE,yBAAyB,CAAC,KAAK,EAAE,gCAAgC,CAAC,KAAK,CAAU,EAC1G,CAAC,SAAoB,EAAE,kBAAsC,EAAE,QAAoC,EAAE,EAAE;IACnG,SAAS,CAAC,MAAM;SACX,IAAI,CACD,UAAU,CAAC,WAAW,CAAC,EACvB,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,EAAE;QACb,MAAM,MAAM,GAAG,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;QAC9B,MAAM,WAAW,GAAG,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC;QACxC,MAAM,kBAAkB,GAAG,SAAS,EAAE,CAAC;QACvC,OAAO,SAAS,CAAC,MAAM,CAAC,IAAI;QACxB,0FAA0F;QAC1F,sEAAsE;QACtE,EAAE;QACF,8FAA8F;QAC9F,gGAAgG;QAChG,6FAA6F;QAC7F,kDAAkD;QAClD,EAAE;QACF,8FAA8F;QAC9F,kDAAkD;QAClD,UAAU,CAAC,qBAAqB,EAAE,WAAW,CAAC,EAC9C,IAAI,CAAC,CAAC,CAAC,EACP,GAAG,CAAC,GAA6B,EAAE,CAAC;YAChC,CAAC,SAAS,EAAE,GAAG,kBAAkB,CAAC,GAAG,IAAI;YACzC,MAAM;YACN,WAAW;SACd,CAAC,CACL,CAAC;IACN,CAAC,CAAC,CACL;SACA,SAAS,CAAC;QACP,IAAI,EAAE,CAAC,CAAC,WAAW,EAAE,MAAM,EAAE,WAAW,CAAC,EAAE,EAAE;YACzC,IAAI,WAAW,GAAG,oBAAoB;gBAAE,OAAO;YAE/C,MAAM,QAAQ,GAAa;gBACvB,IAAI,EAAE,UAAU;gBAChB,MAAM;gBACN,WAAW;gBACX,WAAW;aACd,CAAC;YACF,kBAAkB,CAAC,aAAa,CAAC,IAAI,gBAAgB,CAAC,UAAU,EAAE,QAAQ,CAAC,CAAC,CAAC;YAC7E,QAAQ,CAAC,KAAK,CAAC,yBAAyB,EAAE,WAAW,GAAG,IAAI,CAAC,CAAC;QAClE,CAAC;KACJ,CAAC,CAAC;AACX,CAAC,CACJ,CAAC","sourcesContent":["import { forActions } from \"@snap/state-management\";\nimport { map, mergeMap, take } from \"rxjs\";\nimport { getTimeMs } from \"../../common/time\";\nimport { Injectable } from \"../../dependency-injection/Injectable\";\nimport { TypedCustomEvent } from \"../../events/TypedCustomEvent\";\nimport { lensStateFactory, LensState } from \"../../session/lensState\";\nimport { MakeTaggedBusinessEvent } from \"../businessEventsReporter\";\nimport { MetricsEventTarget, metricsEventTargetFactory } from \"../metricsEventTarget\";\nimport {\n operationalMetricReporterFactory,\n OperationalMetricsReporter,\n} from \"../operational/operationalMetricsReporter\";\n\n// We ignore short-duration lens waits.\n//\n// The value is documented here:\n// https://docs.google.com/document/d/1-kSzFWCWw9Qo3D08FR1_cqeHTsUtk9p3p3uOptzWDTY/edit#heading=h.q5liip76r9lt\nconst viewTimeThresholdSec = 0.1;\n\n/**\n * The LensWait metric measures the time spent downloading the lens content and required assets. It gives an indication\n * of the real UX impact of download latency. If lens content and assets are pre-loaded, the latency measured here\n * should decrease – we measure between the request to apply a lens and when the lens is ready to render.\n *\n * @category Lenses\n * @category Metrics\n */\n// This type corresponds to the internal CameraKitLensSpin event, described here:\n// https://docs.google.com/document/d/1-kSzFWCWw9Qo3D08FR1_cqeHTsUtk9p3p3uOptzWDTY#heading=h.q5liip76r9lt\nexport type LensWait = MakeTaggedBusinessEvent<\"lensWait\">;\n\n/**\n * Each time a lens is applied, we measure the duration until the lens is fully loaded by LensCore. This\n * includes any time spent downloading the lens content and required assets from the lens manifest.\n *\n * The intention of this event is to measure the experienced UX latency between a user requesting a lens and\n * the lens rendering. Of course, the application may call `applyLens` at any time, and may hide/show the\n * rendered result at any time – but this should give us a good baseline for how much UX latency could be seen.\n *\n * @internal\n */\nexport const reportLensWait = Injectable(\n \"reportLensWait\",\n [lensStateFactory.token, metricsEventTargetFactory.token, operationalMetricReporterFactory.token] as const,\n (lensState: LensState, metricsEventTarget: MetricsEventTarget, reporter: OperationalMetricsReporter) => {\n lensState.events\n .pipe(\n forActions(\"applyLens\"),\n mergeMap(([a]) => {\n const lensId = a.data.lens.id;\n const lensGroupId = a.data.lens.groupId;\n const applyLensStartTime = getTimeMs();\n return lensState.events.pipe(\n // We'll measure the time until either the requested lens was rendered, or a new applyLens\n // request was made (in both cases, we're done waiting for this lens).\n //\n // This does have the side-effect that if a user rapidly switches between lenses, we'll record\n // many low-duration lensWait events that are measuring user behavior instead of system latency.\n // But this is a good trade-off so that we can capture those long-duration lensWaits that are\n // terminated by the user trying a different lens.\n //\n // (This effect can be mitigated by increasing the viewtimeThresholdSec to ignore low-duration\n // waits that are likely caused by user behavior).\n forActions(\"firstFrameProcessed\", \"applyLens\"),\n take(1),\n map((): [number, string, string] => [\n (getTimeMs() - applyLensStartTime) / 1000,\n lensId,\n lensGroupId,\n ])\n );\n })\n )\n .subscribe({\n next: ([viewTimeSec, lensId, lensGroupId]) => {\n if (viewTimeSec < viewTimeThresholdSec) return;\n\n const lensWait: LensWait = {\n name: \"lensWait\",\n lensId,\n viewTimeSec,\n lensGroupId,\n };\n metricsEventTarget.dispatchEvent(new TypedCustomEvent(\"lensWait\", lensWait));\n reporter.timer(\"lens.apply_lens_latency\", viewTimeSec * 1000);\n },\n });\n }\n);\n"]}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { OperationalMetricsReporter } from "../operational/operationalMetricsReporter";
|
|
2
|
+
/**
|
|
3
|
+
* Report the number of total page loads that have support for various capabilities. By dividing by the total number of
|
|
4
|
+
* data points recorded, we can calculate the percent of page loads with support.
|
|
5
|
+
*
|
|
6
|
+
* @internal
|
|
7
|
+
*/
|
|
8
|
+
export declare const reportPlatformCapabilities: {
|
|
9
|
+
(args_0: OperationalMetricsReporter): Promise<void>;
|
|
10
|
+
token: "reportPlatformCapabilities";
|
|
11
|
+
dependencies: readonly ["operationalMetricsReporter"];
|
|
12
|
+
};
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { __awaiter } from "tslib";
|
|
2
|
+
import { Injectable } from "../../dependency-injection/Injectable";
|
|
3
|
+
import { getPlatformCapabilities } from "../../platform/platformCapabilities";
|
|
4
|
+
import { Count } from "../operational/Count";
|
|
5
|
+
import { operationalMetricReporterFactory, } from "../operational/operationalMetricsReporter";
|
|
6
|
+
/**
|
|
7
|
+
* Report the number of total page loads that have support for various capabilities. By dividing by the total number of
|
|
8
|
+
* data points recorded, we can calculate the percent of page loads with support.
|
|
9
|
+
*
|
|
10
|
+
* @internal
|
|
11
|
+
*/
|
|
12
|
+
export const reportPlatformCapabilities = Injectable("reportPlatformCapabilities", [operationalMetricReporterFactory.token], (operationalMetricsReporter) => __awaiter(void 0, void 0, void 0, function* () {
|
|
13
|
+
const { webgl, wasm, webxr } = yield getPlatformCapabilities();
|
|
14
|
+
operationalMetricsReporter.report(Count.count("platform_webgl", webgl.supported ? 1 : 0));
|
|
15
|
+
operationalMetricsReporter.report(Count.count("platform_wasm", wasm.supported ? 1 : 0));
|
|
16
|
+
operationalMetricsReporter.report(Count.count("platform_webxr", webxr.supported ? 1 : 0));
|
|
17
|
+
}));
|
|
18
|
+
//# sourceMappingURL=reportPlatformCapabilities.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"reportPlatformCapabilities.js","sourceRoot":"","sources":["../../../src/metrics/reporters/reportPlatformCapabilities.ts"],"names":[],"mappings":";AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,uCAAuC,CAAC;AACnE,OAAO,EAAE,uBAAuB,EAAE,MAAM,qCAAqC,CAAC;AAC9E,OAAO,EAAE,KAAK,EAAE,MAAM,sBAAsB,CAAC;AAC7C,OAAO,EAEH,gCAAgC,GACnC,MAAM,2CAA2C,CAAC;AAEnD;;;;;GAKG;AACH,MAAM,CAAC,MAAM,0BAA0B,GAAG,UAAU,CAChD,4BAA4B,EAC5B,CAAC,gCAAgC,CAAC,KAAK,CAAU,EACjD,CAAO,0BAAsD,EAAE,EAAE;IAC7D,MAAM,EAAE,KAAK,EAAE,IAAI,EAAE,KAAK,EAAE,GAAG,MAAM,uBAAuB,EAAE,CAAC;IAC/D,0BAA0B,CAAC,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,gBAAgB,EAAE,KAAK,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IAC1F,0BAA0B,CAAC,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,eAAe,EAAE,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IACxF,0BAA0B,CAAC,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,gBAAgB,EAAE,KAAK,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAC9F,CAAC,CAAA,CACJ,CAAC","sourcesContent":["import { Injectable } from \"../../dependency-injection/Injectable\";\nimport { getPlatformCapabilities } from \"../../platform/platformCapabilities\";\nimport { Count } from \"../operational/Count\";\nimport {\n OperationalMetricsReporter,\n operationalMetricReporterFactory,\n} from \"../operational/operationalMetricsReporter\";\n\n/**\n * Report the number of total page loads that have support for various capabilities. By dividing by the total number of\n * data points recorded, we can calculate the percent of page loads with support.\n *\n * @internal\n */\nexport const reportPlatformCapabilities = Injectable(\n \"reportPlatformCapabilities\",\n [operationalMetricReporterFactory.token] as const,\n async (operationalMetricsReporter: OperationalMetricsReporter) => {\n const { webgl, wasm, webxr } = await getPlatformCapabilities();\n operationalMetricsReporter.report(Count.count(\"platform_webgl\", webgl.supported ? 1 : 0));\n operationalMetricsReporter.report(Count.count(\"platform_wasm\", wasm.supported ? 1 : 0));\n operationalMetricsReporter.report(Count.count(\"platform_webxr\", webxr.supported ? 1 : 0));\n }\n);\n"]}
|
|
@@ -11,12 +11,13 @@ export declare const reportGloballyScopedMetrics: PartialContainer<{
|
|
|
11
11
|
reportLegalState: void;
|
|
12
12
|
reportLensAndAssetDownload: void;
|
|
13
13
|
reportHttpMetrics: void;
|
|
14
|
+
reportPlatformCapabilities: Promise<void>;
|
|
14
15
|
}, {
|
|
15
16
|
configuration: import("../..").CameraKitConfiguration;
|
|
16
17
|
requestStateEventTarget: import("../../handlers/requestStateEmittingHandler").RequestStateEventTarget;
|
|
17
18
|
operationalMetricsReporter: import("../operational/operationalMetricsReporter").OperationalMetricsReporter;
|
|
18
|
-
metricsEventTarget: import("../metricsEventTarget").MetricsEventTarget;
|
|
19
19
|
legalState: import("@snap/state-management").StateMachine<import("@snap/state-management").Action<"requestLegalPrompt", undefined> | import("@snap/state-management").Action<"accept", string> | import("@snap/state-management").Action<"reject", string>, import("@snap/state-management").State<"unknown", undefined> | import("@snap/state-management").State<"accepted", undefined> | import("@snap/state-management").State<"rejected", undefined>>;
|
|
20
|
+
metricsEventTarget: import("../metricsEventTarget").MetricsEventTarget;
|
|
20
21
|
}>;
|
|
21
22
|
/**
|
|
22
23
|
* These metrics reporters must be run once for each CameraKitSession DI container created. They may depend on services
|
|
@@ -8,6 +8,7 @@ import { reportLensValidationFailed } from "./reportLensValidationFailed";
|
|
|
8
8
|
import { reportLensView } from "./reportLensView";
|
|
9
9
|
import { reportLensWait } from "./reportLensWait";
|
|
10
10
|
import { reportUserSession } from "./reportUserSession";
|
|
11
|
+
import { reportPlatformCapabilities } from "./reportPlatformCapabilities";
|
|
11
12
|
/**
|
|
12
13
|
* These metrics reporters must be run once in the top-level DI container. They only depend on globally-available
|
|
13
14
|
* services.
|
|
@@ -19,7 +20,8 @@ export const reportGloballyScopedMetrics = new PartialContainer({})
|
|
|
19
20
|
.provides(reportHttpMetrics)
|
|
20
21
|
.provides(reportBenchmarks)
|
|
21
22
|
.provides(reportLensAndAssetDownload)
|
|
22
|
-
.provides(reportLegalState)
|
|
23
|
+
.provides(reportLegalState)
|
|
24
|
+
.provides(reportPlatformCapabilities);
|
|
23
25
|
/**
|
|
24
26
|
* These metrics reporters must be run once for each CameraKitSession DI container created. They may depend on services
|
|
25
27
|
* which are only available at the session scope (e.g. the CameraKitSession itself).
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"reporters.js","sourceRoot":"","sources":["../../../src/metrics/reporters/reporters.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,6CAA6C,CAAC;AAC/E,OAAO,EAAE,sBAAsB,EAAE,MAAM,0BAA0B,CAAC;AAClE,OAAO,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AACtD,OAAO,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AACxD,OAAO,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AACtD,OAAO,EAAE,0BAA0B,EAAE,MAAM,8BAA8B,CAAC;AAC1E,OAAO,EAAE,0BAA0B,EAAE,MAAM,8BAA8B,CAAC;AAC1E,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAClD,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAClD,OAAO,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;
|
|
1
|
+
{"version":3,"file":"reporters.js","sourceRoot":"","sources":["../../../src/metrics/reporters/reporters.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,6CAA6C,CAAC;AAC/E,OAAO,EAAE,sBAAsB,EAAE,MAAM,0BAA0B,CAAC;AAClE,OAAO,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AACtD,OAAO,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AACxD,OAAO,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AACtD,OAAO,EAAE,0BAA0B,EAAE,MAAM,8BAA8B,CAAC;AAC1E,OAAO,EAAE,0BAA0B,EAAE,MAAM,8BAA8B,CAAC;AAC1E,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAClD,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAClD,OAAO,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AACxD,OAAO,EAAE,0BAA0B,EAAE,MAAM,8BAA8B,CAAC;AAE1E;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,2BAA2B,GAAG,IAAI,gBAAgB,CAAC,EAAE,CAAC;KAC9D,QAAQ,CAAC,iBAAiB,CAAC;KAC3B,QAAQ,CAAC,gBAAgB,CAAC;KAC1B,QAAQ,CAAC,0BAA0B,CAAC;KACpC,QAAQ,CAAC,gBAAgB,CAAC;KAC1B,QAAQ,CAAC,0BAA0B,CAAC,CAAC;AAE1C;;;GAGG;AACH,MAAM,CAAC,MAAM,0BAA0B,GAAG,IAAI,gBAAgB,CAAC,EAAE,CAAC;KAC7D,QAAQ,CAAC,iBAAiB,CAAC;KAC3B,QAAQ,CAAC,cAAc,CAAC;KACxB,QAAQ,CAAC,cAAc,CAAC;KACxB,QAAQ,CAAC,sBAAsB,CAAC;KAChC,QAAQ,CAAC,0BAA0B,CAAC,CAAC","sourcesContent":["import { PartialContainer } from \"../../dependency-injection/PartialContainer\";\nimport { reportSessionException } from \"./reportSessionException\";\nimport { reportBenchmarks } from \"./reportBenchmarks\";\nimport { reportHttpMetrics } from \"./reportHttpMetrics\";\nimport { reportLegalState } from \"./reportLegalState\";\nimport { reportLensAndAssetDownload } from \"./reportLensAndAssetDownload\";\nimport { reportLensValidationFailed } from \"./reportLensValidationFailed\";\nimport { reportLensView } from \"./reportLensView\";\nimport { reportLensWait } from \"./reportLensWait\";\nimport { reportUserSession } from \"./reportUserSession\";\nimport { reportPlatformCapabilities } from \"./reportPlatformCapabilities\";\n\n/**\n * These metrics reporters must be run once in the top-level DI container. They only depend on globally-available\n * services.\n *\n * The businessEventsReporter is special, it doesn't create any of its own metrics, it simply listens to the global\n * metricsEventTarget and reports metrics emitted there to our backend.\n */\nexport const reportGloballyScopedMetrics = new PartialContainer({})\n .provides(reportHttpMetrics)\n .provides(reportBenchmarks)\n .provides(reportLensAndAssetDownload)\n .provides(reportLegalState)\n .provides(reportPlatformCapabilities);\n\n/**\n * These metrics reporters must be run once for each CameraKitSession DI container created. They may depend on services\n * which are only available at the session scope (e.g. the CameraKitSession itself).\n */\nexport const reportSessionScopedMetrics = new PartialContainer({})\n .provides(reportUserSession)\n .provides(reportLensView)\n .provides(reportLensWait)\n .provides(reportSessionException)\n .provides(reportLensValidationFailed);\n"]}
|