@metamask/analytics-controller
Advanced tools
+13
-1
@@ -10,2 +10,13 @@ # Changelog | ||
| ## [2.0.0] | ||
| ### Changed | ||
| - **BREAKING:** Optionally enrich non-anonymous track, identify, and view payloads with the user's `country_code`, `region`, and `timezone` under `context.location`, gated behind the new `isGeolocationEnabled` constructor option (default `false`) ([#9691](https://github.com/MetaMask/core/pull/9691), [#9728](https://github.com/MetaMask/core/pull/9728)) | ||
| - `AnalyticsController.init` and `AnalyticsController.optIn` are now asynchronous and return a `Promise<void>`, so await them before tracking events | ||
| - When enabled, geolocation is resolved via `GeolocationController:getGeolocationData` (which compositions must register) only after the user opts in, so location is never requested before they consent to analytics; queued pre-consent events are then enriched on replay (anonymous payloads excluded) | ||
| - Adds `@metamask/geolocation-controller` `^0.1.3` as a dependency | ||
| - Bump `@metamask/messenger` from `^1.2.0` to `^2.0.0` ([#9392](https://github.com/MetaMask/core/pull/9392)) | ||
| - Bump `@metamask/geolocation-controller` from `^0.1.3` to `^1.0.0` ([#9735](https://github.com/MetaMask/core/pull/9735)) | ||
| ## [1.2.1] | ||
@@ -61,3 +72,4 @@ | ||
| [Unreleased]: https://github.com/MetaMask/core/compare/@metamask/analytics-controller@1.2.1...HEAD | ||
| [Unreleased]: https://github.com/MetaMask/core/compare/@metamask/analytics-controller@2.0.0...HEAD | ||
| [2.0.0]: https://github.com/MetaMask/core/compare/@metamask/analytics-controller@1.2.1...@metamask/analytics-controller@2.0.0 | ||
| [1.2.1]: https://github.com/MetaMask/core/compare/@metamask/analytics-controller@1.2.0...@metamask/analytics-controller@1.2.1 | ||
@@ -64,0 +76,0 @@ [1.2.0]: https://github.com/MetaMask/core/compare/@metamask/analytics-controller@1.1.1...@metamask/analytics-controller@1.2.0 |
@@ -1,1 +0,1 @@ | ||
| {"version":3,"file":"AnalyticsController-method-action-types.cjs","sourceRoot":"","sources":["../src/AnalyticsController-method-action-types.ts"],"names":[],"mappings":";AAAA;;;GAGG","sourcesContent":["/**\n * This file is auto generated.\n * Do not edit manually.\n */\n\nimport type { AnalyticsController } from './AnalyticsController';\n\n/**\n * Track an analytics event.\n *\n * Events are only tracked if analytics is enabled.\n *\n * @param event - Analytics event with properties and sensitive properties\n * @param context - Optional platform-specific context forwarded to the platform adapter.\n */\nexport type AnalyticsControllerTrackEventAction = {\n type: `AnalyticsController:trackEvent`;\n handler: AnalyticsController['trackEvent'];\n};\n\n/**\n * Identify a user for analytics.\n *\n * @param traits - User traits/properties\n * @param context - Optional platform-specific context forwarded to the platform adapter.\n */\nexport type AnalyticsControllerIdentifyAction = {\n type: `AnalyticsController:identify`;\n handler: AnalyticsController['identify'];\n};\n\n/**\n * Track a page or screen view.\n *\n * @param name - The identifier/name of the page or screen being viewed (e.g., \"home\", \"settings\", \"wallet\")\n * @param properties - Optional properties associated with the view\n * @param context - Optional platform-specific context forwarded to the platform adapter.\n */\nexport type AnalyticsControllerTrackViewAction = {\n type: `AnalyticsController:trackView`;\n handler: AnalyticsController['trackView'];\n};\n\n/**\n * Opt in to analytics.\n *\n * Records that a consent decision has been made and replays any events that\n * were queued while the user was undecided.\n */\nexport type AnalyticsControllerOptInAction = {\n type: `AnalyticsController:optIn`;\n handler: AnalyticsController['optIn'];\n};\n\n/**\n * Opt out of analytics.\n *\n * Records that a consent decision has been made and discards any persisted\n * events so nothing captured before the decision is ever delivered.\n */\nexport type AnalyticsControllerOptOutAction = {\n type: `AnalyticsController:optOut`;\n handler: AnalyticsController['optOut'];\n};\n\n/**\n * Reset the consent decision back to undecided.\n *\n * Intended for client flows that restart onboarding. Clears the opt-in\n * preference and discards the delivery queue, but preserves any pre-consent\n * events so they can still be replayed if the user opts in again. The user is\n * treated as undecided again.\n */\nexport type AnalyticsControllerResetConsentDecisionAction = {\n type: `AnalyticsController:resetConsentDecision`;\n handler: AnalyticsController['resetConsentDecision'];\n};\n\n/**\n * Union of all AnalyticsController action types.\n */\nexport type AnalyticsControllerMethodActions =\n | AnalyticsControllerTrackEventAction\n | AnalyticsControllerIdentifyAction\n | AnalyticsControllerTrackViewAction\n | AnalyticsControllerOptInAction\n | AnalyticsControllerOptOutAction\n | AnalyticsControllerResetConsentDecisionAction;\n"]} | ||
| {"version":3,"file":"AnalyticsController-method-action-types.cjs","sourceRoot":"","sources":["../src/AnalyticsController-method-action-types.ts"],"names":[],"mappings":";AAAA;;;GAGG","sourcesContent":["/**\n * This file is auto generated.\n * Do not edit manually.\n */\n\nimport type { AnalyticsController } from './AnalyticsController.js';\n\n/**\n * Track an analytics event.\n *\n * Events are only tracked if analytics is enabled.\n *\n * @param event - Analytics event with properties and sensitive properties\n * @param context - Optional platform-specific context forwarded to the platform adapter.\n */\nexport type AnalyticsControllerTrackEventAction = {\n type: `AnalyticsController:trackEvent`;\n handler: AnalyticsController['trackEvent'];\n};\n\n/**\n * Identify a user for analytics.\n *\n * @param traits - User traits/properties\n * @param context - Optional platform-specific context forwarded to the platform adapter.\n */\nexport type AnalyticsControllerIdentifyAction = {\n type: `AnalyticsController:identify`;\n handler: AnalyticsController['identify'];\n};\n\n/**\n * Track a page or screen view.\n *\n * @param name - The identifier/name of the page or screen being viewed (e.g., \"home\", \"settings\", \"wallet\")\n * @param properties - Optional properties associated with the view\n * @param context - Optional platform-specific context forwarded to the platform adapter.\n */\nexport type AnalyticsControllerTrackViewAction = {\n type: `AnalyticsController:trackView`;\n handler: AnalyticsController['trackView'];\n};\n\n/**\n * Opt in to analytics.\n *\n * Records that a consent decision has been made and replays any events that\n * were queued while the user was undecided.\n *\n * When geolocation enrichment is enabled, geolocation is resolved here (once\n * the user has consented) and awaited before the queued events are replayed,\n * so those events are enriched with the resolved location as they are sent.\n *\n * @returns A promise that resolves once opt-in processing has completed.\n */\nexport type AnalyticsControllerOptInAction = {\n type: `AnalyticsController:optIn`;\n handler: AnalyticsController['optIn'];\n};\n\n/**\n * Opt out of analytics.\n *\n * Records that a consent decision has been made and discards any persisted\n * events so nothing captured before the decision is ever delivered.\n */\nexport type AnalyticsControllerOptOutAction = {\n type: `AnalyticsController:optOut`;\n handler: AnalyticsController['optOut'];\n};\n\n/**\n * Reset the consent decision back to undecided.\n *\n * Intended for client flows that restart onboarding. Clears the opt-in\n * preference and discards the delivery queue, but preserves any pre-consent\n * events so they can still be replayed if the user opts in again. The user is\n * treated as undecided again.\n */\nexport type AnalyticsControllerResetConsentDecisionAction = {\n type: `AnalyticsController:resetConsentDecision`;\n handler: AnalyticsController['resetConsentDecision'];\n};\n\n/**\n * Union of all AnalyticsController action types.\n */\nexport type AnalyticsControllerMethodActions =\n | AnalyticsControllerTrackEventAction\n | AnalyticsControllerIdentifyAction\n | AnalyticsControllerTrackViewAction\n | AnalyticsControllerOptInAction\n | AnalyticsControllerOptOutAction\n | AnalyticsControllerResetConsentDecisionAction;\n"]} |
@@ -44,2 +44,8 @@ /** | ||
| * were queued while the user was undecided. | ||
| * | ||
| * When geolocation enrichment is enabled, geolocation is resolved here (once | ||
| * the user has consented) and awaited before the queued events are replayed, | ||
| * so those events are enriched with the resolved location as they are sent. | ||
| * | ||
| * @returns A promise that resolves once opt-in processing has completed. | ||
| */ | ||
@@ -46,0 +52,0 @@ export type AnalyticsControllerOptInAction = { |
@@ -1,1 +0,1 @@ | ||
| {"version":3,"file":"AnalyticsController-method-action-types.d.cts","sourceRoot":"","sources":["../src/AnalyticsController-method-action-types.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,mBAAmB,EAAE,kCAA8B;AAEjE;;;;;;;GAOG;AACH,MAAM,MAAM,mCAAmC,GAAG;IAChD,IAAI,EAAE,gCAAgC,CAAC;IACvC,OAAO,EAAE,mBAAmB,CAAC,YAAY,CAAC,CAAC;CAC5C,CAAC;AAEF;;;;;GAKG;AACH,MAAM,MAAM,iCAAiC,GAAG;IAC9C,IAAI,EAAE,8BAA8B,CAAC;IACrC,OAAO,EAAE,mBAAmB,CAAC,UAAU,CAAC,CAAC;CAC1C,CAAC;AAEF;;;;;;GAMG;AACH,MAAM,MAAM,kCAAkC,GAAG;IAC/C,IAAI,EAAE,+BAA+B,CAAC;IACtC,OAAO,EAAE,mBAAmB,CAAC,WAAW,CAAC,CAAC;CAC3C,CAAC;AAEF;;;;;GAKG;AACH,MAAM,MAAM,8BAA8B,GAAG;IAC3C,IAAI,EAAE,2BAA2B,CAAC;IAClC,OAAO,EAAE,mBAAmB,CAAC,OAAO,CAAC,CAAC;CACvC,CAAC;AAEF;;;;;GAKG;AACH,MAAM,MAAM,+BAA+B,GAAG;IAC5C,IAAI,EAAE,4BAA4B,CAAC;IACnC,OAAO,EAAE,mBAAmB,CAAC,QAAQ,CAAC,CAAC;CACxC,CAAC;AAEF;;;;;;;GAOG;AACH,MAAM,MAAM,6CAA6C,GAAG;IAC1D,IAAI,EAAE,0CAA0C,CAAC;IACjD,OAAO,EAAE,mBAAmB,CAAC,sBAAsB,CAAC,CAAC;CACtD,CAAC;AAEF;;GAEG;AACH,MAAM,MAAM,gCAAgC,GACxC,mCAAmC,GACnC,iCAAiC,GACjC,kCAAkC,GAClC,8BAA8B,GAC9B,+BAA+B,GAC/B,6CAA6C,CAAC"} | ||
| {"version":3,"file":"AnalyticsController-method-action-types.d.cts","sourceRoot":"","sources":["../src/AnalyticsController-method-action-types.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,mBAAmB,EAAE,kCAAiC;AAEpE;;;;;;;GAOG;AACH,MAAM,MAAM,mCAAmC,GAAG;IAChD,IAAI,EAAE,gCAAgC,CAAC;IACvC,OAAO,EAAE,mBAAmB,CAAC,YAAY,CAAC,CAAC;CAC5C,CAAC;AAEF;;;;;GAKG;AACH,MAAM,MAAM,iCAAiC,GAAG;IAC9C,IAAI,EAAE,8BAA8B,CAAC;IACrC,OAAO,EAAE,mBAAmB,CAAC,UAAU,CAAC,CAAC;CAC1C,CAAC;AAEF;;;;;;GAMG;AACH,MAAM,MAAM,kCAAkC,GAAG;IAC/C,IAAI,EAAE,+BAA+B,CAAC;IACtC,OAAO,EAAE,mBAAmB,CAAC,WAAW,CAAC,CAAC;CAC3C,CAAC;AAEF;;;;;;;;;;;GAWG;AACH,MAAM,MAAM,8BAA8B,GAAG;IAC3C,IAAI,EAAE,2BAA2B,CAAC;IAClC,OAAO,EAAE,mBAAmB,CAAC,OAAO,CAAC,CAAC;CACvC,CAAC;AAEF;;;;;GAKG;AACH,MAAM,MAAM,+BAA+B,GAAG;IAC5C,IAAI,EAAE,4BAA4B,CAAC;IACnC,OAAO,EAAE,mBAAmB,CAAC,QAAQ,CAAC,CAAC;CACxC,CAAC;AAEF;;;;;;;GAOG;AACH,MAAM,MAAM,6CAA6C,GAAG;IAC1D,IAAI,EAAE,0CAA0C,CAAC;IACjD,OAAO,EAAE,mBAAmB,CAAC,sBAAsB,CAAC,CAAC;CACtD,CAAC;AAEF;;GAEG;AACH,MAAM,MAAM,gCAAgC,GACxC,mCAAmC,GACnC,iCAAiC,GACjC,kCAAkC,GAClC,8BAA8B,GAC9B,+BAA+B,GAC/B,6CAA6C,CAAC"} |
@@ -44,2 +44,8 @@ /** | ||
| * were queued while the user was undecided. | ||
| * | ||
| * When geolocation enrichment is enabled, geolocation is resolved here (once | ||
| * the user has consented) and awaited before the queued events are replayed, | ||
| * so those events are enriched with the resolved location as they are sent. | ||
| * | ||
| * @returns A promise that resolves once opt-in processing has completed. | ||
| */ | ||
@@ -46,0 +52,0 @@ export type AnalyticsControllerOptInAction = { |
@@ -1,1 +0,1 @@ | ||
| {"version":3,"file":"AnalyticsController-method-action-types.d.mts","sourceRoot":"","sources":["../src/AnalyticsController-method-action-types.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,mBAAmB,EAAE,kCAA8B;AAEjE;;;;;;;GAOG;AACH,MAAM,MAAM,mCAAmC,GAAG;IAChD,IAAI,EAAE,gCAAgC,CAAC;IACvC,OAAO,EAAE,mBAAmB,CAAC,YAAY,CAAC,CAAC;CAC5C,CAAC;AAEF;;;;;GAKG;AACH,MAAM,MAAM,iCAAiC,GAAG;IAC9C,IAAI,EAAE,8BAA8B,CAAC;IACrC,OAAO,EAAE,mBAAmB,CAAC,UAAU,CAAC,CAAC;CAC1C,CAAC;AAEF;;;;;;GAMG;AACH,MAAM,MAAM,kCAAkC,GAAG;IAC/C,IAAI,EAAE,+BAA+B,CAAC;IACtC,OAAO,EAAE,mBAAmB,CAAC,WAAW,CAAC,CAAC;CAC3C,CAAC;AAEF;;;;;GAKG;AACH,MAAM,MAAM,8BAA8B,GAAG;IAC3C,IAAI,EAAE,2BAA2B,CAAC;IAClC,OAAO,EAAE,mBAAmB,CAAC,OAAO,CAAC,CAAC;CACvC,CAAC;AAEF;;;;;GAKG;AACH,MAAM,MAAM,+BAA+B,GAAG;IAC5C,IAAI,EAAE,4BAA4B,CAAC;IACnC,OAAO,EAAE,mBAAmB,CAAC,QAAQ,CAAC,CAAC;CACxC,CAAC;AAEF;;;;;;;GAOG;AACH,MAAM,MAAM,6CAA6C,GAAG;IAC1D,IAAI,EAAE,0CAA0C,CAAC;IACjD,OAAO,EAAE,mBAAmB,CAAC,sBAAsB,CAAC,CAAC;CACtD,CAAC;AAEF;;GAEG;AACH,MAAM,MAAM,gCAAgC,GACxC,mCAAmC,GACnC,iCAAiC,GACjC,kCAAkC,GAClC,8BAA8B,GAC9B,+BAA+B,GAC/B,6CAA6C,CAAC"} | ||
| {"version":3,"file":"AnalyticsController-method-action-types.d.mts","sourceRoot":"","sources":["../src/AnalyticsController-method-action-types.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,mBAAmB,EAAE,kCAAiC;AAEpE;;;;;;;GAOG;AACH,MAAM,MAAM,mCAAmC,GAAG;IAChD,IAAI,EAAE,gCAAgC,CAAC;IACvC,OAAO,EAAE,mBAAmB,CAAC,YAAY,CAAC,CAAC;CAC5C,CAAC;AAEF;;;;;GAKG;AACH,MAAM,MAAM,iCAAiC,GAAG;IAC9C,IAAI,EAAE,8BAA8B,CAAC;IACrC,OAAO,EAAE,mBAAmB,CAAC,UAAU,CAAC,CAAC;CAC1C,CAAC;AAEF;;;;;;GAMG;AACH,MAAM,MAAM,kCAAkC,GAAG;IAC/C,IAAI,EAAE,+BAA+B,CAAC;IACtC,OAAO,EAAE,mBAAmB,CAAC,WAAW,CAAC,CAAC;CAC3C,CAAC;AAEF;;;;;;;;;;;GAWG;AACH,MAAM,MAAM,8BAA8B,GAAG;IAC3C,IAAI,EAAE,2BAA2B,CAAC;IAClC,OAAO,EAAE,mBAAmB,CAAC,OAAO,CAAC,CAAC;CACvC,CAAC;AAEF;;;;;GAKG;AACH,MAAM,MAAM,+BAA+B,GAAG;IAC5C,IAAI,EAAE,4BAA4B,CAAC;IACnC,OAAO,EAAE,mBAAmB,CAAC,QAAQ,CAAC,CAAC;CACxC,CAAC;AAEF;;;;;;;GAOG;AACH,MAAM,MAAM,6CAA6C,GAAG;IAC1D,IAAI,EAAE,0CAA0C,CAAC;IACjD,OAAO,EAAE,mBAAmB,CAAC,sBAAsB,CAAC,CAAC;CACtD,CAAC;AAEF;;GAEG;AACH,MAAM,MAAM,gCAAgC,GACxC,mCAAmC,GACnC,iCAAiC,GACjC,kCAAkC,GAClC,8BAA8B,GAC9B,+BAA+B,GAC/B,6CAA6C,CAAC"} |
@@ -1,1 +0,1 @@ | ||
| {"version":3,"file":"AnalyticsController-method-action-types.mjs","sourceRoot":"","sources":["../src/AnalyticsController-method-action-types.ts"],"names":[],"mappings":"AAAA;;;GAGG","sourcesContent":["/**\n * This file is auto generated.\n * Do not edit manually.\n */\n\nimport type { AnalyticsController } from './AnalyticsController';\n\n/**\n * Track an analytics event.\n *\n * Events are only tracked if analytics is enabled.\n *\n * @param event - Analytics event with properties and sensitive properties\n * @param context - Optional platform-specific context forwarded to the platform adapter.\n */\nexport type AnalyticsControllerTrackEventAction = {\n type: `AnalyticsController:trackEvent`;\n handler: AnalyticsController['trackEvent'];\n};\n\n/**\n * Identify a user for analytics.\n *\n * @param traits - User traits/properties\n * @param context - Optional platform-specific context forwarded to the platform adapter.\n */\nexport type AnalyticsControllerIdentifyAction = {\n type: `AnalyticsController:identify`;\n handler: AnalyticsController['identify'];\n};\n\n/**\n * Track a page or screen view.\n *\n * @param name - The identifier/name of the page or screen being viewed (e.g., \"home\", \"settings\", \"wallet\")\n * @param properties - Optional properties associated with the view\n * @param context - Optional platform-specific context forwarded to the platform adapter.\n */\nexport type AnalyticsControllerTrackViewAction = {\n type: `AnalyticsController:trackView`;\n handler: AnalyticsController['trackView'];\n};\n\n/**\n * Opt in to analytics.\n *\n * Records that a consent decision has been made and replays any events that\n * were queued while the user was undecided.\n */\nexport type AnalyticsControllerOptInAction = {\n type: `AnalyticsController:optIn`;\n handler: AnalyticsController['optIn'];\n};\n\n/**\n * Opt out of analytics.\n *\n * Records that a consent decision has been made and discards any persisted\n * events so nothing captured before the decision is ever delivered.\n */\nexport type AnalyticsControllerOptOutAction = {\n type: `AnalyticsController:optOut`;\n handler: AnalyticsController['optOut'];\n};\n\n/**\n * Reset the consent decision back to undecided.\n *\n * Intended for client flows that restart onboarding. Clears the opt-in\n * preference and discards the delivery queue, but preserves any pre-consent\n * events so they can still be replayed if the user opts in again. The user is\n * treated as undecided again.\n */\nexport type AnalyticsControllerResetConsentDecisionAction = {\n type: `AnalyticsController:resetConsentDecision`;\n handler: AnalyticsController['resetConsentDecision'];\n};\n\n/**\n * Union of all AnalyticsController action types.\n */\nexport type AnalyticsControllerMethodActions =\n | AnalyticsControllerTrackEventAction\n | AnalyticsControllerIdentifyAction\n | AnalyticsControllerTrackViewAction\n | AnalyticsControllerOptInAction\n | AnalyticsControllerOptOutAction\n | AnalyticsControllerResetConsentDecisionAction;\n"]} | ||
| {"version":3,"file":"AnalyticsController-method-action-types.mjs","sourceRoot":"","sources":["../src/AnalyticsController-method-action-types.ts"],"names":[],"mappings":"AAAA;;;GAGG","sourcesContent":["/**\n * This file is auto generated.\n * Do not edit manually.\n */\n\nimport type { AnalyticsController } from './AnalyticsController.js';\n\n/**\n * Track an analytics event.\n *\n * Events are only tracked if analytics is enabled.\n *\n * @param event - Analytics event with properties and sensitive properties\n * @param context - Optional platform-specific context forwarded to the platform adapter.\n */\nexport type AnalyticsControllerTrackEventAction = {\n type: `AnalyticsController:trackEvent`;\n handler: AnalyticsController['trackEvent'];\n};\n\n/**\n * Identify a user for analytics.\n *\n * @param traits - User traits/properties\n * @param context - Optional platform-specific context forwarded to the platform adapter.\n */\nexport type AnalyticsControllerIdentifyAction = {\n type: `AnalyticsController:identify`;\n handler: AnalyticsController['identify'];\n};\n\n/**\n * Track a page or screen view.\n *\n * @param name - The identifier/name of the page or screen being viewed (e.g., \"home\", \"settings\", \"wallet\")\n * @param properties - Optional properties associated with the view\n * @param context - Optional platform-specific context forwarded to the platform adapter.\n */\nexport type AnalyticsControllerTrackViewAction = {\n type: `AnalyticsController:trackView`;\n handler: AnalyticsController['trackView'];\n};\n\n/**\n * Opt in to analytics.\n *\n * Records that a consent decision has been made and replays any events that\n * were queued while the user was undecided.\n *\n * When geolocation enrichment is enabled, geolocation is resolved here (once\n * the user has consented) and awaited before the queued events are replayed,\n * so those events are enriched with the resolved location as they are sent.\n *\n * @returns A promise that resolves once opt-in processing has completed.\n */\nexport type AnalyticsControllerOptInAction = {\n type: `AnalyticsController:optIn`;\n handler: AnalyticsController['optIn'];\n};\n\n/**\n * Opt out of analytics.\n *\n * Records that a consent decision has been made and discards any persisted\n * events so nothing captured before the decision is ever delivered.\n */\nexport type AnalyticsControllerOptOutAction = {\n type: `AnalyticsController:optOut`;\n handler: AnalyticsController['optOut'];\n};\n\n/**\n * Reset the consent decision back to undecided.\n *\n * Intended for client flows that restart onboarding. Clears the opt-in\n * preference and discards the delivery queue, but preserves any pre-consent\n * events so they can still be replayed if the user opts in again. The user is\n * treated as undecided again.\n */\nexport type AnalyticsControllerResetConsentDecisionAction = {\n type: `AnalyticsController:resetConsentDecision`;\n handler: AnalyticsController['resetConsentDecision'];\n};\n\n/**\n * Union of all AnalyticsController action types.\n */\nexport type AnalyticsControllerMethodActions =\n | AnalyticsControllerTrackEventAction\n | AnalyticsControllerIdentifyAction\n | AnalyticsControllerTrackViewAction\n | AnalyticsControllerOptInAction\n | AnalyticsControllerOptOutAction\n | AnalyticsControllerResetConsentDecisionAction;\n"]} |
+184
-58
@@ -13,3 +13,3 @@ "use strict"; | ||
| }; | ||
| var _AnalyticsController_instances, _AnalyticsController_platformAdapter, _AnalyticsController_isAnonymousEventsFeatureEnabled, _AnalyticsController_isEventQueuePersistenceEnabled, _AnalyticsController_isPreConsentQueueEnabled, _AnalyticsController_initialized, _AnalyticsController_sendOrQueueTrackEvent, _AnalyticsController_sendOrQueueIdentifyEvent, _AnalyticsController_sendOrQueueViewEvent, _AnalyticsController_enqueueEvent, _AnalyticsController_sendQueuedEvent, _AnalyticsController_replayQueuedEvents, _AnalyticsController_removeQueuedEvent, _AnalyticsController_clearQueuedEvents, _AnalyticsController_enqueuePreConsentEvent, _AnalyticsController_replayPreConsentEvents, _AnalyticsController_clearPreConsentEvents, _AnalyticsController_reconcilePreConsentEvents; | ||
| var _AnalyticsController_instances, _AnalyticsController_platformAdapter, _AnalyticsController_isAnonymousEventsFeatureEnabled, _AnalyticsController_isEventQueuePersistenceEnabled, _AnalyticsController_isPreConsentQueueEnabled, _AnalyticsController_isGeolocationEnabled, _AnalyticsController_initPromise, _AnalyticsController_locationResolvePromise, _AnalyticsController_locationContext, _AnalyticsController_performInit, _AnalyticsController_maybeResolveLocation, _AnalyticsController_resolveLocationContext, _AnalyticsController_withLocationContext, _AnalyticsController_sendOrQueueTrackEvent, _AnalyticsController_sendOrQueueIdentifyEvent, _AnalyticsController_sendOrQueueViewEvent, _AnalyticsController_enqueueEvent, _AnalyticsController_sendQueuedEvent, _AnalyticsController_replayQueuedEvents, _AnalyticsController_removeQueuedEvent, _AnalyticsController_clearQueuedEvents, _AnalyticsController_enqueuePreConsentEvent, _AnalyticsController_replayPreConsentEvents, _AnalyticsController_enrichPreConsentEvent, _AnalyticsController_clearPreConsentEvents, _AnalyticsController_reconcilePreConsentEvents; | ||
| Object.defineProperty(exports, "__esModule", { value: true }); | ||
@@ -20,5 +20,5 @@ exports.AnalyticsController = exports.getDefaultAnalyticsControllerState = exports.controllerName = void 0; | ||
| const uuid_1 = require("uuid"); | ||
| const analyticsControllerStateValidator_1 = require("./analyticsControllerStateValidator.cjs"); | ||
| const AnalyticsLogger_1 = require("./AnalyticsLogger.cjs"); | ||
| const selectors_1 = require("./selectors.cjs"); | ||
| const analyticsControllerStateValidator_js_1 = require("./analyticsControllerStateValidator.cjs"); | ||
| const AnalyticsLogger_js_1 = require("./AnalyticsLogger.cjs"); | ||
| const selectors_js_1 = require("./selectors.cjs"); | ||
| // === GENERAL === | ||
@@ -103,2 +103,32 @@ /** | ||
| /** | ||
| * Returns whether a JSON value is a non-array object. | ||
| * | ||
| * @param value - The value to check. | ||
| * @returns True if the value is a JSON record. | ||
| */ | ||
| function isJsonRecord(value) { | ||
| return value !== null && typeof value === 'object' && !Array.isArray(value); | ||
| } | ||
| /** | ||
| * Builds the analytics location context from geolocation data, keeping only | ||
| * the fields the geolocation API was able to determine. | ||
| * | ||
| * @param geolocation - The geolocation data to convert. | ||
| * @returns The location context, or `undefined` when no field is known. | ||
| */ | ||
| function buildLocationContext(geolocation) { | ||
| const locationContext = { | ||
| ...(geolocation.country === null | ||
| ? {} | ||
| : { country_code: geolocation.country }), | ||
| ...(geolocation.region === null ? {} : { region: geolocation.region }), | ||
| ...(geolocation.timezone === null | ||
| ? {} | ||
| : { timezone: geolocation.timezone }), | ||
| }; | ||
| return Object.keys(locationContext).length === 0 | ||
| ? undefined | ||
| : locationContext; | ||
| } | ||
| /** | ||
| * Returns whether a value is a valid persisted analytics event. | ||
@@ -159,6 +189,7 @@ * | ||
| * @param options.isPreConsentQueueEnabled - Whether the pre-consent event queue is enabled | ||
| * @param options.isGeolocationEnabled - Whether geolocation enrichment is enabled | ||
| * @throws Error if state.analyticsId is missing or not a valid UUIDv4 | ||
| * @remarks After construction, call {@link AnalyticsController.init} to complete initialization. | ||
| */ | ||
| constructor({ state, messenger, platformAdapter, isAnonymousEventsFeatureEnabled = false, isEventQueuePersistenceEnabled = false, isPreConsentQueueEnabled = false, }) { | ||
| constructor({ state, messenger, platformAdapter, isAnonymousEventsFeatureEnabled = false, isEventQueuePersistenceEnabled = false, isPreConsentQueueEnabled = false, isGeolocationEnabled = false, }) { | ||
| const initialState = { | ||
@@ -168,3 +199,3 @@ ...getDefaultAnalyticsControllerState(), | ||
| }; | ||
| (0, analyticsControllerStateValidator_1.validateAnalyticsControllerState)(initialState, platformAdapter.skipUUIDv4Check === true); | ||
| (0, analyticsControllerStateValidator_js_1.validateAnalyticsControllerState)(initialState, platformAdapter.skipUUIDv4Check === true); | ||
| super({ | ||
@@ -181,11 +212,25 @@ name: exports.controllerName, | ||
| _AnalyticsController_isPreConsentQueueEnabled.set(this, void 0); | ||
| _AnalyticsController_initialized.set(this, void 0); | ||
| _AnalyticsController_isGeolocationEnabled.set(this, void 0); | ||
| /** | ||
| * The in-flight (or settled) initialization promise. Set on the first | ||
| * {@link init} call and returned by subsequent calls so overlapping callers | ||
| * await the same work rather than observing a premature completion. | ||
| */ | ||
| _AnalyticsController_initPromise.set(this, void 0); | ||
| /** | ||
| * The in-flight (or settled) geolocation resolution, if any. Its presence | ||
| * marks that resolution has been started, so it runs at most once. | ||
| */ | ||
| _AnalyticsController_locationResolvePromise.set(this, void 0); | ||
| _AnalyticsController_locationContext.set(this, void 0); | ||
| __classPrivateFieldSet(this, _AnalyticsController_isAnonymousEventsFeatureEnabled, isAnonymousEventsFeatureEnabled, "f"); | ||
| __classPrivateFieldSet(this, _AnalyticsController_isEventQueuePersistenceEnabled, isEventQueuePersistenceEnabled, "f"); | ||
| __classPrivateFieldSet(this, _AnalyticsController_isPreConsentQueueEnabled, isPreConsentQueueEnabled, "f"); | ||
| __classPrivateFieldSet(this, _AnalyticsController_isGeolocationEnabled, isGeolocationEnabled, "f"); | ||
| __classPrivateFieldSet(this, _AnalyticsController_platformAdapter, platformAdapter, "f"); | ||
| __classPrivateFieldSet(this, _AnalyticsController_initialized, false, "f"); | ||
| __classPrivateFieldSet(this, _AnalyticsController_initPromise, undefined, "f"); | ||
| __classPrivateFieldSet(this, _AnalyticsController_locationResolvePromise, undefined, "f"); | ||
| this.messenger.registerMethodActionHandlers(this, MESSENGER_EXPOSED_METHODS); | ||
| (0, AnalyticsLogger_1.projectLogger)('AnalyticsController initialized and ready', { | ||
| enabled: selectors_1.analyticsControllerSelectors.selectEnabled(this.state), | ||
| (0, AnalyticsLogger_js_1.projectLogger)('AnalyticsController initialized and ready', { | ||
| enabled: selectors_js_1.analyticsControllerSelectors.selectEnabled(this.state), | ||
| optedIn: this.state.optedIn, | ||
@@ -196,25 +241,30 @@ consentDecisionMade: this.state.consentDecisionMade, | ||
| preConsentQueueEnabled: __classPrivateFieldGet(this, _AnalyticsController_isPreConsentQueueEnabled, "f"), | ||
| geolocationEnabled: __classPrivateFieldGet(this, _AnalyticsController_isGeolocationEnabled, "f"), | ||
| }); | ||
| } | ||
| /** | ||
| * Initialize the controller by calling the platform adapter's onSetupCompleted lifecycle hook. | ||
| * This method must be called after construction to complete the setup process. | ||
| * Initialize the controller by calling the platform adapter's | ||
| * onSetupCompleted lifecycle hook and replaying any queued events. This | ||
| * method must be called after construction to complete the setup process. | ||
| * | ||
| * When geolocation enrichment is enabled (`isGeolocationEnabled`), geolocation | ||
| * is resolved only for a user who is already opted in; for undecided or | ||
| * opted-out users it is deferred until they opt in (see {@link optIn}), so a | ||
| * user's location is never requested before they consent to analytics. In | ||
| * either case the `GeolocationController` and its | ||
| * `GeolocationController:getGeolocationData` action must be registered before | ||
| * resolution occurs, or enrichment is skipped for the session (a message is | ||
| * logged, see {@link #resolveLocationContext}). | ||
| * | ||
| * Safe to call more than once: the first call performs initialization and | ||
| * subsequent calls return the same in-flight (or settled) promise. | ||
| * | ||
| * @returns A promise that resolves once initialization has completed. | ||
| */ | ||
| init() { | ||
| if (__classPrivateFieldGet(this, _AnalyticsController_initialized, "f")) { | ||
| (0, AnalyticsLogger_1.projectLogger)('AnalyticsController already initialized.'); | ||
| return; | ||
| } | ||
| __classPrivateFieldSet(this, _AnalyticsController_initialized, true, "f"); | ||
| // Call onSetupCompleted lifecycle hook after initialization | ||
| // State is already validated, so analyticsId is guaranteed to be a valid UUIDv4 | ||
| try { | ||
| __classPrivateFieldGet(this, _AnalyticsController_platformAdapter, "f").onSetupCompleted(this.state.analyticsId); | ||
| } | ||
| catch (error) { | ||
| // Log error but don't throw - adapter setup failure shouldn't break controller | ||
| (0, AnalyticsLogger_1.projectLogger)('Error calling platformAdapter.onSetupCompleted', error); | ||
| } | ||
| __classPrivateFieldGet(this, _AnalyticsController_instances, "m", _AnalyticsController_replayQueuedEvents).call(this); | ||
| __classPrivateFieldGet(this, _AnalyticsController_instances, "m", _AnalyticsController_reconcilePreConsentEvents).call(this); | ||
| // Cache the in-flight promise so repeated or overlapping calls share a | ||
| // single initialization and all await the same completion (rather than an | ||
| // early call observing a finished init while work is still pending). | ||
| __classPrivateFieldSet(this, _AnalyticsController_initPromise, __classPrivateFieldGet(this, _AnalyticsController_initPromise, "f") ?? __classPrivateFieldGet(this, _AnalyticsController_instances, "m", _AnalyticsController_performInit).call(this), "f"); | ||
| return __classPrivateFieldGet(this, _AnalyticsController_initPromise, "f"); | ||
| } | ||
@@ -230,3 +280,3 @@ /** | ||
| trackEvent(event, context) { | ||
| if (!selectors_1.analyticsControllerSelectors.selectEnabled(this.state)) { | ||
| if (!selectors_js_1.analyticsControllerSelectors.selectEnabled(this.state)) { | ||
| // While the user is undecided, fall through so the event is processed and | ||
@@ -244,3 +294,3 @@ // captured in the pre-consent queue (see #sendOrQueueTrackEvent) to be | ||
| if (!event.hasProperties) { | ||
| __classPrivateFieldGet(this, _AnalyticsController_instances, "m", _AnalyticsController_sendOrQueueTrackEvent).call(this, event.name, undefined, context); | ||
| __classPrivateFieldGet(this, _AnalyticsController_instances, "m", _AnalyticsController_sendOrQueueTrackEvent).call(this, event.name, undefined, __classPrivateFieldGet(this, _AnalyticsController_instances, "m", _AnalyticsController_withLocationContext).call(this, context)); | ||
| return; | ||
@@ -254,3 +304,3 @@ } | ||
| ...event.properties, | ||
| }, context); | ||
| }, __classPrivateFieldGet(this, _AnalyticsController_instances, "m", _AnalyticsController_withLocationContext).call(this, context)); | ||
| } | ||
@@ -263,3 +313,9 @@ const hasSensitiveProperties = Object.keys(event.sensitiveProperties).length > 0; | ||
| ...(hasSensitiveProperties && { anonymous: true }), | ||
| }, context); | ||
| }, | ||
| // When the anonymous events feature is enabled, this payload is the | ||
| // anonymous one and must carry no geolocation. When the feature is | ||
| // disabled, this is the single identified payload, so it is enriched. | ||
| __classPrivateFieldGet(this, _AnalyticsController_isAnonymousEventsFeatureEnabled, "f") | ||
| ? context | ||
| : __classPrivateFieldGet(this, _AnalyticsController_instances, "m", _AnalyticsController_withLocationContext).call(this, context)); | ||
| } | ||
@@ -274,7 +330,7 @@ } | ||
| identify(traits, context) { | ||
| if (!selectors_1.analyticsControllerSelectors.selectEnabled(this.state)) { | ||
| if (!selectors_js_1.analyticsControllerSelectors.selectEnabled(this.state)) { | ||
| return; | ||
| } | ||
| // Delegate to platform adapter using the current analytics ID | ||
| __classPrivateFieldGet(this, _AnalyticsController_instances, "m", _AnalyticsController_sendOrQueueIdentifyEvent).call(this, this.state.analyticsId, traits, context); | ||
| __classPrivateFieldGet(this, _AnalyticsController_instances, "m", _AnalyticsController_sendOrQueueIdentifyEvent).call(this, this.state.analyticsId, traits, __classPrivateFieldGet(this, _AnalyticsController_instances, "m", _AnalyticsController_withLocationContext).call(this, context)); | ||
| } | ||
@@ -289,7 +345,7 @@ /** | ||
| trackView(name, properties, context) { | ||
| if (!selectors_1.analyticsControllerSelectors.selectEnabled(this.state)) { | ||
| if (!selectors_js_1.analyticsControllerSelectors.selectEnabled(this.state)) { | ||
| return; | ||
| } | ||
| // Delegate to platform adapter | ||
| __classPrivateFieldGet(this, _AnalyticsController_instances, "m", _AnalyticsController_sendOrQueueViewEvent).call(this, name, properties, context); | ||
| __classPrivateFieldGet(this, _AnalyticsController_instances, "m", _AnalyticsController_sendOrQueueViewEvent).call(this, name, properties, __classPrivateFieldGet(this, _AnalyticsController_instances, "m", _AnalyticsController_withLocationContext).call(this, context)); | ||
| } | ||
@@ -301,4 +357,10 @@ /** | ||
| * were queued while the user was undecided. | ||
| * | ||
| * When geolocation enrichment is enabled, geolocation is resolved here (once | ||
| * the user has consented) and awaited before the queued events are replayed, | ||
| * so those events are enriched with the resolved location as they are sent. | ||
| * | ||
| * @returns A promise that resolves once opt-in processing has completed. | ||
| */ | ||
| optIn() { | ||
| async optIn() { | ||
| this.update((state) => { | ||
@@ -308,3 +370,10 @@ state.optedIn = true; | ||
| }); | ||
| __classPrivateFieldGet(this, _AnalyticsController_instances, "m", _AnalyticsController_replayPreConsentEvents).call(this); | ||
| // Now that the user has consented, resolve geolocation (once) and wait for | ||
| // it so the queued pre-consent events can be enriched as they replay. | ||
| await __classPrivateFieldGet(this, _AnalyticsController_instances, "m", _AnalyticsController_maybeResolveLocation).call(this); | ||
| // Reconcile against the current state rather than replaying blindly: the | ||
| // consent decision may have changed while geolocation was resolving (e.g. | ||
| // resetConsentDecision ran during the await), and preserved pre-consent | ||
| // events must not be delivered once the user is no longer opted in. | ||
| __classPrivateFieldGet(this, _AnalyticsController_instances, "m", _AnalyticsController_reconcilePreConsentEvents).call(this); | ||
| } | ||
@@ -342,5 +411,58 @@ /** | ||
| exports.AnalyticsController = AnalyticsController; | ||
| _AnalyticsController_platformAdapter = new WeakMap(), _AnalyticsController_isAnonymousEventsFeatureEnabled = new WeakMap(), _AnalyticsController_isEventQueuePersistenceEnabled = new WeakMap(), _AnalyticsController_isPreConsentQueueEnabled = new WeakMap(), _AnalyticsController_initialized = new WeakMap(), _AnalyticsController_instances = new WeakSet(), _AnalyticsController_sendOrQueueTrackEvent = function _AnalyticsController_sendOrQueueTrackEvent(eventName, properties, context) { | ||
| _AnalyticsController_platformAdapter = new WeakMap(), _AnalyticsController_isAnonymousEventsFeatureEnabled = new WeakMap(), _AnalyticsController_isEventQueuePersistenceEnabled = new WeakMap(), _AnalyticsController_isPreConsentQueueEnabled = new WeakMap(), _AnalyticsController_isGeolocationEnabled = new WeakMap(), _AnalyticsController_initPromise = new WeakMap(), _AnalyticsController_locationResolvePromise = new WeakMap(), _AnalyticsController_locationContext = new WeakMap(), _AnalyticsController_instances = new WeakSet(), _AnalyticsController_performInit = | ||
| /** | ||
| * Performs the one-time initialization work: resolve geolocation, run the | ||
| * platform adapter's onSetupCompleted lifecycle hook, then replay any queued | ||
| * and pre-consent events. | ||
| */ | ||
| async function _AnalyticsController_performInit() { | ||
| // Resolve geolocation only when the user is already opted in; for undecided | ||
| // or opted-out users it is deferred to {@link optIn}. Awaited so that an | ||
| // already-opted-in session has location available before events replay. | ||
| await __classPrivateFieldGet(this, _AnalyticsController_instances, "m", _AnalyticsController_maybeResolveLocation).call(this); | ||
| // Call onSetupCompleted lifecycle hook after initialization | ||
| // State is already validated, so analyticsId is guaranteed to be a valid UUIDv4 | ||
| try { | ||
| __classPrivateFieldGet(this, _AnalyticsController_platformAdapter, "f").onSetupCompleted(this.state.analyticsId); | ||
| } | ||
| catch (error) { | ||
| // Log error but don't throw - adapter setup failure shouldn't break controller | ||
| (0, AnalyticsLogger_js_1.projectLogger)('Error calling platformAdapter.onSetupCompleted', error); | ||
| } | ||
| __classPrivateFieldGet(this, _AnalyticsController_instances, "m", _AnalyticsController_replayQueuedEvents).call(this); | ||
| __classPrivateFieldGet(this, _AnalyticsController_instances, "m", _AnalyticsController_reconcilePreConsentEvents).call(this); | ||
| }, _AnalyticsController_maybeResolveLocation = function _AnalyticsController_maybeResolveLocation() { | ||
| if (__classPrivateFieldGet(this, _AnalyticsController_isGeolocationEnabled, "f") && | ||
| __classPrivateFieldGet(this, _AnalyticsController_locationResolvePromise, "f") === undefined && | ||
| selectors_js_1.analyticsControllerSelectors.selectEnabled(this.state)) { | ||
| __classPrivateFieldSet(this, _AnalyticsController_locationResolvePromise, __classPrivateFieldGet(this, _AnalyticsController_instances, "m", _AnalyticsController_resolveLocationContext).call(this), "f"); | ||
| } | ||
| return __classPrivateFieldGet(this, _AnalyticsController_locationResolvePromise, "f"); | ||
| }, _AnalyticsController_resolveLocationContext = async function _AnalyticsController_resolveLocationContext() { | ||
| try { | ||
| const geolocation = await this.messenger.call('GeolocationController:getGeolocationData'); | ||
| __classPrivateFieldSet(this, _AnalyticsController_locationContext, buildLocationContext(geolocation), "f"); | ||
| } | ||
| catch (error) { | ||
| // A common cause is the GeolocationController not being registered before | ||
| // resolution runs (at init for an opted-in user, otherwise at opt-in). | ||
| // Name it here so the failure is diagnosable, since enrichment is | ||
| // otherwise skipped silently for the session. | ||
| (0, AnalyticsLogger_js_1.projectLogger)('Failed to resolve geolocation for analytics enrichment; events will be sent without location. Ensure the GeolocationController is registered and initialized before the user opts in when geolocation is enabled.', error); | ||
| } | ||
| }, _AnalyticsController_withLocationContext = function _AnalyticsController_withLocationContext(context) { | ||
| if (!__classPrivateFieldGet(this, _AnalyticsController_locationContext, "f")) { | ||
| return context; | ||
| } | ||
| const callerLocation = context?.location; | ||
| return { | ||
| ...context, | ||
| location: { | ||
| ...(isJsonRecord(callerLocation) ? callerLocation : {}), | ||
| ...__classPrivateFieldGet(this, _AnalyticsController_locationContext, "f"), | ||
| }, | ||
| }; | ||
| }, _AnalyticsController_sendOrQueueTrackEvent = function _AnalyticsController_sendOrQueueTrackEvent(eventName, properties, context) { | ||
| // Direct delivery: enabled and not persisting. | ||
| if (selectors_1.analyticsControllerSelectors.selectEnabled(this.state) && | ||
| if (selectors_js_1.analyticsControllerSelectors.selectEnabled(this.state) && | ||
| !__classPrivateFieldGet(this, _AnalyticsController_isEventQueuePersistenceEnabled, "f")) { | ||
@@ -360,3 +482,3 @@ __classPrivateFieldGet(this, _AnalyticsController_platformAdapter, "f").track(eventName, properties, context); | ||
| // enabled): hold the event until the user opts in. | ||
| if (!selectors_1.analyticsControllerSelectors.selectEnabled(this.state)) { | ||
| if (!selectors_js_1.analyticsControllerSelectors.selectEnabled(this.state)) { | ||
| __classPrivateFieldGet(this, _AnalyticsController_instances, "m", _AnalyticsController_enqueuePreConsentEvent).call(this, queuedEvent); | ||
@@ -406,3 +528,3 @@ return; | ||
| if (Number.isNaN(timestamp.getTime())) { | ||
| (0, AnalyticsLogger_1.projectLogger)('Dropping queued analytics event with invalid timestamp', { | ||
| (0, AnalyticsLogger_js_1.projectLogger)('Dropping queued analytics event with invalid timestamp', { | ||
| messageId: queuedEvent.messageId, | ||
@@ -418,3 +540,3 @@ }); | ||
| if (error) { | ||
| (0, AnalyticsLogger_1.projectLogger)('Queued analytics event delivery failed', { | ||
| (0, AnalyticsLogger_js_1.projectLogger)('Queued analytics event delivery failed', { | ||
| messageId: queuedEvent.messageId, | ||
@@ -439,3 +561,3 @@ error, | ||
| catch (error) { | ||
| (0, AnalyticsLogger_1.projectLogger)('Error sending queued analytics event', { | ||
| (0, AnalyticsLogger_js_1.projectLogger)('Error sending queued analytics event', { | ||
| messageId: queuedEvent.messageId, | ||
@@ -449,3 +571,3 @@ error, | ||
| } | ||
| if (!selectors_1.analyticsControllerSelectors.selectEnabled(this.state)) { | ||
| if (!selectors_js_1.analyticsControllerSelectors.selectEnabled(this.state)) { | ||
| __classPrivateFieldGet(this, _AnalyticsController_instances, "m", _AnalyticsController_clearQueuedEvents).call(this); | ||
@@ -457,3 +579,3 @@ return; | ||
| queuedEvent.messageId !== messageId) { | ||
| (0, AnalyticsLogger_1.projectLogger)('Dropping invalid queued analytics event', { messageId }); | ||
| (0, AnalyticsLogger_js_1.projectLogger)('Dropping invalid queued analytics event', { messageId }); | ||
| __classPrivateFieldGet(this, _AnalyticsController_instances, "m", _AnalyticsController_removeQueuedEvent).call(this, messageId); | ||
@@ -490,10 +612,3 @@ continue; | ||
| }); | ||
| }, _AnalyticsController_replayPreConsentEvents = function _AnalyticsController_replayPreConsentEvents() { | ||
| if (!__classPrivateFieldGet(this, _AnalyticsController_isPreConsentQueueEnabled, "f")) { | ||
| return; | ||
| } | ||
| const queue = this.state.preConsentEventQueue; | ||
| if (!queue) { | ||
| return; | ||
| } | ||
| }, _AnalyticsController_replayPreConsentEvents = function _AnalyticsController_replayPreConsentEvents(queue) { | ||
| __classPrivateFieldGet(this, _AnalyticsController_instances, "m", _AnalyticsController_clearPreConsentEvents).call(this); | ||
@@ -503,3 +618,3 @@ for (const [messageId, queuedEvent] of Object.entries(queue)) { | ||
| queuedEvent.messageId !== messageId) { | ||
| (0, AnalyticsLogger_1.projectLogger)('Dropping invalid queued pre-consent analytics event', { | ||
| (0, AnalyticsLogger_js_1.projectLogger)('Dropping invalid queued pre-consent analytics event', { | ||
| messageId, | ||
@@ -509,9 +624,20 @@ }); | ||
| } | ||
| const eventToReplay = __classPrivateFieldGet(this, _AnalyticsController_instances, "m", _AnalyticsController_enrichPreConsentEvent).call(this, queuedEvent); | ||
| if (__classPrivateFieldGet(this, _AnalyticsController_isEventQueuePersistenceEnabled, "f")) { | ||
| __classPrivateFieldGet(this, _AnalyticsController_instances, "m", _AnalyticsController_enqueueEvent).call(this, queuedEvent); | ||
| __classPrivateFieldGet(this, _AnalyticsController_instances, "m", _AnalyticsController_enqueueEvent).call(this, eventToReplay); | ||
| } | ||
| else { | ||
| __classPrivateFieldGet(this, _AnalyticsController_instances, "m", _AnalyticsController_sendQueuedEvent).call(this, queuedEvent); | ||
| __classPrivateFieldGet(this, _AnalyticsController_instances, "m", _AnalyticsController_sendQueuedEvent).call(this, eventToReplay); | ||
| } | ||
| } | ||
| }, _AnalyticsController_enrichPreConsentEvent = function _AnalyticsController_enrichPreConsentEvent(queuedEvent) { | ||
| if (queuedEvent.type === 'track' && | ||
| queuedEvent.properties?.anonymous === true) { | ||
| return queuedEvent; | ||
| } | ||
| const context = __classPrivateFieldGet(this, _AnalyticsController_instances, "m", _AnalyticsController_withLocationContext).call(this, queuedEvent.context); | ||
| return { | ||
| ...queuedEvent, | ||
| ...(context === undefined ? {} : { context }), | ||
| }; | ||
| }, _AnalyticsController_clearPreConsentEvents = function _AnalyticsController_clearPreConsentEvents() { | ||
@@ -534,3 +660,3 @@ if (!this.state.preConsentEventQueue) { | ||
| if (this.state.optedIn) { | ||
| __classPrivateFieldGet(this, _AnalyticsController_instances, "m", _AnalyticsController_replayPreConsentEvents).call(this); | ||
| __classPrivateFieldGet(this, _AnalyticsController_instances, "m", _AnalyticsController_replayPreConsentEvents).call(this, queue); | ||
| } | ||
@@ -537,0 +663,0 @@ else if (this.state.consentDecisionMade) { |
@@ -1,1 +0,1 @@ | ||
| {"version":3,"file":"AnalyticsController.cjs","sourceRoot":"","sources":["../src/AnalyticsController.ts"],"names":[],"mappings":"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","sourcesContent":["import type {\n ControllerGetStateAction,\n ControllerStateChangeEvent,\n StateMetadata,\n} from '@metamask/base-controller';\nimport { BaseController } from '@metamask/base-controller';\nimport type { Messenger } from '@metamask/messenger';\nimport type { Json } from '@metamask/utils';\nimport { cloneDeep } from 'lodash';\nimport { v4 as uuid } from 'uuid';\n\nimport type { AnalyticsControllerMethodActions } from './AnalyticsController-method-action-types';\nimport { validateAnalyticsControllerState } from './analyticsControllerStateValidator';\nimport { projectLogger as log } from './AnalyticsLogger';\nimport type {\n AnalyticsPlatformAdapter,\n AnalyticsDeliveryOptions,\n AnalyticsContext,\n AnalyticsEventProperties,\n AnalyticsUserTraits,\n AnalyticsTrackingEvent,\n} from './AnalyticsPlatformAdapter.types';\nimport { analyticsControllerSelectors } from './selectors';\n\n// === GENERAL ===\n\n/**\n * The name of the {@link AnalyticsController}, used to namespace the\n * controller's actions and events and to namespace the controller's state data\n * when composed with other controllers.\n */\nexport const controllerName = 'AnalyticsController';\n\n// === STATE ===\n\n/**\n * Describes the shape of the state object for {@link AnalyticsController}.\n */\nexport type AnalyticsControllerState = {\n /**\n * Whether the user has opted in to analytics.\n */\n optedIn: boolean;\n\n /**\n * User's UUIDv4 analytics identifier.\n * This is an identity (unique per user), not a preference.\n * Must be provided by the platform - the controller does not generate it.\n */\n analyticsId: string;\n\n /**\n * Persisted queue of analytics events waiting for delivery acknowledgement.\n * This is only used when event queue persistence is enabled.\n */\n eventQueue?: Record<string, Json>;\n\n /**\n * Whether the user has made a consent decision (opted in or opted out).\n *\n * This distinguishes the \"undecided\" state (e.g. during onboarding, before\n * the user has answered the analytics prompt) from an explicit opt-out.\n * Defaults to `false` and is set to `true` by {@link AnalyticsController.optIn}\n * or {@link AnalyticsController.optOut}, and back to `false` by\n * {@link AnalyticsController.resetConsentDecision}. Optional for backward\n * compatibility with persisted state that predates this field.\n */\n consentDecisionMade?: boolean;\n\n /**\n * Persisted queue of track events ({@link AnalyticsQueuedTrackEvent}) captured\n * while the user is undecided (no consent decision made yet). Replayed on\n * opt-in and cleared on opt-out.\n * Preserved across {@link AnalyticsController.resetConsentDecision} so onboarding\n * restarts do not drop install-time events.\n * This is only used when the pre-consent queue is enabled.\n */\n preConsentEventQueue?: Record<string, Json>;\n};\n\n/**\n * Event types supported by the persisted analytics event queue.\n */\nexport type AnalyticsQueuedEventType = 'track' | 'identify' | 'view';\n\n/**\n * Base persisted event queue entry.\n */\nexport type AnalyticsQueuedEventBase = {\n /**\n * Event type used to replay the payload with the platform adapter.\n */\n type: AnalyticsQueuedEventType;\n\n /**\n * Stable identifier for the analytics payload.\n */\n messageId: string;\n\n /**\n * Original payload timestamp serialized for persistence.\n */\n timestamp: string;\n};\n\n/**\n * Persisted track event queue entry.\n */\nexport type AnalyticsQueuedTrackEvent = AnalyticsQueuedEventBase & {\n type: 'track';\n eventName: string;\n properties?: AnalyticsEventProperties;\n context?: AnalyticsContext;\n};\n\n/**\n * Persisted identify event queue entry.\n */\nexport type AnalyticsQueuedIdentifyEvent = AnalyticsQueuedEventBase & {\n type: 'identify';\n userId: string;\n traits?: AnalyticsUserTraits;\n context?: AnalyticsContext;\n};\n\n/**\n * Persisted view event queue entry.\n */\nexport type AnalyticsQueuedViewEvent = AnalyticsQueuedEventBase & {\n type: 'view';\n name: string;\n properties?: AnalyticsEventProperties;\n context?: AnalyticsContext;\n};\n\n/**\n * Persisted analytics event queue entry.\n */\nexport type AnalyticsQueuedEvent =\n | AnalyticsQueuedTrackEvent\n | AnalyticsQueuedIdentifyEvent\n | AnalyticsQueuedViewEvent;\n\n/**\n * Persisted analytics event queue keyed by message ID.\n */\nexport type AnalyticsEventQueue = Record<string, AnalyticsQueuedEvent>;\n\n/**\n * Returns default values for AnalyticsController state.\n *\n * Note: analyticsId is NOT included - it's an identity that must be\n * provided by the platform (generated once on first run, then persisted).\n *\n * @returns Default state without analyticsId\n */\nexport function getDefaultAnalyticsControllerState(): Omit<\n AnalyticsControllerState,\n 'analyticsId'\n> {\n return {\n optedIn: false,\n consentDecisionMade: false,\n };\n}\n\n/**\n * The metadata for each property in {@link AnalyticsControllerState}.\n *\n * Both `optedIn` and `analyticsId` are persisted (`persist: true`).\n * The platform must supply a valid UUIDv4 `analyticsId` on first run.\n */\nconst analyticsControllerMetadata = {\n optedIn: {\n includeInStateLogs: true,\n persist: true,\n includeInDebugSnapshot: true,\n usedInUi: true,\n },\n analyticsId: {\n includeInStateLogs: true,\n persist: true,\n includeInDebugSnapshot: true,\n usedInUi: false,\n },\n eventQueue: {\n includeInStateLogs: false,\n persist: true,\n includeInDebugSnapshot: false,\n usedInUi: false,\n },\n consentDecisionMade: {\n includeInStateLogs: true,\n persist: true,\n includeInDebugSnapshot: true,\n usedInUi: true,\n },\n preConsentEventQueue: {\n includeInStateLogs: false,\n persist: true,\n includeInDebugSnapshot: false,\n usedInUi: false,\n },\n} satisfies StateMetadata<AnalyticsControllerState>;\n\n// === MESSENGER ===\n\nconst MESSENGER_EXPOSED_METHODS = [\n 'trackEvent',\n 'identify',\n 'trackView',\n 'optIn',\n 'optOut',\n 'resetConsentDecision',\n] as const;\n\n/**\n * Returns the state of the {@link AnalyticsController}.\n */\nexport type AnalyticsControllerGetStateAction = ControllerGetStateAction<\n typeof controllerName,\n AnalyticsControllerState\n>;\n\n/**\n * Actions that {@link AnalyticsControllerMessenger} exposes to other consumers.\n */\nexport type AnalyticsControllerActions =\n | AnalyticsControllerGetStateAction\n | AnalyticsControllerMethodActions;\n\n/**\n * Actions from other messengers that {@link AnalyticsControllerMessenger} calls.\n */\ntype AllowedActions = never;\n\n/**\n * Event emitted when the state of the {@link AnalyticsController} changes.\n */\nexport type AnalyticsControllerStateChangeEvent = ControllerStateChangeEvent<\n typeof controllerName,\n AnalyticsControllerState\n>;\n\n/**\n * Events that {@link AnalyticsControllerMessenger} exposes to other consumers.\n */\nexport type AnalyticsControllerEvents = AnalyticsControllerStateChangeEvent;\n\n/**\n * Events from other messengers that {@link AnalyticsControllerMessenger} subscribes to.\n */\ntype AllowedEvents = never;\n\n/**\n * The messenger restricted to actions and events accessed by\n * {@link AnalyticsController}.\n */\nexport type AnalyticsControllerMessenger = Messenger<\n typeof controllerName,\n AnalyticsControllerActions | AllowedActions,\n AnalyticsControllerEvents | AllowedEvents\n>;\n\n// === CONTROLLER DEFINITION ===\n\n/**\n * The options that AnalyticsController takes.\n */\nexport type AnalyticsControllerOptions = {\n /**\n * Initial controller state. Must include a valid UUIDv4 `analyticsId`.\n * The platform is responsible for generating the ID on first run.\n * It is then persisted with controller state when using a persisted store.\n */\n state: AnalyticsControllerState;\n /**\n * Messenger used to communicate with BaseController and other controllers.\n */\n messenger: AnalyticsControllerMessenger;\n /**\n * Platform adapter implementation for tracking events.\n */\n platformAdapter: AnalyticsPlatformAdapter;\n\n /**\n * Whether the anonymous events feature is enabled.\n *\n * @default false\n */\n isAnonymousEventsFeatureEnabled?: boolean;\n\n /**\n * Whether analytics event queue persistence is enabled.\n *\n * When enabled, AnalyticsController persists each platform adapter payload\n * until the adapter reports successful delivery.\n *\n * @default false\n */\n isEventQueuePersistenceEnabled?: boolean;\n\n /**\n * Whether the pre-consent event queue is enabled.\n *\n * When enabled, track events received while the user is undecided\n * (no consent decision made yet) are persisted and replayed on opt-in,\n * or dropped on opt-out. When disabled, such events are dropped immediately,\n * preserving the legacy behavior.\n *\n * @default false\n */\n isPreConsentQueueEnabled?: boolean;\n};\n\n/**\n * Returns whether a value is a non-array object.\n *\n * @param value - The value to check.\n * @returns True if the value is a record.\n */\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return value !== null && typeof value === 'object' && !Array.isArray(value);\n}\n\n/**\n * Returns whether a value is a valid persisted analytics event.\n *\n * @param value - The value to check.\n * @returns True if the value is a queued analytics event.\n */\nfunction isAnalyticsQueuedEvent(value: unknown): value is AnalyticsQueuedEvent {\n if (!isRecord(value)) {\n return false;\n }\n\n if (\n typeof value.messageId !== 'string' ||\n typeof value.timestamp !== 'string'\n ) {\n return false;\n }\n\n if (value.type === 'track') {\n return (\n typeof value.eventName === 'string' &&\n (value.properties === undefined || isRecord(value.properties)) &&\n (value.context === undefined || isRecord(value.context))\n );\n }\n\n if (value.type === 'identify') {\n return (\n typeof value.userId === 'string' &&\n (value.traits === undefined || isRecord(value.traits)) &&\n (value.context === undefined || isRecord(value.context))\n );\n }\n\n if (value.type === 'view') {\n return (\n typeof value.name === 'string' &&\n (value.properties === undefined || isRecord(value.properties)) &&\n (value.context === undefined || isRecord(value.context))\n );\n }\n\n return false;\n}\n\n/**\n * The AnalyticsController manages analytics tracking across platforms (Mobile/Extension).\n * It provides a unified interface for tracking events, identifying users, and managing\n * analytics preferences while delegating platform-specific implementation to an\n * {@link AnalyticsPlatformAdapter}.\n *\n * This controller follows the MetaMask controller pattern and integrates with the\n * messenger system to allow other controllers and components to track analytics events.\n * It delegates platform-specific implementation to an {@link AnalyticsPlatformAdapter}.\n *\n * The controller persists `optedIn` and `analyticsId` when composed with a persisted\n * store. The platform must supply a valid `analyticsId` on first launch.\n */\nexport class AnalyticsController extends BaseController<\n 'AnalyticsController',\n AnalyticsControllerState,\n AnalyticsControllerMessenger\n> {\n readonly #platformAdapter: AnalyticsPlatformAdapter;\n\n readonly #isAnonymousEventsFeatureEnabled: boolean;\n\n readonly #isEventQueuePersistenceEnabled: boolean;\n\n readonly #isPreConsentQueueEnabled: boolean;\n\n #initialized: boolean;\n\n /**\n * Constructs an AnalyticsController instance.\n *\n * @param options - Controller options\n * @param options.state - Initial controller state. Must include a valid UUIDv4 `analyticsId`.\n * Use `getDefaultAnalyticsControllerState()` for default opt-in preferences.\n * @param options.messenger - Messenger used to communicate with BaseController\n * @param options.platformAdapter - Platform adapter implementation for tracking\n * @param options.isAnonymousEventsFeatureEnabled - Whether the anonymous events feature is enabled\n * @param options.isEventQueuePersistenceEnabled - Whether analytics event queue persistence is enabled\n * @param options.isPreConsentQueueEnabled - Whether the pre-consent event queue is enabled\n * @throws Error if state.analyticsId is missing or not a valid UUIDv4\n * @remarks After construction, call {@link AnalyticsController.init} to complete initialization.\n */\n constructor({\n state,\n messenger,\n platformAdapter,\n isAnonymousEventsFeatureEnabled = false,\n isEventQueuePersistenceEnabled = false,\n isPreConsentQueueEnabled = false,\n }: AnalyticsControllerOptions) {\n const initialState: AnalyticsControllerState = {\n ...getDefaultAnalyticsControllerState(),\n ...state,\n };\n\n validateAnalyticsControllerState(\n initialState,\n platformAdapter.skipUUIDv4Check === true,\n );\n\n super({\n name: controllerName,\n metadata: analyticsControllerMetadata,\n state: initialState,\n messenger,\n });\n\n this.#isAnonymousEventsFeatureEnabled = isAnonymousEventsFeatureEnabled;\n this.#isEventQueuePersistenceEnabled = isEventQueuePersistenceEnabled;\n this.#isPreConsentQueueEnabled = isPreConsentQueueEnabled;\n this.#platformAdapter = platformAdapter;\n this.#initialized = false;\n\n this.messenger.registerMethodActionHandlers(\n this,\n MESSENGER_EXPOSED_METHODS,\n );\n\n log('AnalyticsController initialized and ready', {\n enabled: analyticsControllerSelectors.selectEnabled(this.state),\n optedIn: this.state.optedIn,\n consentDecisionMade: this.state.consentDecisionMade,\n analyticsId: this.state.analyticsId,\n eventQueuePersistenceEnabled: this.#isEventQueuePersistenceEnabled,\n preConsentQueueEnabled: this.#isPreConsentQueueEnabled,\n });\n }\n\n /**\n * Initialize the controller by calling the platform adapter's onSetupCompleted lifecycle hook.\n * This method must be called after construction to complete the setup process.\n */\n init(): void {\n if (this.#initialized) {\n log('AnalyticsController already initialized.');\n return;\n }\n\n this.#initialized = true;\n\n // Call onSetupCompleted lifecycle hook after initialization\n // State is already validated, so analyticsId is guaranteed to be a valid UUIDv4\n try {\n this.#platformAdapter.onSetupCompleted(this.state.analyticsId);\n } catch (error) {\n // Log error but don't throw - adapter setup failure shouldn't break controller\n log('Error calling platformAdapter.onSetupCompleted', error);\n }\n\n this.#replayQueuedEvents();\n this.#reconcilePreConsentEvents();\n }\n\n /**\n * Send final track payload through the platform adapter or queue it if persistence is enabled.\n *\n * @param eventName - The name of the event.\n * @param properties - Optional event properties.\n * @param context - Optional platform-specific context.\n */\n #sendOrQueueTrackEvent(\n eventName: string,\n properties?: AnalyticsEventProperties,\n context?: AnalyticsContext,\n ): void {\n // Direct delivery: enabled and not persisting.\n if (\n analyticsControllerSelectors.selectEnabled(this.state) &&\n !this.#isEventQueuePersistenceEnabled\n ) {\n this.#platformAdapter.track(eventName, properties, context);\n return;\n }\n\n const queuedEvent: AnalyticsQueuedTrackEvent = {\n type: 'track',\n eventName,\n messageId: uuid(),\n timestamp: new Date().toISOString(),\n ...(properties === undefined ? {} : { properties }),\n ...(context === undefined ? {} : { context }),\n };\n\n // Not yet enabled (reached only while undecided with the pre-consent queue\n // enabled): hold the event until the user opts in.\n if (!analyticsControllerSelectors.selectEnabled(this.state)) {\n this.#enqueuePreConsentEvent(queuedEvent);\n return;\n }\n\n this.#enqueueEvent(queuedEvent);\n }\n\n /**\n * Send final identify payload through the platform adapter or queue it if persistence is enabled.\n *\n * @param userId - The user ID.\n * @param traits - Optional user traits.\n * @param context - Optional platform-specific context.\n */\n #sendOrQueueIdentifyEvent(\n userId: string,\n traits?: AnalyticsUserTraits,\n context?: AnalyticsContext,\n ): void {\n if (!this.#isEventQueuePersistenceEnabled) {\n this.#platformAdapter.identify(userId, traits, context);\n return;\n }\n\n const queuedEvent: AnalyticsQueuedIdentifyEvent = {\n type: 'identify',\n userId,\n messageId: uuid(),\n timestamp: new Date().toISOString(),\n ...(traits === undefined ? {} : { traits }),\n ...(context === undefined ? {} : { context }),\n };\n\n this.#enqueueEvent(queuedEvent);\n }\n\n /**\n * Send final view payload through the platform adapter or queue it if persistence is enabled.\n *\n * @param name - The view name.\n * @param properties - Optional view properties.\n * @param context - Optional platform-specific context.\n */\n #sendOrQueueViewEvent(\n name: string,\n properties?: AnalyticsEventProperties,\n context?: AnalyticsContext,\n ): void {\n if (!this.#isEventQueuePersistenceEnabled) {\n this.#platformAdapter.view(name, properties, context);\n return;\n }\n\n const queuedEvent: AnalyticsQueuedViewEvent = {\n type: 'view',\n name,\n messageId: uuid(),\n timestamp: new Date().toISOString(),\n ...(properties === undefined ? {} : { properties }),\n ...(context === undefined ? {} : { context }),\n };\n\n this.#enqueueEvent(queuedEvent);\n }\n\n /**\n * Add an analytics event to the queue and send it.\n *\n * @param queuedEvent - The event to enqueue and deliver.\n */\n #enqueueEvent(queuedEvent: AnalyticsQueuedEvent): void {\n const eventQueue: Record<string, Json> = {\n ...(this.state.eventQueue ?? {}),\n [queuedEvent.messageId]: queuedEvent as unknown as Json,\n };\n\n this.update((state) => {\n state.eventQueue = eventQueue as never;\n });\n\n this.#sendQueuedEvent(queuedEvent);\n }\n\n /**\n * Send a queued event through the platform adapter.\n *\n * @param queuedEvent - The queued event to deliver.\n */\n #sendQueuedEvent(queuedEvent: AnalyticsQueuedEvent): void {\n const timestamp = new Date(queuedEvent.timestamp);\n\n if (Number.isNaN(timestamp.getTime())) {\n log('Dropping queued analytics event with invalid timestamp', {\n messageId: queuedEvent.messageId,\n });\n this.#removeQueuedEvent(queuedEvent.messageId);\n return;\n }\n\n const options: AnalyticsDeliveryOptions = {\n messageId: queuedEvent.messageId,\n timestamp,\n callback: (error?: unknown) => {\n if (error) {\n log('Queued analytics event delivery failed', {\n messageId: queuedEvent.messageId,\n error,\n });\n }\n\n this.#removeQueuedEvent(queuedEvent.messageId);\n },\n };\n\n try {\n if (queuedEvent.type === 'track') {\n this.#platformAdapter.track(\n queuedEvent.eventName,\n cloneDeep(queuedEvent.properties),\n cloneDeep(queuedEvent.context),\n options,\n );\n } else if (queuedEvent.type === 'identify') {\n this.#platformAdapter.identify(\n queuedEvent.userId,\n cloneDeep(queuedEvent.traits),\n cloneDeep(queuedEvent.context),\n options,\n );\n } else {\n this.#platformAdapter.view(\n queuedEvent.name,\n cloneDeep(queuedEvent.properties),\n cloneDeep(queuedEvent.context),\n options,\n );\n }\n } catch (error) {\n log('Error sending queued analytics event', {\n messageId: queuedEvent.messageId,\n error,\n });\n }\n }\n\n /**\n * Replay persisted analytics events.\n */\n #replayQueuedEvents(): void {\n if (!this.#isEventQueuePersistenceEnabled || !this.state.eventQueue) {\n return;\n }\n\n if (!analyticsControllerSelectors.selectEnabled(this.state)) {\n this.#clearQueuedEvents();\n return;\n }\n\n for (const [messageId, queuedEvent] of Object.entries(\n this.state.eventQueue,\n )) {\n if (\n !isAnalyticsQueuedEvent(queuedEvent) ||\n queuedEvent.messageId !== messageId\n ) {\n log('Dropping invalid queued analytics event', { messageId });\n this.#removeQueuedEvent(messageId);\n continue;\n }\n\n this.#sendQueuedEvent(queuedEvent);\n }\n }\n\n /**\n * Remove a queued analytics event.\n *\n * @param messageId - The queued event message ID.\n */\n #removeQueuedEvent(messageId: string): void {\n const currentEventQueue = this.state.eventQueue;\n\n if (\n !currentEventQueue ||\n !Object.prototype.hasOwnProperty.call(currentEventQueue, messageId)\n ) {\n return;\n }\n\n const { [messageId]: _deletedEvent, ...eventQueue } = currentEventQueue;\n\n this.update((state) => {\n state.eventQueue = eventQueue as never;\n });\n }\n\n /**\n * Clear all queued analytics events.\n */\n #clearQueuedEvents(): void {\n if (\n !this.state.eventQueue ||\n Object.keys(this.state.eventQueue).length === 0\n ) {\n return;\n }\n\n this.update((state) => {\n state.eventQueue = {} as never;\n });\n }\n\n /**\n * Add an event to the pre-consent queue without delivering it.\n *\n * @param queuedEvent - The event to hold until the user opts in.\n */\n #enqueuePreConsentEvent(queuedEvent: AnalyticsQueuedEvent): void {\n const preConsentEventQueue: Record<string, Json> = {\n ...(this.state.preConsentEventQueue ?? {}),\n [queuedEvent.messageId]: queuedEvent as unknown as Json,\n };\n\n this.update((state) => {\n state.preConsentEventQueue = preConsentEventQueue as never;\n });\n }\n\n /**\n * Replay queued pre-consent events through the delivery path.\n *\n * Called on opt-in, once analytics is enabled. The queue is cleared before\n * replaying so events cannot be re-queued or replayed twice.\n */\n #replayPreConsentEvents(): void {\n if (!this.#isPreConsentQueueEnabled) {\n return;\n }\n\n const queue = this.state.preConsentEventQueue;\n\n if (!queue) {\n return;\n }\n\n this.#clearPreConsentEvents();\n\n for (const [messageId, queuedEvent] of Object.entries(queue)) {\n if (\n !isAnalyticsQueuedEvent(queuedEvent) ||\n queuedEvent.messageId !== messageId\n ) {\n log('Dropping invalid queued pre-consent analytics event', {\n messageId,\n });\n continue;\n }\n\n if (this.#isEventQueuePersistenceEnabled) {\n this.#enqueueEvent(queuedEvent);\n } else {\n this.#sendQueuedEvent(queuedEvent);\n }\n }\n }\n\n /**\n * Clear all queued pre-consent events.\n */\n #clearPreConsentEvents(): void {\n if (!this.state.preConsentEventQueue) {\n return;\n }\n\n this.update((state) => {\n state.preConsentEventQueue = {} as never;\n });\n }\n\n /**\n * Reconcile the pre-consent queue on initialization.\n *\n * The queue should normally be empty unless the user is still undecided. This\n * handles the rare cases where a consent decision was persisted but the queue\n * was not flushed/cleared (e.g. an interrupted shutdown): replay it if the\n * user is opted in, or clear it if they opted out.\n *\n * If the pre-consent queue is disabled, any stale persisted entries (e.g. from\n * a previous session where it was enabled) are dropped so they can never be\n * replayed.\n */\n #reconcilePreConsentEvents(): void {\n const queue = this.state.preConsentEventQueue;\n\n if (!queue) {\n return;\n }\n\n if (!this.#isPreConsentQueueEnabled) {\n this.#clearPreConsentEvents();\n return;\n }\n\n if (this.state.optedIn) {\n this.#replayPreConsentEvents();\n } else if (this.state.consentDecisionMade) {\n this.#clearPreConsentEvents();\n }\n }\n\n /**\n * Track an analytics event.\n *\n * Events are only tracked if analytics is enabled.\n *\n * @param event - Analytics event with properties and sensitive properties\n * @param context - Optional platform-specific context forwarded to the platform adapter.\n */\n trackEvent(event: AnalyticsTrackingEvent, context?: AnalyticsContext): void {\n if (!analyticsControllerSelectors.selectEnabled(this.state)) {\n // While the user is undecided, fall through so the event is processed and\n // captured in the pre-consent queue (see #sendOrQueueTrackEvent) to be\n // replayed if they later opt in. Otherwise (opted out, or pre-consent\n // queue disabled) drop it.\n const shouldQueuePreConsent =\n this.#isPreConsentQueueEnabled && !this.state.consentDecisionMade;\n if (!shouldQueuePreConsent) {\n return;\n }\n }\n\n // if event does not have properties, send event without properties\n // and return to prevent any additional processing\n if (!event.hasProperties) {\n this.#sendOrQueueTrackEvent(event.name, undefined, context);\n return;\n }\n\n // Track regular properties first if anonymous events feature is enabled\n if (this.#isAnonymousEventsFeatureEnabled) {\n // Note: Even if regular properties object is empty, we still send it to ensure\n // an event with user ID is tracked.\n this.#sendOrQueueTrackEvent(\n event.name,\n {\n ...event.properties,\n },\n context,\n );\n }\n\n const hasSensitiveProperties =\n Object.keys(event.sensitiveProperties).length > 0;\n\n if (!this.#isAnonymousEventsFeatureEnabled || hasSensitiveProperties) {\n this.#sendOrQueueTrackEvent(\n event.name,\n {\n ...event.properties,\n ...event.sensitiveProperties,\n ...(hasSensitiveProperties && { anonymous: true }),\n },\n context,\n );\n }\n }\n\n /**\n * Identify a user for analytics.\n *\n * @param traits - User traits/properties\n * @param context - Optional platform-specific context forwarded to the platform adapter.\n */\n identify(traits?: AnalyticsUserTraits, context?: AnalyticsContext): void {\n if (!analyticsControllerSelectors.selectEnabled(this.state)) {\n return;\n }\n\n // Delegate to platform adapter using the current analytics ID\n this.#sendOrQueueIdentifyEvent(this.state.analyticsId, traits, context);\n }\n\n /**\n * Track a page or screen view.\n *\n * @param name - The identifier/name of the page or screen being viewed (e.g., \"home\", \"settings\", \"wallet\")\n * @param properties - Optional properties associated with the view\n * @param context - Optional platform-specific context forwarded to the platform adapter.\n */\n trackView(\n name: string,\n properties?: AnalyticsEventProperties,\n context?: AnalyticsContext,\n ): void {\n if (!analyticsControllerSelectors.selectEnabled(this.state)) {\n return;\n }\n\n // Delegate to platform adapter\n this.#sendOrQueueViewEvent(name, properties, context);\n }\n\n /**\n * Opt in to analytics.\n *\n * Records that a consent decision has been made and replays any events that\n * were queued while the user was undecided.\n */\n optIn(): void {\n this.update((state) => {\n state.optedIn = true;\n state.consentDecisionMade = true;\n });\n\n this.#replayPreConsentEvents();\n }\n\n /**\n * Opt out of analytics.\n *\n * Records that a consent decision has been made and discards any persisted\n * events so nothing captured before the decision is ever delivered.\n */\n optOut(): void {\n this.update((state) => {\n state.optedIn = false;\n state.consentDecisionMade = true;\n });\n\n this.#clearQueuedEvents();\n this.#clearPreConsentEvents();\n }\n\n /**\n * Reset the consent decision back to undecided.\n *\n * Intended for client flows that restart onboarding. Clears the opt-in\n * preference and discards the delivery queue, but preserves any pre-consent\n * events so they can still be replayed if the user opts in again. The user is\n * treated as undecided again.\n */\n resetConsentDecision(): void {\n this.update((state) => {\n state.optedIn = false;\n state.consentDecisionMade = false;\n });\n\n this.#clearQueuedEvents();\n }\n}\n"]} | ||
| {"version":3,"file":"AnalyticsController.cjs","sourceRoot":"","sources":["../src/AnalyticsController.ts"],"names":[],"mappings":"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","sourcesContent":["import type {\n ControllerGetStateAction,\n ControllerStateChangeEvent,\n StateMetadata,\n} from '@metamask/base-controller';\nimport { BaseController } from '@metamask/base-controller';\nimport type {\n GeolocationControllerGetGeolocationDataAction,\n GeolocationData,\n} from '@metamask/geolocation-controller';\nimport type { Messenger } from '@metamask/messenger';\nimport type { Json } from '@metamask/utils';\nimport { cloneDeep } from 'lodash';\nimport { v4 as uuid } from 'uuid';\n\nimport type { AnalyticsControllerMethodActions } from './AnalyticsController-method-action-types.js';\nimport { validateAnalyticsControllerState } from './analyticsControllerStateValidator.js';\nimport { projectLogger as log } from './AnalyticsLogger.js';\nimport type {\n AnalyticsPlatformAdapter,\n AnalyticsDeliveryOptions,\n AnalyticsContext,\n AnalyticsEventProperties,\n AnalyticsLocationContext,\n AnalyticsUserTraits,\n AnalyticsTrackingEvent,\n} from './AnalyticsPlatformAdapter.types';\nimport { analyticsControllerSelectors } from './selectors.js';\n\n// === GENERAL ===\n\n/**\n * The name of the {@link AnalyticsController}, used to namespace the\n * controller's actions and events and to namespace the controller's state data\n * when composed with other controllers.\n */\nexport const controllerName = 'AnalyticsController';\n\n// === STATE ===\n\n/**\n * Describes the shape of the state object for {@link AnalyticsController}.\n */\nexport type AnalyticsControllerState = {\n /**\n * Whether the user has opted in to analytics.\n */\n optedIn: boolean;\n\n /**\n * User's UUIDv4 analytics identifier.\n * This is an identity (unique per user), not a preference.\n * Must be provided by the platform - the controller does not generate it.\n */\n analyticsId: string;\n\n /**\n * Persisted queue of analytics events waiting for delivery acknowledgement.\n * This is only used when event queue persistence is enabled.\n */\n eventQueue?: Record<string, Json>;\n\n /**\n * Whether the user has made a consent decision (opted in or opted out).\n *\n * This distinguishes the \"undecided\" state (e.g. during onboarding, before\n * the user has answered the analytics prompt) from an explicit opt-out.\n * Defaults to `false` and is set to `true` by {@link AnalyticsController.optIn}\n * or {@link AnalyticsController.optOut}, and back to `false` by\n * {@link AnalyticsController.resetConsentDecision}. Optional for backward\n * compatibility with persisted state that predates this field.\n */\n consentDecisionMade?: boolean;\n\n /**\n * Persisted queue of track events ({@link AnalyticsQueuedTrackEvent}) captured\n * while the user is undecided (no consent decision made yet). Replayed on\n * opt-in and cleared on opt-out.\n * Preserved across {@link AnalyticsController.resetConsentDecision} so onboarding\n * restarts do not drop install-time events.\n * This is only used when the pre-consent queue is enabled.\n */\n preConsentEventQueue?: Record<string, Json>;\n};\n\n/**\n * Event types supported by the persisted analytics event queue.\n */\nexport type AnalyticsQueuedEventType = 'track' | 'identify' | 'view';\n\n/**\n * Base persisted event queue entry.\n */\nexport type AnalyticsQueuedEventBase = {\n /**\n * Event type used to replay the payload with the platform adapter.\n */\n type: AnalyticsQueuedEventType;\n\n /**\n * Stable identifier for the analytics payload.\n */\n messageId: string;\n\n /**\n * Original payload timestamp serialized for persistence.\n */\n timestamp: string;\n};\n\n/**\n * Persisted track event queue entry.\n */\nexport type AnalyticsQueuedTrackEvent = AnalyticsQueuedEventBase & {\n type: 'track';\n eventName: string;\n properties?: AnalyticsEventProperties;\n context?: AnalyticsContext;\n};\n\n/**\n * Persisted identify event queue entry.\n */\nexport type AnalyticsQueuedIdentifyEvent = AnalyticsQueuedEventBase & {\n type: 'identify';\n userId: string;\n traits?: AnalyticsUserTraits;\n context?: AnalyticsContext;\n};\n\n/**\n * Persisted view event queue entry.\n */\nexport type AnalyticsQueuedViewEvent = AnalyticsQueuedEventBase & {\n type: 'view';\n name: string;\n properties?: AnalyticsEventProperties;\n context?: AnalyticsContext;\n};\n\n/**\n * Persisted analytics event queue entry.\n */\nexport type AnalyticsQueuedEvent =\n | AnalyticsQueuedTrackEvent\n | AnalyticsQueuedIdentifyEvent\n | AnalyticsQueuedViewEvent;\n\n/**\n * Persisted analytics event queue keyed by message ID.\n */\nexport type AnalyticsEventQueue = Record<string, AnalyticsQueuedEvent>;\n\n/**\n * Returns default values for AnalyticsController state.\n *\n * Note: analyticsId is NOT included - it's an identity that must be\n * provided by the platform (generated once on first run, then persisted).\n *\n * @returns Default state without analyticsId\n */\nexport function getDefaultAnalyticsControllerState(): Omit<\n AnalyticsControllerState,\n 'analyticsId'\n> {\n return {\n optedIn: false,\n consentDecisionMade: false,\n };\n}\n\n/**\n * The metadata for each property in {@link AnalyticsControllerState}.\n *\n * Both `optedIn` and `analyticsId` are persisted (`persist: true`).\n * The platform must supply a valid UUIDv4 `analyticsId` on first run.\n */\nconst analyticsControllerMetadata = {\n optedIn: {\n includeInStateLogs: true,\n persist: true,\n includeInDebugSnapshot: true,\n usedInUi: true,\n },\n analyticsId: {\n includeInStateLogs: true,\n persist: true,\n includeInDebugSnapshot: true,\n usedInUi: false,\n },\n eventQueue: {\n includeInStateLogs: false,\n persist: true,\n includeInDebugSnapshot: false,\n usedInUi: false,\n },\n consentDecisionMade: {\n includeInStateLogs: true,\n persist: true,\n includeInDebugSnapshot: true,\n usedInUi: true,\n },\n preConsentEventQueue: {\n includeInStateLogs: false,\n persist: true,\n includeInDebugSnapshot: false,\n usedInUi: false,\n },\n} satisfies StateMetadata<AnalyticsControllerState>;\n\n// === MESSENGER ===\n\nconst MESSENGER_EXPOSED_METHODS = [\n 'trackEvent',\n 'identify',\n 'trackView',\n 'optIn',\n 'optOut',\n 'resetConsentDecision',\n] as const;\n\n/**\n * Returns the state of the {@link AnalyticsController}.\n */\nexport type AnalyticsControllerGetStateAction = ControllerGetStateAction<\n typeof controllerName,\n AnalyticsControllerState\n>;\n\n/**\n * Actions that {@link AnalyticsControllerMessenger} exposes to other consumers.\n */\nexport type AnalyticsControllerActions =\n | AnalyticsControllerGetStateAction\n | AnalyticsControllerMethodActions;\n\n/**\n * Actions from other messengers that {@link AnalyticsControllerMessenger} calls.\n */\ntype AllowedActions = GeolocationControllerGetGeolocationDataAction;\n\n/**\n * Event emitted when the state of the {@link AnalyticsController} changes.\n */\nexport type AnalyticsControllerStateChangeEvent = ControllerStateChangeEvent<\n typeof controllerName,\n AnalyticsControllerState\n>;\n\n/**\n * Events that {@link AnalyticsControllerMessenger} exposes to other consumers.\n */\nexport type AnalyticsControllerEvents = AnalyticsControllerStateChangeEvent;\n\n/**\n * Events from other messengers that {@link AnalyticsControllerMessenger} subscribes to.\n */\ntype AllowedEvents = never;\n\n/**\n * The messenger restricted to actions and events accessed by\n * {@link AnalyticsController}.\n */\nexport type AnalyticsControllerMessenger = Messenger<\n typeof controllerName,\n AnalyticsControllerActions | AllowedActions,\n AnalyticsControllerEvents | AllowedEvents\n>;\n\n// === CONTROLLER DEFINITION ===\n\n/**\n * The options that AnalyticsController takes.\n */\nexport type AnalyticsControllerOptions = {\n /**\n * Initial controller state. Must include a valid UUIDv4 `analyticsId`.\n * The platform is responsible for generating the ID on first run.\n * It is then persisted with controller state when using a persisted store.\n */\n state: AnalyticsControllerState;\n /**\n * Messenger used to communicate with BaseController and other controllers.\n */\n messenger: AnalyticsControllerMessenger;\n /**\n * Platform adapter implementation for tracking events.\n */\n platformAdapter: AnalyticsPlatformAdapter;\n\n /**\n * Whether the anonymous events feature is enabled.\n *\n * @default false\n */\n isAnonymousEventsFeatureEnabled?: boolean;\n\n /**\n * Whether analytics event queue persistence is enabled.\n *\n * When enabled, AnalyticsController persists each platform adapter payload\n * until the adapter reports successful delivery.\n *\n * @default false\n */\n isEventQueuePersistenceEnabled?: boolean;\n\n /**\n * Whether the pre-consent event queue is enabled.\n *\n * When enabled, track events received while the user is undecided\n * (no consent decision made yet) are persisted and replayed on opt-in,\n * or dropped on opt-out. When disabled, such events are dropped immediately,\n * preserving the legacy behavior.\n *\n * @default false\n */\n isPreConsentQueueEnabled?: boolean;\n\n /**\n * Whether geolocation enrichment is enabled.\n *\n * When enabled, {@link AnalyticsController.init} resolves the user's\n * country, region, and timezone via `GeolocationController:getGeolocationData`\n * and attaches them to `context.location` on non-anonymous payloads.\n * Compositions must register that action when this is enabled. When disabled,\n * the controller never calls the geolocation action and events are delivered\n * without location.\n *\n * @default false\n */\n isGeolocationEnabled?: boolean;\n};\n\n/**\n * Returns whether a value is a non-array object.\n *\n * @param value - The value to check.\n * @returns True if the value is a record.\n */\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return value !== null && typeof value === 'object' && !Array.isArray(value);\n}\n\n/**\n * Returns whether a JSON value is a non-array object.\n *\n * @param value - The value to check.\n * @returns True if the value is a JSON record.\n */\nfunction isJsonRecord(value: Json | undefined): value is Record<string, Json> {\n return value !== null && typeof value === 'object' && !Array.isArray(value);\n}\n\n/**\n * Builds the analytics location context from geolocation data, keeping only\n * the fields the geolocation API was able to determine.\n *\n * @param geolocation - The geolocation data to convert.\n * @returns The location context, or `undefined` when no field is known.\n */\nfunction buildLocationContext(\n geolocation: GeolocationData,\n): AnalyticsLocationContext | undefined {\n const locationContext: AnalyticsLocationContext = {\n ...(geolocation.country === null\n ? {}\n : { country_code: geolocation.country }),\n ...(geolocation.region === null ? {} : { region: geolocation.region }),\n ...(geolocation.timezone === null\n ? {}\n : { timezone: geolocation.timezone }),\n };\n\n return Object.keys(locationContext).length === 0\n ? undefined\n : locationContext;\n}\n\n/**\n * Returns whether a value is a valid persisted analytics event.\n *\n * @param value - The value to check.\n * @returns True if the value is a queued analytics event.\n */\nfunction isAnalyticsQueuedEvent(value: unknown): value is AnalyticsQueuedEvent {\n if (!isRecord(value)) {\n return false;\n }\n\n if (\n typeof value.messageId !== 'string' ||\n typeof value.timestamp !== 'string'\n ) {\n return false;\n }\n\n if (value.type === 'track') {\n return (\n typeof value.eventName === 'string' &&\n (value.properties === undefined || isRecord(value.properties)) &&\n (value.context === undefined || isRecord(value.context))\n );\n }\n\n if (value.type === 'identify') {\n return (\n typeof value.userId === 'string' &&\n (value.traits === undefined || isRecord(value.traits)) &&\n (value.context === undefined || isRecord(value.context))\n );\n }\n\n if (value.type === 'view') {\n return (\n typeof value.name === 'string' &&\n (value.properties === undefined || isRecord(value.properties)) &&\n (value.context === undefined || isRecord(value.context))\n );\n }\n\n return false;\n}\n\n/**\n * The AnalyticsController manages analytics tracking across platforms (Mobile/Extension).\n * It provides a unified interface for tracking events, identifying users, and managing\n * analytics preferences while delegating platform-specific implementation to an\n * {@link AnalyticsPlatformAdapter}.\n *\n * This controller follows the MetaMask controller pattern and integrates with the\n * messenger system to allow other controllers and components to track analytics events.\n * It delegates platform-specific implementation to an {@link AnalyticsPlatformAdapter}.\n *\n * The controller persists `optedIn` and `analyticsId` when composed with a persisted\n * store. The platform must supply a valid `analyticsId` on first launch.\n */\nexport class AnalyticsController extends BaseController<\n 'AnalyticsController',\n AnalyticsControllerState,\n AnalyticsControllerMessenger\n> {\n readonly #platformAdapter: AnalyticsPlatformAdapter;\n\n readonly #isAnonymousEventsFeatureEnabled: boolean;\n\n readonly #isEventQueuePersistenceEnabled: boolean;\n\n readonly #isPreConsentQueueEnabled: boolean;\n\n readonly #isGeolocationEnabled: boolean;\n\n /**\n * The in-flight (or settled) initialization promise. Set on the first\n * {@link init} call and returned by subsequent calls so overlapping callers\n * await the same work rather than observing a premature completion.\n */\n #initPromise: Promise<void> | undefined;\n\n /**\n * The in-flight (or settled) geolocation resolution, if any. Its presence\n * marks that resolution has been started, so it runs at most once.\n */\n #locationResolvePromise: Promise<void> | undefined;\n\n #locationContext: AnalyticsLocationContext | undefined;\n\n /**\n * Constructs an AnalyticsController instance.\n *\n * @param options - Controller options\n * @param options.state - Initial controller state. Must include a valid UUIDv4 `analyticsId`.\n * Use `getDefaultAnalyticsControllerState()` for default opt-in preferences.\n * @param options.messenger - Messenger used to communicate with BaseController\n * @param options.platformAdapter - Platform adapter implementation for tracking\n * @param options.isAnonymousEventsFeatureEnabled - Whether the anonymous events feature is enabled\n * @param options.isEventQueuePersistenceEnabled - Whether analytics event queue persistence is enabled\n * @param options.isPreConsentQueueEnabled - Whether the pre-consent event queue is enabled\n * @param options.isGeolocationEnabled - Whether geolocation enrichment is enabled\n * @throws Error if state.analyticsId is missing or not a valid UUIDv4\n * @remarks After construction, call {@link AnalyticsController.init} to complete initialization.\n */\n constructor({\n state,\n messenger,\n platformAdapter,\n isAnonymousEventsFeatureEnabled = false,\n isEventQueuePersistenceEnabled = false,\n isPreConsentQueueEnabled = false,\n isGeolocationEnabled = false,\n }: AnalyticsControllerOptions) {\n const initialState: AnalyticsControllerState = {\n ...getDefaultAnalyticsControllerState(),\n ...state,\n };\n\n validateAnalyticsControllerState(\n initialState,\n platformAdapter.skipUUIDv4Check === true,\n );\n\n super({\n name: controllerName,\n metadata: analyticsControllerMetadata,\n state: initialState,\n messenger,\n });\n\n this.#isAnonymousEventsFeatureEnabled = isAnonymousEventsFeatureEnabled;\n this.#isEventQueuePersistenceEnabled = isEventQueuePersistenceEnabled;\n this.#isPreConsentQueueEnabled = isPreConsentQueueEnabled;\n this.#isGeolocationEnabled = isGeolocationEnabled;\n this.#platformAdapter = platformAdapter;\n this.#initPromise = undefined;\n this.#locationResolvePromise = undefined;\n\n this.messenger.registerMethodActionHandlers(\n this,\n MESSENGER_EXPOSED_METHODS,\n );\n\n log('AnalyticsController initialized and ready', {\n enabled: analyticsControllerSelectors.selectEnabled(this.state),\n optedIn: this.state.optedIn,\n consentDecisionMade: this.state.consentDecisionMade,\n analyticsId: this.state.analyticsId,\n eventQueuePersistenceEnabled: this.#isEventQueuePersistenceEnabled,\n preConsentQueueEnabled: this.#isPreConsentQueueEnabled,\n geolocationEnabled: this.#isGeolocationEnabled,\n });\n }\n\n /**\n * Initialize the controller by calling the platform adapter's\n * onSetupCompleted lifecycle hook and replaying any queued events. This\n * method must be called after construction to complete the setup process.\n *\n * When geolocation enrichment is enabled (`isGeolocationEnabled`), geolocation\n * is resolved only for a user who is already opted in; for undecided or\n * opted-out users it is deferred until they opt in (see {@link optIn}), so a\n * user's location is never requested before they consent to analytics. In\n * either case the `GeolocationController` and its\n * `GeolocationController:getGeolocationData` action must be registered before\n * resolution occurs, or enrichment is skipped for the session (a message is\n * logged, see {@link #resolveLocationContext}).\n *\n * Safe to call more than once: the first call performs initialization and\n * subsequent calls return the same in-flight (or settled) promise.\n *\n * @returns A promise that resolves once initialization has completed.\n */\n init(): Promise<void> {\n // Cache the in-flight promise so repeated or overlapping calls share a\n // single initialization and all await the same completion (rather than an\n // early call observing a finished init while work is still pending).\n this.#initPromise ??= this.#performInit();\n return this.#initPromise;\n }\n\n /**\n * Performs the one-time initialization work: resolve geolocation, run the\n * platform adapter's onSetupCompleted lifecycle hook, then replay any queued\n * and pre-consent events.\n */\n async #performInit(): Promise<void> {\n // Resolve geolocation only when the user is already opted in; for undecided\n // or opted-out users it is deferred to {@link optIn}. Awaited so that an\n // already-opted-in session has location available before events replay.\n await this.#maybeResolveLocation();\n\n // Call onSetupCompleted lifecycle hook after initialization\n // State is already validated, so analyticsId is guaranteed to be a valid UUIDv4\n try {\n this.#platformAdapter.onSetupCompleted(this.state.analyticsId);\n } catch (error) {\n // Log error but don't throw - adapter setup failure shouldn't break controller\n log('Error calling platformAdapter.onSetupCompleted', error);\n }\n\n this.#replayQueuedEvents();\n this.#reconcilePreConsentEvents();\n }\n\n /**\n * Start resolving the geolocation context if warranted, and return the\n * in-flight (or settled) resolution so callers can await it. No-op unless\n * enrichment is enabled, the user is opted in, and a resolution has not\n * already been started. Deferring resolution until opt-in ensures a user's\n * location is never requested before they consent to analytics (for example,\n * during onboarding).\n *\n * Resolution runs at most once per controller session: the settled promise\n * is retained, so the outcome — including a failure (see\n * {@link #resolveLocationContext}) — is not retried, and events are delivered\n * without location for the rest of the session.\n *\n * @returns The geolocation resolution promise, or `undefined` when no\n * resolution is warranted.\n */\n #maybeResolveLocation(): Promise<void> | undefined {\n if (\n this.#isGeolocationEnabled &&\n this.#locationResolvePromise === undefined &&\n analyticsControllerSelectors.selectEnabled(this.state)\n ) {\n this.#locationResolvePromise = this.#resolveLocationContext();\n }\n\n return this.#locationResolvePromise;\n }\n\n async #resolveLocationContext(): Promise<void> {\n try {\n const geolocation = await this.messenger.call(\n 'GeolocationController:getGeolocationData',\n );\n\n this.#locationContext = buildLocationContext(geolocation);\n } catch (error) {\n // A common cause is the GeolocationController not being registered before\n // resolution runs (at init for an opted-in user, otherwise at opt-in).\n // Name it here so the failure is diagnosable, since enrichment is\n // otherwise skipped silently for the session.\n log(\n 'Failed to resolve geolocation for analytics enrichment; events will be sent without location. Ensure the GeolocationController is registered and initialized before the user opts in when geolocation is enabled.',\n error,\n );\n }\n }\n\n /**\n * Merge the resolved location context into a caller-provided context.\n *\n * Caller-provided `location` fields are preserved, but the fields the\n * controller resolves take precedence over them.\n *\n * @param context - Optional caller-provided context.\n * @returns The context enriched with location, or the original context when\n * no location is known.\n */\n #withLocationContext(\n context?: AnalyticsContext,\n ): AnalyticsContext | undefined {\n if (!this.#locationContext) {\n return context;\n }\n\n const callerLocation = context?.location;\n\n return {\n ...context,\n location: {\n ...(isJsonRecord(callerLocation) ? callerLocation : {}),\n ...this.#locationContext,\n },\n };\n }\n\n /**\n * Send final track payload through the platform adapter or queue it if persistence is enabled.\n *\n * @param eventName - The name of the event.\n * @param properties - Optional event properties.\n * @param context - Optional platform-specific context.\n */\n #sendOrQueueTrackEvent(\n eventName: string,\n properties?: AnalyticsEventProperties,\n context?: AnalyticsContext,\n ): void {\n // Direct delivery: enabled and not persisting.\n if (\n analyticsControllerSelectors.selectEnabled(this.state) &&\n !this.#isEventQueuePersistenceEnabled\n ) {\n this.#platformAdapter.track(eventName, properties, context);\n return;\n }\n\n const queuedEvent: AnalyticsQueuedTrackEvent = {\n type: 'track',\n eventName,\n messageId: uuid(),\n timestamp: new Date().toISOString(),\n ...(properties === undefined ? {} : { properties }),\n ...(context === undefined ? {} : { context }),\n };\n\n // Not yet enabled (reached only while undecided with the pre-consent queue\n // enabled): hold the event until the user opts in.\n if (!analyticsControllerSelectors.selectEnabled(this.state)) {\n this.#enqueuePreConsentEvent(queuedEvent);\n return;\n }\n\n this.#enqueueEvent(queuedEvent);\n }\n\n /**\n * Send final identify payload through the platform adapter or queue it if persistence is enabled.\n *\n * @param userId - The user ID.\n * @param traits - Optional user traits.\n * @param context - Optional platform-specific context.\n */\n #sendOrQueueIdentifyEvent(\n userId: string,\n traits?: AnalyticsUserTraits,\n context?: AnalyticsContext,\n ): void {\n if (!this.#isEventQueuePersistenceEnabled) {\n this.#platformAdapter.identify(userId, traits, context);\n return;\n }\n\n const queuedEvent: AnalyticsQueuedIdentifyEvent = {\n type: 'identify',\n userId,\n messageId: uuid(),\n timestamp: new Date().toISOString(),\n ...(traits === undefined ? {} : { traits }),\n ...(context === undefined ? {} : { context }),\n };\n\n this.#enqueueEvent(queuedEvent);\n }\n\n /**\n * Send final view payload through the platform adapter or queue it if persistence is enabled.\n *\n * @param name - The view name.\n * @param properties - Optional view properties.\n * @param context - Optional platform-specific context.\n */\n #sendOrQueueViewEvent(\n name: string,\n properties?: AnalyticsEventProperties,\n context?: AnalyticsContext,\n ): void {\n if (!this.#isEventQueuePersistenceEnabled) {\n this.#platformAdapter.view(name, properties, context);\n return;\n }\n\n const queuedEvent: AnalyticsQueuedViewEvent = {\n type: 'view',\n name,\n messageId: uuid(),\n timestamp: new Date().toISOString(),\n ...(properties === undefined ? {} : { properties }),\n ...(context === undefined ? {} : { context }),\n };\n\n this.#enqueueEvent(queuedEvent);\n }\n\n /**\n * Add an analytics event to the queue and send it.\n *\n * @param queuedEvent - The event to enqueue and deliver.\n */\n #enqueueEvent(queuedEvent: AnalyticsQueuedEvent): void {\n const eventQueue: Record<string, Json> = {\n ...(this.state.eventQueue ?? {}),\n [queuedEvent.messageId]: queuedEvent as unknown as Json,\n };\n\n this.update((state) => {\n state.eventQueue = eventQueue as never;\n });\n\n this.#sendQueuedEvent(queuedEvent);\n }\n\n /**\n * Send a queued event through the platform adapter.\n *\n * @param queuedEvent - The queued event to deliver.\n */\n #sendQueuedEvent(queuedEvent: AnalyticsQueuedEvent): void {\n const timestamp = new Date(queuedEvent.timestamp);\n\n if (Number.isNaN(timestamp.getTime())) {\n log('Dropping queued analytics event with invalid timestamp', {\n messageId: queuedEvent.messageId,\n });\n this.#removeQueuedEvent(queuedEvent.messageId);\n return;\n }\n\n const options: AnalyticsDeliveryOptions = {\n messageId: queuedEvent.messageId,\n timestamp,\n callback: (error?: unknown) => {\n if (error) {\n log('Queued analytics event delivery failed', {\n messageId: queuedEvent.messageId,\n error,\n });\n }\n\n this.#removeQueuedEvent(queuedEvent.messageId);\n },\n };\n\n try {\n if (queuedEvent.type === 'track') {\n this.#platformAdapter.track(\n queuedEvent.eventName,\n cloneDeep(queuedEvent.properties),\n cloneDeep(queuedEvent.context),\n options,\n );\n } else if (queuedEvent.type === 'identify') {\n this.#platformAdapter.identify(\n queuedEvent.userId,\n cloneDeep(queuedEvent.traits),\n cloneDeep(queuedEvent.context),\n options,\n );\n } else {\n this.#platformAdapter.view(\n queuedEvent.name,\n cloneDeep(queuedEvent.properties),\n cloneDeep(queuedEvent.context),\n options,\n );\n }\n } catch (error) {\n log('Error sending queued analytics event', {\n messageId: queuedEvent.messageId,\n error,\n });\n }\n }\n\n /**\n * Replay persisted analytics events.\n */\n #replayQueuedEvents(): void {\n if (!this.#isEventQueuePersistenceEnabled || !this.state.eventQueue) {\n return;\n }\n\n if (!analyticsControllerSelectors.selectEnabled(this.state)) {\n this.#clearQueuedEvents();\n return;\n }\n\n for (const [messageId, queuedEvent] of Object.entries(\n this.state.eventQueue,\n )) {\n if (\n !isAnalyticsQueuedEvent(queuedEvent) ||\n queuedEvent.messageId !== messageId\n ) {\n log('Dropping invalid queued analytics event', { messageId });\n this.#removeQueuedEvent(messageId);\n continue;\n }\n\n this.#sendQueuedEvent(queuedEvent);\n }\n }\n\n /**\n * Remove a queued analytics event.\n *\n * @param messageId - The queued event message ID.\n */\n #removeQueuedEvent(messageId: string): void {\n const currentEventQueue = this.state.eventQueue;\n\n if (\n !currentEventQueue ||\n !Object.prototype.hasOwnProperty.call(currentEventQueue, messageId)\n ) {\n return;\n }\n\n const { [messageId]: _deletedEvent, ...eventQueue } = currentEventQueue;\n\n this.update((state) => {\n state.eventQueue = eventQueue as never;\n });\n }\n\n /**\n * Clear all queued analytics events.\n */\n #clearQueuedEvents(): void {\n if (\n !this.state.eventQueue ||\n Object.keys(this.state.eventQueue).length === 0\n ) {\n return;\n }\n\n this.update((state) => {\n state.eventQueue = {} as never;\n });\n }\n\n /**\n * Add an event to the pre-consent queue without delivering it.\n *\n * @param queuedEvent - The event to hold until the user opts in.\n */\n #enqueuePreConsentEvent(queuedEvent: AnalyticsQueuedEvent): void {\n const preConsentEventQueue: Record<string, Json> = {\n ...(this.state.preConsentEventQueue ?? {}),\n [queuedEvent.messageId]: queuedEvent as unknown as Json,\n };\n\n this.update((state) => {\n state.preConsentEventQueue = preConsentEventQueue as never;\n });\n }\n\n /**\n * Replay queued pre-consent events through the delivery path.\n *\n * Only called by {@link #reconcilePreConsentEvents}, which guarantees the\n * pre-consent queue is enabled and that the user is opted in. The queue is\n * cleared before replaying so events cannot be re-queued or replayed twice.\n *\n * @param queue - The pre-consent event queue to replay.\n */\n #replayPreConsentEvents(queue: Record<string, Json>): void {\n this.#clearPreConsentEvents();\n\n for (const [messageId, queuedEvent] of Object.entries(queue)) {\n if (\n !isAnalyticsQueuedEvent(queuedEvent) ||\n queuedEvent.messageId !== messageId\n ) {\n log('Dropping invalid queued pre-consent analytics event', {\n messageId,\n });\n continue;\n }\n\n const eventToReplay = this.#enrichPreConsentEvent(queuedEvent);\n\n if (this.#isEventQueuePersistenceEnabled) {\n this.#enqueueEvent(eventToReplay);\n } else {\n this.#sendQueuedEvent(eventToReplay);\n }\n }\n }\n\n /**\n * Enrich a pre-consent event with the geolocation resolved on opt-in.\n *\n * Pre-consent events are captured while geolocation is not yet resolved, so\n * they are re-enriched here as they replay. Anonymous track payloads are left\n * untouched, since they must never carry location.\n *\n * @param queuedEvent - The queued pre-consent event.\n * @returns The event with its context enriched, or the event unchanged when\n * enrichment does not apply.\n */\n #enrichPreConsentEvent(\n queuedEvent: AnalyticsQueuedEvent,\n ): AnalyticsQueuedEvent {\n if (\n queuedEvent.type === 'track' &&\n queuedEvent.properties?.anonymous === true\n ) {\n return queuedEvent;\n }\n\n const context = this.#withLocationContext(queuedEvent.context);\n\n return {\n ...queuedEvent,\n ...(context === undefined ? {} : { context }),\n };\n }\n\n /**\n * Clear all queued pre-consent events.\n */\n #clearPreConsentEvents(): void {\n if (!this.state.preConsentEventQueue) {\n return;\n }\n\n this.update((state) => {\n state.preConsentEventQueue = {} as never;\n });\n }\n\n /**\n * Reconcile the pre-consent queue on initialization.\n *\n * The queue should normally be empty unless the user is still undecided. This\n * handles the rare cases where a consent decision was persisted but the queue\n * was not flushed/cleared (e.g. an interrupted shutdown): replay it if the\n * user is opted in, or clear it if they opted out.\n *\n * If the pre-consent queue is disabled, any stale persisted entries (e.g. from\n * a previous session where it was enabled) are dropped so they can never be\n * replayed.\n */\n #reconcilePreConsentEvents(): void {\n const queue = this.state.preConsentEventQueue;\n\n if (!queue) {\n return;\n }\n\n if (!this.#isPreConsentQueueEnabled) {\n this.#clearPreConsentEvents();\n return;\n }\n\n if (this.state.optedIn) {\n this.#replayPreConsentEvents(queue);\n } else if (this.state.consentDecisionMade) {\n this.#clearPreConsentEvents();\n }\n }\n\n /**\n * Track an analytics event.\n *\n * Events are only tracked if analytics is enabled.\n *\n * @param event - Analytics event with properties and sensitive properties\n * @param context - Optional platform-specific context forwarded to the platform adapter.\n */\n trackEvent(event: AnalyticsTrackingEvent, context?: AnalyticsContext): void {\n if (!analyticsControllerSelectors.selectEnabled(this.state)) {\n // While the user is undecided, fall through so the event is processed and\n // captured in the pre-consent queue (see #sendOrQueueTrackEvent) to be\n // replayed if they later opt in. Otherwise (opted out, or pre-consent\n // queue disabled) drop it.\n const shouldQueuePreConsent =\n this.#isPreConsentQueueEnabled && !this.state.consentDecisionMade;\n if (!shouldQueuePreConsent) {\n return;\n }\n }\n\n // if event does not have properties, send event without properties\n // and return to prevent any additional processing\n if (!event.hasProperties) {\n this.#sendOrQueueTrackEvent(\n event.name,\n undefined,\n this.#withLocationContext(context),\n );\n return;\n }\n\n // Track regular properties first if anonymous events feature is enabled\n if (this.#isAnonymousEventsFeatureEnabled) {\n // Note: Even if regular properties object is empty, we still send it to ensure\n // an event with user ID is tracked.\n this.#sendOrQueueTrackEvent(\n event.name,\n {\n ...event.properties,\n },\n this.#withLocationContext(context),\n );\n }\n\n const hasSensitiveProperties =\n Object.keys(event.sensitiveProperties).length > 0;\n\n if (!this.#isAnonymousEventsFeatureEnabled || hasSensitiveProperties) {\n this.#sendOrQueueTrackEvent(\n event.name,\n {\n ...event.properties,\n ...event.sensitiveProperties,\n ...(hasSensitiveProperties && { anonymous: true }),\n },\n // When the anonymous events feature is enabled, this payload is the\n // anonymous one and must carry no geolocation. When the feature is\n // disabled, this is the single identified payload, so it is enriched.\n this.#isAnonymousEventsFeatureEnabled\n ? context\n : this.#withLocationContext(context),\n );\n }\n }\n\n /**\n * Identify a user for analytics.\n *\n * @param traits - User traits/properties\n * @param context - Optional platform-specific context forwarded to the platform adapter.\n */\n identify(traits?: AnalyticsUserTraits, context?: AnalyticsContext): void {\n if (!analyticsControllerSelectors.selectEnabled(this.state)) {\n return;\n }\n\n // Delegate to platform adapter using the current analytics ID\n this.#sendOrQueueIdentifyEvent(\n this.state.analyticsId,\n traits,\n this.#withLocationContext(context),\n );\n }\n\n /**\n * Track a page or screen view.\n *\n * @param name - The identifier/name of the page or screen being viewed (e.g., \"home\", \"settings\", \"wallet\")\n * @param properties - Optional properties associated with the view\n * @param context - Optional platform-specific context forwarded to the platform adapter.\n */\n trackView(\n name: string,\n properties?: AnalyticsEventProperties,\n context?: AnalyticsContext,\n ): void {\n if (!analyticsControllerSelectors.selectEnabled(this.state)) {\n return;\n }\n\n // Delegate to platform adapter\n this.#sendOrQueueViewEvent(\n name,\n properties,\n this.#withLocationContext(context),\n );\n }\n\n /**\n * Opt in to analytics.\n *\n * Records that a consent decision has been made and replays any events that\n * were queued while the user was undecided.\n *\n * When geolocation enrichment is enabled, geolocation is resolved here (once\n * the user has consented) and awaited before the queued events are replayed,\n * so those events are enriched with the resolved location as they are sent.\n *\n * @returns A promise that resolves once opt-in processing has completed.\n */\n async optIn(): Promise<void> {\n this.update((state) => {\n state.optedIn = true;\n state.consentDecisionMade = true;\n });\n\n // Now that the user has consented, resolve geolocation (once) and wait for\n // it so the queued pre-consent events can be enriched as they replay.\n await this.#maybeResolveLocation();\n\n // Reconcile against the current state rather than replaying blindly: the\n // consent decision may have changed while geolocation was resolving (e.g.\n // resetConsentDecision ran during the await), and preserved pre-consent\n // events must not be delivered once the user is no longer opted in.\n this.#reconcilePreConsentEvents();\n }\n\n /**\n * Opt out of analytics.\n *\n * Records that a consent decision has been made and discards any persisted\n * events so nothing captured before the decision is ever delivered.\n */\n optOut(): void {\n this.update((state) => {\n state.optedIn = false;\n state.consentDecisionMade = true;\n });\n\n this.#clearQueuedEvents();\n this.#clearPreConsentEvents();\n }\n\n /**\n * Reset the consent decision back to undecided.\n *\n * Intended for client flows that restart onboarding. Clears the opt-in\n * preference and discards the delivery queue, but preserves any pre-consent\n * events so they can still be replayed if the user opts in again. The user is\n * treated as undecided again.\n */\n resetConsentDecision(): void {\n this.update((state) => {\n state.optedIn = false;\n state.consentDecisionMade = false;\n });\n\n this.#clearQueuedEvents();\n }\n}\n"]} |
| import type { ControllerGetStateAction, ControllerStateChangeEvent } from "@metamask/base-controller"; | ||
| import { BaseController } from "@metamask/base-controller"; | ||
| import type { GeolocationControllerGetGeolocationDataAction } from "@metamask/geolocation-controller"; | ||
| import type { Messenger } from "@metamask/messenger"; | ||
@@ -129,3 +130,3 @@ import type { Json } from "@metamask/utils"; | ||
| */ | ||
| type AllowedActions = never; | ||
| type AllowedActions = GeolocationControllerGetGeolocationDataAction; | ||
| /** | ||
@@ -192,2 +193,15 @@ * Event emitted when the state of the {@link AnalyticsController} changes. | ||
| isPreConsentQueueEnabled?: boolean; | ||
| /** | ||
| * Whether geolocation enrichment is enabled. | ||
| * | ||
| * When enabled, {@link AnalyticsController.init} resolves the user's | ||
| * country, region, and timezone via `GeolocationController:getGeolocationData` | ||
| * and attaches them to `context.location` on non-anonymous payloads. | ||
| * Compositions must register that action when this is enabled. When disabled, | ||
| * the controller never calls the geolocation action and events are delivered | ||
| * without location. | ||
| * | ||
| * @default false | ||
| */ | ||
| isGeolocationEnabled?: boolean; | ||
| }; | ||
@@ -220,11 +234,27 @@ /** | ||
| * @param options.isPreConsentQueueEnabled - Whether the pre-consent event queue is enabled | ||
| * @param options.isGeolocationEnabled - Whether geolocation enrichment is enabled | ||
| * @throws Error if state.analyticsId is missing or not a valid UUIDv4 | ||
| * @remarks After construction, call {@link AnalyticsController.init} to complete initialization. | ||
| */ | ||
| constructor({ state, messenger, platformAdapter, isAnonymousEventsFeatureEnabled, isEventQueuePersistenceEnabled, isPreConsentQueueEnabled, }: AnalyticsControllerOptions); | ||
| constructor({ state, messenger, platformAdapter, isAnonymousEventsFeatureEnabled, isEventQueuePersistenceEnabled, isPreConsentQueueEnabled, isGeolocationEnabled, }: AnalyticsControllerOptions); | ||
| /** | ||
| * Initialize the controller by calling the platform adapter's onSetupCompleted lifecycle hook. | ||
| * This method must be called after construction to complete the setup process. | ||
| * Initialize the controller by calling the platform adapter's | ||
| * onSetupCompleted lifecycle hook and replaying any queued events. This | ||
| * method must be called after construction to complete the setup process. | ||
| * | ||
| * When geolocation enrichment is enabled (`isGeolocationEnabled`), geolocation | ||
| * is resolved only for a user who is already opted in; for undecided or | ||
| * opted-out users it is deferred until they opt in (see {@link optIn}), so a | ||
| * user's location is never requested before they consent to analytics. In | ||
| * either case the `GeolocationController` and its | ||
| * `GeolocationController:getGeolocationData` action must be registered before | ||
| * resolution occurs, or enrichment is skipped for the session (a message is | ||
| * logged, see {@link #resolveLocationContext}). | ||
| * | ||
| * Safe to call more than once: the first call performs initialization and | ||
| * subsequent calls return the same in-flight (or settled) promise. | ||
| * | ||
| * @returns A promise that resolves once initialization has completed. | ||
| */ | ||
| init(): void; | ||
| init(): Promise<void>; | ||
| /** | ||
@@ -259,4 +289,10 @@ * Track an analytics event. | ||
| * were queued while the user was undecided. | ||
| * | ||
| * When geolocation enrichment is enabled, geolocation is resolved here (once | ||
| * the user has consented) and awaited before the queued events are replayed, | ||
| * so those events are enriched with the resolved location as they are sent. | ||
| * | ||
| * @returns A promise that resolves once opt-in processing has completed. | ||
| */ | ||
| optIn(): void; | ||
| optIn(): Promise<void>; | ||
| /** | ||
@@ -263,0 +299,0 @@ * Opt out of analytics. |
@@ -1,1 +0,1 @@ | ||
| {"version":3,"file":"AnalyticsController.d.cts","sourceRoot":"","sources":["../src/AnalyticsController.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,wBAAwB,EACxB,0BAA0B,EAE3B,kCAAkC;AACnC,OAAO,EAAE,cAAc,EAAE,kCAAkC;AAC3D,OAAO,KAAK,EAAE,SAAS,EAAE,4BAA4B;AACrD,OAAO,KAAK,EAAE,IAAI,EAAE,wBAAwB;AAI5C,OAAO,KAAK,EAAE,gCAAgC,EAAE,sDAAkD;AAGlG,OAAO,KAAK,EACV,wBAAwB,EAExB,gBAAgB,EAChB,wBAAwB,EACxB,mBAAmB,EACnB,sBAAsB,EACvB,6CAAyC;AAK1C;;;;GAIG;AACH,eAAO,MAAM,cAAc,wBAAwB,CAAC;AAIpD;;GAEG;AACH,MAAM,MAAM,wBAAwB,GAAG;IACrC;;OAEG;IACH,OAAO,EAAE,OAAO,CAAC;IAEjB;;;;OAIG;IACH,WAAW,EAAE,MAAM,CAAC;IAEpB;;;OAGG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;IAElC;;;;;;;;;OASG;IACH,mBAAmB,CAAC,EAAE,OAAO,CAAC;IAE9B;;;;;;;OAOG;IACH,oBAAoB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;CAC7C,CAAC;AAEF;;GAEG;AACH,MAAM,MAAM,wBAAwB,GAAG,OAAO,GAAG,UAAU,GAAG,MAAM,CAAC;AAErE;;GAEG;AACH,MAAM,MAAM,wBAAwB,GAAG;IACrC;;OAEG;IACH,IAAI,EAAE,wBAAwB,CAAC;IAE/B;;OAEG;IACH,SAAS,EAAE,MAAM,CAAC;IAElB;;OAEG;IACH,SAAS,EAAE,MAAM,CAAC;CACnB,CAAC;AAEF;;GAEG;AACH,MAAM,MAAM,yBAAyB,GAAG,wBAAwB,GAAG;IACjE,IAAI,EAAE,OAAO,CAAC;IACd,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,CAAC,EAAE,wBAAwB,CAAC;IACtC,OAAO,CAAC,EAAE,gBAAgB,CAAC;CAC5B,CAAC;AAEF;;GAEG;AACH,MAAM,MAAM,4BAA4B,GAAG,wBAAwB,GAAG;IACpE,IAAI,EAAE,UAAU,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,mBAAmB,CAAC;IAC7B,OAAO,CAAC,EAAE,gBAAgB,CAAC;CAC5B,CAAC;AAEF;;GAEG;AACH,MAAM,MAAM,wBAAwB,GAAG,wBAAwB,GAAG;IAChE,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,CAAC,EAAE,wBAAwB,CAAC;IACtC,OAAO,CAAC,EAAE,gBAAgB,CAAC;CAC5B,CAAC;AAEF;;GAEG;AACH,MAAM,MAAM,oBAAoB,GAC5B,yBAAyB,GACzB,4BAA4B,GAC5B,wBAAwB,CAAC;AAE7B;;GAEG;AACH,MAAM,MAAM,mBAAmB,GAAG,MAAM,CAAC,MAAM,EAAE,oBAAoB,CAAC,CAAC;AAEvE;;;;;;;GAOG;AACH,wBAAgB,kCAAkC,IAAI,IAAI,CACxD,wBAAwB,EACxB,aAAa,CACd,CAKA;AAoDD;;GAEG;AACH,MAAM,MAAM,iCAAiC,GAAG,wBAAwB,CACtE,OAAO,cAAc,EACrB,wBAAwB,CACzB,CAAC;AAEF;;GAEG;AACH,MAAM,MAAM,0BAA0B,GAClC,iCAAiC,GACjC,gCAAgC,CAAC;AAErC;;GAEG;AACH,KAAK,cAAc,GAAG,KAAK,CAAC;AAE5B;;GAEG;AACH,MAAM,MAAM,mCAAmC,GAAG,0BAA0B,CAC1E,OAAO,cAAc,EACrB,wBAAwB,CACzB,CAAC;AAEF;;GAEG;AACH,MAAM,MAAM,yBAAyB,GAAG,mCAAmC,CAAC;AAE5E;;GAEG;AACH,KAAK,aAAa,GAAG,KAAK,CAAC;AAE3B;;;GAGG;AACH,MAAM,MAAM,4BAA4B,GAAG,SAAS,CAClD,OAAO,cAAc,EACrB,0BAA0B,GAAG,cAAc,EAC3C,yBAAyB,GAAG,aAAa,CAC1C,CAAC;AAIF;;GAEG;AACH,MAAM,MAAM,0BAA0B,GAAG;IACvC;;;;OAIG;IACH,KAAK,EAAE,wBAAwB,CAAC;IAChC;;OAEG;IACH,SAAS,EAAE,4BAA4B,CAAC;IACxC;;OAEG;IACH,eAAe,EAAE,wBAAwB,CAAC;IAE1C;;;;OAIG;IACH,+BAA+B,CAAC,EAAE,OAAO,CAAC;IAE1C;;;;;;;OAOG;IACH,8BAA8B,CAAC,EAAE,OAAO,CAAC;IAEzC;;;;;;;;;OASG;IACH,wBAAwB,CAAC,EAAE,OAAO,CAAC;CACpC,CAAC;AAyDF;;;;;;;;;;;;GAYG;AACH,qBAAa,mBAAoB,SAAQ,cAAc,CACrD,qBAAqB,EACrB,wBAAwB,EACxB,4BAA4B,CAC7B;;IAWC;;;;;;;;;;;;;OAaG;gBACS,EACV,KAAK,EACL,SAAS,EACT,eAAe,EACf,+BAAuC,EACvC,8BAAsC,EACtC,wBAAgC,GACjC,EAAE,0BAA0B;IAuC7B;;;OAGG;IACH,IAAI,IAAI,IAAI;IA4WZ;;;;;;;OAOG;IACH,UAAU,CAAC,KAAK,EAAE,sBAAsB,EAAE,OAAO,CAAC,EAAE,gBAAgB,GAAG,IAAI;IAiD3E;;;;;OAKG;IACH,QAAQ,CAAC,MAAM,CAAC,EAAE,mBAAmB,EAAE,OAAO,CAAC,EAAE,gBAAgB,GAAG,IAAI;IASxE;;;;;;OAMG;IACH,SAAS,CACP,IAAI,EAAE,MAAM,EACZ,UAAU,CAAC,EAAE,wBAAwB,EACrC,OAAO,CAAC,EAAE,gBAAgB,GACzB,IAAI;IASP;;;;;OAKG;IACH,KAAK,IAAI,IAAI;IASb;;;;;OAKG;IACH,MAAM,IAAI,IAAI;IAUd;;;;;;;OAOG;IACH,oBAAoB,IAAI,IAAI;CAQ7B"} | ||
| {"version":3,"file":"AnalyticsController.d.cts","sourceRoot":"","sources":["../src/AnalyticsController.ts"],"names":[],"mappings":"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"} |
| import type { ControllerGetStateAction, ControllerStateChangeEvent } from "@metamask/base-controller"; | ||
| import { BaseController } from "@metamask/base-controller"; | ||
| import type { GeolocationControllerGetGeolocationDataAction } from "@metamask/geolocation-controller"; | ||
| import type { Messenger } from "@metamask/messenger"; | ||
@@ -129,3 +130,3 @@ import type { Json } from "@metamask/utils"; | ||
| */ | ||
| type AllowedActions = never; | ||
| type AllowedActions = GeolocationControllerGetGeolocationDataAction; | ||
| /** | ||
@@ -192,2 +193,15 @@ * Event emitted when the state of the {@link AnalyticsController} changes. | ||
| isPreConsentQueueEnabled?: boolean; | ||
| /** | ||
| * Whether geolocation enrichment is enabled. | ||
| * | ||
| * When enabled, {@link AnalyticsController.init} resolves the user's | ||
| * country, region, and timezone via `GeolocationController:getGeolocationData` | ||
| * and attaches them to `context.location` on non-anonymous payloads. | ||
| * Compositions must register that action when this is enabled. When disabled, | ||
| * the controller never calls the geolocation action and events are delivered | ||
| * without location. | ||
| * | ||
| * @default false | ||
| */ | ||
| isGeolocationEnabled?: boolean; | ||
| }; | ||
@@ -220,11 +234,27 @@ /** | ||
| * @param options.isPreConsentQueueEnabled - Whether the pre-consent event queue is enabled | ||
| * @param options.isGeolocationEnabled - Whether geolocation enrichment is enabled | ||
| * @throws Error if state.analyticsId is missing or not a valid UUIDv4 | ||
| * @remarks After construction, call {@link AnalyticsController.init} to complete initialization. | ||
| */ | ||
| constructor({ state, messenger, platformAdapter, isAnonymousEventsFeatureEnabled, isEventQueuePersistenceEnabled, isPreConsentQueueEnabled, }: AnalyticsControllerOptions); | ||
| constructor({ state, messenger, platformAdapter, isAnonymousEventsFeatureEnabled, isEventQueuePersistenceEnabled, isPreConsentQueueEnabled, isGeolocationEnabled, }: AnalyticsControllerOptions); | ||
| /** | ||
| * Initialize the controller by calling the platform adapter's onSetupCompleted lifecycle hook. | ||
| * This method must be called after construction to complete the setup process. | ||
| * Initialize the controller by calling the platform adapter's | ||
| * onSetupCompleted lifecycle hook and replaying any queued events. This | ||
| * method must be called after construction to complete the setup process. | ||
| * | ||
| * When geolocation enrichment is enabled (`isGeolocationEnabled`), geolocation | ||
| * is resolved only for a user who is already opted in; for undecided or | ||
| * opted-out users it is deferred until they opt in (see {@link optIn}), so a | ||
| * user's location is never requested before they consent to analytics. In | ||
| * either case the `GeolocationController` and its | ||
| * `GeolocationController:getGeolocationData` action must be registered before | ||
| * resolution occurs, or enrichment is skipped for the session (a message is | ||
| * logged, see {@link #resolveLocationContext}). | ||
| * | ||
| * Safe to call more than once: the first call performs initialization and | ||
| * subsequent calls return the same in-flight (or settled) promise. | ||
| * | ||
| * @returns A promise that resolves once initialization has completed. | ||
| */ | ||
| init(): void; | ||
| init(): Promise<void>; | ||
| /** | ||
@@ -259,4 +289,10 @@ * Track an analytics event. | ||
| * were queued while the user was undecided. | ||
| * | ||
| * When geolocation enrichment is enabled, geolocation is resolved here (once | ||
| * the user has consented) and awaited before the queued events are replayed, | ||
| * so those events are enriched with the resolved location as they are sent. | ||
| * | ||
| * @returns A promise that resolves once opt-in processing has completed. | ||
| */ | ||
| optIn(): void; | ||
| optIn(): Promise<void>; | ||
| /** | ||
@@ -263,0 +299,0 @@ * Opt out of analytics. |
@@ -1,1 +0,1 @@ | ||
| {"version":3,"file":"AnalyticsController.d.mts","sourceRoot":"","sources":["../src/AnalyticsController.ts"],"names":[],"mappings":"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"} | ||
| {"version":3,"file":"AnalyticsController.d.mts","sourceRoot":"","sources":["../src/AnalyticsController.ts"],"names":[],"mappings":"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"} |
+167
-41
@@ -12,3 +12,3 @@ var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) { | ||
| }; | ||
| var _AnalyticsController_instances, _AnalyticsController_platformAdapter, _AnalyticsController_isAnonymousEventsFeatureEnabled, _AnalyticsController_isEventQueuePersistenceEnabled, _AnalyticsController_isPreConsentQueueEnabled, _AnalyticsController_initialized, _AnalyticsController_sendOrQueueTrackEvent, _AnalyticsController_sendOrQueueIdentifyEvent, _AnalyticsController_sendOrQueueViewEvent, _AnalyticsController_enqueueEvent, _AnalyticsController_sendQueuedEvent, _AnalyticsController_replayQueuedEvents, _AnalyticsController_removeQueuedEvent, _AnalyticsController_clearQueuedEvents, _AnalyticsController_enqueuePreConsentEvent, _AnalyticsController_replayPreConsentEvents, _AnalyticsController_clearPreConsentEvents, _AnalyticsController_reconcilePreConsentEvents; | ||
| var _AnalyticsController_instances, _AnalyticsController_platformAdapter, _AnalyticsController_isAnonymousEventsFeatureEnabled, _AnalyticsController_isEventQueuePersistenceEnabled, _AnalyticsController_isPreConsentQueueEnabled, _AnalyticsController_isGeolocationEnabled, _AnalyticsController_initPromise, _AnalyticsController_locationResolvePromise, _AnalyticsController_locationContext, _AnalyticsController_performInit, _AnalyticsController_maybeResolveLocation, _AnalyticsController_resolveLocationContext, _AnalyticsController_withLocationContext, _AnalyticsController_sendOrQueueTrackEvent, _AnalyticsController_sendOrQueueIdentifyEvent, _AnalyticsController_sendOrQueueViewEvent, _AnalyticsController_enqueueEvent, _AnalyticsController_sendQueuedEvent, _AnalyticsController_replayQueuedEvents, _AnalyticsController_removeQueuedEvent, _AnalyticsController_clearQueuedEvents, _AnalyticsController_enqueuePreConsentEvent, _AnalyticsController_replayPreConsentEvents, _AnalyticsController_enrichPreConsentEvent, _AnalyticsController_clearPreConsentEvents, _AnalyticsController_reconcilePreConsentEvents; | ||
| import { BaseController } from "@metamask/base-controller"; | ||
@@ -99,2 +99,32 @@ import $lodash from "lodash"; | ||
| /** | ||
| * Returns whether a JSON value is a non-array object. | ||
| * | ||
| * @param value - The value to check. | ||
| * @returns True if the value is a JSON record. | ||
| */ | ||
| function isJsonRecord(value) { | ||
| return value !== null && typeof value === 'object' && !Array.isArray(value); | ||
| } | ||
| /** | ||
| * Builds the analytics location context from geolocation data, keeping only | ||
| * the fields the geolocation API was able to determine. | ||
| * | ||
| * @param geolocation - The geolocation data to convert. | ||
| * @returns The location context, or `undefined` when no field is known. | ||
| */ | ||
| function buildLocationContext(geolocation) { | ||
| const locationContext = { | ||
| ...(geolocation.country === null | ||
| ? {} | ||
| : { country_code: geolocation.country }), | ||
| ...(geolocation.region === null ? {} : { region: geolocation.region }), | ||
| ...(geolocation.timezone === null | ||
| ? {} | ||
| : { timezone: geolocation.timezone }), | ||
| }; | ||
| return Object.keys(locationContext).length === 0 | ||
| ? undefined | ||
| : locationContext; | ||
| } | ||
| /** | ||
| * Returns whether a value is a valid persisted analytics event. | ||
@@ -155,6 +185,7 @@ * | ||
| * @param options.isPreConsentQueueEnabled - Whether the pre-consent event queue is enabled | ||
| * @param options.isGeolocationEnabled - Whether geolocation enrichment is enabled | ||
| * @throws Error if state.analyticsId is missing or not a valid UUIDv4 | ||
| * @remarks After construction, call {@link AnalyticsController.init} to complete initialization. | ||
| */ | ||
| constructor({ state, messenger, platformAdapter, isAnonymousEventsFeatureEnabled = false, isEventQueuePersistenceEnabled = false, isPreConsentQueueEnabled = false, }) { | ||
| constructor({ state, messenger, platformAdapter, isAnonymousEventsFeatureEnabled = false, isEventQueuePersistenceEnabled = false, isPreConsentQueueEnabled = false, isGeolocationEnabled = false, }) { | ||
| const initialState = { | ||
@@ -176,8 +207,22 @@ ...getDefaultAnalyticsControllerState(), | ||
| _AnalyticsController_isPreConsentQueueEnabled.set(this, void 0); | ||
| _AnalyticsController_initialized.set(this, void 0); | ||
| _AnalyticsController_isGeolocationEnabled.set(this, void 0); | ||
| /** | ||
| * The in-flight (or settled) initialization promise. Set on the first | ||
| * {@link init} call and returned by subsequent calls so overlapping callers | ||
| * await the same work rather than observing a premature completion. | ||
| */ | ||
| _AnalyticsController_initPromise.set(this, void 0); | ||
| /** | ||
| * The in-flight (or settled) geolocation resolution, if any. Its presence | ||
| * marks that resolution has been started, so it runs at most once. | ||
| */ | ||
| _AnalyticsController_locationResolvePromise.set(this, void 0); | ||
| _AnalyticsController_locationContext.set(this, void 0); | ||
| __classPrivateFieldSet(this, _AnalyticsController_isAnonymousEventsFeatureEnabled, isAnonymousEventsFeatureEnabled, "f"); | ||
| __classPrivateFieldSet(this, _AnalyticsController_isEventQueuePersistenceEnabled, isEventQueuePersistenceEnabled, "f"); | ||
| __classPrivateFieldSet(this, _AnalyticsController_isPreConsentQueueEnabled, isPreConsentQueueEnabled, "f"); | ||
| __classPrivateFieldSet(this, _AnalyticsController_isGeolocationEnabled, isGeolocationEnabled, "f"); | ||
| __classPrivateFieldSet(this, _AnalyticsController_platformAdapter, platformAdapter, "f"); | ||
| __classPrivateFieldSet(this, _AnalyticsController_initialized, false, "f"); | ||
| __classPrivateFieldSet(this, _AnalyticsController_initPromise, undefined, "f"); | ||
| __classPrivateFieldSet(this, _AnalyticsController_locationResolvePromise, undefined, "f"); | ||
| this.messenger.registerMethodActionHandlers(this, MESSENGER_EXPOSED_METHODS); | ||
@@ -191,25 +236,30 @@ log('AnalyticsController initialized and ready', { | ||
| preConsentQueueEnabled: __classPrivateFieldGet(this, _AnalyticsController_isPreConsentQueueEnabled, "f"), | ||
| geolocationEnabled: __classPrivateFieldGet(this, _AnalyticsController_isGeolocationEnabled, "f"), | ||
| }); | ||
| } | ||
| /** | ||
| * Initialize the controller by calling the platform adapter's onSetupCompleted lifecycle hook. | ||
| * This method must be called after construction to complete the setup process. | ||
| * Initialize the controller by calling the platform adapter's | ||
| * onSetupCompleted lifecycle hook and replaying any queued events. This | ||
| * method must be called after construction to complete the setup process. | ||
| * | ||
| * When geolocation enrichment is enabled (`isGeolocationEnabled`), geolocation | ||
| * is resolved only for a user who is already opted in; for undecided or | ||
| * opted-out users it is deferred until they opt in (see {@link optIn}), so a | ||
| * user's location is never requested before they consent to analytics. In | ||
| * either case the `GeolocationController` and its | ||
| * `GeolocationController:getGeolocationData` action must be registered before | ||
| * resolution occurs, or enrichment is skipped for the session (a message is | ||
| * logged, see {@link #resolveLocationContext}). | ||
| * | ||
| * Safe to call more than once: the first call performs initialization and | ||
| * subsequent calls return the same in-flight (or settled) promise. | ||
| * | ||
| * @returns A promise that resolves once initialization has completed. | ||
| */ | ||
| init() { | ||
| if (__classPrivateFieldGet(this, _AnalyticsController_initialized, "f")) { | ||
| log('AnalyticsController already initialized.'); | ||
| return; | ||
| } | ||
| __classPrivateFieldSet(this, _AnalyticsController_initialized, true, "f"); | ||
| // Call onSetupCompleted lifecycle hook after initialization | ||
| // State is already validated, so analyticsId is guaranteed to be a valid UUIDv4 | ||
| try { | ||
| __classPrivateFieldGet(this, _AnalyticsController_platformAdapter, "f").onSetupCompleted(this.state.analyticsId); | ||
| } | ||
| catch (error) { | ||
| // Log error but don't throw - adapter setup failure shouldn't break controller | ||
| log('Error calling platformAdapter.onSetupCompleted', error); | ||
| } | ||
| __classPrivateFieldGet(this, _AnalyticsController_instances, "m", _AnalyticsController_replayQueuedEvents).call(this); | ||
| __classPrivateFieldGet(this, _AnalyticsController_instances, "m", _AnalyticsController_reconcilePreConsentEvents).call(this); | ||
| // Cache the in-flight promise so repeated or overlapping calls share a | ||
| // single initialization and all await the same completion (rather than an | ||
| // early call observing a finished init while work is still pending). | ||
| __classPrivateFieldSet(this, _AnalyticsController_initPromise, __classPrivateFieldGet(this, _AnalyticsController_initPromise, "f") ?? __classPrivateFieldGet(this, _AnalyticsController_instances, "m", _AnalyticsController_performInit).call(this), "f"); | ||
| return __classPrivateFieldGet(this, _AnalyticsController_initPromise, "f"); | ||
| } | ||
@@ -238,3 +288,3 @@ /** | ||
| if (!event.hasProperties) { | ||
| __classPrivateFieldGet(this, _AnalyticsController_instances, "m", _AnalyticsController_sendOrQueueTrackEvent).call(this, event.name, undefined, context); | ||
| __classPrivateFieldGet(this, _AnalyticsController_instances, "m", _AnalyticsController_sendOrQueueTrackEvent).call(this, event.name, undefined, __classPrivateFieldGet(this, _AnalyticsController_instances, "m", _AnalyticsController_withLocationContext).call(this, context)); | ||
| return; | ||
@@ -248,3 +298,3 @@ } | ||
| ...event.properties, | ||
| }, context); | ||
| }, __classPrivateFieldGet(this, _AnalyticsController_instances, "m", _AnalyticsController_withLocationContext).call(this, context)); | ||
| } | ||
@@ -257,3 +307,9 @@ const hasSensitiveProperties = Object.keys(event.sensitiveProperties).length > 0; | ||
| ...(hasSensitiveProperties && { anonymous: true }), | ||
| }, context); | ||
| }, | ||
| // When the anonymous events feature is enabled, this payload is the | ||
| // anonymous one and must carry no geolocation. When the feature is | ||
| // disabled, this is the single identified payload, so it is enriched. | ||
| __classPrivateFieldGet(this, _AnalyticsController_isAnonymousEventsFeatureEnabled, "f") | ||
| ? context | ||
| : __classPrivateFieldGet(this, _AnalyticsController_instances, "m", _AnalyticsController_withLocationContext).call(this, context)); | ||
| } | ||
@@ -272,3 +328,3 @@ } | ||
| // Delegate to platform adapter using the current analytics ID | ||
| __classPrivateFieldGet(this, _AnalyticsController_instances, "m", _AnalyticsController_sendOrQueueIdentifyEvent).call(this, this.state.analyticsId, traits, context); | ||
| __classPrivateFieldGet(this, _AnalyticsController_instances, "m", _AnalyticsController_sendOrQueueIdentifyEvent).call(this, this.state.analyticsId, traits, __classPrivateFieldGet(this, _AnalyticsController_instances, "m", _AnalyticsController_withLocationContext).call(this, context)); | ||
| } | ||
@@ -287,3 +343,3 @@ /** | ||
| // Delegate to platform adapter | ||
| __classPrivateFieldGet(this, _AnalyticsController_instances, "m", _AnalyticsController_sendOrQueueViewEvent).call(this, name, properties, context); | ||
| __classPrivateFieldGet(this, _AnalyticsController_instances, "m", _AnalyticsController_sendOrQueueViewEvent).call(this, name, properties, __classPrivateFieldGet(this, _AnalyticsController_instances, "m", _AnalyticsController_withLocationContext).call(this, context)); | ||
| } | ||
@@ -295,4 +351,10 @@ /** | ||
| * were queued while the user was undecided. | ||
| * | ||
| * When geolocation enrichment is enabled, geolocation is resolved here (once | ||
| * the user has consented) and awaited before the queued events are replayed, | ||
| * so those events are enriched with the resolved location as they are sent. | ||
| * | ||
| * @returns A promise that resolves once opt-in processing has completed. | ||
| */ | ||
| optIn() { | ||
| async optIn() { | ||
| this.update((state) => { | ||
@@ -302,3 +364,10 @@ state.optedIn = true; | ||
| }); | ||
| __classPrivateFieldGet(this, _AnalyticsController_instances, "m", _AnalyticsController_replayPreConsentEvents).call(this); | ||
| // Now that the user has consented, resolve geolocation (once) and wait for | ||
| // it so the queued pre-consent events can be enriched as they replay. | ||
| await __classPrivateFieldGet(this, _AnalyticsController_instances, "m", _AnalyticsController_maybeResolveLocation).call(this); | ||
| // Reconcile against the current state rather than replaying blindly: the | ||
| // consent decision may have changed while geolocation was resolving (e.g. | ||
| // resetConsentDecision ran during the await), and preserved pre-consent | ||
| // events must not be delivered once the user is no longer opted in. | ||
| __classPrivateFieldGet(this, _AnalyticsController_instances, "m", _AnalyticsController_reconcilePreConsentEvents).call(this); | ||
| } | ||
@@ -335,3 +404,56 @@ /** | ||
| } | ||
| _AnalyticsController_platformAdapter = new WeakMap(), _AnalyticsController_isAnonymousEventsFeatureEnabled = new WeakMap(), _AnalyticsController_isEventQueuePersistenceEnabled = new WeakMap(), _AnalyticsController_isPreConsentQueueEnabled = new WeakMap(), _AnalyticsController_initialized = new WeakMap(), _AnalyticsController_instances = new WeakSet(), _AnalyticsController_sendOrQueueTrackEvent = function _AnalyticsController_sendOrQueueTrackEvent(eventName, properties, context) { | ||
| _AnalyticsController_platformAdapter = new WeakMap(), _AnalyticsController_isAnonymousEventsFeatureEnabled = new WeakMap(), _AnalyticsController_isEventQueuePersistenceEnabled = new WeakMap(), _AnalyticsController_isPreConsentQueueEnabled = new WeakMap(), _AnalyticsController_isGeolocationEnabled = new WeakMap(), _AnalyticsController_initPromise = new WeakMap(), _AnalyticsController_locationResolvePromise = new WeakMap(), _AnalyticsController_locationContext = new WeakMap(), _AnalyticsController_instances = new WeakSet(), _AnalyticsController_performInit = | ||
| /** | ||
| * Performs the one-time initialization work: resolve geolocation, run the | ||
| * platform adapter's onSetupCompleted lifecycle hook, then replay any queued | ||
| * and pre-consent events. | ||
| */ | ||
| async function _AnalyticsController_performInit() { | ||
| // Resolve geolocation only when the user is already opted in; for undecided | ||
| // or opted-out users it is deferred to {@link optIn}. Awaited so that an | ||
| // already-opted-in session has location available before events replay. | ||
| await __classPrivateFieldGet(this, _AnalyticsController_instances, "m", _AnalyticsController_maybeResolveLocation).call(this); | ||
| // Call onSetupCompleted lifecycle hook after initialization | ||
| // State is already validated, so analyticsId is guaranteed to be a valid UUIDv4 | ||
| try { | ||
| __classPrivateFieldGet(this, _AnalyticsController_platformAdapter, "f").onSetupCompleted(this.state.analyticsId); | ||
| } | ||
| catch (error) { | ||
| // Log error but don't throw - adapter setup failure shouldn't break controller | ||
| log('Error calling platformAdapter.onSetupCompleted', error); | ||
| } | ||
| __classPrivateFieldGet(this, _AnalyticsController_instances, "m", _AnalyticsController_replayQueuedEvents).call(this); | ||
| __classPrivateFieldGet(this, _AnalyticsController_instances, "m", _AnalyticsController_reconcilePreConsentEvents).call(this); | ||
| }, _AnalyticsController_maybeResolveLocation = function _AnalyticsController_maybeResolveLocation() { | ||
| if (__classPrivateFieldGet(this, _AnalyticsController_isGeolocationEnabled, "f") && | ||
| __classPrivateFieldGet(this, _AnalyticsController_locationResolvePromise, "f") === undefined && | ||
| analyticsControllerSelectors.selectEnabled(this.state)) { | ||
| __classPrivateFieldSet(this, _AnalyticsController_locationResolvePromise, __classPrivateFieldGet(this, _AnalyticsController_instances, "m", _AnalyticsController_resolveLocationContext).call(this), "f"); | ||
| } | ||
| return __classPrivateFieldGet(this, _AnalyticsController_locationResolvePromise, "f"); | ||
| }, _AnalyticsController_resolveLocationContext = async function _AnalyticsController_resolveLocationContext() { | ||
| try { | ||
| const geolocation = await this.messenger.call('GeolocationController:getGeolocationData'); | ||
| __classPrivateFieldSet(this, _AnalyticsController_locationContext, buildLocationContext(geolocation), "f"); | ||
| } | ||
| catch (error) { | ||
| // A common cause is the GeolocationController not being registered before | ||
| // resolution runs (at init for an opted-in user, otherwise at opt-in). | ||
| // Name it here so the failure is diagnosable, since enrichment is | ||
| // otherwise skipped silently for the session. | ||
| log('Failed to resolve geolocation for analytics enrichment; events will be sent without location. Ensure the GeolocationController is registered and initialized before the user opts in when geolocation is enabled.', error); | ||
| } | ||
| }, _AnalyticsController_withLocationContext = function _AnalyticsController_withLocationContext(context) { | ||
| if (!__classPrivateFieldGet(this, _AnalyticsController_locationContext, "f")) { | ||
| return context; | ||
| } | ||
| const callerLocation = context?.location; | ||
| return { | ||
| ...context, | ||
| location: { | ||
| ...(isJsonRecord(callerLocation) ? callerLocation : {}), | ||
| ...__classPrivateFieldGet(this, _AnalyticsController_locationContext, "f"), | ||
| }, | ||
| }; | ||
| }, _AnalyticsController_sendOrQueueTrackEvent = function _AnalyticsController_sendOrQueueTrackEvent(eventName, properties, context) { | ||
| // Direct delivery: enabled and not persisting. | ||
@@ -477,10 +599,3 @@ if (analyticsControllerSelectors.selectEnabled(this.state) && | ||
| }); | ||
| }, _AnalyticsController_replayPreConsentEvents = function _AnalyticsController_replayPreConsentEvents() { | ||
| if (!__classPrivateFieldGet(this, _AnalyticsController_isPreConsentQueueEnabled, "f")) { | ||
| return; | ||
| } | ||
| const queue = this.state.preConsentEventQueue; | ||
| if (!queue) { | ||
| return; | ||
| } | ||
| }, _AnalyticsController_replayPreConsentEvents = function _AnalyticsController_replayPreConsentEvents(queue) { | ||
| __classPrivateFieldGet(this, _AnalyticsController_instances, "m", _AnalyticsController_clearPreConsentEvents).call(this); | ||
@@ -495,9 +610,20 @@ for (const [messageId, queuedEvent] of Object.entries(queue)) { | ||
| } | ||
| const eventToReplay = __classPrivateFieldGet(this, _AnalyticsController_instances, "m", _AnalyticsController_enrichPreConsentEvent).call(this, queuedEvent); | ||
| if (__classPrivateFieldGet(this, _AnalyticsController_isEventQueuePersistenceEnabled, "f")) { | ||
| __classPrivateFieldGet(this, _AnalyticsController_instances, "m", _AnalyticsController_enqueueEvent).call(this, queuedEvent); | ||
| __classPrivateFieldGet(this, _AnalyticsController_instances, "m", _AnalyticsController_enqueueEvent).call(this, eventToReplay); | ||
| } | ||
| else { | ||
| __classPrivateFieldGet(this, _AnalyticsController_instances, "m", _AnalyticsController_sendQueuedEvent).call(this, queuedEvent); | ||
| __classPrivateFieldGet(this, _AnalyticsController_instances, "m", _AnalyticsController_sendQueuedEvent).call(this, eventToReplay); | ||
| } | ||
| } | ||
| }, _AnalyticsController_enrichPreConsentEvent = function _AnalyticsController_enrichPreConsentEvent(queuedEvent) { | ||
| if (queuedEvent.type === 'track' && | ||
| queuedEvent.properties?.anonymous === true) { | ||
| return queuedEvent; | ||
| } | ||
| const context = __classPrivateFieldGet(this, _AnalyticsController_instances, "m", _AnalyticsController_withLocationContext).call(this, queuedEvent.context); | ||
| return { | ||
| ...queuedEvent, | ||
| ...(context === undefined ? {} : { context }), | ||
| }; | ||
| }, _AnalyticsController_clearPreConsentEvents = function _AnalyticsController_clearPreConsentEvents() { | ||
@@ -520,3 +646,3 @@ if (!this.state.preConsentEventQueue) { | ||
| if (this.state.optedIn) { | ||
| __classPrivateFieldGet(this, _AnalyticsController_instances, "m", _AnalyticsController_replayPreConsentEvents).call(this); | ||
| __classPrivateFieldGet(this, _AnalyticsController_instances, "m", _AnalyticsController_replayPreConsentEvents).call(this, queue); | ||
| } | ||
@@ -523,0 +649,0 @@ else if (this.state.consentDecisionMade) { |
@@ -1,1 +0,1 @@ | ||
| {"version":3,"file":"AnalyticsController.mjs","sourceRoot":"","sources":["../src/AnalyticsController.ts"],"names":[],"mappings":"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","sourcesContent":["import type {\n ControllerGetStateAction,\n ControllerStateChangeEvent,\n StateMetadata,\n} from '@metamask/base-controller';\nimport { BaseController } from '@metamask/base-controller';\nimport type { Messenger } from '@metamask/messenger';\nimport type { Json } from '@metamask/utils';\nimport { cloneDeep } from 'lodash';\nimport { v4 as uuid } from 'uuid';\n\nimport type { AnalyticsControllerMethodActions } from './AnalyticsController-method-action-types';\nimport { validateAnalyticsControllerState } from './analyticsControllerStateValidator';\nimport { projectLogger as log } from './AnalyticsLogger';\nimport type {\n AnalyticsPlatformAdapter,\n AnalyticsDeliveryOptions,\n AnalyticsContext,\n AnalyticsEventProperties,\n AnalyticsUserTraits,\n AnalyticsTrackingEvent,\n} from './AnalyticsPlatformAdapter.types';\nimport { analyticsControllerSelectors } from './selectors';\n\n// === GENERAL ===\n\n/**\n * The name of the {@link AnalyticsController}, used to namespace the\n * controller's actions and events and to namespace the controller's state data\n * when composed with other controllers.\n */\nexport const controllerName = 'AnalyticsController';\n\n// === STATE ===\n\n/**\n * Describes the shape of the state object for {@link AnalyticsController}.\n */\nexport type AnalyticsControllerState = {\n /**\n * Whether the user has opted in to analytics.\n */\n optedIn: boolean;\n\n /**\n * User's UUIDv4 analytics identifier.\n * This is an identity (unique per user), not a preference.\n * Must be provided by the platform - the controller does not generate it.\n */\n analyticsId: string;\n\n /**\n * Persisted queue of analytics events waiting for delivery acknowledgement.\n * This is only used when event queue persistence is enabled.\n */\n eventQueue?: Record<string, Json>;\n\n /**\n * Whether the user has made a consent decision (opted in or opted out).\n *\n * This distinguishes the \"undecided\" state (e.g. during onboarding, before\n * the user has answered the analytics prompt) from an explicit opt-out.\n * Defaults to `false` and is set to `true` by {@link AnalyticsController.optIn}\n * or {@link AnalyticsController.optOut}, and back to `false` by\n * {@link AnalyticsController.resetConsentDecision}. Optional for backward\n * compatibility with persisted state that predates this field.\n */\n consentDecisionMade?: boolean;\n\n /**\n * Persisted queue of track events ({@link AnalyticsQueuedTrackEvent}) captured\n * while the user is undecided (no consent decision made yet). Replayed on\n * opt-in and cleared on opt-out.\n * Preserved across {@link AnalyticsController.resetConsentDecision} so onboarding\n * restarts do not drop install-time events.\n * This is only used when the pre-consent queue is enabled.\n */\n preConsentEventQueue?: Record<string, Json>;\n};\n\n/**\n * Event types supported by the persisted analytics event queue.\n */\nexport type AnalyticsQueuedEventType = 'track' | 'identify' | 'view';\n\n/**\n * Base persisted event queue entry.\n */\nexport type AnalyticsQueuedEventBase = {\n /**\n * Event type used to replay the payload with the platform adapter.\n */\n type: AnalyticsQueuedEventType;\n\n /**\n * Stable identifier for the analytics payload.\n */\n messageId: string;\n\n /**\n * Original payload timestamp serialized for persistence.\n */\n timestamp: string;\n};\n\n/**\n * Persisted track event queue entry.\n */\nexport type AnalyticsQueuedTrackEvent = AnalyticsQueuedEventBase & {\n type: 'track';\n eventName: string;\n properties?: AnalyticsEventProperties;\n context?: AnalyticsContext;\n};\n\n/**\n * Persisted identify event queue entry.\n */\nexport type AnalyticsQueuedIdentifyEvent = AnalyticsQueuedEventBase & {\n type: 'identify';\n userId: string;\n traits?: AnalyticsUserTraits;\n context?: AnalyticsContext;\n};\n\n/**\n * Persisted view event queue entry.\n */\nexport type AnalyticsQueuedViewEvent = AnalyticsQueuedEventBase & {\n type: 'view';\n name: string;\n properties?: AnalyticsEventProperties;\n context?: AnalyticsContext;\n};\n\n/**\n * Persisted analytics event queue entry.\n */\nexport type AnalyticsQueuedEvent =\n | AnalyticsQueuedTrackEvent\n | AnalyticsQueuedIdentifyEvent\n | AnalyticsQueuedViewEvent;\n\n/**\n * Persisted analytics event queue keyed by message ID.\n */\nexport type AnalyticsEventQueue = Record<string, AnalyticsQueuedEvent>;\n\n/**\n * Returns default values for AnalyticsController state.\n *\n * Note: analyticsId is NOT included - it's an identity that must be\n * provided by the platform (generated once on first run, then persisted).\n *\n * @returns Default state without analyticsId\n */\nexport function getDefaultAnalyticsControllerState(): Omit<\n AnalyticsControllerState,\n 'analyticsId'\n> {\n return {\n optedIn: false,\n consentDecisionMade: false,\n };\n}\n\n/**\n * The metadata for each property in {@link AnalyticsControllerState}.\n *\n * Both `optedIn` and `analyticsId` are persisted (`persist: true`).\n * The platform must supply a valid UUIDv4 `analyticsId` on first run.\n */\nconst analyticsControllerMetadata = {\n optedIn: {\n includeInStateLogs: true,\n persist: true,\n includeInDebugSnapshot: true,\n usedInUi: true,\n },\n analyticsId: {\n includeInStateLogs: true,\n persist: true,\n includeInDebugSnapshot: true,\n usedInUi: false,\n },\n eventQueue: {\n includeInStateLogs: false,\n persist: true,\n includeInDebugSnapshot: false,\n usedInUi: false,\n },\n consentDecisionMade: {\n includeInStateLogs: true,\n persist: true,\n includeInDebugSnapshot: true,\n usedInUi: true,\n },\n preConsentEventQueue: {\n includeInStateLogs: false,\n persist: true,\n includeInDebugSnapshot: false,\n usedInUi: false,\n },\n} satisfies StateMetadata<AnalyticsControllerState>;\n\n// === MESSENGER ===\n\nconst MESSENGER_EXPOSED_METHODS = [\n 'trackEvent',\n 'identify',\n 'trackView',\n 'optIn',\n 'optOut',\n 'resetConsentDecision',\n] as const;\n\n/**\n * Returns the state of the {@link AnalyticsController}.\n */\nexport type AnalyticsControllerGetStateAction = ControllerGetStateAction<\n typeof controllerName,\n AnalyticsControllerState\n>;\n\n/**\n * Actions that {@link AnalyticsControllerMessenger} exposes to other consumers.\n */\nexport type AnalyticsControllerActions =\n | AnalyticsControllerGetStateAction\n | AnalyticsControllerMethodActions;\n\n/**\n * Actions from other messengers that {@link AnalyticsControllerMessenger} calls.\n */\ntype AllowedActions = never;\n\n/**\n * Event emitted when the state of the {@link AnalyticsController} changes.\n */\nexport type AnalyticsControllerStateChangeEvent = ControllerStateChangeEvent<\n typeof controllerName,\n AnalyticsControllerState\n>;\n\n/**\n * Events that {@link AnalyticsControllerMessenger} exposes to other consumers.\n */\nexport type AnalyticsControllerEvents = AnalyticsControllerStateChangeEvent;\n\n/**\n * Events from other messengers that {@link AnalyticsControllerMessenger} subscribes to.\n */\ntype AllowedEvents = never;\n\n/**\n * The messenger restricted to actions and events accessed by\n * {@link AnalyticsController}.\n */\nexport type AnalyticsControllerMessenger = Messenger<\n typeof controllerName,\n AnalyticsControllerActions | AllowedActions,\n AnalyticsControllerEvents | AllowedEvents\n>;\n\n// === CONTROLLER DEFINITION ===\n\n/**\n * The options that AnalyticsController takes.\n */\nexport type AnalyticsControllerOptions = {\n /**\n * Initial controller state. Must include a valid UUIDv4 `analyticsId`.\n * The platform is responsible for generating the ID on first run.\n * It is then persisted with controller state when using a persisted store.\n */\n state: AnalyticsControllerState;\n /**\n * Messenger used to communicate with BaseController and other controllers.\n */\n messenger: AnalyticsControllerMessenger;\n /**\n * Platform adapter implementation for tracking events.\n */\n platformAdapter: AnalyticsPlatformAdapter;\n\n /**\n * Whether the anonymous events feature is enabled.\n *\n * @default false\n */\n isAnonymousEventsFeatureEnabled?: boolean;\n\n /**\n * Whether analytics event queue persistence is enabled.\n *\n * When enabled, AnalyticsController persists each platform adapter payload\n * until the adapter reports successful delivery.\n *\n * @default false\n */\n isEventQueuePersistenceEnabled?: boolean;\n\n /**\n * Whether the pre-consent event queue is enabled.\n *\n * When enabled, track events received while the user is undecided\n * (no consent decision made yet) are persisted and replayed on opt-in,\n * or dropped on opt-out. When disabled, such events are dropped immediately,\n * preserving the legacy behavior.\n *\n * @default false\n */\n isPreConsentQueueEnabled?: boolean;\n};\n\n/**\n * Returns whether a value is a non-array object.\n *\n * @param value - The value to check.\n * @returns True if the value is a record.\n */\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return value !== null && typeof value === 'object' && !Array.isArray(value);\n}\n\n/**\n * Returns whether a value is a valid persisted analytics event.\n *\n * @param value - The value to check.\n * @returns True if the value is a queued analytics event.\n */\nfunction isAnalyticsQueuedEvent(value: unknown): value is AnalyticsQueuedEvent {\n if (!isRecord(value)) {\n return false;\n }\n\n if (\n typeof value.messageId !== 'string' ||\n typeof value.timestamp !== 'string'\n ) {\n return false;\n }\n\n if (value.type === 'track') {\n return (\n typeof value.eventName === 'string' &&\n (value.properties === undefined || isRecord(value.properties)) &&\n (value.context === undefined || isRecord(value.context))\n );\n }\n\n if (value.type === 'identify') {\n return (\n typeof value.userId === 'string' &&\n (value.traits === undefined || isRecord(value.traits)) &&\n (value.context === undefined || isRecord(value.context))\n );\n }\n\n if (value.type === 'view') {\n return (\n typeof value.name === 'string' &&\n (value.properties === undefined || isRecord(value.properties)) &&\n (value.context === undefined || isRecord(value.context))\n );\n }\n\n return false;\n}\n\n/**\n * The AnalyticsController manages analytics tracking across platforms (Mobile/Extension).\n * It provides a unified interface for tracking events, identifying users, and managing\n * analytics preferences while delegating platform-specific implementation to an\n * {@link AnalyticsPlatformAdapter}.\n *\n * This controller follows the MetaMask controller pattern and integrates with the\n * messenger system to allow other controllers and components to track analytics events.\n * It delegates platform-specific implementation to an {@link AnalyticsPlatformAdapter}.\n *\n * The controller persists `optedIn` and `analyticsId` when composed with a persisted\n * store. The platform must supply a valid `analyticsId` on first launch.\n */\nexport class AnalyticsController extends BaseController<\n 'AnalyticsController',\n AnalyticsControllerState,\n AnalyticsControllerMessenger\n> {\n readonly #platformAdapter: AnalyticsPlatformAdapter;\n\n readonly #isAnonymousEventsFeatureEnabled: boolean;\n\n readonly #isEventQueuePersistenceEnabled: boolean;\n\n readonly #isPreConsentQueueEnabled: boolean;\n\n #initialized: boolean;\n\n /**\n * Constructs an AnalyticsController instance.\n *\n * @param options - Controller options\n * @param options.state - Initial controller state. Must include a valid UUIDv4 `analyticsId`.\n * Use `getDefaultAnalyticsControllerState()` for default opt-in preferences.\n * @param options.messenger - Messenger used to communicate with BaseController\n * @param options.platformAdapter - Platform adapter implementation for tracking\n * @param options.isAnonymousEventsFeatureEnabled - Whether the anonymous events feature is enabled\n * @param options.isEventQueuePersistenceEnabled - Whether analytics event queue persistence is enabled\n * @param options.isPreConsentQueueEnabled - Whether the pre-consent event queue is enabled\n * @throws Error if state.analyticsId is missing or not a valid UUIDv4\n * @remarks After construction, call {@link AnalyticsController.init} to complete initialization.\n */\n constructor({\n state,\n messenger,\n platformAdapter,\n isAnonymousEventsFeatureEnabled = false,\n isEventQueuePersistenceEnabled = false,\n isPreConsentQueueEnabled = false,\n }: AnalyticsControllerOptions) {\n const initialState: AnalyticsControllerState = {\n ...getDefaultAnalyticsControllerState(),\n ...state,\n };\n\n validateAnalyticsControllerState(\n initialState,\n platformAdapter.skipUUIDv4Check === true,\n );\n\n super({\n name: controllerName,\n metadata: analyticsControllerMetadata,\n state: initialState,\n messenger,\n });\n\n this.#isAnonymousEventsFeatureEnabled = isAnonymousEventsFeatureEnabled;\n this.#isEventQueuePersistenceEnabled = isEventQueuePersistenceEnabled;\n this.#isPreConsentQueueEnabled = isPreConsentQueueEnabled;\n this.#platformAdapter = platformAdapter;\n this.#initialized = false;\n\n this.messenger.registerMethodActionHandlers(\n this,\n MESSENGER_EXPOSED_METHODS,\n );\n\n log('AnalyticsController initialized and ready', {\n enabled: analyticsControllerSelectors.selectEnabled(this.state),\n optedIn: this.state.optedIn,\n consentDecisionMade: this.state.consentDecisionMade,\n analyticsId: this.state.analyticsId,\n eventQueuePersistenceEnabled: this.#isEventQueuePersistenceEnabled,\n preConsentQueueEnabled: this.#isPreConsentQueueEnabled,\n });\n }\n\n /**\n * Initialize the controller by calling the platform adapter's onSetupCompleted lifecycle hook.\n * This method must be called after construction to complete the setup process.\n */\n init(): void {\n if (this.#initialized) {\n log('AnalyticsController already initialized.');\n return;\n }\n\n this.#initialized = true;\n\n // Call onSetupCompleted lifecycle hook after initialization\n // State is already validated, so analyticsId is guaranteed to be a valid UUIDv4\n try {\n this.#platformAdapter.onSetupCompleted(this.state.analyticsId);\n } catch (error) {\n // Log error but don't throw - adapter setup failure shouldn't break controller\n log('Error calling platformAdapter.onSetupCompleted', error);\n }\n\n this.#replayQueuedEvents();\n this.#reconcilePreConsentEvents();\n }\n\n /**\n * Send final track payload through the platform adapter or queue it if persistence is enabled.\n *\n * @param eventName - The name of the event.\n * @param properties - Optional event properties.\n * @param context - Optional platform-specific context.\n */\n #sendOrQueueTrackEvent(\n eventName: string,\n properties?: AnalyticsEventProperties,\n context?: AnalyticsContext,\n ): void {\n // Direct delivery: enabled and not persisting.\n if (\n analyticsControllerSelectors.selectEnabled(this.state) &&\n !this.#isEventQueuePersistenceEnabled\n ) {\n this.#platformAdapter.track(eventName, properties, context);\n return;\n }\n\n const queuedEvent: AnalyticsQueuedTrackEvent = {\n type: 'track',\n eventName,\n messageId: uuid(),\n timestamp: new Date().toISOString(),\n ...(properties === undefined ? {} : { properties }),\n ...(context === undefined ? {} : { context }),\n };\n\n // Not yet enabled (reached only while undecided with the pre-consent queue\n // enabled): hold the event until the user opts in.\n if (!analyticsControllerSelectors.selectEnabled(this.state)) {\n this.#enqueuePreConsentEvent(queuedEvent);\n return;\n }\n\n this.#enqueueEvent(queuedEvent);\n }\n\n /**\n * Send final identify payload through the platform adapter or queue it if persistence is enabled.\n *\n * @param userId - The user ID.\n * @param traits - Optional user traits.\n * @param context - Optional platform-specific context.\n */\n #sendOrQueueIdentifyEvent(\n userId: string,\n traits?: AnalyticsUserTraits,\n context?: AnalyticsContext,\n ): void {\n if (!this.#isEventQueuePersistenceEnabled) {\n this.#platformAdapter.identify(userId, traits, context);\n return;\n }\n\n const queuedEvent: AnalyticsQueuedIdentifyEvent = {\n type: 'identify',\n userId,\n messageId: uuid(),\n timestamp: new Date().toISOString(),\n ...(traits === undefined ? {} : { traits }),\n ...(context === undefined ? {} : { context }),\n };\n\n this.#enqueueEvent(queuedEvent);\n }\n\n /**\n * Send final view payload through the platform adapter or queue it if persistence is enabled.\n *\n * @param name - The view name.\n * @param properties - Optional view properties.\n * @param context - Optional platform-specific context.\n */\n #sendOrQueueViewEvent(\n name: string,\n properties?: AnalyticsEventProperties,\n context?: AnalyticsContext,\n ): void {\n if (!this.#isEventQueuePersistenceEnabled) {\n this.#platformAdapter.view(name, properties, context);\n return;\n }\n\n const queuedEvent: AnalyticsQueuedViewEvent = {\n type: 'view',\n name,\n messageId: uuid(),\n timestamp: new Date().toISOString(),\n ...(properties === undefined ? {} : { properties }),\n ...(context === undefined ? {} : { context }),\n };\n\n this.#enqueueEvent(queuedEvent);\n }\n\n /**\n * Add an analytics event to the queue and send it.\n *\n * @param queuedEvent - The event to enqueue and deliver.\n */\n #enqueueEvent(queuedEvent: AnalyticsQueuedEvent): void {\n const eventQueue: Record<string, Json> = {\n ...(this.state.eventQueue ?? {}),\n [queuedEvent.messageId]: queuedEvent as unknown as Json,\n };\n\n this.update((state) => {\n state.eventQueue = eventQueue as never;\n });\n\n this.#sendQueuedEvent(queuedEvent);\n }\n\n /**\n * Send a queued event through the platform adapter.\n *\n * @param queuedEvent - The queued event to deliver.\n */\n #sendQueuedEvent(queuedEvent: AnalyticsQueuedEvent): void {\n const timestamp = new Date(queuedEvent.timestamp);\n\n if (Number.isNaN(timestamp.getTime())) {\n log('Dropping queued analytics event with invalid timestamp', {\n messageId: queuedEvent.messageId,\n });\n this.#removeQueuedEvent(queuedEvent.messageId);\n return;\n }\n\n const options: AnalyticsDeliveryOptions = {\n messageId: queuedEvent.messageId,\n timestamp,\n callback: (error?: unknown) => {\n if (error) {\n log('Queued analytics event delivery failed', {\n messageId: queuedEvent.messageId,\n error,\n });\n }\n\n this.#removeQueuedEvent(queuedEvent.messageId);\n },\n };\n\n try {\n if (queuedEvent.type === 'track') {\n this.#platformAdapter.track(\n queuedEvent.eventName,\n cloneDeep(queuedEvent.properties),\n cloneDeep(queuedEvent.context),\n options,\n );\n } else if (queuedEvent.type === 'identify') {\n this.#platformAdapter.identify(\n queuedEvent.userId,\n cloneDeep(queuedEvent.traits),\n cloneDeep(queuedEvent.context),\n options,\n );\n } else {\n this.#platformAdapter.view(\n queuedEvent.name,\n cloneDeep(queuedEvent.properties),\n cloneDeep(queuedEvent.context),\n options,\n );\n }\n } catch (error) {\n log('Error sending queued analytics event', {\n messageId: queuedEvent.messageId,\n error,\n });\n }\n }\n\n /**\n * Replay persisted analytics events.\n */\n #replayQueuedEvents(): void {\n if (!this.#isEventQueuePersistenceEnabled || !this.state.eventQueue) {\n return;\n }\n\n if (!analyticsControllerSelectors.selectEnabled(this.state)) {\n this.#clearQueuedEvents();\n return;\n }\n\n for (const [messageId, queuedEvent] of Object.entries(\n this.state.eventQueue,\n )) {\n if (\n !isAnalyticsQueuedEvent(queuedEvent) ||\n queuedEvent.messageId !== messageId\n ) {\n log('Dropping invalid queued analytics event', { messageId });\n this.#removeQueuedEvent(messageId);\n continue;\n }\n\n this.#sendQueuedEvent(queuedEvent);\n }\n }\n\n /**\n * Remove a queued analytics event.\n *\n * @param messageId - The queued event message ID.\n */\n #removeQueuedEvent(messageId: string): void {\n const currentEventQueue = this.state.eventQueue;\n\n if (\n !currentEventQueue ||\n !Object.prototype.hasOwnProperty.call(currentEventQueue, messageId)\n ) {\n return;\n }\n\n const { [messageId]: _deletedEvent, ...eventQueue } = currentEventQueue;\n\n this.update((state) => {\n state.eventQueue = eventQueue as never;\n });\n }\n\n /**\n * Clear all queued analytics events.\n */\n #clearQueuedEvents(): void {\n if (\n !this.state.eventQueue ||\n Object.keys(this.state.eventQueue).length === 0\n ) {\n return;\n }\n\n this.update((state) => {\n state.eventQueue = {} as never;\n });\n }\n\n /**\n * Add an event to the pre-consent queue without delivering it.\n *\n * @param queuedEvent - The event to hold until the user opts in.\n */\n #enqueuePreConsentEvent(queuedEvent: AnalyticsQueuedEvent): void {\n const preConsentEventQueue: Record<string, Json> = {\n ...(this.state.preConsentEventQueue ?? {}),\n [queuedEvent.messageId]: queuedEvent as unknown as Json,\n };\n\n this.update((state) => {\n state.preConsentEventQueue = preConsentEventQueue as never;\n });\n }\n\n /**\n * Replay queued pre-consent events through the delivery path.\n *\n * Called on opt-in, once analytics is enabled. The queue is cleared before\n * replaying so events cannot be re-queued or replayed twice.\n */\n #replayPreConsentEvents(): void {\n if (!this.#isPreConsentQueueEnabled) {\n return;\n }\n\n const queue = this.state.preConsentEventQueue;\n\n if (!queue) {\n return;\n }\n\n this.#clearPreConsentEvents();\n\n for (const [messageId, queuedEvent] of Object.entries(queue)) {\n if (\n !isAnalyticsQueuedEvent(queuedEvent) ||\n queuedEvent.messageId !== messageId\n ) {\n log('Dropping invalid queued pre-consent analytics event', {\n messageId,\n });\n continue;\n }\n\n if (this.#isEventQueuePersistenceEnabled) {\n this.#enqueueEvent(queuedEvent);\n } else {\n this.#sendQueuedEvent(queuedEvent);\n }\n }\n }\n\n /**\n * Clear all queued pre-consent events.\n */\n #clearPreConsentEvents(): void {\n if (!this.state.preConsentEventQueue) {\n return;\n }\n\n this.update((state) => {\n state.preConsentEventQueue = {} as never;\n });\n }\n\n /**\n * Reconcile the pre-consent queue on initialization.\n *\n * The queue should normally be empty unless the user is still undecided. This\n * handles the rare cases where a consent decision was persisted but the queue\n * was not flushed/cleared (e.g. an interrupted shutdown): replay it if the\n * user is opted in, or clear it if they opted out.\n *\n * If the pre-consent queue is disabled, any stale persisted entries (e.g. from\n * a previous session where it was enabled) are dropped so they can never be\n * replayed.\n */\n #reconcilePreConsentEvents(): void {\n const queue = this.state.preConsentEventQueue;\n\n if (!queue) {\n return;\n }\n\n if (!this.#isPreConsentQueueEnabled) {\n this.#clearPreConsentEvents();\n return;\n }\n\n if (this.state.optedIn) {\n this.#replayPreConsentEvents();\n } else if (this.state.consentDecisionMade) {\n this.#clearPreConsentEvents();\n }\n }\n\n /**\n * Track an analytics event.\n *\n * Events are only tracked if analytics is enabled.\n *\n * @param event - Analytics event with properties and sensitive properties\n * @param context - Optional platform-specific context forwarded to the platform adapter.\n */\n trackEvent(event: AnalyticsTrackingEvent, context?: AnalyticsContext): void {\n if (!analyticsControllerSelectors.selectEnabled(this.state)) {\n // While the user is undecided, fall through so the event is processed and\n // captured in the pre-consent queue (see #sendOrQueueTrackEvent) to be\n // replayed if they later opt in. Otherwise (opted out, or pre-consent\n // queue disabled) drop it.\n const shouldQueuePreConsent =\n this.#isPreConsentQueueEnabled && !this.state.consentDecisionMade;\n if (!shouldQueuePreConsent) {\n return;\n }\n }\n\n // if event does not have properties, send event without properties\n // and return to prevent any additional processing\n if (!event.hasProperties) {\n this.#sendOrQueueTrackEvent(event.name, undefined, context);\n return;\n }\n\n // Track regular properties first if anonymous events feature is enabled\n if (this.#isAnonymousEventsFeatureEnabled) {\n // Note: Even if regular properties object is empty, we still send it to ensure\n // an event with user ID is tracked.\n this.#sendOrQueueTrackEvent(\n event.name,\n {\n ...event.properties,\n },\n context,\n );\n }\n\n const hasSensitiveProperties =\n Object.keys(event.sensitiveProperties).length > 0;\n\n if (!this.#isAnonymousEventsFeatureEnabled || hasSensitiveProperties) {\n this.#sendOrQueueTrackEvent(\n event.name,\n {\n ...event.properties,\n ...event.sensitiveProperties,\n ...(hasSensitiveProperties && { anonymous: true }),\n },\n context,\n );\n }\n }\n\n /**\n * Identify a user for analytics.\n *\n * @param traits - User traits/properties\n * @param context - Optional platform-specific context forwarded to the platform adapter.\n */\n identify(traits?: AnalyticsUserTraits, context?: AnalyticsContext): void {\n if (!analyticsControllerSelectors.selectEnabled(this.state)) {\n return;\n }\n\n // Delegate to platform adapter using the current analytics ID\n this.#sendOrQueueIdentifyEvent(this.state.analyticsId, traits, context);\n }\n\n /**\n * Track a page or screen view.\n *\n * @param name - The identifier/name of the page or screen being viewed (e.g., \"home\", \"settings\", \"wallet\")\n * @param properties - Optional properties associated with the view\n * @param context - Optional platform-specific context forwarded to the platform adapter.\n */\n trackView(\n name: string,\n properties?: AnalyticsEventProperties,\n context?: AnalyticsContext,\n ): void {\n if (!analyticsControllerSelectors.selectEnabled(this.state)) {\n return;\n }\n\n // Delegate to platform adapter\n this.#sendOrQueueViewEvent(name, properties, context);\n }\n\n /**\n * Opt in to analytics.\n *\n * Records that a consent decision has been made and replays any events that\n * were queued while the user was undecided.\n */\n optIn(): void {\n this.update((state) => {\n state.optedIn = true;\n state.consentDecisionMade = true;\n });\n\n this.#replayPreConsentEvents();\n }\n\n /**\n * Opt out of analytics.\n *\n * Records that a consent decision has been made and discards any persisted\n * events so nothing captured before the decision is ever delivered.\n */\n optOut(): void {\n this.update((state) => {\n state.optedIn = false;\n state.consentDecisionMade = true;\n });\n\n this.#clearQueuedEvents();\n this.#clearPreConsentEvents();\n }\n\n /**\n * Reset the consent decision back to undecided.\n *\n * Intended for client flows that restart onboarding. Clears the opt-in\n * preference and discards the delivery queue, but preserves any pre-consent\n * events so they can still be replayed if the user opts in again. The user is\n * treated as undecided again.\n */\n resetConsentDecision(): void {\n this.update((state) => {\n state.optedIn = false;\n state.consentDecisionMade = false;\n });\n\n this.#clearQueuedEvents();\n }\n}\n"]} | ||
| {"version":3,"file":"AnalyticsController.mjs","sourceRoot":"","sources":["../src/AnalyticsController.ts"],"names":[],"mappings":"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","sourcesContent":["import type {\n ControllerGetStateAction,\n ControllerStateChangeEvent,\n StateMetadata,\n} from '@metamask/base-controller';\nimport { BaseController } from '@metamask/base-controller';\nimport type {\n GeolocationControllerGetGeolocationDataAction,\n GeolocationData,\n} from '@metamask/geolocation-controller';\nimport type { Messenger } from '@metamask/messenger';\nimport type { Json } from '@metamask/utils';\nimport { cloneDeep } from 'lodash';\nimport { v4 as uuid } from 'uuid';\n\nimport type { AnalyticsControllerMethodActions } from './AnalyticsController-method-action-types.js';\nimport { validateAnalyticsControllerState } from './analyticsControllerStateValidator.js';\nimport { projectLogger as log } from './AnalyticsLogger.js';\nimport type {\n AnalyticsPlatformAdapter,\n AnalyticsDeliveryOptions,\n AnalyticsContext,\n AnalyticsEventProperties,\n AnalyticsLocationContext,\n AnalyticsUserTraits,\n AnalyticsTrackingEvent,\n} from './AnalyticsPlatformAdapter.types';\nimport { analyticsControllerSelectors } from './selectors.js';\n\n// === GENERAL ===\n\n/**\n * The name of the {@link AnalyticsController}, used to namespace the\n * controller's actions and events and to namespace the controller's state data\n * when composed with other controllers.\n */\nexport const controllerName = 'AnalyticsController';\n\n// === STATE ===\n\n/**\n * Describes the shape of the state object for {@link AnalyticsController}.\n */\nexport type AnalyticsControllerState = {\n /**\n * Whether the user has opted in to analytics.\n */\n optedIn: boolean;\n\n /**\n * User's UUIDv4 analytics identifier.\n * This is an identity (unique per user), not a preference.\n * Must be provided by the platform - the controller does not generate it.\n */\n analyticsId: string;\n\n /**\n * Persisted queue of analytics events waiting for delivery acknowledgement.\n * This is only used when event queue persistence is enabled.\n */\n eventQueue?: Record<string, Json>;\n\n /**\n * Whether the user has made a consent decision (opted in or opted out).\n *\n * This distinguishes the \"undecided\" state (e.g. during onboarding, before\n * the user has answered the analytics prompt) from an explicit opt-out.\n * Defaults to `false` and is set to `true` by {@link AnalyticsController.optIn}\n * or {@link AnalyticsController.optOut}, and back to `false` by\n * {@link AnalyticsController.resetConsentDecision}. Optional for backward\n * compatibility with persisted state that predates this field.\n */\n consentDecisionMade?: boolean;\n\n /**\n * Persisted queue of track events ({@link AnalyticsQueuedTrackEvent}) captured\n * while the user is undecided (no consent decision made yet). Replayed on\n * opt-in and cleared on opt-out.\n * Preserved across {@link AnalyticsController.resetConsentDecision} so onboarding\n * restarts do not drop install-time events.\n * This is only used when the pre-consent queue is enabled.\n */\n preConsentEventQueue?: Record<string, Json>;\n};\n\n/**\n * Event types supported by the persisted analytics event queue.\n */\nexport type AnalyticsQueuedEventType = 'track' | 'identify' | 'view';\n\n/**\n * Base persisted event queue entry.\n */\nexport type AnalyticsQueuedEventBase = {\n /**\n * Event type used to replay the payload with the platform adapter.\n */\n type: AnalyticsQueuedEventType;\n\n /**\n * Stable identifier for the analytics payload.\n */\n messageId: string;\n\n /**\n * Original payload timestamp serialized for persistence.\n */\n timestamp: string;\n};\n\n/**\n * Persisted track event queue entry.\n */\nexport type AnalyticsQueuedTrackEvent = AnalyticsQueuedEventBase & {\n type: 'track';\n eventName: string;\n properties?: AnalyticsEventProperties;\n context?: AnalyticsContext;\n};\n\n/**\n * Persisted identify event queue entry.\n */\nexport type AnalyticsQueuedIdentifyEvent = AnalyticsQueuedEventBase & {\n type: 'identify';\n userId: string;\n traits?: AnalyticsUserTraits;\n context?: AnalyticsContext;\n};\n\n/**\n * Persisted view event queue entry.\n */\nexport type AnalyticsQueuedViewEvent = AnalyticsQueuedEventBase & {\n type: 'view';\n name: string;\n properties?: AnalyticsEventProperties;\n context?: AnalyticsContext;\n};\n\n/**\n * Persisted analytics event queue entry.\n */\nexport type AnalyticsQueuedEvent =\n | AnalyticsQueuedTrackEvent\n | AnalyticsQueuedIdentifyEvent\n | AnalyticsQueuedViewEvent;\n\n/**\n * Persisted analytics event queue keyed by message ID.\n */\nexport type AnalyticsEventQueue = Record<string, AnalyticsQueuedEvent>;\n\n/**\n * Returns default values for AnalyticsController state.\n *\n * Note: analyticsId is NOT included - it's an identity that must be\n * provided by the platform (generated once on first run, then persisted).\n *\n * @returns Default state without analyticsId\n */\nexport function getDefaultAnalyticsControllerState(): Omit<\n AnalyticsControllerState,\n 'analyticsId'\n> {\n return {\n optedIn: false,\n consentDecisionMade: false,\n };\n}\n\n/**\n * The metadata for each property in {@link AnalyticsControllerState}.\n *\n * Both `optedIn` and `analyticsId` are persisted (`persist: true`).\n * The platform must supply a valid UUIDv4 `analyticsId` on first run.\n */\nconst analyticsControllerMetadata = {\n optedIn: {\n includeInStateLogs: true,\n persist: true,\n includeInDebugSnapshot: true,\n usedInUi: true,\n },\n analyticsId: {\n includeInStateLogs: true,\n persist: true,\n includeInDebugSnapshot: true,\n usedInUi: false,\n },\n eventQueue: {\n includeInStateLogs: false,\n persist: true,\n includeInDebugSnapshot: false,\n usedInUi: false,\n },\n consentDecisionMade: {\n includeInStateLogs: true,\n persist: true,\n includeInDebugSnapshot: true,\n usedInUi: true,\n },\n preConsentEventQueue: {\n includeInStateLogs: false,\n persist: true,\n includeInDebugSnapshot: false,\n usedInUi: false,\n },\n} satisfies StateMetadata<AnalyticsControllerState>;\n\n// === MESSENGER ===\n\nconst MESSENGER_EXPOSED_METHODS = [\n 'trackEvent',\n 'identify',\n 'trackView',\n 'optIn',\n 'optOut',\n 'resetConsentDecision',\n] as const;\n\n/**\n * Returns the state of the {@link AnalyticsController}.\n */\nexport type AnalyticsControllerGetStateAction = ControllerGetStateAction<\n typeof controllerName,\n AnalyticsControllerState\n>;\n\n/**\n * Actions that {@link AnalyticsControllerMessenger} exposes to other consumers.\n */\nexport type AnalyticsControllerActions =\n | AnalyticsControllerGetStateAction\n | AnalyticsControllerMethodActions;\n\n/**\n * Actions from other messengers that {@link AnalyticsControllerMessenger} calls.\n */\ntype AllowedActions = GeolocationControllerGetGeolocationDataAction;\n\n/**\n * Event emitted when the state of the {@link AnalyticsController} changes.\n */\nexport type AnalyticsControllerStateChangeEvent = ControllerStateChangeEvent<\n typeof controllerName,\n AnalyticsControllerState\n>;\n\n/**\n * Events that {@link AnalyticsControllerMessenger} exposes to other consumers.\n */\nexport type AnalyticsControllerEvents = AnalyticsControllerStateChangeEvent;\n\n/**\n * Events from other messengers that {@link AnalyticsControllerMessenger} subscribes to.\n */\ntype AllowedEvents = never;\n\n/**\n * The messenger restricted to actions and events accessed by\n * {@link AnalyticsController}.\n */\nexport type AnalyticsControllerMessenger = Messenger<\n typeof controllerName,\n AnalyticsControllerActions | AllowedActions,\n AnalyticsControllerEvents | AllowedEvents\n>;\n\n// === CONTROLLER DEFINITION ===\n\n/**\n * The options that AnalyticsController takes.\n */\nexport type AnalyticsControllerOptions = {\n /**\n * Initial controller state. Must include a valid UUIDv4 `analyticsId`.\n * The platform is responsible for generating the ID on first run.\n * It is then persisted with controller state when using a persisted store.\n */\n state: AnalyticsControllerState;\n /**\n * Messenger used to communicate with BaseController and other controllers.\n */\n messenger: AnalyticsControllerMessenger;\n /**\n * Platform adapter implementation for tracking events.\n */\n platformAdapter: AnalyticsPlatformAdapter;\n\n /**\n * Whether the anonymous events feature is enabled.\n *\n * @default false\n */\n isAnonymousEventsFeatureEnabled?: boolean;\n\n /**\n * Whether analytics event queue persistence is enabled.\n *\n * When enabled, AnalyticsController persists each platform adapter payload\n * until the adapter reports successful delivery.\n *\n * @default false\n */\n isEventQueuePersistenceEnabled?: boolean;\n\n /**\n * Whether the pre-consent event queue is enabled.\n *\n * When enabled, track events received while the user is undecided\n * (no consent decision made yet) are persisted and replayed on opt-in,\n * or dropped on opt-out. When disabled, such events are dropped immediately,\n * preserving the legacy behavior.\n *\n * @default false\n */\n isPreConsentQueueEnabled?: boolean;\n\n /**\n * Whether geolocation enrichment is enabled.\n *\n * When enabled, {@link AnalyticsController.init} resolves the user's\n * country, region, and timezone via `GeolocationController:getGeolocationData`\n * and attaches them to `context.location` on non-anonymous payloads.\n * Compositions must register that action when this is enabled. When disabled,\n * the controller never calls the geolocation action and events are delivered\n * without location.\n *\n * @default false\n */\n isGeolocationEnabled?: boolean;\n};\n\n/**\n * Returns whether a value is a non-array object.\n *\n * @param value - The value to check.\n * @returns True if the value is a record.\n */\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return value !== null && typeof value === 'object' && !Array.isArray(value);\n}\n\n/**\n * Returns whether a JSON value is a non-array object.\n *\n * @param value - The value to check.\n * @returns True if the value is a JSON record.\n */\nfunction isJsonRecord(value: Json | undefined): value is Record<string, Json> {\n return value !== null && typeof value === 'object' && !Array.isArray(value);\n}\n\n/**\n * Builds the analytics location context from geolocation data, keeping only\n * the fields the geolocation API was able to determine.\n *\n * @param geolocation - The geolocation data to convert.\n * @returns The location context, or `undefined` when no field is known.\n */\nfunction buildLocationContext(\n geolocation: GeolocationData,\n): AnalyticsLocationContext | undefined {\n const locationContext: AnalyticsLocationContext = {\n ...(geolocation.country === null\n ? {}\n : { country_code: geolocation.country }),\n ...(geolocation.region === null ? {} : { region: geolocation.region }),\n ...(geolocation.timezone === null\n ? {}\n : { timezone: geolocation.timezone }),\n };\n\n return Object.keys(locationContext).length === 0\n ? undefined\n : locationContext;\n}\n\n/**\n * Returns whether a value is a valid persisted analytics event.\n *\n * @param value - The value to check.\n * @returns True if the value is a queued analytics event.\n */\nfunction isAnalyticsQueuedEvent(value: unknown): value is AnalyticsQueuedEvent {\n if (!isRecord(value)) {\n return false;\n }\n\n if (\n typeof value.messageId !== 'string' ||\n typeof value.timestamp !== 'string'\n ) {\n return false;\n }\n\n if (value.type === 'track') {\n return (\n typeof value.eventName === 'string' &&\n (value.properties === undefined || isRecord(value.properties)) &&\n (value.context === undefined || isRecord(value.context))\n );\n }\n\n if (value.type === 'identify') {\n return (\n typeof value.userId === 'string' &&\n (value.traits === undefined || isRecord(value.traits)) &&\n (value.context === undefined || isRecord(value.context))\n );\n }\n\n if (value.type === 'view') {\n return (\n typeof value.name === 'string' &&\n (value.properties === undefined || isRecord(value.properties)) &&\n (value.context === undefined || isRecord(value.context))\n );\n }\n\n return false;\n}\n\n/**\n * The AnalyticsController manages analytics tracking across platforms (Mobile/Extension).\n * It provides a unified interface for tracking events, identifying users, and managing\n * analytics preferences while delegating platform-specific implementation to an\n * {@link AnalyticsPlatformAdapter}.\n *\n * This controller follows the MetaMask controller pattern and integrates with the\n * messenger system to allow other controllers and components to track analytics events.\n * It delegates platform-specific implementation to an {@link AnalyticsPlatformAdapter}.\n *\n * The controller persists `optedIn` and `analyticsId` when composed with a persisted\n * store. The platform must supply a valid `analyticsId` on first launch.\n */\nexport class AnalyticsController extends BaseController<\n 'AnalyticsController',\n AnalyticsControllerState,\n AnalyticsControllerMessenger\n> {\n readonly #platformAdapter: AnalyticsPlatformAdapter;\n\n readonly #isAnonymousEventsFeatureEnabled: boolean;\n\n readonly #isEventQueuePersistenceEnabled: boolean;\n\n readonly #isPreConsentQueueEnabled: boolean;\n\n readonly #isGeolocationEnabled: boolean;\n\n /**\n * The in-flight (or settled) initialization promise. Set on the first\n * {@link init} call and returned by subsequent calls so overlapping callers\n * await the same work rather than observing a premature completion.\n */\n #initPromise: Promise<void> | undefined;\n\n /**\n * The in-flight (or settled) geolocation resolution, if any. Its presence\n * marks that resolution has been started, so it runs at most once.\n */\n #locationResolvePromise: Promise<void> | undefined;\n\n #locationContext: AnalyticsLocationContext | undefined;\n\n /**\n * Constructs an AnalyticsController instance.\n *\n * @param options - Controller options\n * @param options.state - Initial controller state. Must include a valid UUIDv4 `analyticsId`.\n * Use `getDefaultAnalyticsControllerState()` for default opt-in preferences.\n * @param options.messenger - Messenger used to communicate with BaseController\n * @param options.platformAdapter - Platform adapter implementation for tracking\n * @param options.isAnonymousEventsFeatureEnabled - Whether the anonymous events feature is enabled\n * @param options.isEventQueuePersistenceEnabled - Whether analytics event queue persistence is enabled\n * @param options.isPreConsentQueueEnabled - Whether the pre-consent event queue is enabled\n * @param options.isGeolocationEnabled - Whether geolocation enrichment is enabled\n * @throws Error if state.analyticsId is missing or not a valid UUIDv4\n * @remarks After construction, call {@link AnalyticsController.init} to complete initialization.\n */\n constructor({\n state,\n messenger,\n platformAdapter,\n isAnonymousEventsFeatureEnabled = false,\n isEventQueuePersistenceEnabled = false,\n isPreConsentQueueEnabled = false,\n isGeolocationEnabled = false,\n }: AnalyticsControllerOptions) {\n const initialState: AnalyticsControllerState = {\n ...getDefaultAnalyticsControllerState(),\n ...state,\n };\n\n validateAnalyticsControllerState(\n initialState,\n platformAdapter.skipUUIDv4Check === true,\n );\n\n super({\n name: controllerName,\n metadata: analyticsControllerMetadata,\n state: initialState,\n messenger,\n });\n\n this.#isAnonymousEventsFeatureEnabled = isAnonymousEventsFeatureEnabled;\n this.#isEventQueuePersistenceEnabled = isEventQueuePersistenceEnabled;\n this.#isPreConsentQueueEnabled = isPreConsentQueueEnabled;\n this.#isGeolocationEnabled = isGeolocationEnabled;\n this.#platformAdapter = platformAdapter;\n this.#initPromise = undefined;\n this.#locationResolvePromise = undefined;\n\n this.messenger.registerMethodActionHandlers(\n this,\n MESSENGER_EXPOSED_METHODS,\n );\n\n log('AnalyticsController initialized and ready', {\n enabled: analyticsControllerSelectors.selectEnabled(this.state),\n optedIn: this.state.optedIn,\n consentDecisionMade: this.state.consentDecisionMade,\n analyticsId: this.state.analyticsId,\n eventQueuePersistenceEnabled: this.#isEventQueuePersistenceEnabled,\n preConsentQueueEnabled: this.#isPreConsentQueueEnabled,\n geolocationEnabled: this.#isGeolocationEnabled,\n });\n }\n\n /**\n * Initialize the controller by calling the platform adapter's\n * onSetupCompleted lifecycle hook and replaying any queued events. This\n * method must be called after construction to complete the setup process.\n *\n * When geolocation enrichment is enabled (`isGeolocationEnabled`), geolocation\n * is resolved only for a user who is already opted in; for undecided or\n * opted-out users it is deferred until they opt in (see {@link optIn}), so a\n * user's location is never requested before they consent to analytics. In\n * either case the `GeolocationController` and its\n * `GeolocationController:getGeolocationData` action must be registered before\n * resolution occurs, or enrichment is skipped for the session (a message is\n * logged, see {@link #resolveLocationContext}).\n *\n * Safe to call more than once: the first call performs initialization and\n * subsequent calls return the same in-flight (or settled) promise.\n *\n * @returns A promise that resolves once initialization has completed.\n */\n init(): Promise<void> {\n // Cache the in-flight promise so repeated or overlapping calls share a\n // single initialization and all await the same completion (rather than an\n // early call observing a finished init while work is still pending).\n this.#initPromise ??= this.#performInit();\n return this.#initPromise;\n }\n\n /**\n * Performs the one-time initialization work: resolve geolocation, run the\n * platform adapter's onSetupCompleted lifecycle hook, then replay any queued\n * and pre-consent events.\n */\n async #performInit(): Promise<void> {\n // Resolve geolocation only when the user is already opted in; for undecided\n // or opted-out users it is deferred to {@link optIn}. Awaited so that an\n // already-opted-in session has location available before events replay.\n await this.#maybeResolveLocation();\n\n // Call onSetupCompleted lifecycle hook after initialization\n // State is already validated, so analyticsId is guaranteed to be a valid UUIDv4\n try {\n this.#platformAdapter.onSetupCompleted(this.state.analyticsId);\n } catch (error) {\n // Log error but don't throw - adapter setup failure shouldn't break controller\n log('Error calling platformAdapter.onSetupCompleted', error);\n }\n\n this.#replayQueuedEvents();\n this.#reconcilePreConsentEvents();\n }\n\n /**\n * Start resolving the geolocation context if warranted, and return the\n * in-flight (or settled) resolution so callers can await it. No-op unless\n * enrichment is enabled, the user is opted in, and a resolution has not\n * already been started. Deferring resolution until opt-in ensures a user's\n * location is never requested before they consent to analytics (for example,\n * during onboarding).\n *\n * Resolution runs at most once per controller session: the settled promise\n * is retained, so the outcome — including a failure (see\n * {@link #resolveLocationContext}) — is not retried, and events are delivered\n * without location for the rest of the session.\n *\n * @returns The geolocation resolution promise, or `undefined` when no\n * resolution is warranted.\n */\n #maybeResolveLocation(): Promise<void> | undefined {\n if (\n this.#isGeolocationEnabled &&\n this.#locationResolvePromise === undefined &&\n analyticsControllerSelectors.selectEnabled(this.state)\n ) {\n this.#locationResolvePromise = this.#resolveLocationContext();\n }\n\n return this.#locationResolvePromise;\n }\n\n async #resolveLocationContext(): Promise<void> {\n try {\n const geolocation = await this.messenger.call(\n 'GeolocationController:getGeolocationData',\n );\n\n this.#locationContext = buildLocationContext(geolocation);\n } catch (error) {\n // A common cause is the GeolocationController not being registered before\n // resolution runs (at init for an opted-in user, otherwise at opt-in).\n // Name it here so the failure is diagnosable, since enrichment is\n // otherwise skipped silently for the session.\n log(\n 'Failed to resolve geolocation for analytics enrichment; events will be sent without location. Ensure the GeolocationController is registered and initialized before the user opts in when geolocation is enabled.',\n error,\n );\n }\n }\n\n /**\n * Merge the resolved location context into a caller-provided context.\n *\n * Caller-provided `location` fields are preserved, but the fields the\n * controller resolves take precedence over them.\n *\n * @param context - Optional caller-provided context.\n * @returns The context enriched with location, or the original context when\n * no location is known.\n */\n #withLocationContext(\n context?: AnalyticsContext,\n ): AnalyticsContext | undefined {\n if (!this.#locationContext) {\n return context;\n }\n\n const callerLocation = context?.location;\n\n return {\n ...context,\n location: {\n ...(isJsonRecord(callerLocation) ? callerLocation : {}),\n ...this.#locationContext,\n },\n };\n }\n\n /**\n * Send final track payload through the platform adapter or queue it if persistence is enabled.\n *\n * @param eventName - The name of the event.\n * @param properties - Optional event properties.\n * @param context - Optional platform-specific context.\n */\n #sendOrQueueTrackEvent(\n eventName: string,\n properties?: AnalyticsEventProperties,\n context?: AnalyticsContext,\n ): void {\n // Direct delivery: enabled and not persisting.\n if (\n analyticsControllerSelectors.selectEnabled(this.state) &&\n !this.#isEventQueuePersistenceEnabled\n ) {\n this.#platformAdapter.track(eventName, properties, context);\n return;\n }\n\n const queuedEvent: AnalyticsQueuedTrackEvent = {\n type: 'track',\n eventName,\n messageId: uuid(),\n timestamp: new Date().toISOString(),\n ...(properties === undefined ? {} : { properties }),\n ...(context === undefined ? {} : { context }),\n };\n\n // Not yet enabled (reached only while undecided with the pre-consent queue\n // enabled): hold the event until the user opts in.\n if (!analyticsControllerSelectors.selectEnabled(this.state)) {\n this.#enqueuePreConsentEvent(queuedEvent);\n return;\n }\n\n this.#enqueueEvent(queuedEvent);\n }\n\n /**\n * Send final identify payload through the platform adapter or queue it if persistence is enabled.\n *\n * @param userId - The user ID.\n * @param traits - Optional user traits.\n * @param context - Optional platform-specific context.\n */\n #sendOrQueueIdentifyEvent(\n userId: string,\n traits?: AnalyticsUserTraits,\n context?: AnalyticsContext,\n ): void {\n if (!this.#isEventQueuePersistenceEnabled) {\n this.#platformAdapter.identify(userId, traits, context);\n return;\n }\n\n const queuedEvent: AnalyticsQueuedIdentifyEvent = {\n type: 'identify',\n userId,\n messageId: uuid(),\n timestamp: new Date().toISOString(),\n ...(traits === undefined ? {} : { traits }),\n ...(context === undefined ? {} : { context }),\n };\n\n this.#enqueueEvent(queuedEvent);\n }\n\n /**\n * Send final view payload through the platform adapter or queue it if persistence is enabled.\n *\n * @param name - The view name.\n * @param properties - Optional view properties.\n * @param context - Optional platform-specific context.\n */\n #sendOrQueueViewEvent(\n name: string,\n properties?: AnalyticsEventProperties,\n context?: AnalyticsContext,\n ): void {\n if (!this.#isEventQueuePersistenceEnabled) {\n this.#platformAdapter.view(name, properties, context);\n return;\n }\n\n const queuedEvent: AnalyticsQueuedViewEvent = {\n type: 'view',\n name,\n messageId: uuid(),\n timestamp: new Date().toISOString(),\n ...(properties === undefined ? {} : { properties }),\n ...(context === undefined ? {} : { context }),\n };\n\n this.#enqueueEvent(queuedEvent);\n }\n\n /**\n * Add an analytics event to the queue and send it.\n *\n * @param queuedEvent - The event to enqueue and deliver.\n */\n #enqueueEvent(queuedEvent: AnalyticsQueuedEvent): void {\n const eventQueue: Record<string, Json> = {\n ...(this.state.eventQueue ?? {}),\n [queuedEvent.messageId]: queuedEvent as unknown as Json,\n };\n\n this.update((state) => {\n state.eventQueue = eventQueue as never;\n });\n\n this.#sendQueuedEvent(queuedEvent);\n }\n\n /**\n * Send a queued event through the platform adapter.\n *\n * @param queuedEvent - The queued event to deliver.\n */\n #sendQueuedEvent(queuedEvent: AnalyticsQueuedEvent): void {\n const timestamp = new Date(queuedEvent.timestamp);\n\n if (Number.isNaN(timestamp.getTime())) {\n log('Dropping queued analytics event with invalid timestamp', {\n messageId: queuedEvent.messageId,\n });\n this.#removeQueuedEvent(queuedEvent.messageId);\n return;\n }\n\n const options: AnalyticsDeliveryOptions = {\n messageId: queuedEvent.messageId,\n timestamp,\n callback: (error?: unknown) => {\n if (error) {\n log('Queued analytics event delivery failed', {\n messageId: queuedEvent.messageId,\n error,\n });\n }\n\n this.#removeQueuedEvent(queuedEvent.messageId);\n },\n };\n\n try {\n if (queuedEvent.type === 'track') {\n this.#platformAdapter.track(\n queuedEvent.eventName,\n cloneDeep(queuedEvent.properties),\n cloneDeep(queuedEvent.context),\n options,\n );\n } else if (queuedEvent.type === 'identify') {\n this.#platformAdapter.identify(\n queuedEvent.userId,\n cloneDeep(queuedEvent.traits),\n cloneDeep(queuedEvent.context),\n options,\n );\n } else {\n this.#platformAdapter.view(\n queuedEvent.name,\n cloneDeep(queuedEvent.properties),\n cloneDeep(queuedEvent.context),\n options,\n );\n }\n } catch (error) {\n log('Error sending queued analytics event', {\n messageId: queuedEvent.messageId,\n error,\n });\n }\n }\n\n /**\n * Replay persisted analytics events.\n */\n #replayQueuedEvents(): void {\n if (!this.#isEventQueuePersistenceEnabled || !this.state.eventQueue) {\n return;\n }\n\n if (!analyticsControllerSelectors.selectEnabled(this.state)) {\n this.#clearQueuedEvents();\n return;\n }\n\n for (const [messageId, queuedEvent] of Object.entries(\n this.state.eventQueue,\n )) {\n if (\n !isAnalyticsQueuedEvent(queuedEvent) ||\n queuedEvent.messageId !== messageId\n ) {\n log('Dropping invalid queued analytics event', { messageId });\n this.#removeQueuedEvent(messageId);\n continue;\n }\n\n this.#sendQueuedEvent(queuedEvent);\n }\n }\n\n /**\n * Remove a queued analytics event.\n *\n * @param messageId - The queued event message ID.\n */\n #removeQueuedEvent(messageId: string): void {\n const currentEventQueue = this.state.eventQueue;\n\n if (\n !currentEventQueue ||\n !Object.prototype.hasOwnProperty.call(currentEventQueue, messageId)\n ) {\n return;\n }\n\n const { [messageId]: _deletedEvent, ...eventQueue } = currentEventQueue;\n\n this.update((state) => {\n state.eventQueue = eventQueue as never;\n });\n }\n\n /**\n * Clear all queued analytics events.\n */\n #clearQueuedEvents(): void {\n if (\n !this.state.eventQueue ||\n Object.keys(this.state.eventQueue).length === 0\n ) {\n return;\n }\n\n this.update((state) => {\n state.eventQueue = {} as never;\n });\n }\n\n /**\n * Add an event to the pre-consent queue without delivering it.\n *\n * @param queuedEvent - The event to hold until the user opts in.\n */\n #enqueuePreConsentEvent(queuedEvent: AnalyticsQueuedEvent): void {\n const preConsentEventQueue: Record<string, Json> = {\n ...(this.state.preConsentEventQueue ?? {}),\n [queuedEvent.messageId]: queuedEvent as unknown as Json,\n };\n\n this.update((state) => {\n state.preConsentEventQueue = preConsentEventQueue as never;\n });\n }\n\n /**\n * Replay queued pre-consent events through the delivery path.\n *\n * Only called by {@link #reconcilePreConsentEvents}, which guarantees the\n * pre-consent queue is enabled and that the user is opted in. The queue is\n * cleared before replaying so events cannot be re-queued or replayed twice.\n *\n * @param queue - The pre-consent event queue to replay.\n */\n #replayPreConsentEvents(queue: Record<string, Json>): void {\n this.#clearPreConsentEvents();\n\n for (const [messageId, queuedEvent] of Object.entries(queue)) {\n if (\n !isAnalyticsQueuedEvent(queuedEvent) ||\n queuedEvent.messageId !== messageId\n ) {\n log('Dropping invalid queued pre-consent analytics event', {\n messageId,\n });\n continue;\n }\n\n const eventToReplay = this.#enrichPreConsentEvent(queuedEvent);\n\n if (this.#isEventQueuePersistenceEnabled) {\n this.#enqueueEvent(eventToReplay);\n } else {\n this.#sendQueuedEvent(eventToReplay);\n }\n }\n }\n\n /**\n * Enrich a pre-consent event with the geolocation resolved on opt-in.\n *\n * Pre-consent events are captured while geolocation is not yet resolved, so\n * they are re-enriched here as they replay. Anonymous track payloads are left\n * untouched, since they must never carry location.\n *\n * @param queuedEvent - The queued pre-consent event.\n * @returns The event with its context enriched, or the event unchanged when\n * enrichment does not apply.\n */\n #enrichPreConsentEvent(\n queuedEvent: AnalyticsQueuedEvent,\n ): AnalyticsQueuedEvent {\n if (\n queuedEvent.type === 'track' &&\n queuedEvent.properties?.anonymous === true\n ) {\n return queuedEvent;\n }\n\n const context = this.#withLocationContext(queuedEvent.context);\n\n return {\n ...queuedEvent,\n ...(context === undefined ? {} : { context }),\n };\n }\n\n /**\n * Clear all queued pre-consent events.\n */\n #clearPreConsentEvents(): void {\n if (!this.state.preConsentEventQueue) {\n return;\n }\n\n this.update((state) => {\n state.preConsentEventQueue = {} as never;\n });\n }\n\n /**\n * Reconcile the pre-consent queue on initialization.\n *\n * The queue should normally be empty unless the user is still undecided. This\n * handles the rare cases where a consent decision was persisted but the queue\n * was not flushed/cleared (e.g. an interrupted shutdown): replay it if the\n * user is opted in, or clear it if they opted out.\n *\n * If the pre-consent queue is disabled, any stale persisted entries (e.g. from\n * a previous session where it was enabled) are dropped so they can never be\n * replayed.\n */\n #reconcilePreConsentEvents(): void {\n const queue = this.state.preConsentEventQueue;\n\n if (!queue) {\n return;\n }\n\n if (!this.#isPreConsentQueueEnabled) {\n this.#clearPreConsentEvents();\n return;\n }\n\n if (this.state.optedIn) {\n this.#replayPreConsentEvents(queue);\n } else if (this.state.consentDecisionMade) {\n this.#clearPreConsentEvents();\n }\n }\n\n /**\n * Track an analytics event.\n *\n * Events are only tracked if analytics is enabled.\n *\n * @param event - Analytics event with properties and sensitive properties\n * @param context - Optional platform-specific context forwarded to the platform adapter.\n */\n trackEvent(event: AnalyticsTrackingEvent, context?: AnalyticsContext): void {\n if (!analyticsControllerSelectors.selectEnabled(this.state)) {\n // While the user is undecided, fall through so the event is processed and\n // captured in the pre-consent queue (see #sendOrQueueTrackEvent) to be\n // replayed if they later opt in. Otherwise (opted out, or pre-consent\n // queue disabled) drop it.\n const shouldQueuePreConsent =\n this.#isPreConsentQueueEnabled && !this.state.consentDecisionMade;\n if (!shouldQueuePreConsent) {\n return;\n }\n }\n\n // if event does not have properties, send event without properties\n // and return to prevent any additional processing\n if (!event.hasProperties) {\n this.#sendOrQueueTrackEvent(\n event.name,\n undefined,\n this.#withLocationContext(context),\n );\n return;\n }\n\n // Track regular properties first if anonymous events feature is enabled\n if (this.#isAnonymousEventsFeatureEnabled) {\n // Note: Even if regular properties object is empty, we still send it to ensure\n // an event with user ID is tracked.\n this.#sendOrQueueTrackEvent(\n event.name,\n {\n ...event.properties,\n },\n this.#withLocationContext(context),\n );\n }\n\n const hasSensitiveProperties =\n Object.keys(event.sensitiveProperties).length > 0;\n\n if (!this.#isAnonymousEventsFeatureEnabled || hasSensitiveProperties) {\n this.#sendOrQueueTrackEvent(\n event.name,\n {\n ...event.properties,\n ...event.sensitiveProperties,\n ...(hasSensitiveProperties && { anonymous: true }),\n },\n // When the anonymous events feature is enabled, this payload is the\n // anonymous one and must carry no geolocation. When the feature is\n // disabled, this is the single identified payload, so it is enriched.\n this.#isAnonymousEventsFeatureEnabled\n ? context\n : this.#withLocationContext(context),\n );\n }\n }\n\n /**\n * Identify a user for analytics.\n *\n * @param traits - User traits/properties\n * @param context - Optional platform-specific context forwarded to the platform adapter.\n */\n identify(traits?: AnalyticsUserTraits, context?: AnalyticsContext): void {\n if (!analyticsControllerSelectors.selectEnabled(this.state)) {\n return;\n }\n\n // Delegate to platform adapter using the current analytics ID\n this.#sendOrQueueIdentifyEvent(\n this.state.analyticsId,\n traits,\n this.#withLocationContext(context),\n );\n }\n\n /**\n * Track a page or screen view.\n *\n * @param name - The identifier/name of the page or screen being viewed (e.g., \"home\", \"settings\", \"wallet\")\n * @param properties - Optional properties associated with the view\n * @param context - Optional platform-specific context forwarded to the platform adapter.\n */\n trackView(\n name: string,\n properties?: AnalyticsEventProperties,\n context?: AnalyticsContext,\n ): void {\n if (!analyticsControllerSelectors.selectEnabled(this.state)) {\n return;\n }\n\n // Delegate to platform adapter\n this.#sendOrQueueViewEvent(\n name,\n properties,\n this.#withLocationContext(context),\n );\n }\n\n /**\n * Opt in to analytics.\n *\n * Records that a consent decision has been made and replays any events that\n * were queued while the user was undecided.\n *\n * When geolocation enrichment is enabled, geolocation is resolved here (once\n * the user has consented) and awaited before the queued events are replayed,\n * so those events are enriched with the resolved location as they are sent.\n *\n * @returns A promise that resolves once opt-in processing has completed.\n */\n async optIn(): Promise<void> {\n this.update((state) => {\n state.optedIn = true;\n state.consentDecisionMade = true;\n });\n\n // Now that the user has consented, resolve geolocation (once) and wait for\n // it so the queued pre-consent events can be enriched as they replay.\n await this.#maybeResolveLocation();\n\n // Reconcile against the current state rather than replaying blindly: the\n // consent decision may have changed while geolocation was resolving (e.g.\n // resetConsentDecision ran during the await), and preserved pre-consent\n // events must not be delivered once the user is no longer opted in.\n this.#reconcilePreConsentEvents();\n }\n\n /**\n * Opt out of analytics.\n *\n * Records that a consent decision has been made and discards any persisted\n * events so nothing captured before the decision is ever delivered.\n */\n optOut(): void {\n this.update((state) => {\n state.optedIn = false;\n state.consentDecisionMade = true;\n });\n\n this.#clearQueuedEvents();\n this.#clearPreConsentEvents();\n }\n\n /**\n * Reset the consent decision back to undecided.\n *\n * Intended for client flows that restart onboarding. Clears the opt-in\n * preference and discards the delivery queue, but preserves any pre-consent\n * events so they can still be replayed if the user opts in again. The user is\n * treated as undecided again.\n */\n resetConsentDecision(): void {\n this.update((state) => {\n state.optedIn = false;\n state.consentDecisionMade = false;\n });\n\n this.#clearQueuedEvents();\n }\n}\n"]} |
@@ -1,1 +0,1 @@ | ||
| {"version":3,"file":"analyticsControllerStateValidator.cjs","sourceRoot":"","sources":["../src/analyticsControllerStateValidator.ts"],"names":[],"mappings":";;;AAEA;;;;;;GAMG;AACH,MAAM,aAAa,GACjB,yEAAyE,CAAC;AAE5E;;;;;GAKG;AACH,SAAgB,aAAa,CAAC,KAAa;IACzC,OAAO,OAAO,KAAK,KAAK,QAAQ,IAAI,aAAa,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;AAChE,CAAC;AAFD,sCAEC;AAED;;;;;;GAMG;AACH,SAAgB,gCAAgC,CAC9C,KAA+B,EAC/B,eAAyB;IAEzB,IACE,CAAC,KAAK,CAAC,WAAW;QAClB,CAAC,eAAe,KAAK,IAAI,IAAI,CAAC,aAAa,CAAC,KAAK,CAAC,WAAW,CAAC,CAAC,EAC/D,CAAC;QACD,MAAM,IAAI,KAAK,CAAC,qBAAqB,CAAC,CAAC;IACzC,CAAC;AACH,CAAC;AAVD,4EAUC","sourcesContent":["import type { AnalyticsControllerState } from './AnalyticsController';\n\n/**\n * UUIDv4 format regex pattern.\n * Format: xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx\n * - x is any hexadecimal digit [0-9a-f]\n * - 4 indicates UUID version 4\n * - y is the variant indicator [89ab]\n */\nconst UUID_V4_REGEX =\n /^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/iu;\n\n/**\n * Validates that a string is a valid UUIDv4 format.\n *\n * @param value - The string to validate\n * @returns True if the string matches UUIDv4 format\n */\nexport function isValidUUIDv4(value: string): boolean {\n return typeof value === 'string' && UUID_V4_REGEX.test(value);\n}\n\n/**\n * Validates that the analytics state has a valid UUIDv4 analyticsId.\n *\n * @param state - The analytics controller state to validate\n * @param skipUUIDv4Check - When `true`, skips UUIDv4 format validation\n * @throws Error if analyticsId is missing or not a valid UUIDv4\n */\nexport function validateAnalyticsControllerState(\n state: AnalyticsControllerState,\n skipUUIDv4Check?: boolean,\n): void {\n if (\n !state.analyticsId ||\n (skipUUIDv4Check !== true && !isValidUUIDv4(state.analyticsId))\n ) {\n throw new Error('Invalid analyticsId');\n }\n}\n"]} | ||
| {"version":3,"file":"analyticsControllerStateValidator.cjs","sourceRoot":"","sources":["../src/analyticsControllerStateValidator.ts"],"names":[],"mappings":";;;AAEA;;;;;;GAMG;AACH,MAAM,aAAa,GACjB,yEAAyE,CAAC;AAE5E;;;;;GAKG;AACH,SAAgB,aAAa,CAAC,KAAa;IACzC,OAAO,OAAO,KAAK,KAAK,QAAQ,IAAI,aAAa,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;AAChE,CAAC;AAFD,sCAEC;AAED;;;;;;GAMG;AACH,SAAgB,gCAAgC,CAC9C,KAA+B,EAC/B,eAAyB;IAEzB,IACE,CAAC,KAAK,CAAC,WAAW;QAClB,CAAC,eAAe,KAAK,IAAI,IAAI,CAAC,aAAa,CAAC,KAAK,CAAC,WAAW,CAAC,CAAC,EAC/D,CAAC;QACD,MAAM,IAAI,KAAK,CAAC,qBAAqB,CAAC,CAAC;IACzC,CAAC;AACH,CAAC;AAVD,4EAUC","sourcesContent":["import type { AnalyticsControllerState } from './AnalyticsController.js';\n\n/**\n * UUIDv4 format regex pattern.\n * Format: xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx\n * - x is any hexadecimal digit [0-9a-f]\n * - 4 indicates UUID version 4\n * - y is the variant indicator [89ab]\n */\nconst UUID_V4_REGEX =\n /^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/iu;\n\n/**\n * Validates that a string is a valid UUIDv4 format.\n *\n * @param value - The string to validate\n * @returns True if the string matches UUIDv4 format\n */\nexport function isValidUUIDv4(value: string): boolean {\n return typeof value === 'string' && UUID_V4_REGEX.test(value);\n}\n\n/**\n * Validates that the analytics state has a valid UUIDv4 analyticsId.\n *\n * @param state - The analytics controller state to validate\n * @param skipUUIDv4Check - When `true`, skips UUIDv4 format validation\n * @throws Error if analyticsId is missing or not a valid UUIDv4\n */\nexport function validateAnalyticsControllerState(\n state: AnalyticsControllerState,\n skipUUIDv4Check?: boolean,\n): void {\n if (\n !state.analyticsId ||\n (skipUUIDv4Check !== true && !isValidUUIDv4(state.analyticsId))\n ) {\n throw new Error('Invalid analyticsId');\n }\n}\n"]} |
@@ -1,1 +0,1 @@ | ||
| {"version":3,"file":"analyticsControllerStateValidator.d.cts","sourceRoot":"","sources":["../src/analyticsControllerStateValidator.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,wBAAwB,EAAE,kCAA8B;AAYtE;;;;;GAKG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAEpD;AAED;;;;;;GAMG;AACH,wBAAgB,gCAAgC,CAC9C,KAAK,EAAE,wBAAwB,EAC/B,eAAe,CAAC,EAAE,OAAO,GACxB,IAAI,CAON"} | ||
| {"version":3,"file":"analyticsControllerStateValidator.d.cts","sourceRoot":"","sources":["../src/analyticsControllerStateValidator.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,wBAAwB,EAAE,kCAAiC;AAYzE;;;;;GAKG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAEpD;AAED;;;;;;GAMG;AACH,wBAAgB,gCAAgC,CAC9C,KAAK,EAAE,wBAAwB,EAC/B,eAAe,CAAC,EAAE,OAAO,GACxB,IAAI,CAON"} |
@@ -1,1 +0,1 @@ | ||
| {"version":3,"file":"analyticsControllerStateValidator.d.mts","sourceRoot":"","sources":["../src/analyticsControllerStateValidator.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,wBAAwB,EAAE,kCAA8B;AAYtE;;;;;GAKG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAEpD;AAED;;;;;;GAMG;AACH,wBAAgB,gCAAgC,CAC9C,KAAK,EAAE,wBAAwB,EAC/B,eAAe,CAAC,EAAE,OAAO,GACxB,IAAI,CAON"} | ||
| {"version":3,"file":"analyticsControllerStateValidator.d.mts","sourceRoot":"","sources":["../src/analyticsControllerStateValidator.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,wBAAwB,EAAE,kCAAiC;AAYzE;;;;;GAKG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAEpD;AAED;;;;;;GAMG;AACH,wBAAgB,gCAAgC,CAC9C,KAAK,EAAE,wBAAwB,EAC/B,eAAe,CAAC,EAAE,OAAO,GACxB,IAAI,CAON"} |
@@ -1,1 +0,1 @@ | ||
| {"version":3,"file":"analyticsControllerStateValidator.mjs","sourceRoot":"","sources":["../src/analyticsControllerStateValidator.ts"],"names":[],"mappings":"AAEA;;;;;;GAMG;AACH,MAAM,aAAa,GACjB,yEAAyE,CAAC;AAE5E;;;;;GAKG;AACH,MAAM,UAAU,aAAa,CAAC,KAAa;IACzC,OAAO,OAAO,KAAK,KAAK,QAAQ,IAAI,aAAa,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;AAChE,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,gCAAgC,CAC9C,KAA+B,EAC/B,eAAyB;IAEzB,IACE,CAAC,KAAK,CAAC,WAAW;QAClB,CAAC,eAAe,KAAK,IAAI,IAAI,CAAC,aAAa,CAAC,KAAK,CAAC,WAAW,CAAC,CAAC,EAC/D,CAAC;QACD,MAAM,IAAI,KAAK,CAAC,qBAAqB,CAAC,CAAC;IACzC,CAAC;AACH,CAAC","sourcesContent":["import type { AnalyticsControllerState } from './AnalyticsController';\n\n/**\n * UUIDv4 format regex pattern.\n * Format: xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx\n * - x is any hexadecimal digit [0-9a-f]\n * - 4 indicates UUID version 4\n * - y is the variant indicator [89ab]\n */\nconst UUID_V4_REGEX =\n /^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/iu;\n\n/**\n * Validates that a string is a valid UUIDv4 format.\n *\n * @param value - The string to validate\n * @returns True if the string matches UUIDv4 format\n */\nexport function isValidUUIDv4(value: string): boolean {\n return typeof value === 'string' && UUID_V4_REGEX.test(value);\n}\n\n/**\n * Validates that the analytics state has a valid UUIDv4 analyticsId.\n *\n * @param state - The analytics controller state to validate\n * @param skipUUIDv4Check - When `true`, skips UUIDv4 format validation\n * @throws Error if analyticsId is missing or not a valid UUIDv4\n */\nexport function validateAnalyticsControllerState(\n state: AnalyticsControllerState,\n skipUUIDv4Check?: boolean,\n): void {\n if (\n !state.analyticsId ||\n (skipUUIDv4Check !== true && !isValidUUIDv4(state.analyticsId))\n ) {\n throw new Error('Invalid analyticsId');\n }\n}\n"]} | ||
| {"version":3,"file":"analyticsControllerStateValidator.mjs","sourceRoot":"","sources":["../src/analyticsControllerStateValidator.ts"],"names":[],"mappings":"AAEA;;;;;;GAMG;AACH,MAAM,aAAa,GACjB,yEAAyE,CAAC;AAE5E;;;;;GAKG;AACH,MAAM,UAAU,aAAa,CAAC,KAAa;IACzC,OAAO,OAAO,KAAK,KAAK,QAAQ,IAAI,aAAa,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;AAChE,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,gCAAgC,CAC9C,KAA+B,EAC/B,eAAyB;IAEzB,IACE,CAAC,KAAK,CAAC,WAAW;QAClB,CAAC,eAAe,KAAK,IAAI,IAAI,CAAC,aAAa,CAAC,KAAK,CAAC,WAAW,CAAC,CAAC,EAC/D,CAAC;QACD,MAAM,IAAI,KAAK,CAAC,qBAAqB,CAAC,CAAC;IACzC,CAAC;AACH,CAAC","sourcesContent":["import type { AnalyticsControllerState } from './AnalyticsController.js';\n\n/**\n * UUIDv4 format regex pattern.\n * Format: xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx\n * - x is any hexadecimal digit [0-9a-f]\n * - 4 indicates UUID version 4\n * - y is the variant indicator [89ab]\n */\nconst UUID_V4_REGEX =\n /^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/iu;\n\n/**\n * Validates that a string is a valid UUIDv4 format.\n *\n * @param value - The string to validate\n * @returns True if the string matches UUIDv4 format\n */\nexport function isValidUUIDv4(value: string): boolean {\n return typeof value === 'string' && UUID_V4_REGEX.test(value);\n}\n\n/**\n * Validates that the analytics state has a valid UUIDv4 analyticsId.\n *\n * @param state - The analytics controller state to validate\n * @param skipUUIDv4Check - When `true`, skips UUIDv4 format validation\n * @throws Error if analyticsId is missing or not a valid UUIDv4\n */\nexport function validateAnalyticsControllerState(\n state: AnalyticsControllerState,\n skipUUIDv4Check?: boolean,\n): void {\n if (\n !state.analyticsId ||\n (skipUUIDv4Check !== true && !isValidUUIDv4(state.analyticsId))\n ) {\n throw new Error('Invalid analyticsId');\n }\n}\n"]} |
@@ -1,1 +0,1 @@ | ||
| {"version":3,"file":"AnalyticsPlatformAdapter.types.cjs","sourceRoot":"","sources":["../src/AnalyticsPlatformAdapter.types.ts"],"names":[],"mappings":"","sourcesContent":["import type { Json } from '@metamask/utils';\n\n/**\n * Analytics event properties\n */\nexport type AnalyticsEventProperties = Record<string, Json>;\n\n/**\n * User traits/properties for analytics identification\n */\nexport type AnalyticsUserTraits = Record<string, Json>;\n\n/**\n * Callback invoked by the platform adapter after an analytics payload is\n * delivered or fails.\n */\nexport type AnalyticsInvocationCallback = (error?: unknown) => void;\n\n/**\n * Internal delivery metadata used by AnalyticsController when event queue\n * persistence is enabled.\n */\nexport type AnalyticsDeliveryOptions = {\n /**\n * Stable identifier for the analytics payload.\n */\n messageId?: string;\n\n /**\n * Original timestamp for the analytics payload.\n */\n timestamp?: Date;\n\n /**\n * Callback for delivery acknowledgement.\n */\n callback?: AnalyticsInvocationCallback;\n};\n\n/**\n * Event properties structure with two distinct properties lists for regular and sensitive data.\n * Similar to ITrackingEvent from legacy analytics but decoupled for platform agnosticism.\n * Sensitivity is derived from the presence of sensitiveProperties (if sensitiveProperties has keys, the event is sensitive).\n */\nexport type AnalyticsTrackingEvent = {\n readonly name: string;\n properties: AnalyticsEventProperties;\n sensitiveProperties: AnalyticsEventProperties;\n /**\n * Legacy property handled by the mobile app.\n * This property is ignored by the analytics controller and will be removed from the type in the future.\n * The mobile app will use the future analytics privacy controller to handle this functionality.\n */\n saveDataRecording: boolean;\n readonly hasProperties: boolean;\n};\n\n/**\n * Optional analytics context payload (for example Segment-style context).\n */\nexport type AnalyticsContext = Record<string, Json>;\n\n/**\n * Platform adapter interface for analytics tracking\n * Implementations should handle platform-specific details (Segment SDK, etc.)\n */\nexport type AnalyticsPlatformAdapter = {\n /**\n * When `true`, the controller accepts any non-empty `analyticsId` string\n * instead of requiring UUIDv4 format. Defaults to validation against UUIDv4 when omitted or `false`.\n */\n skipUUIDv4Check?: boolean;\n\n /**\n * Track an analytics event.\n *\n * This is the same as trackEvent in the old analytics system\n *\n * @param eventName - The name of the event\n * @param properties - Event properties. If not provided, the event has no properties.\n * The privacy plugin should check for `isSensitive === true` to determine if an event contains sensitive data.\n * @param context - Optional platform-specific context attached to the invocation.\n * @param options - Optional delivery metadata for platform adapters.\n */\n track(\n eventName: string,\n properties?: AnalyticsEventProperties,\n context?: AnalyticsContext,\n options?: AnalyticsDeliveryOptions,\n ): void;\n\n /**\n * Identify a user with traits.\n *\n * @param userId - The user identifier (e.g., metametrics ID)\n * @param traits - User traits/properties\n * @param context - Optional platform-specific context attached to the invocation.\n * @param options - Optional delivery metadata for platform adapters.\n */\n identify(\n userId: string,\n traits?: AnalyticsUserTraits,\n context?: AnalyticsContext,\n options?: AnalyticsDeliveryOptions,\n ): void;\n\n /**\n * Track a UI unit (page or screen) view depending on the platform\n *\n * This method delegates to platform-specific Segment SDK methods:\n * - Web adapters should call `analytics.page(name, properties)`\n * - Mobile adapters should call `analytics.screen(name, properties)`\n *\n * @param name - The identifier/name of the page or screen being viewed (e.g., \"home\", \"settings\", \"wallet\")\n * @param properties - Optional properties associated with the view\n * @param context - Optional platform-specific context attached to the invocation.\n * @param options - Optional delivery metadata for platform adapters.\n */\n view(\n name: string,\n properties?: AnalyticsEventProperties,\n context?: AnalyticsContext,\n options?: AnalyticsDeliveryOptions,\n ): void;\n\n /**\n * Lifecycle hook called after the AnalyticsController is fully initialized.\n *\n * This hook allows platform-specific adapters to perform setup that requires\n * access to the controller's state (e.g., analyticsId).\n *\n * The controller calls this method once after initialization, passing the\n * analyticsId from controller state. The analyticsId is guaranteed to be set\n * when this method is called - this is the definition of \"completed\" setup.\n *\n * @param analyticsId - The analytics ID from controller state. Always set (never empty).\n * @throws {AnalyticsPlatformAdapterSetupError} May throw errors during setup (e.g., configuration errors, network failures).\n * Errors thrown by this method are caught and logged by the controller, but do not prevent\n * controller initialization from completing successfully.\n *\n * @example\n * ```typescript\n * onSetupCompleted(analyticsId: string): void {\n * // Add platform-specific plugins that require analyticsId\n * client.add({\n * plugin: new PrivacyPlugin(analyticsId),\n * });\n * }\n * ```\n */\n onSetupCompleted(analyticsId: string): void;\n};\n"]} | ||
| {"version":3,"file":"AnalyticsPlatformAdapter.types.cjs","sourceRoot":"","sources":["../src/AnalyticsPlatformAdapter.types.ts"],"names":[],"mappings":"","sourcesContent":["import type { Json } from '@metamask/utils';\n\n/**\n * Analytics event properties\n */\nexport type AnalyticsEventProperties = Record<string, Json>;\n\n/**\n * User traits/properties for analytics identification\n */\nexport type AnalyticsUserTraits = Record<string, Json>;\n\n/**\n * Callback invoked by the platform adapter after an analytics payload is\n * delivered or fails.\n */\nexport type AnalyticsInvocationCallback = (error?: unknown) => void;\n\n/**\n * Internal delivery metadata used by AnalyticsController when event queue\n * persistence is enabled.\n */\nexport type AnalyticsDeliveryOptions = {\n /**\n * Stable identifier for the analytics payload.\n */\n messageId?: string;\n\n /**\n * Original timestamp for the analytics payload.\n */\n timestamp?: Date;\n\n /**\n * Callback for delivery acknowledgement.\n */\n callback?: AnalyticsInvocationCallback;\n};\n\n/**\n * Event properties structure with two distinct properties lists for regular and sensitive data.\n * Similar to ITrackingEvent from legacy analytics but decoupled for platform agnosticism.\n * Sensitivity is derived from the presence of sensitiveProperties (if sensitiveProperties has keys, the event is sensitive).\n */\nexport type AnalyticsTrackingEvent = {\n readonly name: string;\n properties: AnalyticsEventProperties;\n sensitiveProperties: AnalyticsEventProperties;\n /**\n * Legacy property handled by the mobile app.\n * This property is ignored by the analytics controller and will be removed from the type in the future.\n * The mobile app will use the future analytics privacy controller to handle this functionality.\n */\n saveDataRecording: boolean;\n readonly hasProperties: boolean;\n};\n\n/**\n * Optional analytics context payload (for example Segment-style context).\n */\nexport type AnalyticsContext = Record<string, Json>;\n\n/**\n * Names of the geolocation fields attached to an analytics event.\n *\n * These follow the schema that downstream analytics destinations expect, which\n * is why they are snake_case rather than camelCase:\n *\n * - `country_code` is an ISO 3166-1 alpha-2 country code (e.g. `US`).\n * - `region` is an ISO 3166-2 subdivision code without the country prefix\n * (e.g. `WA`).\n * - `timezone` is an IANA time zone name (e.g. `America/Los_Angeles`).\n */\nexport type AnalyticsLocationField = 'country_code' | 'region' | 'timezone';\n\n/**\n * Geolocation fields attached to the `location` key of {@link AnalyticsContext}.\n *\n * Each field is only present when the geolocation API returned a valid value\n * for it.\n */\nexport type AnalyticsLocationContext = Partial<\n Record<AnalyticsLocationField, string>\n>;\n\n/**\n * Platform adapter interface for analytics tracking\n * Implementations should handle platform-specific details (Segment SDK, etc.)\n */\nexport type AnalyticsPlatformAdapter = {\n /**\n * When `true`, the controller accepts any non-empty `analyticsId` string\n * instead of requiring UUIDv4 format. Defaults to validation against UUIDv4 when omitted or `false`.\n */\n skipUUIDv4Check?: boolean;\n\n /**\n * Track an analytics event.\n *\n * This is the same as trackEvent in the old analytics system\n *\n * @param eventName - The name of the event\n * @param properties - Event properties. If not provided, the event has no properties.\n * The privacy plugin should check for `isSensitive === true` to determine if an event contains sensitive data.\n * @param context - Optional platform-specific context attached to the invocation.\n * @param options - Optional delivery metadata for platform adapters.\n */\n track(\n eventName: string,\n properties?: AnalyticsEventProperties,\n context?: AnalyticsContext,\n options?: AnalyticsDeliveryOptions,\n ): void;\n\n /**\n * Identify a user with traits.\n *\n * @param userId - The user identifier (e.g., metametrics ID)\n * @param traits - User traits/properties\n * @param context - Optional platform-specific context attached to the invocation.\n * @param options - Optional delivery metadata for platform adapters.\n */\n identify(\n userId: string,\n traits?: AnalyticsUserTraits,\n context?: AnalyticsContext,\n options?: AnalyticsDeliveryOptions,\n ): void;\n\n /**\n * Track a UI unit (page or screen) view depending on the platform\n *\n * This method delegates to platform-specific Segment SDK methods:\n * - Web adapters should call `analytics.page(name, properties)`\n * - Mobile adapters should call `analytics.screen(name, properties)`\n *\n * @param name - The identifier/name of the page or screen being viewed (e.g., \"home\", \"settings\", \"wallet\")\n * @param properties - Optional properties associated with the view\n * @param context - Optional platform-specific context attached to the invocation.\n * @param options - Optional delivery metadata for platform adapters.\n */\n view(\n name: string,\n properties?: AnalyticsEventProperties,\n context?: AnalyticsContext,\n options?: AnalyticsDeliveryOptions,\n ): void;\n\n /**\n * Lifecycle hook called after the AnalyticsController is fully initialized.\n *\n * This hook allows platform-specific adapters to perform setup that requires\n * access to the controller's state (e.g., analyticsId).\n *\n * The controller calls this method once after initialization, passing the\n * analyticsId from controller state. The analyticsId is guaranteed to be set\n * when this method is called - this is the definition of \"completed\" setup.\n *\n * @param analyticsId - The analytics ID from controller state. Always set (never empty).\n * @throws {AnalyticsPlatformAdapterSetupError} May throw errors during setup (e.g., configuration errors, network failures).\n * Errors thrown by this method are caught and logged by the controller, but do not prevent\n * controller initialization from completing successfully.\n *\n * @example\n * ```typescript\n * onSetupCompleted(analyticsId: string): void {\n * // Add platform-specific plugins that require analyticsId\n * client.add({\n * plugin: new PrivacyPlugin(analyticsId),\n * });\n * }\n * ```\n */\n onSetupCompleted(analyticsId: string): void;\n};\n"]} |
@@ -55,2 +55,21 @@ import type { Json } from "@metamask/utils"; | ||
| /** | ||
| * Names of the geolocation fields attached to an analytics event. | ||
| * | ||
| * These follow the schema that downstream analytics destinations expect, which | ||
| * is why they are snake_case rather than camelCase: | ||
| * | ||
| * - `country_code` is an ISO 3166-1 alpha-2 country code (e.g. `US`). | ||
| * - `region` is an ISO 3166-2 subdivision code without the country prefix | ||
| * (e.g. `WA`). | ||
| * - `timezone` is an IANA time zone name (e.g. `America/Los_Angeles`). | ||
| */ | ||
| export type AnalyticsLocationField = 'country_code' | 'region' | 'timezone'; | ||
| /** | ||
| * Geolocation fields attached to the `location` key of {@link AnalyticsContext}. | ||
| * | ||
| * Each field is only present when the geolocation API returned a valid value | ||
| * for it. | ||
| */ | ||
| export type AnalyticsLocationContext = Partial<Record<AnalyticsLocationField, string>>; | ||
| /** | ||
| * Platform adapter interface for analytics tracking | ||
@@ -57,0 +76,0 @@ * Implementations should handle platform-specific details (Segment SDK, etc.) |
@@ -1,1 +0,1 @@ | ||
| {"version":3,"file":"AnalyticsPlatformAdapter.types.d.cts","sourceRoot":"","sources":["../src/AnalyticsPlatformAdapter.types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,wBAAwB;AAE5C;;GAEG;AACH,MAAM,MAAM,wBAAwB,GAAG,MAAM,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;AAE5D;;GAEG;AACH,MAAM,MAAM,mBAAmB,GAAG,MAAM,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;AAEvD;;;GAGG;AACH,MAAM,MAAM,2BAA2B,GAAG,CAAC,KAAK,CAAC,EAAE,OAAO,KAAK,IAAI,CAAC;AAEpE;;;GAGG;AACH,MAAM,MAAM,wBAAwB,GAAG;IACrC;;OAEG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IAEnB;;OAEG;IACH,SAAS,CAAC,EAAE,IAAI,CAAC;IAEjB;;OAEG;IACH,QAAQ,CAAC,EAAE,2BAA2B,CAAC;CACxC,CAAC;AAEF;;;;GAIG;AACH,MAAM,MAAM,sBAAsB,GAAG;IACnC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,UAAU,EAAE,wBAAwB,CAAC;IACrC,mBAAmB,EAAE,wBAAwB,CAAC;IAC9C;;;;OAIG;IACH,iBAAiB,EAAE,OAAO,CAAC;IAC3B,QAAQ,CAAC,aAAa,EAAE,OAAO,CAAC;CACjC,CAAC;AAEF;;GAEG;AACH,MAAM,MAAM,gBAAgB,GAAG,MAAM,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;AAEpD;;;GAGG;AACH,MAAM,MAAM,wBAAwB,GAAG;IACrC;;;OAGG;IACH,eAAe,CAAC,EAAE,OAAO,CAAC;IAE1B;;;;;;;;;;OAUG;IACH,KAAK,CACH,SAAS,EAAE,MAAM,EACjB,UAAU,CAAC,EAAE,wBAAwB,EACrC,OAAO,CAAC,EAAE,gBAAgB,EAC1B,OAAO,CAAC,EAAE,wBAAwB,GACjC,IAAI,CAAC;IAER;;;;;;;OAOG;IACH,QAAQ,CACN,MAAM,EAAE,MAAM,EACd,MAAM,CAAC,EAAE,mBAAmB,EAC5B,OAAO,CAAC,EAAE,gBAAgB,EAC1B,OAAO,CAAC,EAAE,wBAAwB,GACjC,IAAI,CAAC;IAER;;;;;;;;;;;OAWG;IACH,IAAI,CACF,IAAI,EAAE,MAAM,EACZ,UAAU,CAAC,EAAE,wBAAwB,EACrC,OAAO,CAAC,EAAE,gBAAgB,EAC1B,OAAO,CAAC,EAAE,wBAAwB,GACjC,IAAI,CAAC;IAER;;;;;;;;;;;;;;;;;;;;;;;;OAwBG;IACH,gBAAgB,CAAC,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;CAC7C,CAAC"} | ||
| {"version":3,"file":"AnalyticsPlatformAdapter.types.d.cts","sourceRoot":"","sources":["../src/AnalyticsPlatformAdapter.types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,wBAAwB;AAE5C;;GAEG;AACH,MAAM,MAAM,wBAAwB,GAAG,MAAM,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;AAE5D;;GAEG;AACH,MAAM,MAAM,mBAAmB,GAAG,MAAM,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;AAEvD;;;GAGG;AACH,MAAM,MAAM,2BAA2B,GAAG,CAAC,KAAK,CAAC,EAAE,OAAO,KAAK,IAAI,CAAC;AAEpE;;;GAGG;AACH,MAAM,MAAM,wBAAwB,GAAG;IACrC;;OAEG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IAEnB;;OAEG;IACH,SAAS,CAAC,EAAE,IAAI,CAAC;IAEjB;;OAEG;IACH,QAAQ,CAAC,EAAE,2BAA2B,CAAC;CACxC,CAAC;AAEF;;;;GAIG;AACH,MAAM,MAAM,sBAAsB,GAAG;IACnC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,UAAU,EAAE,wBAAwB,CAAC;IACrC,mBAAmB,EAAE,wBAAwB,CAAC;IAC9C;;;;OAIG;IACH,iBAAiB,EAAE,OAAO,CAAC;IAC3B,QAAQ,CAAC,aAAa,EAAE,OAAO,CAAC;CACjC,CAAC;AAEF;;GAEG;AACH,MAAM,MAAM,gBAAgB,GAAG,MAAM,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;AAEpD;;;;;;;;;;GAUG;AACH,MAAM,MAAM,sBAAsB,GAAG,cAAc,GAAG,QAAQ,GAAG,UAAU,CAAC;AAE5E;;;;;GAKG;AACH,MAAM,MAAM,wBAAwB,GAAG,OAAO,CAC5C,MAAM,CAAC,sBAAsB,EAAE,MAAM,CAAC,CACvC,CAAC;AAEF;;;GAGG;AACH,MAAM,MAAM,wBAAwB,GAAG;IACrC;;;OAGG;IACH,eAAe,CAAC,EAAE,OAAO,CAAC;IAE1B;;;;;;;;;;OAUG;IACH,KAAK,CACH,SAAS,EAAE,MAAM,EACjB,UAAU,CAAC,EAAE,wBAAwB,EACrC,OAAO,CAAC,EAAE,gBAAgB,EAC1B,OAAO,CAAC,EAAE,wBAAwB,GACjC,IAAI,CAAC;IAER;;;;;;;OAOG;IACH,QAAQ,CACN,MAAM,EAAE,MAAM,EACd,MAAM,CAAC,EAAE,mBAAmB,EAC5B,OAAO,CAAC,EAAE,gBAAgB,EAC1B,OAAO,CAAC,EAAE,wBAAwB,GACjC,IAAI,CAAC;IAER;;;;;;;;;;;OAWG;IACH,IAAI,CACF,IAAI,EAAE,MAAM,EACZ,UAAU,CAAC,EAAE,wBAAwB,EACrC,OAAO,CAAC,EAAE,gBAAgB,EAC1B,OAAO,CAAC,EAAE,wBAAwB,GACjC,IAAI,CAAC;IAER;;;;;;;;;;;;;;;;;;;;;;;;OAwBG;IACH,gBAAgB,CAAC,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;CAC7C,CAAC"} |
@@ -55,2 +55,21 @@ import type { Json } from "@metamask/utils"; | ||
| /** | ||
| * Names of the geolocation fields attached to an analytics event. | ||
| * | ||
| * These follow the schema that downstream analytics destinations expect, which | ||
| * is why they are snake_case rather than camelCase: | ||
| * | ||
| * - `country_code` is an ISO 3166-1 alpha-2 country code (e.g. `US`). | ||
| * - `region` is an ISO 3166-2 subdivision code without the country prefix | ||
| * (e.g. `WA`). | ||
| * - `timezone` is an IANA time zone name (e.g. `America/Los_Angeles`). | ||
| */ | ||
| export type AnalyticsLocationField = 'country_code' | 'region' | 'timezone'; | ||
| /** | ||
| * Geolocation fields attached to the `location` key of {@link AnalyticsContext}. | ||
| * | ||
| * Each field is only present when the geolocation API returned a valid value | ||
| * for it. | ||
| */ | ||
| export type AnalyticsLocationContext = Partial<Record<AnalyticsLocationField, string>>; | ||
| /** | ||
| * Platform adapter interface for analytics tracking | ||
@@ -57,0 +76,0 @@ * Implementations should handle platform-specific details (Segment SDK, etc.) |
@@ -1,1 +0,1 @@ | ||
| {"version":3,"file":"AnalyticsPlatformAdapter.types.d.mts","sourceRoot":"","sources":["../src/AnalyticsPlatformAdapter.types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,wBAAwB;AAE5C;;GAEG;AACH,MAAM,MAAM,wBAAwB,GAAG,MAAM,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;AAE5D;;GAEG;AACH,MAAM,MAAM,mBAAmB,GAAG,MAAM,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;AAEvD;;;GAGG;AACH,MAAM,MAAM,2BAA2B,GAAG,CAAC,KAAK,CAAC,EAAE,OAAO,KAAK,IAAI,CAAC;AAEpE;;;GAGG;AACH,MAAM,MAAM,wBAAwB,GAAG;IACrC;;OAEG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IAEnB;;OAEG;IACH,SAAS,CAAC,EAAE,IAAI,CAAC;IAEjB;;OAEG;IACH,QAAQ,CAAC,EAAE,2BAA2B,CAAC;CACxC,CAAC;AAEF;;;;GAIG;AACH,MAAM,MAAM,sBAAsB,GAAG;IACnC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,UAAU,EAAE,wBAAwB,CAAC;IACrC,mBAAmB,EAAE,wBAAwB,CAAC;IAC9C;;;;OAIG;IACH,iBAAiB,EAAE,OAAO,CAAC;IAC3B,QAAQ,CAAC,aAAa,EAAE,OAAO,CAAC;CACjC,CAAC;AAEF;;GAEG;AACH,MAAM,MAAM,gBAAgB,GAAG,MAAM,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;AAEpD;;;GAGG;AACH,MAAM,MAAM,wBAAwB,GAAG;IACrC;;;OAGG;IACH,eAAe,CAAC,EAAE,OAAO,CAAC;IAE1B;;;;;;;;;;OAUG;IACH,KAAK,CACH,SAAS,EAAE,MAAM,EACjB,UAAU,CAAC,EAAE,wBAAwB,EACrC,OAAO,CAAC,EAAE,gBAAgB,EAC1B,OAAO,CAAC,EAAE,wBAAwB,GACjC,IAAI,CAAC;IAER;;;;;;;OAOG;IACH,QAAQ,CACN,MAAM,EAAE,MAAM,EACd,MAAM,CAAC,EAAE,mBAAmB,EAC5B,OAAO,CAAC,EAAE,gBAAgB,EAC1B,OAAO,CAAC,EAAE,wBAAwB,GACjC,IAAI,CAAC;IAER;;;;;;;;;;;OAWG;IACH,IAAI,CACF,IAAI,EAAE,MAAM,EACZ,UAAU,CAAC,EAAE,wBAAwB,EACrC,OAAO,CAAC,EAAE,gBAAgB,EAC1B,OAAO,CAAC,EAAE,wBAAwB,GACjC,IAAI,CAAC;IAER;;;;;;;;;;;;;;;;;;;;;;;;OAwBG;IACH,gBAAgB,CAAC,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;CAC7C,CAAC"} | ||
| {"version":3,"file":"AnalyticsPlatformAdapter.types.d.mts","sourceRoot":"","sources":["../src/AnalyticsPlatformAdapter.types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,wBAAwB;AAE5C;;GAEG;AACH,MAAM,MAAM,wBAAwB,GAAG,MAAM,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;AAE5D;;GAEG;AACH,MAAM,MAAM,mBAAmB,GAAG,MAAM,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;AAEvD;;;GAGG;AACH,MAAM,MAAM,2BAA2B,GAAG,CAAC,KAAK,CAAC,EAAE,OAAO,KAAK,IAAI,CAAC;AAEpE;;;GAGG;AACH,MAAM,MAAM,wBAAwB,GAAG;IACrC;;OAEG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IAEnB;;OAEG;IACH,SAAS,CAAC,EAAE,IAAI,CAAC;IAEjB;;OAEG;IACH,QAAQ,CAAC,EAAE,2BAA2B,CAAC;CACxC,CAAC;AAEF;;;;GAIG;AACH,MAAM,MAAM,sBAAsB,GAAG;IACnC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,UAAU,EAAE,wBAAwB,CAAC;IACrC,mBAAmB,EAAE,wBAAwB,CAAC;IAC9C;;;;OAIG;IACH,iBAAiB,EAAE,OAAO,CAAC;IAC3B,QAAQ,CAAC,aAAa,EAAE,OAAO,CAAC;CACjC,CAAC;AAEF;;GAEG;AACH,MAAM,MAAM,gBAAgB,GAAG,MAAM,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;AAEpD;;;;;;;;;;GAUG;AACH,MAAM,MAAM,sBAAsB,GAAG,cAAc,GAAG,QAAQ,GAAG,UAAU,CAAC;AAE5E;;;;;GAKG;AACH,MAAM,MAAM,wBAAwB,GAAG,OAAO,CAC5C,MAAM,CAAC,sBAAsB,EAAE,MAAM,CAAC,CACvC,CAAC;AAEF;;;GAGG;AACH,MAAM,MAAM,wBAAwB,GAAG;IACrC;;;OAGG;IACH,eAAe,CAAC,EAAE,OAAO,CAAC;IAE1B;;;;;;;;;;OAUG;IACH,KAAK,CACH,SAAS,EAAE,MAAM,EACjB,UAAU,CAAC,EAAE,wBAAwB,EACrC,OAAO,CAAC,EAAE,gBAAgB,EAC1B,OAAO,CAAC,EAAE,wBAAwB,GACjC,IAAI,CAAC;IAER;;;;;;;OAOG;IACH,QAAQ,CACN,MAAM,EAAE,MAAM,EACd,MAAM,CAAC,EAAE,mBAAmB,EAC5B,OAAO,CAAC,EAAE,gBAAgB,EAC1B,OAAO,CAAC,EAAE,wBAAwB,GACjC,IAAI,CAAC;IAER;;;;;;;;;;;OAWG;IACH,IAAI,CACF,IAAI,EAAE,MAAM,EACZ,UAAU,CAAC,EAAE,wBAAwB,EACrC,OAAO,CAAC,EAAE,gBAAgB,EAC1B,OAAO,CAAC,EAAE,wBAAwB,GACjC,IAAI,CAAC;IAER;;;;;;;;;;;;;;;;;;;;;;;;OAwBG;IACH,gBAAgB,CAAC,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;CAC7C,CAAC"} |
@@ -1,1 +0,1 @@ | ||
| {"version":3,"file":"AnalyticsPlatformAdapter.types.mjs","sourceRoot":"","sources":["../src/AnalyticsPlatformAdapter.types.ts"],"names":[],"mappings":"","sourcesContent":["import type { Json } from '@metamask/utils';\n\n/**\n * Analytics event properties\n */\nexport type AnalyticsEventProperties = Record<string, Json>;\n\n/**\n * User traits/properties for analytics identification\n */\nexport type AnalyticsUserTraits = Record<string, Json>;\n\n/**\n * Callback invoked by the platform adapter after an analytics payload is\n * delivered or fails.\n */\nexport type AnalyticsInvocationCallback = (error?: unknown) => void;\n\n/**\n * Internal delivery metadata used by AnalyticsController when event queue\n * persistence is enabled.\n */\nexport type AnalyticsDeliveryOptions = {\n /**\n * Stable identifier for the analytics payload.\n */\n messageId?: string;\n\n /**\n * Original timestamp for the analytics payload.\n */\n timestamp?: Date;\n\n /**\n * Callback for delivery acknowledgement.\n */\n callback?: AnalyticsInvocationCallback;\n};\n\n/**\n * Event properties structure with two distinct properties lists for regular and sensitive data.\n * Similar to ITrackingEvent from legacy analytics but decoupled for platform agnosticism.\n * Sensitivity is derived from the presence of sensitiveProperties (if sensitiveProperties has keys, the event is sensitive).\n */\nexport type AnalyticsTrackingEvent = {\n readonly name: string;\n properties: AnalyticsEventProperties;\n sensitiveProperties: AnalyticsEventProperties;\n /**\n * Legacy property handled by the mobile app.\n * This property is ignored by the analytics controller and will be removed from the type in the future.\n * The mobile app will use the future analytics privacy controller to handle this functionality.\n */\n saveDataRecording: boolean;\n readonly hasProperties: boolean;\n};\n\n/**\n * Optional analytics context payload (for example Segment-style context).\n */\nexport type AnalyticsContext = Record<string, Json>;\n\n/**\n * Platform adapter interface for analytics tracking\n * Implementations should handle platform-specific details (Segment SDK, etc.)\n */\nexport type AnalyticsPlatformAdapter = {\n /**\n * When `true`, the controller accepts any non-empty `analyticsId` string\n * instead of requiring UUIDv4 format. Defaults to validation against UUIDv4 when omitted or `false`.\n */\n skipUUIDv4Check?: boolean;\n\n /**\n * Track an analytics event.\n *\n * This is the same as trackEvent in the old analytics system\n *\n * @param eventName - The name of the event\n * @param properties - Event properties. If not provided, the event has no properties.\n * The privacy plugin should check for `isSensitive === true` to determine if an event contains sensitive data.\n * @param context - Optional platform-specific context attached to the invocation.\n * @param options - Optional delivery metadata for platform adapters.\n */\n track(\n eventName: string,\n properties?: AnalyticsEventProperties,\n context?: AnalyticsContext,\n options?: AnalyticsDeliveryOptions,\n ): void;\n\n /**\n * Identify a user with traits.\n *\n * @param userId - The user identifier (e.g., metametrics ID)\n * @param traits - User traits/properties\n * @param context - Optional platform-specific context attached to the invocation.\n * @param options - Optional delivery metadata for platform adapters.\n */\n identify(\n userId: string,\n traits?: AnalyticsUserTraits,\n context?: AnalyticsContext,\n options?: AnalyticsDeliveryOptions,\n ): void;\n\n /**\n * Track a UI unit (page or screen) view depending on the platform\n *\n * This method delegates to platform-specific Segment SDK methods:\n * - Web adapters should call `analytics.page(name, properties)`\n * - Mobile adapters should call `analytics.screen(name, properties)`\n *\n * @param name - The identifier/name of the page or screen being viewed (e.g., \"home\", \"settings\", \"wallet\")\n * @param properties - Optional properties associated with the view\n * @param context - Optional platform-specific context attached to the invocation.\n * @param options - Optional delivery metadata for platform adapters.\n */\n view(\n name: string,\n properties?: AnalyticsEventProperties,\n context?: AnalyticsContext,\n options?: AnalyticsDeliveryOptions,\n ): void;\n\n /**\n * Lifecycle hook called after the AnalyticsController is fully initialized.\n *\n * This hook allows platform-specific adapters to perform setup that requires\n * access to the controller's state (e.g., analyticsId).\n *\n * The controller calls this method once after initialization, passing the\n * analyticsId from controller state. The analyticsId is guaranteed to be set\n * when this method is called - this is the definition of \"completed\" setup.\n *\n * @param analyticsId - The analytics ID from controller state. Always set (never empty).\n * @throws {AnalyticsPlatformAdapterSetupError} May throw errors during setup (e.g., configuration errors, network failures).\n * Errors thrown by this method are caught and logged by the controller, but do not prevent\n * controller initialization from completing successfully.\n *\n * @example\n * ```typescript\n * onSetupCompleted(analyticsId: string): void {\n * // Add platform-specific plugins that require analyticsId\n * client.add({\n * plugin: new PrivacyPlugin(analyticsId),\n * });\n * }\n * ```\n */\n onSetupCompleted(analyticsId: string): void;\n};\n"]} | ||
| {"version":3,"file":"AnalyticsPlatformAdapter.types.mjs","sourceRoot":"","sources":["../src/AnalyticsPlatformAdapter.types.ts"],"names":[],"mappings":"","sourcesContent":["import type { Json } from '@metamask/utils';\n\n/**\n * Analytics event properties\n */\nexport type AnalyticsEventProperties = Record<string, Json>;\n\n/**\n * User traits/properties for analytics identification\n */\nexport type AnalyticsUserTraits = Record<string, Json>;\n\n/**\n * Callback invoked by the platform adapter after an analytics payload is\n * delivered or fails.\n */\nexport type AnalyticsInvocationCallback = (error?: unknown) => void;\n\n/**\n * Internal delivery metadata used by AnalyticsController when event queue\n * persistence is enabled.\n */\nexport type AnalyticsDeliveryOptions = {\n /**\n * Stable identifier for the analytics payload.\n */\n messageId?: string;\n\n /**\n * Original timestamp for the analytics payload.\n */\n timestamp?: Date;\n\n /**\n * Callback for delivery acknowledgement.\n */\n callback?: AnalyticsInvocationCallback;\n};\n\n/**\n * Event properties structure with two distinct properties lists for regular and sensitive data.\n * Similar to ITrackingEvent from legacy analytics but decoupled for platform agnosticism.\n * Sensitivity is derived from the presence of sensitiveProperties (if sensitiveProperties has keys, the event is sensitive).\n */\nexport type AnalyticsTrackingEvent = {\n readonly name: string;\n properties: AnalyticsEventProperties;\n sensitiveProperties: AnalyticsEventProperties;\n /**\n * Legacy property handled by the mobile app.\n * This property is ignored by the analytics controller and will be removed from the type in the future.\n * The mobile app will use the future analytics privacy controller to handle this functionality.\n */\n saveDataRecording: boolean;\n readonly hasProperties: boolean;\n};\n\n/**\n * Optional analytics context payload (for example Segment-style context).\n */\nexport type AnalyticsContext = Record<string, Json>;\n\n/**\n * Names of the geolocation fields attached to an analytics event.\n *\n * These follow the schema that downstream analytics destinations expect, which\n * is why they are snake_case rather than camelCase:\n *\n * - `country_code` is an ISO 3166-1 alpha-2 country code (e.g. `US`).\n * - `region` is an ISO 3166-2 subdivision code without the country prefix\n * (e.g. `WA`).\n * - `timezone` is an IANA time zone name (e.g. `America/Los_Angeles`).\n */\nexport type AnalyticsLocationField = 'country_code' | 'region' | 'timezone';\n\n/**\n * Geolocation fields attached to the `location` key of {@link AnalyticsContext}.\n *\n * Each field is only present when the geolocation API returned a valid value\n * for it.\n */\nexport type AnalyticsLocationContext = Partial<\n Record<AnalyticsLocationField, string>\n>;\n\n/**\n * Platform adapter interface for analytics tracking\n * Implementations should handle platform-specific details (Segment SDK, etc.)\n */\nexport type AnalyticsPlatformAdapter = {\n /**\n * When `true`, the controller accepts any non-empty `analyticsId` string\n * instead of requiring UUIDv4 format. Defaults to validation against UUIDv4 when omitted or `false`.\n */\n skipUUIDv4Check?: boolean;\n\n /**\n * Track an analytics event.\n *\n * This is the same as trackEvent in the old analytics system\n *\n * @param eventName - The name of the event\n * @param properties - Event properties. If not provided, the event has no properties.\n * The privacy plugin should check for `isSensitive === true` to determine if an event contains sensitive data.\n * @param context - Optional platform-specific context attached to the invocation.\n * @param options - Optional delivery metadata for platform adapters.\n */\n track(\n eventName: string,\n properties?: AnalyticsEventProperties,\n context?: AnalyticsContext,\n options?: AnalyticsDeliveryOptions,\n ): void;\n\n /**\n * Identify a user with traits.\n *\n * @param userId - The user identifier (e.g., metametrics ID)\n * @param traits - User traits/properties\n * @param context - Optional platform-specific context attached to the invocation.\n * @param options - Optional delivery metadata for platform adapters.\n */\n identify(\n userId: string,\n traits?: AnalyticsUserTraits,\n context?: AnalyticsContext,\n options?: AnalyticsDeliveryOptions,\n ): void;\n\n /**\n * Track a UI unit (page or screen) view depending on the platform\n *\n * This method delegates to platform-specific Segment SDK methods:\n * - Web adapters should call `analytics.page(name, properties)`\n * - Mobile adapters should call `analytics.screen(name, properties)`\n *\n * @param name - The identifier/name of the page or screen being viewed (e.g., \"home\", \"settings\", \"wallet\")\n * @param properties - Optional properties associated with the view\n * @param context - Optional platform-specific context attached to the invocation.\n * @param options - Optional delivery metadata for platform adapters.\n */\n view(\n name: string,\n properties?: AnalyticsEventProperties,\n context?: AnalyticsContext,\n options?: AnalyticsDeliveryOptions,\n ): void;\n\n /**\n * Lifecycle hook called after the AnalyticsController is fully initialized.\n *\n * This hook allows platform-specific adapters to perform setup that requires\n * access to the controller's state (e.g., analyticsId).\n *\n * The controller calls this method once after initialization, passing the\n * analyticsId from controller state. The analyticsId is guaranteed to be set\n * when this method is called - this is the definition of \"completed\" setup.\n *\n * @param analyticsId - The analytics ID from controller state. Always set (never empty).\n * @throws {AnalyticsPlatformAdapterSetupError} May throw errors during setup (e.g., configuration errors, network failures).\n * Errors thrown by this method are caught and logged by the controller, but do not prevent\n * controller initialization from completing successfully.\n *\n * @example\n * ```typescript\n * onSetupCompleted(analyticsId: string): void {\n * // Add platform-specific plugins that require analyticsId\n * client.add({\n * plugin: new PrivacyPlugin(analyticsId),\n * });\n * }\n * ```\n */\n onSetupCompleted(analyticsId: string): void;\n};\n"]} |
+7
-7
@@ -5,11 +5,11 @@ "use strict"; | ||
| // Export controller class and state utilities | ||
| var AnalyticsController_1 = require("./AnalyticsController.cjs"); | ||
| Object.defineProperty(exports, "AnalyticsController", { enumerable: true, get: function () { return AnalyticsController_1.AnalyticsController; } }); | ||
| Object.defineProperty(exports, "getDefaultAnalyticsControllerState", { enumerable: true, get: function () { return AnalyticsController_1.getDefaultAnalyticsControllerState; } }); | ||
| var AnalyticsController_js_1 = require("./AnalyticsController.cjs"); | ||
| Object.defineProperty(exports, "AnalyticsController", { enumerable: true, get: function () { return AnalyticsController_js_1.AnalyticsController; } }); | ||
| Object.defineProperty(exports, "getDefaultAnalyticsControllerState", { enumerable: true, get: function () { return AnalyticsController_js_1.getDefaultAnalyticsControllerState; } }); | ||
| // Export errors | ||
| var AnalyticsPlatformAdapterSetupError_1 = require("./AnalyticsPlatformAdapterSetupError.cjs"); | ||
| Object.defineProperty(exports, "AnalyticsPlatformAdapterSetupError", { enumerable: true, get: function () { return AnalyticsPlatformAdapterSetupError_1.AnalyticsPlatformAdapterSetupError; } }); | ||
| var AnalyticsPlatformAdapterSetupError_js_1 = require("./AnalyticsPlatformAdapterSetupError.cjs"); | ||
| Object.defineProperty(exports, "AnalyticsPlatformAdapterSetupError", { enumerable: true, get: function () { return AnalyticsPlatformAdapterSetupError_js_1.AnalyticsPlatformAdapterSetupError; } }); | ||
| // Export selectors | ||
| var selectors_1 = require("./selectors.cjs"); | ||
| Object.defineProperty(exports, "analyticsControllerSelectors", { enumerable: true, get: function () { return selectors_1.analyticsControllerSelectors; } }); | ||
| var selectors_js_1 = require("./selectors.cjs"); | ||
| Object.defineProperty(exports, "analyticsControllerSelectors", { enumerable: true, get: function () { return selectors_js_1.analyticsControllerSelectors; } }); | ||
| //# sourceMappingURL=index.cjs.map |
@@ -1,1 +0,1 @@ | ||
| {"version":3,"file":"index.cjs","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;AAAA,8CAA8C;AAC9C,iEAG+B;AAF7B,0HAAA,mBAAmB,OAAA;AACnB,yIAAA,kCAAkC,OAAA;AAIpC,gBAAgB;AAChB,+FAA0F;AAAjF,wJAAA,kCAAkC,OAAA;AAwB3C,mBAAmB;AACnB,6CAA2D;AAAlD,yHAAA,4BAA4B,OAAA","sourcesContent":["// Export controller class and state utilities\nexport {\n AnalyticsController,\n getDefaultAnalyticsControllerState,\n} from './AnalyticsController';\nexport type { AnalyticsControllerOptions } from './AnalyticsController';\n\n// Export errors\nexport { AnalyticsPlatformAdapterSetupError } from './AnalyticsPlatformAdapterSetupError';\n\n// Export types\nexport type {\n AnalyticsContext,\n AnalyticsEventProperties,\n AnalyticsDeliveryOptions,\n AnalyticsInvocationCallback,\n AnalyticsUserTraits,\n AnalyticsPlatformAdapter,\n AnalyticsTrackingEvent,\n} from './AnalyticsPlatformAdapter.types';\n\n// Export state types\nexport type {\n AnalyticsControllerState,\n AnalyticsEventQueue,\n AnalyticsQueuedEvent,\n AnalyticsQueuedEventType,\n AnalyticsQueuedTrackEvent,\n AnalyticsQueuedIdentifyEvent,\n AnalyticsQueuedViewEvent,\n} from './AnalyticsController';\n\n// Export selectors\nexport { analyticsControllerSelectors } from './selectors';\n\n// Export messenger types\nexport type { AnalyticsControllerMessenger } from './AnalyticsController';\n\n// Export action and event types\nexport type {\n AnalyticsControllerActions,\n AnalyticsControllerEvents,\n AnalyticsControllerGetStateAction,\n AnalyticsControllerStateChangeEvent,\n} from './AnalyticsController';\nexport type {\n AnalyticsControllerTrackEventAction,\n AnalyticsControllerIdentifyAction,\n AnalyticsControllerTrackViewAction,\n AnalyticsControllerOptInAction,\n AnalyticsControllerOptOutAction,\n AnalyticsControllerResetConsentDecisionAction,\n AnalyticsControllerMethodActions,\n} from './AnalyticsController-method-action-types';\n"]} | ||
| {"version":3,"file":"index.cjs","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;AAAA,8CAA8C;AAC9C,oEAGkC;AAFhC,6HAAA,mBAAmB,OAAA;AACnB,4IAAA,kCAAkC,OAAA;AAIpC,gBAAgB;AAChB,kGAA6F;AAApF,2JAAA,kCAAkC,OAAA;AA0B3C,mBAAmB;AACnB,gDAA8D;AAArD,4HAAA,4BAA4B,OAAA","sourcesContent":["// Export controller class and state utilities\nexport {\n AnalyticsController,\n getDefaultAnalyticsControllerState,\n} from './AnalyticsController.js';\nexport type { AnalyticsControllerOptions } from './AnalyticsController.js';\n\n// Export errors\nexport { AnalyticsPlatformAdapterSetupError } from './AnalyticsPlatformAdapterSetupError.js';\n\n// Export types\nexport type {\n AnalyticsContext,\n AnalyticsEventProperties,\n AnalyticsDeliveryOptions,\n AnalyticsInvocationCallback,\n AnalyticsLocationContext,\n AnalyticsLocationField,\n AnalyticsUserTraits,\n AnalyticsPlatformAdapter,\n AnalyticsTrackingEvent,\n} from './AnalyticsPlatformAdapter.types';\n\n// Export state types\nexport type {\n AnalyticsControllerState,\n AnalyticsEventQueue,\n AnalyticsQueuedEvent,\n AnalyticsQueuedEventType,\n AnalyticsQueuedTrackEvent,\n AnalyticsQueuedIdentifyEvent,\n AnalyticsQueuedViewEvent,\n} from './AnalyticsController.js';\n\n// Export selectors\nexport { analyticsControllerSelectors } from './selectors.js';\n\n// Export messenger types\nexport type { AnalyticsControllerMessenger } from './AnalyticsController.js';\n\n// Export action and event types\nexport type {\n AnalyticsControllerActions,\n AnalyticsControllerEvents,\n AnalyticsControllerGetStateAction,\n AnalyticsControllerStateChangeEvent,\n} from './AnalyticsController.js';\nexport type {\n AnalyticsControllerTrackEventAction,\n AnalyticsControllerIdentifyAction,\n AnalyticsControllerTrackViewAction,\n AnalyticsControllerOptInAction,\n AnalyticsControllerOptOutAction,\n AnalyticsControllerResetConsentDecisionAction,\n AnalyticsControllerMethodActions,\n} from './AnalyticsController-method-action-types.js';\n"]} |
+1
-1
| export { AnalyticsController, getDefaultAnalyticsControllerState, } from "./AnalyticsController.cjs"; | ||
| export type { AnalyticsControllerOptions } from "./AnalyticsController.cjs"; | ||
| export { AnalyticsPlatformAdapterSetupError } from "./AnalyticsPlatformAdapterSetupError.cjs"; | ||
| export type { AnalyticsContext, AnalyticsEventProperties, AnalyticsDeliveryOptions, AnalyticsInvocationCallback, AnalyticsUserTraits, AnalyticsPlatformAdapter, AnalyticsTrackingEvent, } from "./AnalyticsPlatformAdapter.types.cjs"; | ||
| export type { AnalyticsContext, AnalyticsEventProperties, AnalyticsDeliveryOptions, AnalyticsInvocationCallback, AnalyticsLocationContext, AnalyticsLocationField, AnalyticsUserTraits, AnalyticsPlatformAdapter, AnalyticsTrackingEvent, } from "./AnalyticsPlatformAdapter.types.cjs"; | ||
| export type { AnalyticsControllerState, AnalyticsEventQueue, AnalyticsQueuedEvent, AnalyticsQueuedEventType, AnalyticsQueuedTrackEvent, AnalyticsQueuedIdentifyEvent, AnalyticsQueuedViewEvent, } from "./AnalyticsController.cjs"; | ||
@@ -6,0 +6,0 @@ export { analyticsControllerSelectors } from "./selectors.cjs"; |
@@ -1,1 +0,1 @@ | ||
| {"version":3,"file":"index.d.cts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EACL,mBAAmB,EACnB,kCAAkC,GACnC,kCAA8B;AAC/B,YAAY,EAAE,0BAA0B,EAAE,kCAA8B;AAGxE,OAAO,EAAE,kCAAkC,EAAE,iDAA6C;AAG1F,YAAY,EACV,gBAAgB,EAChB,wBAAwB,EACxB,wBAAwB,EACxB,2BAA2B,EAC3B,mBAAmB,EACnB,wBAAwB,EACxB,sBAAsB,GACvB,6CAAyC;AAG1C,YAAY,EACV,wBAAwB,EACxB,mBAAmB,EACnB,oBAAoB,EACpB,wBAAwB,EACxB,yBAAyB,EACzB,4BAA4B,EAC5B,wBAAwB,GACzB,kCAA8B;AAG/B,OAAO,EAAE,4BAA4B,EAAE,wBAAoB;AAG3D,YAAY,EAAE,4BAA4B,EAAE,kCAA8B;AAG1E,YAAY,EACV,0BAA0B,EAC1B,yBAAyB,EACzB,iCAAiC,EACjC,mCAAmC,GACpC,kCAA8B;AAC/B,YAAY,EACV,mCAAmC,EACnC,iCAAiC,EACjC,kCAAkC,EAClC,8BAA8B,EAC9B,+BAA+B,EAC/B,6CAA6C,EAC7C,gCAAgC,GACjC,sDAAkD"} | ||
| {"version":3,"file":"index.d.cts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EACL,mBAAmB,EACnB,kCAAkC,GACnC,kCAAiC;AAClC,YAAY,EAAE,0BAA0B,EAAE,kCAAiC;AAG3E,OAAO,EAAE,kCAAkC,EAAE,iDAAgD;AAG7F,YAAY,EACV,gBAAgB,EAChB,wBAAwB,EACxB,wBAAwB,EACxB,2BAA2B,EAC3B,wBAAwB,EACxB,sBAAsB,EACtB,mBAAmB,EACnB,wBAAwB,EACxB,sBAAsB,GACvB,6CAAyC;AAG1C,YAAY,EACV,wBAAwB,EACxB,mBAAmB,EACnB,oBAAoB,EACpB,wBAAwB,EACxB,yBAAyB,EACzB,4BAA4B,EAC5B,wBAAwB,GACzB,kCAAiC;AAGlC,OAAO,EAAE,4BAA4B,EAAE,wBAAuB;AAG9D,YAAY,EAAE,4BAA4B,EAAE,kCAAiC;AAG7E,YAAY,EACV,0BAA0B,EAC1B,yBAAyB,EACzB,iCAAiC,EACjC,mCAAmC,GACpC,kCAAiC;AAClC,YAAY,EACV,mCAAmC,EACnC,iCAAiC,EACjC,kCAAkC,EAClC,8BAA8B,EAC9B,+BAA+B,EAC/B,6CAA6C,EAC7C,gCAAgC,GACjC,sDAAqD"} |
+1
-1
| export { AnalyticsController, getDefaultAnalyticsControllerState, } from "./AnalyticsController.mjs"; | ||
| export type { AnalyticsControllerOptions } from "./AnalyticsController.mjs"; | ||
| export { AnalyticsPlatformAdapterSetupError } from "./AnalyticsPlatformAdapterSetupError.mjs"; | ||
| export type { AnalyticsContext, AnalyticsEventProperties, AnalyticsDeliveryOptions, AnalyticsInvocationCallback, AnalyticsUserTraits, AnalyticsPlatformAdapter, AnalyticsTrackingEvent, } from "./AnalyticsPlatformAdapter.types.mjs"; | ||
| export type { AnalyticsContext, AnalyticsEventProperties, AnalyticsDeliveryOptions, AnalyticsInvocationCallback, AnalyticsLocationContext, AnalyticsLocationField, AnalyticsUserTraits, AnalyticsPlatformAdapter, AnalyticsTrackingEvent, } from "./AnalyticsPlatformAdapter.types.mjs"; | ||
| export type { AnalyticsControllerState, AnalyticsEventQueue, AnalyticsQueuedEvent, AnalyticsQueuedEventType, AnalyticsQueuedTrackEvent, AnalyticsQueuedIdentifyEvent, AnalyticsQueuedViewEvent, } from "./AnalyticsController.mjs"; | ||
@@ -6,0 +6,0 @@ export { analyticsControllerSelectors } from "./selectors.mjs"; |
@@ -1,1 +0,1 @@ | ||
| {"version":3,"file":"index.d.mts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EACL,mBAAmB,EACnB,kCAAkC,GACnC,kCAA8B;AAC/B,YAAY,EAAE,0BAA0B,EAAE,kCAA8B;AAGxE,OAAO,EAAE,kCAAkC,EAAE,iDAA6C;AAG1F,YAAY,EACV,gBAAgB,EAChB,wBAAwB,EACxB,wBAAwB,EACxB,2BAA2B,EAC3B,mBAAmB,EACnB,wBAAwB,EACxB,sBAAsB,GACvB,6CAAyC;AAG1C,YAAY,EACV,wBAAwB,EACxB,mBAAmB,EACnB,oBAAoB,EACpB,wBAAwB,EACxB,yBAAyB,EACzB,4BAA4B,EAC5B,wBAAwB,GACzB,kCAA8B;AAG/B,OAAO,EAAE,4BAA4B,EAAE,wBAAoB;AAG3D,YAAY,EAAE,4BAA4B,EAAE,kCAA8B;AAG1E,YAAY,EACV,0BAA0B,EAC1B,yBAAyB,EACzB,iCAAiC,EACjC,mCAAmC,GACpC,kCAA8B;AAC/B,YAAY,EACV,mCAAmC,EACnC,iCAAiC,EACjC,kCAAkC,EAClC,8BAA8B,EAC9B,+BAA+B,EAC/B,6CAA6C,EAC7C,gCAAgC,GACjC,sDAAkD"} | ||
| {"version":3,"file":"index.d.mts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EACL,mBAAmB,EACnB,kCAAkC,GACnC,kCAAiC;AAClC,YAAY,EAAE,0BAA0B,EAAE,kCAAiC;AAG3E,OAAO,EAAE,kCAAkC,EAAE,iDAAgD;AAG7F,YAAY,EACV,gBAAgB,EAChB,wBAAwB,EACxB,wBAAwB,EACxB,2BAA2B,EAC3B,wBAAwB,EACxB,sBAAsB,EACtB,mBAAmB,EACnB,wBAAwB,EACxB,sBAAsB,GACvB,6CAAyC;AAG1C,YAAY,EACV,wBAAwB,EACxB,mBAAmB,EACnB,oBAAoB,EACpB,wBAAwB,EACxB,yBAAyB,EACzB,4BAA4B,EAC5B,wBAAwB,GACzB,kCAAiC;AAGlC,OAAO,EAAE,4BAA4B,EAAE,wBAAuB;AAG9D,YAAY,EAAE,4BAA4B,EAAE,kCAAiC;AAG7E,YAAY,EACV,0BAA0B,EAC1B,yBAAyB,EACzB,iCAAiC,EACjC,mCAAmC,GACpC,kCAAiC;AAClC,YAAY,EACV,mCAAmC,EACnC,iCAAiC,EACjC,kCAAkC,EAClC,8BAA8B,EAC9B,+BAA+B,EAC/B,6CAA6C,EAC7C,gCAAgC,GACjC,sDAAqD"} |
@@ -1,1 +0,1 @@ | ||
| {"version":3,"file":"index.mjs","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,8CAA8C;AAC9C,OAAO,EACL,mBAAmB,EACnB,kCAAkC,EACnC,kCAA8B;AAG/B,gBAAgB;AAChB,OAAO,EAAE,kCAAkC,EAAE,iDAA6C;AAwB1F,mBAAmB;AACnB,OAAO,EAAE,4BAA4B,EAAE,wBAAoB","sourcesContent":["// Export controller class and state utilities\nexport {\n AnalyticsController,\n getDefaultAnalyticsControllerState,\n} from './AnalyticsController';\nexport type { AnalyticsControllerOptions } from './AnalyticsController';\n\n// Export errors\nexport { AnalyticsPlatformAdapterSetupError } from './AnalyticsPlatformAdapterSetupError';\n\n// Export types\nexport type {\n AnalyticsContext,\n AnalyticsEventProperties,\n AnalyticsDeliveryOptions,\n AnalyticsInvocationCallback,\n AnalyticsUserTraits,\n AnalyticsPlatformAdapter,\n AnalyticsTrackingEvent,\n} from './AnalyticsPlatformAdapter.types';\n\n// Export state types\nexport type {\n AnalyticsControllerState,\n AnalyticsEventQueue,\n AnalyticsQueuedEvent,\n AnalyticsQueuedEventType,\n AnalyticsQueuedTrackEvent,\n AnalyticsQueuedIdentifyEvent,\n AnalyticsQueuedViewEvent,\n} from './AnalyticsController';\n\n// Export selectors\nexport { analyticsControllerSelectors } from './selectors';\n\n// Export messenger types\nexport type { AnalyticsControllerMessenger } from './AnalyticsController';\n\n// Export action and event types\nexport type {\n AnalyticsControllerActions,\n AnalyticsControllerEvents,\n AnalyticsControllerGetStateAction,\n AnalyticsControllerStateChangeEvent,\n} from './AnalyticsController';\nexport type {\n AnalyticsControllerTrackEventAction,\n AnalyticsControllerIdentifyAction,\n AnalyticsControllerTrackViewAction,\n AnalyticsControllerOptInAction,\n AnalyticsControllerOptOutAction,\n AnalyticsControllerResetConsentDecisionAction,\n AnalyticsControllerMethodActions,\n} from './AnalyticsController-method-action-types';\n"]} | ||
| {"version":3,"file":"index.mjs","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,8CAA8C;AAC9C,OAAO,EACL,mBAAmB,EACnB,kCAAkC,EACnC,kCAAiC;AAGlC,gBAAgB;AAChB,OAAO,EAAE,kCAAkC,EAAE,iDAAgD;AA0B7F,mBAAmB;AACnB,OAAO,EAAE,4BAA4B,EAAE,wBAAuB","sourcesContent":["// Export controller class and state utilities\nexport {\n AnalyticsController,\n getDefaultAnalyticsControllerState,\n} from './AnalyticsController.js';\nexport type { AnalyticsControllerOptions } from './AnalyticsController.js';\n\n// Export errors\nexport { AnalyticsPlatformAdapterSetupError } from './AnalyticsPlatformAdapterSetupError.js';\n\n// Export types\nexport type {\n AnalyticsContext,\n AnalyticsEventProperties,\n AnalyticsDeliveryOptions,\n AnalyticsInvocationCallback,\n AnalyticsLocationContext,\n AnalyticsLocationField,\n AnalyticsUserTraits,\n AnalyticsPlatformAdapter,\n AnalyticsTrackingEvent,\n} from './AnalyticsPlatformAdapter.types';\n\n// Export state types\nexport type {\n AnalyticsControllerState,\n AnalyticsEventQueue,\n AnalyticsQueuedEvent,\n AnalyticsQueuedEventType,\n AnalyticsQueuedTrackEvent,\n AnalyticsQueuedIdentifyEvent,\n AnalyticsQueuedViewEvent,\n} from './AnalyticsController.js';\n\n// Export selectors\nexport { analyticsControllerSelectors } from './selectors.js';\n\n// Export messenger types\nexport type { AnalyticsControllerMessenger } from './AnalyticsController.js';\n\n// Export action and event types\nexport type {\n AnalyticsControllerActions,\n AnalyticsControllerEvents,\n AnalyticsControllerGetStateAction,\n AnalyticsControllerStateChangeEvent,\n} from './AnalyticsController.js';\nexport type {\n AnalyticsControllerTrackEventAction,\n AnalyticsControllerIdentifyAction,\n AnalyticsControllerTrackViewAction,\n AnalyticsControllerOptInAction,\n AnalyticsControllerOptOutAction,\n AnalyticsControllerResetConsentDecisionAction,\n AnalyticsControllerMethodActions,\n} from './AnalyticsController-method-action-types.js';\n"]} |
@@ -1,1 +0,1 @@ | ||
| {"version":3,"file":"selectors.cjs","sourceRoot":"","sources":["../src/selectors.ts"],"names":[],"mappings":";;;AAEA;;;;;GAKG;AACH,MAAM,iBAAiB,GAAG,CAAC,KAA+B,EAAU,EAAE,CACpE,KAAK,CAAC,WAAW,CAAC;AAEpB;;;;;;GAMG;AACH,MAAM,aAAa,GAAG,CAAC,KAA+B,EAAW,EAAE,CACjE,KAAK,CAAC,OAAO,CAAC;AAEhB;;;;;;GAMG;AACH,MAAM,aAAa,GAAG,CAAC,KAA+B,EAAW,EAAE,CACjE,KAAK,CAAC,OAAO,CAAC;AAEhB;;;;;;;GAOG;AACH,MAAM,yBAAyB,GAAG,CAAC,KAA+B,EAAW,EAAE,CAC7E,KAAK,CAAC,mBAAmB,IAAI,KAAK,CAAC;AAErC;;;GAGG;AACU,QAAA,4BAA4B,GAAG;IAC1C,iBAAiB;IACjB,aAAa;IACb,aAAa;IACb,yBAAyB;CAC1B,CAAC","sourcesContent":["import type { AnalyticsControllerState } from './AnalyticsController';\n\n/**\n * Selects the analytics ID from the controller state.\n *\n * @param state - The controller state\n * @returns The analytics ID\n */\nconst selectAnalyticsId = (state: AnalyticsControllerState): string =>\n state.analyticsId;\n\n/**\n * Selects the opted-in user status from the controller state.\n * Use this selector to read the user's opt-in preference (e.g., for UI display).\n *\n * @param state - The controller state\n * @returns Whether the user has opted in to analytics\n */\nconst selectOptedIn = (state: AnalyticsControllerState): boolean =>\n state.optedIn;\n\n/**\n * Selects whether analytics tracking is enabled.\n * Use this selector to determine if tracking should occur (e.g., in controller methods).\n *\n * @param state - The controller state\n * @returns Whether analytics tracking is enabled\n */\nconst selectEnabled = (state: AnalyticsControllerState): boolean =>\n state.optedIn;\n\n/**\n * Selects whether the user has made a consent decision (opted in or opted out).\n * Use this selector to distinguish the \"undecided\" state (e.g. during\n * onboarding) from an explicit opt-out.\n *\n * @param state - The controller state\n * @returns Whether the user has made a consent decision\n */\nconst selectConsentDecisionMade = (state: AnalyticsControllerState): boolean =>\n state.consentDecisionMade ?? false;\n\n/**\n * Selectors for the AnalyticsController state.\n * These can be used with Redux or directly with controller state.\n */\nexport const analyticsControllerSelectors = {\n selectAnalyticsId,\n selectOptedIn,\n selectEnabled,\n selectConsentDecisionMade,\n};\n"]} | ||
| {"version":3,"file":"selectors.cjs","sourceRoot":"","sources":["../src/selectors.ts"],"names":[],"mappings":";;;AAEA;;;;;GAKG;AACH,MAAM,iBAAiB,GAAG,CAAC,KAA+B,EAAU,EAAE,CACpE,KAAK,CAAC,WAAW,CAAC;AAEpB;;;;;;GAMG;AACH,MAAM,aAAa,GAAG,CAAC,KAA+B,EAAW,EAAE,CACjE,KAAK,CAAC,OAAO,CAAC;AAEhB;;;;;;GAMG;AACH,MAAM,aAAa,GAAG,CAAC,KAA+B,EAAW,EAAE,CACjE,KAAK,CAAC,OAAO,CAAC;AAEhB;;;;;;;GAOG;AACH,MAAM,yBAAyB,GAAG,CAAC,KAA+B,EAAW,EAAE,CAC7E,KAAK,CAAC,mBAAmB,IAAI,KAAK,CAAC;AAErC;;;GAGG;AACU,QAAA,4BAA4B,GAAG;IAC1C,iBAAiB;IACjB,aAAa;IACb,aAAa;IACb,yBAAyB;CAC1B,CAAC","sourcesContent":["import type { AnalyticsControllerState } from './AnalyticsController.js';\n\n/**\n * Selects the analytics ID from the controller state.\n *\n * @param state - The controller state\n * @returns The analytics ID\n */\nconst selectAnalyticsId = (state: AnalyticsControllerState): string =>\n state.analyticsId;\n\n/**\n * Selects the opted-in user status from the controller state.\n * Use this selector to read the user's opt-in preference (e.g., for UI display).\n *\n * @param state - The controller state\n * @returns Whether the user has opted in to analytics\n */\nconst selectOptedIn = (state: AnalyticsControllerState): boolean =>\n state.optedIn;\n\n/**\n * Selects whether analytics tracking is enabled.\n * Use this selector to determine if tracking should occur (e.g., in controller methods).\n *\n * @param state - The controller state\n * @returns Whether analytics tracking is enabled\n */\nconst selectEnabled = (state: AnalyticsControllerState): boolean =>\n state.optedIn;\n\n/**\n * Selects whether the user has made a consent decision (opted in or opted out).\n * Use this selector to distinguish the \"undecided\" state (e.g. during\n * onboarding) from an explicit opt-out.\n *\n * @param state - The controller state\n * @returns Whether the user has made a consent decision\n */\nconst selectConsentDecisionMade = (state: AnalyticsControllerState): boolean =>\n state.consentDecisionMade ?? false;\n\n/**\n * Selectors for the AnalyticsController state.\n * These can be used with Redux or directly with controller state.\n */\nexport const analyticsControllerSelectors = {\n selectAnalyticsId,\n selectOptedIn,\n selectEnabled,\n selectConsentDecisionMade,\n};\n"]} |
@@ -1,1 +0,1 @@ | ||
| {"version":3,"file":"selectors.d.cts","sourceRoot":"","sources":["../src/selectors.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,wBAAwB,EAAE,kCAA8B;AA0CtE;;;GAGG;AACH,eAAO,MAAM,4BAA4B;+BAtCP,wBAAwB,KAAG,MAAM;2BAUrC,wBAAwB,KAAG,OAAO;2BAUlC,wBAAwB,KAAG,OAAO;uCAWtB,wBAAwB,KAAG,OAAO;CAY3E,CAAC"} | ||
| {"version":3,"file":"selectors.d.cts","sourceRoot":"","sources":["../src/selectors.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,wBAAwB,EAAE,kCAAiC;AA0CzE;;;GAGG;AACH,eAAO,MAAM,4BAA4B;+BAtCP,wBAAwB,KAAG,MAAM;2BAUrC,wBAAwB,KAAG,OAAO;2BAUlC,wBAAwB,KAAG,OAAO;uCAWtB,wBAAwB,KAAG,OAAO;CAY3E,CAAC"} |
@@ -1,1 +0,1 @@ | ||
| {"version":3,"file":"selectors.d.mts","sourceRoot":"","sources":["../src/selectors.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,wBAAwB,EAAE,kCAA8B;AA0CtE;;;GAGG;AACH,eAAO,MAAM,4BAA4B;+BAtCP,wBAAwB,KAAG,MAAM;2BAUrC,wBAAwB,KAAG,OAAO;2BAUlC,wBAAwB,KAAG,OAAO;uCAWtB,wBAAwB,KAAG,OAAO;CAY3E,CAAC"} | ||
| {"version":3,"file":"selectors.d.mts","sourceRoot":"","sources":["../src/selectors.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,wBAAwB,EAAE,kCAAiC;AA0CzE;;;GAGG;AACH,eAAO,MAAM,4BAA4B;+BAtCP,wBAAwB,KAAG,MAAM;2BAUrC,wBAAwB,KAAG,OAAO;2BAUlC,wBAAwB,KAAG,OAAO;uCAWtB,wBAAwB,KAAG,OAAO;CAY3E,CAAC"} |
@@ -1,1 +0,1 @@ | ||
| {"version":3,"file":"selectors.mjs","sourceRoot":"","sources":["../src/selectors.ts"],"names":[],"mappings":"AAEA;;;;;GAKG;AACH,MAAM,iBAAiB,GAAG,CAAC,KAA+B,EAAU,EAAE,CACpE,KAAK,CAAC,WAAW,CAAC;AAEpB;;;;;;GAMG;AACH,MAAM,aAAa,GAAG,CAAC,KAA+B,EAAW,EAAE,CACjE,KAAK,CAAC,OAAO,CAAC;AAEhB;;;;;;GAMG;AACH,MAAM,aAAa,GAAG,CAAC,KAA+B,EAAW,EAAE,CACjE,KAAK,CAAC,OAAO,CAAC;AAEhB;;;;;;;GAOG;AACH,MAAM,yBAAyB,GAAG,CAAC,KAA+B,EAAW,EAAE,CAC7E,KAAK,CAAC,mBAAmB,IAAI,KAAK,CAAC;AAErC;;;GAGG;AACH,MAAM,CAAC,MAAM,4BAA4B,GAAG;IAC1C,iBAAiB;IACjB,aAAa;IACb,aAAa;IACb,yBAAyB;CAC1B,CAAC","sourcesContent":["import type { AnalyticsControllerState } from './AnalyticsController';\n\n/**\n * Selects the analytics ID from the controller state.\n *\n * @param state - The controller state\n * @returns The analytics ID\n */\nconst selectAnalyticsId = (state: AnalyticsControllerState): string =>\n state.analyticsId;\n\n/**\n * Selects the opted-in user status from the controller state.\n * Use this selector to read the user's opt-in preference (e.g., for UI display).\n *\n * @param state - The controller state\n * @returns Whether the user has opted in to analytics\n */\nconst selectOptedIn = (state: AnalyticsControllerState): boolean =>\n state.optedIn;\n\n/**\n * Selects whether analytics tracking is enabled.\n * Use this selector to determine if tracking should occur (e.g., in controller methods).\n *\n * @param state - The controller state\n * @returns Whether analytics tracking is enabled\n */\nconst selectEnabled = (state: AnalyticsControllerState): boolean =>\n state.optedIn;\n\n/**\n * Selects whether the user has made a consent decision (opted in or opted out).\n * Use this selector to distinguish the \"undecided\" state (e.g. during\n * onboarding) from an explicit opt-out.\n *\n * @param state - The controller state\n * @returns Whether the user has made a consent decision\n */\nconst selectConsentDecisionMade = (state: AnalyticsControllerState): boolean =>\n state.consentDecisionMade ?? false;\n\n/**\n * Selectors for the AnalyticsController state.\n * These can be used with Redux or directly with controller state.\n */\nexport const analyticsControllerSelectors = {\n selectAnalyticsId,\n selectOptedIn,\n selectEnabled,\n selectConsentDecisionMade,\n};\n"]} | ||
| {"version":3,"file":"selectors.mjs","sourceRoot":"","sources":["../src/selectors.ts"],"names":[],"mappings":"AAEA;;;;;GAKG;AACH,MAAM,iBAAiB,GAAG,CAAC,KAA+B,EAAU,EAAE,CACpE,KAAK,CAAC,WAAW,CAAC;AAEpB;;;;;;GAMG;AACH,MAAM,aAAa,GAAG,CAAC,KAA+B,EAAW,EAAE,CACjE,KAAK,CAAC,OAAO,CAAC;AAEhB;;;;;;GAMG;AACH,MAAM,aAAa,GAAG,CAAC,KAA+B,EAAW,EAAE,CACjE,KAAK,CAAC,OAAO,CAAC;AAEhB;;;;;;;GAOG;AACH,MAAM,yBAAyB,GAAG,CAAC,KAA+B,EAAW,EAAE,CAC7E,KAAK,CAAC,mBAAmB,IAAI,KAAK,CAAC;AAErC;;;GAGG;AACH,MAAM,CAAC,MAAM,4BAA4B,GAAG;IAC1C,iBAAiB;IACjB,aAAa;IACb,aAAa;IACb,yBAAyB;CAC1B,CAAC","sourcesContent":["import type { AnalyticsControllerState } from './AnalyticsController.js';\n\n/**\n * Selects the analytics ID from the controller state.\n *\n * @param state - The controller state\n * @returns The analytics ID\n */\nconst selectAnalyticsId = (state: AnalyticsControllerState): string =>\n state.analyticsId;\n\n/**\n * Selects the opted-in user status from the controller state.\n * Use this selector to read the user's opt-in preference (e.g., for UI display).\n *\n * @param state - The controller state\n * @returns Whether the user has opted in to analytics\n */\nconst selectOptedIn = (state: AnalyticsControllerState): boolean =>\n state.optedIn;\n\n/**\n * Selects whether analytics tracking is enabled.\n * Use this selector to determine if tracking should occur (e.g., in controller methods).\n *\n * @param state - The controller state\n * @returns Whether analytics tracking is enabled\n */\nconst selectEnabled = (state: AnalyticsControllerState): boolean =>\n state.optedIn;\n\n/**\n * Selects whether the user has made a consent decision (opted in or opted out).\n * Use this selector to distinguish the \"undecided\" state (e.g. during\n * onboarding) from an explicit opt-out.\n *\n * @param state - The controller state\n * @returns Whether the user has made a consent decision\n */\nconst selectConsentDecisionMade = (state: AnalyticsControllerState): boolean =>\n state.consentDecisionMade ?? false;\n\n/**\n * Selectors for the AnalyticsController state.\n * These can be used with Redux or directly with controller state.\n */\nexport const analyticsControllerSelectors = {\n selectAnalyticsId,\n selectOptedIn,\n selectEnabled,\n selectConsentDecisionMade,\n};\n"]} |
+10
-7
| { | ||
| "name": "@metamask/analytics-controller", | ||
| "version": "1.2.1", | ||
| "version": "2.0.0", | ||
| "description": "Common Analytics controller for event tracking", | ||
@@ -47,4 +47,6 @@ "keywords": [ | ||
| "changelog:validate": "../../scripts/validate-changelog.sh @metamask/analytics-controller", | ||
| "messenger-action-types:check": "tsx ../../packages/messenger-cli/src/cli.ts --formatter oxfmt --check", | ||
| "messenger-action-types:generate": "tsx ../../packages/messenger-cli/src/cli.ts --formatter oxfmt --generate", | ||
| "lint:tsconfigs": "tsx ../../scripts/lint-tsconfigs/lint-tsconfigs.mts", | ||
| "lint:tsconfigs:fix": "tsx ../../scripts/lint-tsconfigs/lint-tsconfigs.mts --fix", | ||
| "messenger-action-types:check": "tsx ../../packages/messenger-cli/src/cli.ts --formatter oxfmt --esm --check", | ||
| "messenger-action-types:generate": "tsx ../../packages/messenger-cli/src/cli.ts --formatter oxfmt --esm --generate", | ||
| "since-latest-release": "../../scripts/since-latest-release.sh", | ||
@@ -58,3 +60,4 @@ "test": "NODE_OPTIONS=--experimental-vm-modules jest --reporters=jest-silent-reporter", | ||
| "@metamask/base-controller": "^9.1.0", | ||
| "@metamask/messenger": "^1.2.0", | ||
| "@metamask/geolocation-controller": "^1.0.0", | ||
| "@metamask/messenger": "^2.0.0", | ||
| "@metamask/utils": "^11.11.0", | ||
@@ -67,7 +70,7 @@ "lodash": "^4.17.21", | ||
| "@ts-bridge/cli": "^0.6.4", | ||
| "@types/jest": "^29.5.14", | ||
| "@types/jest": "^30.0.0", | ||
| "@types/uuid": "^8.3.0", | ||
| "deepmerge": "^4.2.2", | ||
| "jest": "^29.7.0", | ||
| "ts-jest": "^29.2.5", | ||
| "jest": "^30.4.2", | ||
| "ts-jest": "^29.4.11", | ||
| "tsx": "^4.20.5", | ||
@@ -74,0 +77,0 @@ "typedoc": "^0.25.13", |
313530
20.51%1518
21.05%6
20%+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
Updated