@formo/analytics-react-native 0.1.4 → 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +25 -0
- package/lib/commonjs/FormoAnalytics.js +158 -79
- package/lib/commonjs/FormoAnalytics.js.map +1 -1
- package/lib/commonjs/FormoAnalyticsProvider.js +32 -26
- package/lib/commonjs/FormoAnalyticsProvider.js.map +1 -1
- package/lib/commonjs/constants/events.js +5 -1
- package/lib/commonjs/constants/events.js.map +1 -1
- package/lib/commonjs/constants/index.js +3 -3
- package/lib/commonjs/constants/storage.js +8 -1
- package/lib/commonjs/constants/storage.js.map +1 -1
- package/lib/commonjs/index.js +7 -7
- package/lib/commonjs/index.js.map +1 -1
- package/lib/commonjs/lib/consent/index.js +8 -8
- package/lib/commonjs/lib/consent/index.js.map +1 -1
- package/lib/commonjs/lib/event/EventFactory.js +135 -52
- package/lib/commonjs/lib/event/EventFactory.js.map +1 -1
- package/lib/commonjs/lib/event/EventManager.js +6 -6
- package/lib/commonjs/lib/event/EventManager.js.map +1 -1
- package/lib/commonjs/lib/event/EventQueue.js +35 -24
- package/lib/commonjs/lib/event/EventQueue.js.map +1 -1
- package/lib/commonjs/lib/event/index.js +4 -4
- package/lib/commonjs/lib/installReferrer/index.js +193 -0
- package/lib/commonjs/lib/installReferrer/index.js.map +1 -0
- package/lib/commonjs/lib/lifecycle/index.js +24 -17
- package/lib/commonjs/lib/lifecycle/index.js.map +1 -1
- package/lib/commonjs/lib/session/index.js +13 -13
- package/lib/commonjs/lib/session/index.js.map +1 -1
- package/lib/commonjs/lib/storage/AsyncStorageAdapter.js +10 -10
- package/lib/commonjs/lib/storage/AsyncStorageAdapter.js.map +1 -1
- package/lib/commonjs/lib/storage/MemoryStorage.js +1 -1
- package/lib/commonjs/lib/storage/StorageBlueprint.js +2 -2
- package/lib/commonjs/lib/storage/StorageBlueprint.js.map +1 -1
- package/lib/commonjs/lib/storage/StorageManager.js +6 -6
- package/lib/commonjs/lib/storage/StorageManager.js.map +1 -1
- package/lib/commonjs/lib/storage/index.js +4 -4
- package/lib/commonjs/lib/wagmi/WagmiEventHandler.js +31 -36
- package/lib/commonjs/lib/wagmi/WagmiEventHandler.js.map +1 -1
- package/lib/commonjs/lib/wagmi/index.js +2 -2
- package/lib/commonjs/package.json +1 -0
- package/lib/commonjs/solana/address.js +110 -0
- package/lib/commonjs/solana/address.js.map +1 -0
- package/lib/commonjs/solana/index.js +28 -0
- package/lib/commonjs/solana/index.js.map +1 -0
- package/lib/commonjs/solana/types.js +47 -0
- package/lib/commonjs/solana/types.js.map +1 -0
- package/lib/commonjs/types/events.js.map +1 -1
- package/lib/commonjs/types/index.js +2 -2
- package/lib/commonjs/utils/address.js +60 -6
- package/lib/commonjs/utils/address.js.map +1 -1
- package/lib/commonjs/utils/hash.js +44 -6
- package/lib/commonjs/utils/hash.js.map +1 -1
- package/lib/commonjs/utils/index.js +5 -5
- package/lib/commonjs/utils/trafficSource.js +74 -13
- package/lib/commonjs/utils/trafficSource.js.map +1 -1
- package/lib/commonjs/version.js +1 -1
- package/lib/module/FormoAnalytics.js +107 -26
- package/lib/module/FormoAnalytics.js.map +1 -1
- package/lib/module/FormoAnalyticsProvider.js +21 -13
- package/lib/module/FormoAnalyticsProvider.js.map +1 -1
- package/lib/module/constants/config.js +2 -0
- package/lib/module/constants/config.js.map +1 -1
- package/lib/module/constants/events.js +6 -0
- package/lib/module/constants/events.js.map +1 -1
- package/lib/module/constants/index.js +5 -3
- package/lib/module/constants/index.js.map +1 -1
- package/lib/module/constants/storage.js +9 -0
- package/lib/module/constants/storage.js.map +1 -1
- package/lib/module/index.js +6 -4
- package/lib/module/index.js.map +1 -1
- package/lib/module/lib/consent/index.js +4 -2
- package/lib/module/lib/consent/index.js.map +1 -1
- package/lib/module/lib/event/EventFactory.js +116 -33
- package/lib/module/lib/event/EventFactory.js.map +1 -1
- package/lib/module/lib/event/EventManager.js +5 -3
- package/lib/module/lib/event/EventManager.js.map +1 -1
- package/lib/module/lib/event/EventQueue.js +18 -5
- package/lib/module/lib/event/EventQueue.js.map +1 -1
- package/lib/module/lib/event/index.js +6 -4
- package/lib/module/lib/event/index.js.map +1 -1
- package/lib/module/lib/event/types.js +2 -0
- package/lib/module/lib/installReferrer/index.js +189 -0
- package/lib/module/lib/installReferrer/index.js.map +1 -0
- package/lib/module/lib/lifecycle/index.js +14 -5
- package/lib/module/lib/lifecycle/index.js.map +1 -1
- package/lib/module/lib/logger/index.js +2 -0
- package/lib/module/lib/logger/index.js.map +1 -1
- package/lib/module/lib/session/index.js +5 -3
- package/lib/module/lib/session/index.js.map +1 -1
- package/lib/module/lib/storage/AsyncStorageAdapter.js +4 -2
- package/lib/module/lib/storage/AsyncStorageAdapter.js.map +1 -1
- package/lib/module/lib/storage/MemoryStorage.js +3 -1
- package/lib/module/lib/storage/MemoryStorage.js.map +1 -1
- package/lib/module/lib/storage/StorageBlueprint.js +3 -1
- package/lib/module/lib/storage/StorageBlueprint.js.map +1 -1
- package/lib/module/lib/storage/StorageManager.js +5 -3
- package/lib/module/lib/storage/StorageManager.js.map +1 -1
- package/lib/module/lib/storage/index.js +6 -4
- package/lib/module/lib/storage/index.js.map +1 -1
- package/lib/module/lib/storage/types.js +1 -1
- package/lib/module/lib/wagmi/WagmiEventHandler.js +5 -8
- package/lib/module/lib/wagmi/WagmiEventHandler.js.map +1 -1
- package/lib/module/lib/wagmi/index.js +4 -2
- package/lib/module/lib/wagmi/index.js.map +1 -1
- package/lib/module/lib/wagmi/types.js +1 -1
- package/lib/module/package.json +1 -0
- package/lib/module/solana/address.js +102 -0
- package/lib/module/solana/address.js.map +1 -0
- package/lib/module/solana/index.js +5 -0
- package/lib/module/solana/index.js.map +1 -0
- package/lib/module/solana/types.js +42 -0
- package/lib/module/solana/types.js.map +1 -0
- package/lib/module/types/base.js +2 -0
- package/lib/module/types/events.js +2 -0
- package/lib/module/types/events.js.map +1 -1
- package/lib/module/types/index.js +4 -2
- package/lib/module/types/index.js.map +1 -1
- package/lib/module/utils/address.js +60 -6
- package/lib/module/utils/address.js.map +1 -1
- package/lib/module/utils/hash.js +46 -6
- package/lib/module/utils/hash.js.map +1 -1
- package/lib/module/utils/helpers.js +2 -0
- package/lib/module/utils/helpers.js.map +1 -1
- package/lib/module/utils/index.js +7 -5
- package/lib/module/utils/index.js.map +1 -1
- package/lib/module/utils/timestamp.js +2 -0
- package/lib/module/utils/timestamp.js.map +1 -1
- package/lib/module/utils/trafficSource.js +64 -3
- package/lib/module/utils/trafficSource.js.map +1 -1
- package/lib/module/version.js +3 -1
- package/lib/module/version.js.map +1 -1
- package/lib/typescript/{FormoAnalytics.d.ts → commonjs/FormoAnalytics.d.ts} +23 -4
- package/lib/typescript/commonjs/FormoAnalytics.d.ts.map +1 -0
- package/lib/typescript/commonjs/FormoAnalyticsProvider.d.ts.map +1 -0
- package/lib/typescript/commonjs/constants/config.d.ts.map +1 -0
- package/lib/typescript/{constants → commonjs/constants}/events.d.ts +1 -0
- package/lib/typescript/commonjs/constants/events.d.ts.map +1 -0
- package/lib/typescript/commonjs/constants/index.d.ts.map +1 -0
- package/lib/typescript/{constants → commonjs/constants}/storage.d.ts +3 -0
- package/lib/typescript/commonjs/constants/storage.d.ts.map +1 -0
- package/lib/typescript/commonjs/index.d.ts.map +1 -0
- package/lib/typescript/commonjs/lib/consent/index.d.ts.map +1 -0
- package/lib/typescript/{lib → commonjs/lib}/event/EventFactory.d.ts +36 -1
- package/lib/typescript/commonjs/lib/event/EventFactory.d.ts.map +1 -0
- package/lib/typescript/commonjs/lib/event/EventManager.d.ts.map +1 -0
- package/lib/typescript/commonjs/lib/event/EventQueue.d.ts.map +1 -0
- package/lib/typescript/commonjs/lib/event/index.d.ts.map +1 -0
- package/lib/typescript/{lib → commonjs/lib}/event/types.d.ts +1 -1
- package/lib/typescript/commonjs/lib/event/types.d.ts.map +1 -0
- package/lib/typescript/commonjs/lib/installReferrer/index.d.ts +39 -0
- package/lib/typescript/commonjs/lib/installReferrer/index.d.ts.map +1 -0
- package/lib/typescript/commonjs/lib/lifecycle/index.d.ts.map +1 -0
- package/lib/typescript/commonjs/lib/logger/index.d.ts.map +1 -0
- package/lib/typescript/commonjs/lib/session/index.d.ts.map +1 -0
- package/lib/typescript/commonjs/lib/storage/AsyncStorageAdapter.d.ts.map +1 -0
- package/lib/typescript/commonjs/lib/storage/MemoryStorage.d.ts.map +1 -0
- package/lib/typescript/commonjs/lib/storage/StorageBlueprint.d.ts.map +1 -0
- package/lib/typescript/commonjs/lib/storage/StorageManager.d.ts.map +1 -0
- package/lib/typescript/commonjs/lib/storage/index.d.ts.map +1 -0
- package/lib/typescript/commonjs/lib/storage/types.d.ts.map +1 -0
- package/lib/typescript/{lib → commonjs/lib}/wagmi/WagmiEventHandler.d.ts +0 -1
- package/lib/typescript/commonjs/lib/wagmi/WagmiEventHandler.d.ts.map +1 -0
- package/lib/typescript/commonjs/lib/wagmi/index.d.ts.map +1 -0
- package/lib/typescript/commonjs/lib/wagmi/types.d.ts.map +1 -0
- package/lib/typescript/commonjs/package.json +1 -0
- package/lib/typescript/commonjs/solana/address.d.ts +42 -0
- package/lib/typescript/commonjs/solana/address.d.ts.map +1 -0
- package/lib/typescript/commonjs/solana/index.d.ts +3 -0
- package/lib/typescript/commonjs/solana/index.d.ts.map +1 -0
- package/lib/typescript/commonjs/solana/types.d.ts +34 -0
- package/lib/typescript/commonjs/solana/types.d.ts.map +1 -0
- package/lib/typescript/{types → commonjs/types}/base.d.ts +39 -1
- package/lib/typescript/commonjs/types/base.d.ts.map +1 -0
- package/lib/typescript/{types → commonjs/types}/events.d.ts +1 -1
- package/lib/typescript/commonjs/types/events.d.ts.map +1 -0
- package/lib/typescript/commonjs/types/index.d.ts.map +1 -0
- package/lib/typescript/commonjs/utils/address.d.ts +45 -0
- package/lib/typescript/commonjs/utils/address.d.ts.map +1 -0
- package/lib/typescript/commonjs/utils/hash.d.ts +18 -0
- package/lib/typescript/commonjs/utils/hash.d.ts.map +1 -0
- package/lib/typescript/commonjs/utils/helpers.d.ts.map +1 -0
- package/lib/typescript/commonjs/utils/index.d.ts.map +1 -0
- package/lib/typescript/commonjs/utils/timestamp.d.ts.map +1 -0
- package/lib/typescript/{utils → commonjs/utils}/trafficSource.d.ts +16 -0
- package/lib/typescript/commonjs/utils/trafficSource.d.ts.map +1 -0
- package/lib/typescript/commonjs/version.d.ts +2 -0
- package/lib/typescript/commonjs/version.d.ts.map +1 -0
- package/lib/typescript/module/FormoAnalytics.d.ts +182 -0
- package/lib/typescript/module/FormoAnalytics.d.ts.map +1 -0
- package/lib/typescript/module/FormoAnalyticsProvider.d.ts +29 -0
- package/lib/typescript/module/FormoAnalyticsProvider.d.ts.map +1 -0
- package/lib/typescript/module/constants/config.d.ts +8 -0
- package/lib/typescript/module/constants/config.d.ts.map +1 -0
- package/lib/typescript/module/constants/events.d.ts +24 -0
- package/lib/typescript/module/constants/events.d.ts.map +1 -0
- package/lib/typescript/module/constants/index.d.ts +4 -0
- package/lib/typescript/module/constants/index.d.ts.map +1 -0
- package/lib/typescript/module/constants/storage.d.ts +13 -0
- package/lib/typescript/module/constants/storage.d.ts.map +1 -0
- package/lib/typescript/module/index.d.ts +44 -0
- package/lib/typescript/module/index.d.ts.map +1 -0
- package/lib/typescript/module/lib/consent/index.d.ts +13 -0
- package/lib/typescript/module/lib/consent/index.d.ts.map +1 -0
- package/lib/typescript/module/lib/event/EventFactory.d.ts +99 -0
- package/lib/typescript/module/lib/event/EventFactory.d.ts.map +1 -0
- package/lib/typescript/module/lib/event/EventManager.d.ts +17 -0
- package/lib/typescript/module/lib/event/EventManager.d.ts.map +1 -0
- package/lib/typescript/module/lib/event/EventQueue.d.ts +74 -0
- package/lib/typescript/module/lib/event/EventQueue.d.ts.map +1 -0
- package/lib/typescript/module/lib/event/index.d.ts +5 -0
- package/lib/typescript/module/lib/event/index.d.ts.map +1 -0
- package/lib/typescript/module/lib/event/types.d.ts +23 -0
- package/lib/typescript/module/lib/event/types.d.ts.map +1 -0
- package/lib/typescript/module/lib/installReferrer/index.d.ts +39 -0
- package/lib/typescript/module/lib/installReferrer/index.d.ts.map +1 -0
- package/lib/typescript/module/lib/lifecycle/index.d.ts +46 -0
- package/lib/typescript/module/lib/lifecycle/index.d.ts.map +1 -0
- package/lib/typescript/module/lib/logger/index.d.ts +19 -0
- package/lib/typescript/module/lib/logger/index.d.ts.map +1 -0
- package/lib/typescript/module/lib/session/index.d.ts +41 -0
- package/lib/typescript/module/lib/session/index.d.ts.map +1 -0
- package/lib/typescript/module/lib/storage/AsyncStorageAdapter.d.ts +48 -0
- package/lib/typescript/module/lib/storage/AsyncStorageAdapter.d.ts.map +1 -0
- package/lib/typescript/module/lib/storage/MemoryStorage.d.ts +18 -0
- package/lib/typescript/module/lib/storage/MemoryStorage.d.ts.map +1 -0
- package/lib/typescript/module/lib/storage/StorageBlueprint.d.ts +21 -0
- package/lib/typescript/module/lib/storage/StorageBlueprint.d.ts.map +1 -0
- package/lib/typescript/module/lib/storage/StorageManager.d.ts +45 -0
- package/lib/typescript/module/lib/storage/StorageManager.d.ts.map +1 -0
- package/lib/typescript/module/lib/storage/index.d.ts +5 -0
- package/lib/typescript/module/lib/storage/index.d.ts.map +1 -0
- package/lib/typescript/module/lib/storage/types.d.ts +22 -0
- package/lib/typescript/module/lib/storage/types.d.ts.map +1 -0
- package/lib/typescript/module/lib/wagmi/WagmiEventHandler.d.ts +103 -0
- package/lib/typescript/module/lib/wagmi/WagmiEventHandler.d.ts.map +1 -0
- package/lib/typescript/module/lib/wagmi/index.d.ts +3 -0
- package/lib/typescript/module/lib/wagmi/index.d.ts.map +1 -0
- package/lib/typescript/module/lib/wagmi/types.d.ts +54 -0
- package/lib/typescript/module/lib/wagmi/types.d.ts.map +1 -0
- package/lib/typescript/module/package.json +1 -0
- package/lib/typescript/module/solana/address.d.ts +42 -0
- package/lib/typescript/module/solana/address.d.ts.map +1 -0
- package/lib/typescript/module/solana/index.d.ts +3 -0
- package/lib/typescript/module/solana/index.d.ts.map +1 -0
- package/lib/typescript/module/solana/types.d.ts +34 -0
- package/lib/typescript/module/solana/types.d.ts.map +1 -0
- package/lib/typescript/module/types/base.d.ts +258 -0
- package/lib/typescript/module/types/base.d.ts.map +1 -0
- package/lib/typescript/module/types/events.d.ts +111 -0
- package/lib/typescript/module/types/events.d.ts.map +1 -0
- package/lib/typescript/module/types/index.d.ts +3 -0
- package/lib/typescript/module/types/index.d.ts.map +1 -0
- package/lib/typescript/module/utils/address.d.ts +45 -0
- package/lib/typescript/module/utils/address.d.ts.map +1 -0
- package/lib/typescript/module/utils/hash.d.ts +18 -0
- package/lib/typescript/module/utils/hash.d.ts.map +1 -0
- package/lib/typescript/module/utils/helpers.d.ts +26 -0
- package/lib/typescript/module/utils/helpers.d.ts.map +1 -0
- package/lib/typescript/module/utils/index.d.ts +6 -0
- package/lib/typescript/module/utils/index.d.ts.map +1 -0
- package/lib/typescript/module/utils/timestamp.d.ts +13 -0
- package/lib/typescript/module/utils/timestamp.d.ts.map +1 -0
- package/lib/typescript/module/utils/trafficSource.d.ts +46 -0
- package/lib/typescript/module/utils/trafficSource.d.ts.map +1 -0
- package/lib/typescript/module/version.d.ts +2 -0
- package/lib/typescript/module/version.d.ts.map +1 -0
- package/package.json +44 -49
- package/src/FormoAnalytics.ts +118 -16
- package/src/constants/events.ts +4 -0
- package/src/constants/storage.ts +7 -0
- package/src/lib/event/EventFactory.ts +129 -29
- package/src/lib/event/EventQueue.ts +14 -0
- package/src/lib/event/types.ts +0 -1
- package/src/lib/installReferrer/index.ts +225 -0
- package/src/lib/lifecycle/index.ts +10 -1
- package/src/lib/wagmi/WagmiEventHandler.ts +0 -4
- package/src/solana/address.ts +122 -0
- package/src/solana/index.ts +2 -0
- package/src/solana/types.ts +46 -0
- package/src/types/base.ts +41 -1
- package/src/types/events.ts +1 -1
- package/src/utils/address.ts +72 -6
- package/src/utils/hash.ts +51 -6
- package/src/utils/trafficSource.ts +73 -0
- package/src/version.ts +1 -1
- package/lib/typescript/FormoAnalytics.d.ts.map +0 -1
- package/lib/typescript/FormoAnalyticsProvider.d.ts.map +0 -1
- package/lib/typescript/constants/config.d.ts.map +0 -1
- package/lib/typescript/constants/events.d.ts.map +0 -1
- package/lib/typescript/constants/index.d.ts.map +0 -1
- package/lib/typescript/constants/storage.d.ts.map +0 -1
- package/lib/typescript/index.d.ts.map +0 -1
- package/lib/typescript/lib/consent/index.d.ts.map +0 -1
- package/lib/typescript/lib/event/EventFactory.d.ts.map +0 -1
- package/lib/typescript/lib/event/EventManager.d.ts.map +0 -1
- package/lib/typescript/lib/event/EventQueue.d.ts.map +0 -1
- package/lib/typescript/lib/event/index.d.ts.map +0 -1
- package/lib/typescript/lib/event/types.d.ts.map +0 -1
- package/lib/typescript/lib/lifecycle/index.d.ts.map +0 -1
- package/lib/typescript/lib/logger/index.d.ts.map +0 -1
- package/lib/typescript/lib/session/index.d.ts.map +0 -1
- package/lib/typescript/lib/storage/AsyncStorageAdapter.d.ts.map +0 -1
- package/lib/typescript/lib/storage/MemoryStorage.d.ts.map +0 -1
- package/lib/typescript/lib/storage/StorageBlueprint.d.ts.map +0 -1
- package/lib/typescript/lib/storage/StorageManager.d.ts.map +0 -1
- package/lib/typescript/lib/storage/index.d.ts.map +0 -1
- package/lib/typescript/lib/storage/types.d.ts.map +0 -1
- package/lib/typescript/lib/wagmi/WagmiEventHandler.d.ts.map +0 -1
- package/lib/typescript/lib/wagmi/index.d.ts.map +0 -1
- package/lib/typescript/lib/wagmi/types.d.ts.map +0 -1
- package/lib/typescript/types/base.d.ts.map +0 -1
- package/lib/typescript/types/events.d.ts.map +0 -1
- package/lib/typescript/types/index.d.ts.map +0 -1
- package/lib/typescript/utils/address.d.ts +0 -25
- package/lib/typescript/utils/address.d.ts.map +0 -1
- package/lib/typescript/utils/hash.d.ts +0 -10
- package/lib/typescript/utils/hash.d.ts.map +0 -1
- package/lib/typescript/utils/helpers.d.ts.map +0 -1
- package/lib/typescript/utils/index.d.ts.map +0 -1
- package/lib/typescript/utils/timestamp.d.ts.map +0 -1
- package/lib/typescript/utils/trafficSource.d.ts.map +0 -1
- package/lib/typescript/version.d.ts +0 -2
- package/lib/typescript/version.d.ts.map +0 -1
- /package/lib/typescript/{FormoAnalyticsProvider.d.ts → commonjs/FormoAnalyticsProvider.d.ts} +0 -0
- /package/lib/typescript/{constants → commonjs/constants}/config.d.ts +0 -0
- /package/lib/typescript/{constants → commonjs/constants}/index.d.ts +0 -0
- /package/lib/typescript/{index.d.ts → commonjs/index.d.ts} +0 -0
- /package/lib/typescript/{lib → commonjs/lib}/consent/index.d.ts +0 -0
- /package/lib/typescript/{lib → commonjs/lib}/event/EventManager.d.ts +0 -0
- /package/lib/typescript/{lib → commonjs/lib}/event/EventQueue.d.ts +0 -0
- /package/lib/typescript/{lib → commonjs/lib}/event/index.d.ts +0 -0
- /package/lib/typescript/{lib → commonjs/lib}/lifecycle/index.d.ts +0 -0
- /package/lib/typescript/{lib → commonjs/lib}/logger/index.d.ts +0 -0
- /package/lib/typescript/{lib → commonjs/lib}/session/index.d.ts +0 -0
- /package/lib/typescript/{lib → commonjs/lib}/storage/AsyncStorageAdapter.d.ts +0 -0
- /package/lib/typescript/{lib → commonjs/lib}/storage/MemoryStorage.d.ts +0 -0
- /package/lib/typescript/{lib → commonjs/lib}/storage/StorageBlueprint.d.ts +0 -0
- /package/lib/typescript/{lib → commonjs/lib}/storage/StorageManager.d.ts +0 -0
- /package/lib/typescript/{lib → commonjs/lib}/storage/index.d.ts +0 -0
- /package/lib/typescript/{lib → commonjs/lib}/storage/types.d.ts +0 -0
- /package/lib/typescript/{lib → commonjs/lib}/wagmi/index.d.ts +0 -0
- /package/lib/typescript/{lib → commonjs/lib}/wagmi/types.d.ts +0 -0
- /package/lib/typescript/{types → commonjs/types}/index.d.ts +0 -0
- /package/lib/typescript/{utils → commonjs/utils}/helpers.d.ts +0 -0
- /package/lib/typescript/{utils → commonjs/utils}/index.d.ts +0 -0
- /package/lib/typescript/{utils → commonjs/utils}/timestamp.d.ts +0 -0
package/package.json
CHANGED
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@formo/analytics-react-native",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "1.0.0",
|
|
4
4
|
"description": "Formo Analytics SDK for React Native - Track wallet events and user analytics in mobile dApps",
|
|
5
|
-
"packageManager": "pnpm@
|
|
5
|
+
"packageManager": "pnpm@11.1.1",
|
|
6
6
|
"repository": {
|
|
7
7
|
"type": "git",
|
|
8
8
|
"url": "git+https://github.com/getformo/sdk-react-native.git"
|
|
9
9
|
},
|
|
10
10
|
"main": "lib/commonjs/index.js",
|
|
11
11
|
"module": "lib/module/index.js",
|
|
12
|
-
"types": "lib/typescript/index.d.ts",
|
|
12
|
+
"types": "lib/typescript/commonjs/index.d.ts",
|
|
13
13
|
"react-native": "src/index.ts",
|
|
14
14
|
"source": "src/index.ts",
|
|
15
15
|
"files": [
|
|
@@ -21,9 +21,14 @@
|
|
|
21
21
|
],
|
|
22
22
|
"exports": {
|
|
23
23
|
".": {
|
|
24
|
-
"import":
|
|
25
|
-
|
|
26
|
-
|
|
24
|
+
"import": {
|
|
25
|
+
"types": "./lib/typescript/module/index.d.ts",
|
|
26
|
+
"default": "./lib/module/index.js"
|
|
27
|
+
},
|
|
28
|
+
"require": {
|
|
29
|
+
"types": "./lib/typescript/commonjs/index.d.ts",
|
|
30
|
+
"default": "./lib/commonjs/index.js"
|
|
31
|
+
}
|
|
27
32
|
}
|
|
28
33
|
},
|
|
29
34
|
"private": false,
|
|
@@ -63,6 +68,7 @@
|
|
|
63
68
|
"react": ">=18.0.0",
|
|
64
69
|
"react-native": ">=0.70.0",
|
|
65
70
|
"react-native-device-info": ">=10.0.0",
|
|
71
|
+
"react-native-play-install-referrer": ">=1.1.8",
|
|
66
72
|
"wagmi": ">=2.0.0"
|
|
67
73
|
},
|
|
68
74
|
"peerDependenciesMeta": {
|
|
@@ -81,66 +87,55 @@
|
|
|
81
87
|
"react-native-device-info": {
|
|
82
88
|
"optional": true
|
|
83
89
|
},
|
|
90
|
+
"react-native-play-install-referrer": {
|
|
91
|
+
"optional": true
|
|
92
|
+
},
|
|
84
93
|
"wagmi": {
|
|
85
94
|
"optional": true
|
|
86
95
|
}
|
|
87
96
|
},
|
|
88
97
|
"dependencies": {
|
|
89
|
-
"@react-native-community/netinfo": "
|
|
98
|
+
"@react-native-community/netinfo": "12.0.1",
|
|
90
99
|
"ethereum-cryptography": "3.2.0"
|
|
91
100
|
},
|
|
92
101
|
"devDependencies": {
|
|
93
|
-
"@babel/preset-env": "^7.29.
|
|
102
|
+
"@babel/preset-env": "^7.29.5",
|
|
94
103
|
"@babel/preset-react": "^7.28.5",
|
|
95
104
|
"@babel/preset-typescript": "^7.28.5",
|
|
96
105
|
"@react-native-async-storage/async-storage": "^1.21.0",
|
|
97
|
-
"@react-native/babel-preset": "^0.
|
|
98
|
-
"@types/jest": "^
|
|
99
|
-
"@types/react": "^
|
|
100
|
-
"@typescript-eslint/eslint-plugin": "^8.
|
|
101
|
-
"@typescript-eslint/parser": "^8.
|
|
102
|
-
"babel-jest": "^
|
|
103
|
-
"eslint": "^10.
|
|
104
|
-
"expo-application": "^
|
|
105
|
-
"expo-device": "^
|
|
106
|
-
"jest": "^
|
|
107
|
-
"react": "^
|
|
108
|
-
"react-native": "^0.
|
|
109
|
-
"react-native-builder-bob": "^0.
|
|
106
|
+
"@react-native/babel-preset": "^0.85.3",
|
|
107
|
+
"@types/jest": "^30.0.0",
|
|
108
|
+
"@types/react": "^19.2.14",
|
|
109
|
+
"@typescript-eslint/eslint-plugin": "^8.59.3",
|
|
110
|
+
"@typescript-eslint/parser": "^8.59.3",
|
|
111
|
+
"babel-jest": "^30.4.1",
|
|
112
|
+
"eslint": "^10.3.0",
|
|
113
|
+
"expo-application": "^55.0.15",
|
|
114
|
+
"expo-device": "^55.0.17",
|
|
115
|
+
"jest": "^30.4.1",
|
|
116
|
+
"react": "^19.2.6",
|
|
117
|
+
"react-native": "^0.85.3",
|
|
118
|
+
"react-native-builder-bob": "^0.41.0",
|
|
110
119
|
"react-native-device-info": "^14.0.0",
|
|
111
|
-
"typescript": "^
|
|
112
|
-
"typescript-eslint": "^8.
|
|
113
|
-
},
|
|
114
|
-
"pnpm": {
|
|
115
|
-
"overrides": {
|
|
116
|
-
"@react-native-community/cli": ">=17.0.1",
|
|
117
|
-
"@react-native-community/cli-server-api": ">=17.0.1",
|
|
118
|
-
"@xmldom/xmldom": ">=0.8.12",
|
|
119
|
-
"brace-expansion@1": ">=1.1.13 <2",
|
|
120
|
-
"brace-expansion@2": ">=2.0.3 <3",
|
|
121
|
-
"fast-xml-parser": ">=4.5.5",
|
|
122
|
-
"minimatch@3": ">=3.1.5 <4",
|
|
123
|
-
"minimatch@5": ">=5.1.9 <6",
|
|
124
|
-
"minimatch@9": ">=9.0.9 <10",
|
|
125
|
-
"minimatch@10": ">=10.2.4",
|
|
126
|
-
"node-forge": ">=1.4.0",
|
|
127
|
-
"picomatch@2": ">=2.3.2 <3",
|
|
128
|
-
"picomatch@3": ">=3.0.2 <4",
|
|
129
|
-
"picomatch@4": ">=4.0.4",
|
|
130
|
-
"semver@5": ">=7.7.4",
|
|
131
|
-
"semver@6": ">=7.7.4",
|
|
132
|
-
"tar": ">=7.5.13",
|
|
133
|
-
"undici": ">=6.24.1 <7",
|
|
134
|
-
"yaml@1": ">=1.10.3 <2",
|
|
135
|
-
"yaml@2": ">=2.8.3 <3"
|
|
136
|
-
}
|
|
120
|
+
"typescript": "^6.0.3",
|
|
121
|
+
"typescript-eslint": "^8.59.3"
|
|
137
122
|
},
|
|
138
123
|
"react-native-builder-bob": {
|
|
139
124
|
"source": "src",
|
|
140
125
|
"output": "lib",
|
|
141
126
|
"targets": [
|
|
142
|
-
|
|
143
|
-
|
|
127
|
+
[
|
|
128
|
+
"commonjs",
|
|
129
|
+
{
|
|
130
|
+
"esm": true
|
|
131
|
+
}
|
|
132
|
+
],
|
|
133
|
+
[
|
|
134
|
+
"module",
|
|
135
|
+
{
|
|
136
|
+
"esm": true
|
|
137
|
+
}
|
|
138
|
+
],
|
|
144
139
|
[
|
|
145
140
|
"typescript",
|
|
146
141
|
{
|
package/src/FormoAnalytics.ts
CHANGED
|
@@ -8,6 +8,8 @@ import {
|
|
|
8
8
|
EVENTS_API_HOST,
|
|
9
9
|
EventType,
|
|
10
10
|
LOCAL_ANONYMOUS_ID_KEY,
|
|
11
|
+
LOCAL_SESSION_ID_KEY,
|
|
12
|
+
LOCAL_SESSION_LAST_ACTIVITY_KEY,
|
|
11
13
|
SESSION_USER_ID_KEY,
|
|
12
14
|
CONSENT_OPT_OUT_KEY,
|
|
13
15
|
TEventType,
|
|
@@ -35,8 +37,10 @@ import {
|
|
|
35
37
|
TrackingOptions,
|
|
36
38
|
TransactionStatus,
|
|
37
39
|
} from "./types";
|
|
38
|
-
import {
|
|
39
|
-
import { parseTrafficSource,
|
|
40
|
+
import { validateAddress } from "./utils";
|
|
41
|
+
import { parseTrafficSource, updateStoredTrafficSource } from "./utils/trafficSource";
|
|
42
|
+
import { captureInstallReferrer } from "./lib/installReferrer";
|
|
43
|
+
import { Linking, EmitterSubscription } from "react-native";
|
|
40
44
|
|
|
41
45
|
export class FormoAnalytics implements IFormoAnalytics {
|
|
42
46
|
private session: FormoAnalyticsSession;
|
|
@@ -44,6 +48,7 @@ export class FormoAnalytics implements IFormoAnalytics {
|
|
|
44
48
|
private eventQueue: EventQueue;
|
|
45
49
|
private wagmiHandler?: WagmiEventHandler;
|
|
46
50
|
private lifecycleManager?: AppLifecycleManager;
|
|
51
|
+
private linkingSubscription?: EmitterSubscription;
|
|
47
52
|
|
|
48
53
|
config: Config;
|
|
49
54
|
currentChainId?: ChainID;
|
|
@@ -128,6 +133,34 @@ export class FormoAnalytics implements IFormoAnalytics {
|
|
|
128
133
|
|
|
129
134
|
const analytics = new FormoAnalytics(writeKey, options);
|
|
130
135
|
|
|
136
|
+
// Capture attribution BEFORE lifecycle tracking so the first
|
|
137
|
+
// Application Installed/Opened events carry utm_*/ref/referrer.
|
|
138
|
+
//
|
|
139
|
+
// Both are awaited so the stored traffic source is populated before
|
|
140
|
+
// lifecycle fires — that's what lets Application Installed report the
|
|
141
|
+
// web-to-mobile referrer (e.g. referrer=example.com). Deep-link initial URL
|
|
142
|
+
// is a fast native bridge call; the Android Play Install Referrer is a fast
|
|
143
|
+
// one-shot native call (and no-ops instantly when the native module or the
|
|
144
|
+
// platform isn't Android), so awaiting it does not meaningfully delay init.
|
|
145
|
+
if (analytics.isAttributionEnabled("deeplinks")) {
|
|
146
|
+
try {
|
|
147
|
+
await analytics.startDeepLinkCapture();
|
|
148
|
+
} catch (error) {
|
|
149
|
+
logger.error("FormoAnalytics: Failed to initialize deep link capture", error);
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
if (analytics.isAttributionEnabled("installReferrer")) {
|
|
154
|
+
try {
|
|
155
|
+
await captureInstallReferrer({
|
|
156
|
+
customRefParams: analytics.options.referral?.queryParams,
|
|
157
|
+
pathPattern: analytics.options.referral?.pathPattern,
|
|
158
|
+
});
|
|
159
|
+
} catch (error) {
|
|
160
|
+
logger.debug("FormoAnalytics: install referrer capture failed", error);
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
|
|
131
164
|
// Initialize lifecycle tracking if enabled
|
|
132
165
|
// Wrapped in try-catch so a transient storage failure doesn't prevent SDK init
|
|
133
166
|
if (analytics.isAutocaptureEnabled("lifecycle")) {
|
|
@@ -147,6 +180,25 @@ export class FormoAnalytics implements IFormoAnalytics {
|
|
|
147
180
|
return analytics;
|
|
148
181
|
}
|
|
149
182
|
|
|
183
|
+
/**
|
|
184
|
+
* Hook into React Native's Linking API to auto-capture traffic source from
|
|
185
|
+
* the launch URL and any subsequent deep-link opens. Awaits the initial URL
|
|
186
|
+
* so attribution is in storage before the first lifecycle event fires.
|
|
187
|
+
*/
|
|
188
|
+
private async startDeepLinkCapture(): Promise<void> {
|
|
189
|
+
try {
|
|
190
|
+
const url = await Linking.getInitialURL();
|
|
191
|
+
if (url) this.setTrafficSourceFromUrl(url);
|
|
192
|
+
} catch (error) {
|
|
193
|
+
logger.debug("FormoAnalytics: Linking.getInitialURL failed", error);
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
// Runtime deep links (foreground opens, universal links).
|
|
197
|
+
this.linkingSubscription = Linking.addEventListener("url", (event) => {
|
|
198
|
+
if (event?.url) this.setTrafficSourceFromUrl(event.url);
|
|
199
|
+
});
|
|
200
|
+
}
|
|
201
|
+
|
|
150
202
|
/**
|
|
151
203
|
* Track a screen view (mobile equivalent of page view)
|
|
152
204
|
*/
|
|
@@ -195,7 +247,10 @@ export class FormoAnalytics implements IFormoAnalytics {
|
|
|
195
247
|
this.options.referral?.queryParams,
|
|
196
248
|
this.options.referral?.pathPattern
|
|
197
249
|
);
|
|
198
|
-
|
|
250
|
+
// Per-field merge: incoming non-empty fields win, empty fields preserve
|
|
251
|
+
// stored values. A non-marketing deep link (e.g. "myapp://home") with only
|
|
252
|
+
// a referrer will not destroy previously captured utm_*/ref attribution.
|
|
253
|
+
updateStoredTrafficSource(trafficSource);
|
|
199
254
|
logger.debug("Traffic source set from URL:", trafficSource);
|
|
200
255
|
}
|
|
201
256
|
|
|
@@ -205,6 +260,8 @@ export class FormoAnalytics implements IFormoAnalytics {
|
|
|
205
260
|
public reset(): void {
|
|
206
261
|
this.currentUserId = undefined;
|
|
207
262
|
storage().remove(LOCAL_ANONYMOUS_ID_KEY);
|
|
263
|
+
storage().remove(LOCAL_SESSION_ID_KEY);
|
|
264
|
+
storage().remove(LOCAL_SESSION_LAST_ACTIVITY_KEY);
|
|
208
265
|
storage().remove(SESSION_USER_ID_KEY);
|
|
209
266
|
this.session.clear();
|
|
210
267
|
}
|
|
@@ -220,6 +277,11 @@ export class FormoAnalytics implements IFormoAnalytics {
|
|
|
220
277
|
this.lifecycleManager = undefined;
|
|
221
278
|
}
|
|
222
279
|
|
|
280
|
+
if (this.linkingSubscription) {
|
|
281
|
+
this.linkingSubscription.remove();
|
|
282
|
+
this.linkingSubscription = undefined;
|
|
283
|
+
}
|
|
284
|
+
|
|
223
285
|
if (this.wagmiHandler) {
|
|
224
286
|
this.wagmiHandler.cleanup();
|
|
225
287
|
this.wagmiHandler = undefined;
|
|
@@ -250,8 +312,8 @@ export class FormoAnalytics implements IFormoAnalytics {
|
|
|
250
312
|
return;
|
|
251
313
|
}
|
|
252
314
|
|
|
253
|
-
const
|
|
254
|
-
if (!
|
|
315
|
+
const validatedAddress = this.validateAndChecksumAddress(address, chainId);
|
|
316
|
+
if (!validatedAddress) {
|
|
255
317
|
logger.warn(`Connect: Invalid address provided ("${address}")`);
|
|
256
318
|
return;
|
|
257
319
|
}
|
|
@@ -259,14 +321,14 @@ export class FormoAnalytics implements IFormoAnalytics {
|
|
|
259
321
|
// Track event before updating state so connect events TO excluded chains are tracked
|
|
260
322
|
await this.trackEvent(
|
|
261
323
|
EventType.CONNECT,
|
|
262
|
-
{ chainId, address:
|
|
324
|
+
{ chainId, address: validatedAddress },
|
|
263
325
|
properties,
|
|
264
326
|
context,
|
|
265
327
|
callback
|
|
266
328
|
);
|
|
267
329
|
|
|
268
330
|
this.currentChainId = chainId;
|
|
269
|
-
this.currentAddress =
|
|
331
|
+
this.currentAddress = validatedAddress;
|
|
270
332
|
}
|
|
271
333
|
|
|
272
334
|
/**
|
|
@@ -345,13 +407,11 @@ export class FormoAnalytics implements IFormoAnalytics {
|
|
|
345
407
|
chainId,
|
|
346
408
|
address,
|
|
347
409
|
message,
|
|
348
|
-
signatureHash,
|
|
349
410
|
}: {
|
|
350
411
|
status: SignatureStatus;
|
|
351
412
|
chainId?: ChainID;
|
|
352
413
|
address: Address;
|
|
353
414
|
message: string;
|
|
354
|
-
signatureHash?: string;
|
|
355
415
|
},
|
|
356
416
|
properties?: IFormoEventProperties,
|
|
357
417
|
context?: IFormoEventContext,
|
|
@@ -368,7 +428,6 @@ export class FormoAnalytics implements IFormoAnalytics {
|
|
|
368
428
|
...(chainId !== undefined && chainId !== null && { chainId }),
|
|
369
429
|
address,
|
|
370
430
|
message,
|
|
371
|
-
...(signatureHash && { signatureHash }),
|
|
372
431
|
},
|
|
373
432
|
properties,
|
|
374
433
|
context,
|
|
@@ -458,6 +517,8 @@ export class FormoAnalytics implements IFormoAnalytics {
|
|
|
458
517
|
return;
|
|
459
518
|
}
|
|
460
519
|
this.currentAddress = validAddress;
|
|
520
|
+
// Note: validateAddress returns Solana addresses unchanged (Base58, case-sensitive)
|
|
521
|
+
// and EVM addresses checksummed.
|
|
461
522
|
} else {
|
|
462
523
|
this.currentAddress = undefined;
|
|
463
524
|
}
|
|
@@ -566,10 +627,19 @@ export class FormoAnalytics implements IFormoAnalytics {
|
|
|
566
627
|
}
|
|
567
628
|
|
|
568
629
|
/**
|
|
569
|
-
* Check if autocapture is enabled for event type
|
|
630
|
+
* Check if autocapture is enabled for a given event type.
|
|
631
|
+
* Applies only to event-generating behaviors (wallet events, lifecycle
|
|
632
|
+
* events). Attribution is controlled separately via `options.attribution`
|
|
633
|
+
* because it enriches events rather than generating them.
|
|
570
634
|
*/
|
|
571
635
|
public isAutocaptureEnabled(
|
|
572
|
-
eventType:
|
|
636
|
+
eventType:
|
|
637
|
+
| "connect"
|
|
638
|
+
| "disconnect"
|
|
639
|
+
| "signature"
|
|
640
|
+
| "transaction"
|
|
641
|
+
| "chain"
|
|
642
|
+
| "lifecycle"
|
|
573
643
|
): boolean {
|
|
574
644
|
if (this.options.autocapture === undefined) {
|
|
575
645
|
return true;
|
|
@@ -590,6 +660,32 @@ export class FormoAnalytics implements IFormoAnalytics {
|
|
|
590
660
|
return true;
|
|
591
661
|
}
|
|
592
662
|
|
|
663
|
+
/**
|
|
664
|
+
* Check if an attribution source is enabled. Attribution is not an event
|
|
665
|
+
* type — it decorates every tracked event with `utm_*`, `ref`, and
|
|
666
|
+
* `referrer` context fields.
|
|
667
|
+
*/
|
|
668
|
+
public isAttributionEnabled(
|
|
669
|
+
source: "deeplinks" | "installReferrer"
|
|
670
|
+
): boolean {
|
|
671
|
+
if (this.options.attribution === undefined) {
|
|
672
|
+
return true;
|
|
673
|
+
}
|
|
674
|
+
|
|
675
|
+
if (typeof this.options.attribution === "boolean") {
|
|
676
|
+
return this.options.attribution;
|
|
677
|
+
}
|
|
678
|
+
|
|
679
|
+
if (
|
|
680
|
+
this.options.attribution !== null &&
|
|
681
|
+
typeof this.options.attribution === "object"
|
|
682
|
+
) {
|
|
683
|
+
return this.options.attribution[source] !== false;
|
|
684
|
+
}
|
|
685
|
+
|
|
686
|
+
return true;
|
|
687
|
+
}
|
|
688
|
+
|
|
593
689
|
/**
|
|
594
690
|
* Internal method to track events
|
|
595
691
|
* This is the single enforcement point for shouldTrack() - all public tracking
|
|
@@ -669,11 +765,17 @@ export class FormoAnalytics implements IFormoAnalytics {
|
|
|
669
765
|
}
|
|
670
766
|
|
|
671
767
|
/**
|
|
672
|
-
* Validate and
|
|
768
|
+
* Validate and normalize an address for the given chain.
|
|
769
|
+
*
|
|
770
|
+
* EVM addresses are returned in EIP-55 checksum format.
|
|
771
|
+
* Solana addresses are returned as-is (Base58 is case-sensitive).
|
|
772
|
+
* When chainId is omitted, EVM is tried first with Solana as fallback.
|
|
673
773
|
*/
|
|
674
|
-
private validateAndChecksumAddress(
|
|
675
|
-
|
|
676
|
-
|
|
774
|
+
private validateAndChecksumAddress(
|
|
775
|
+
address: string,
|
|
776
|
+
chainId?: ChainID
|
|
777
|
+
): Address | undefined {
|
|
778
|
+
return validateAddress(address, chainId);
|
|
677
779
|
}
|
|
678
780
|
|
|
679
781
|
/**
|
package/src/constants/events.ts
CHANGED
|
@@ -24,3 +24,7 @@ export type TEventChannel = Lowercase<EventChannel>;
|
|
|
24
24
|
// React Native SDK uses mobile channel
|
|
25
25
|
export const CHANNEL: TEventChannel = "mobile";
|
|
26
26
|
export const VERSION = "0";
|
|
27
|
+
|
|
28
|
+
// Session inactivity timeout (30 min), matching the GA4/Segment default. A new
|
|
29
|
+
// session_id is minted once the gap since the last tracked event exceeds this.
|
|
30
|
+
export const SESSION_TIMEOUT_MS = 30 * 60 * 1000;
|
package/src/constants/storage.ts
CHANGED
|
@@ -5,6 +5,13 @@ export const STORAGE_PREFIX = "formo_rn_";
|
|
|
5
5
|
export const LOCAL_ANONYMOUS_ID_KEY = "anonymous_id";
|
|
6
6
|
export const LOCAL_APP_VERSION_KEY = "app_version";
|
|
7
7
|
export const LOCAL_APP_BUILD_KEY = "app_build";
|
|
8
|
+
// Session identifier + last-activity marker. Persisted so a session survives an
|
|
9
|
+
// app restart, but expires after SESSION_TIMEOUT_MS of inactivity (see EventFactory).
|
|
10
|
+
export const LOCAL_SESSION_ID_KEY = "session_id";
|
|
11
|
+
export const LOCAL_SESSION_LAST_ACTIVITY_KEY = "session_last_activity";
|
|
12
|
+
// One-shot flag: set once the Android Play Install Referrer attribution has
|
|
13
|
+
// been fetched, so we never call the native API again.
|
|
14
|
+
export const LOCAL_INSTALL_REFERRER_RESOLVED_KEY = "install_referrer_resolved";
|
|
8
15
|
|
|
9
16
|
// Session storage keys (cleared on app restart)
|
|
10
17
|
export const SESSION_USER_ID_KEY = "user_id";
|
|
@@ -25,7 +25,15 @@ try {
|
|
|
25
25
|
} catch {
|
|
26
26
|
// Not available
|
|
27
27
|
}
|
|
28
|
-
import {
|
|
28
|
+
import {
|
|
29
|
+
COUNTRY_LIST,
|
|
30
|
+
LOCAL_ANONYMOUS_ID_KEY,
|
|
31
|
+
LOCAL_SESSION_ID_KEY,
|
|
32
|
+
LOCAL_SESSION_LAST_ACTIVITY_KEY,
|
|
33
|
+
SESSION_TIMEOUT_MS,
|
|
34
|
+
CHANNEL,
|
|
35
|
+
VERSION,
|
|
36
|
+
} from "../../constants";
|
|
29
37
|
import {
|
|
30
38
|
Address,
|
|
31
39
|
APIEvent,
|
|
@@ -39,8 +47,7 @@ import {
|
|
|
39
47
|
TransactionStatus,
|
|
40
48
|
} from "../../types";
|
|
41
49
|
import {
|
|
42
|
-
|
|
43
|
-
getValidAddress,
|
|
50
|
+
validateAddress,
|
|
44
51
|
toSnakeCase,
|
|
45
52
|
mergeDeepRight,
|
|
46
53
|
getStoredTrafficSource,
|
|
@@ -66,6 +73,73 @@ function generateAnonymousId(key: string): string {
|
|
|
66
73
|
return newId;
|
|
67
74
|
}
|
|
68
75
|
|
|
76
|
+
/**
|
|
77
|
+
* Get the current session id, or start a new one.
|
|
78
|
+
*
|
|
79
|
+
* A session persists across app restarts but expires after SESSION_TIMEOUT_MS of
|
|
80
|
+
* inactivity, at which point a fresh id is minted. Every call refreshes the
|
|
81
|
+
* last-activity marker.
|
|
82
|
+
*
|
|
83
|
+
* The mobile SDK owns its session_id rather than letting ingestion derive one.
|
|
84
|
+
* The events-gateway authorizer computes
|
|
85
|
+
* `hash(dailySalt + domain + sourceIp + userAgent)` — a design built for the
|
|
86
|
+
* web, where all three inputs carry real entropy. For a native app they all
|
|
87
|
+
* degenerate at once: there is no Origin header (so `domain` is the constant
|
|
88
|
+
* "unknown"), the HTTP User-Agent is the client library's (`okhttp/…`,
|
|
89
|
+
* `CFNetwork/… Darwin/…`) and is near-identical across users on the same app
|
|
90
|
+
* build, and carrier CGNAT puts many users behind one IP — so unrelated users
|
|
91
|
+
* collapse into a single session. Ingestion honours a body-provided session_id
|
|
92
|
+
* (`obj?.session_id || session_id` in handlerV0), which is the path used here.
|
|
93
|
+
*/
|
|
94
|
+
export function getSessionId(): string {
|
|
95
|
+
const now = Date.now();
|
|
96
|
+
const existingId = storage().get(LOCAL_SESSION_ID_KEY);
|
|
97
|
+
const lastActivityRaw = storage().get(LOCAL_SESSION_LAST_ACTIVITY_KEY);
|
|
98
|
+
const lastActivity = lastActivityRaw ? parseInt(lastActivityRaw, 10) : 0;
|
|
99
|
+
|
|
100
|
+
const isExpired =
|
|
101
|
+
!existingId || !lastActivity || now - lastActivity > SESSION_TIMEOUT_MS;
|
|
102
|
+
const sessionId = isExpired ? generateUUID() : existingId;
|
|
103
|
+
|
|
104
|
+
storage().set(LOCAL_SESSION_ID_KEY, sessionId);
|
|
105
|
+
storage().set(LOCAL_SESSION_LAST_ACTIVITY_KEY, String(now));
|
|
106
|
+
|
|
107
|
+
return sessionId;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* Build a representative User-Agent string from structured device info.
|
|
112
|
+
*
|
|
113
|
+
* The ingestion pipeline classifies device / os / browser purely from the
|
|
114
|
+
* user_agent string; a mobile event with an empty UA is bucketed as "unknown".
|
|
115
|
+
* Platforms without a native UA (e.g. Expo, where DeviceInfo.getUserAgent() is
|
|
116
|
+
* unavailable) would otherwise report device=os=unknown. We synthesize a UA
|
|
117
|
+
* containing the tokens the classifier keys off (iphone/ipad/android + version)
|
|
118
|
+
* so mobile device and OS resolve correctly. Returns "" for unknown platforms.
|
|
119
|
+
*/
|
|
120
|
+
export function synthesizeUserAgent(info: {
|
|
121
|
+
os_name: string;
|
|
122
|
+
os_version: string;
|
|
123
|
+
device_model: string;
|
|
124
|
+
device_type: string;
|
|
125
|
+
}): string {
|
|
126
|
+
const os = (info.os_name || "").toLowerCase();
|
|
127
|
+
const version = info.os_version || "";
|
|
128
|
+
const model = info.device_model || "";
|
|
129
|
+
const isTablet = info.device_type === "tablet";
|
|
130
|
+
|
|
131
|
+
if (os === "ios" || os === "ipados") {
|
|
132
|
+
const device = isTablet ? "iPad" : "iPhone";
|
|
133
|
+
const osVersion = version.replace(/\./g, "_");
|
|
134
|
+
return `Mozilla/5.0 (${device}; CPU ${device} OS ${osVersion} like Mac OS X) FormoAnalytics/ReactNative`;
|
|
135
|
+
}
|
|
136
|
+
if (os === "android") {
|
|
137
|
+
const formFactor = isTablet ? "Tablet" : "Mobile";
|
|
138
|
+
return `Mozilla/5.0 (Linux; Android ${version}; ${model}) ${formFactor} FormoAnalytics/ReactNative`;
|
|
139
|
+
}
|
|
140
|
+
return "";
|
|
141
|
+
}
|
|
142
|
+
|
|
69
143
|
/**
|
|
70
144
|
* Event factory for React Native
|
|
71
145
|
* Creates event payloads with mobile-specific context
|
|
@@ -219,14 +293,24 @@ class EventFactory implements IEventFactory {
|
|
|
219
293
|
DeviceInfo.isTablet(),
|
|
220
294
|
]);
|
|
221
295
|
|
|
296
|
+
const device_type = isTablet ? "tablet" : "mobile";
|
|
297
|
+
const os_version = DeviceInfo.getSystemVersion();
|
|
222
298
|
return {
|
|
223
299
|
os_name: Platform.OS,
|
|
224
|
-
os_version
|
|
300
|
+
os_version,
|
|
225
301
|
device_model: model,
|
|
226
302
|
device_manufacturer: manufacturer,
|
|
227
303
|
device_name: deviceName,
|
|
228
|
-
device_type
|
|
229
|
-
|
|
304
|
+
device_type,
|
|
305
|
+
// Prefer the native UA; fall back to a synthesized one if unavailable.
|
|
306
|
+
user_agent:
|
|
307
|
+
userAgent ||
|
|
308
|
+
synthesizeUserAgent({
|
|
309
|
+
os_name: Platform.OS,
|
|
310
|
+
os_version,
|
|
311
|
+
device_model: model,
|
|
312
|
+
device_type,
|
|
313
|
+
}),
|
|
230
314
|
app_name: DeviceInfo.getApplicationName(),
|
|
231
315
|
app_version: DeviceInfo.getVersion(),
|
|
232
316
|
app_build: DeviceInfo.getBuildNumber(),
|
|
@@ -241,14 +325,25 @@ class EventFactory implements IEventFactory {
|
|
|
241
325
|
if (ExpoDevice || ExpoApplication) {
|
|
242
326
|
try {
|
|
243
327
|
const isTablet = ExpoDevice?.deviceType === ExpoDevice?.DeviceType?.TABLET;
|
|
328
|
+
const os_name = ExpoDevice?.osName || Platform.OS;
|
|
329
|
+
const os_version = ExpoDevice?.osVersion || String(Platform.Version);
|
|
330
|
+
const device_model = ExpoDevice?.modelName || "Unknown";
|
|
331
|
+
const device_type = isTablet ? "tablet" : "mobile";
|
|
244
332
|
return {
|
|
245
|
-
os_name
|
|
246
|
-
os_version
|
|
247
|
-
device_model
|
|
333
|
+
os_name,
|
|
334
|
+
os_version,
|
|
335
|
+
device_model,
|
|
248
336
|
device_manufacturer: ExpoDevice?.manufacturer || "Unknown",
|
|
249
337
|
device_name: ExpoDevice?.deviceName || "Unknown Device",
|
|
250
|
-
device_type
|
|
251
|
-
|
|
338
|
+
device_type,
|
|
339
|
+
// Expo exposes no native UA; synthesize one so the pipeline can
|
|
340
|
+
// classify device/os (both are derived from the UA string).
|
|
341
|
+
user_agent: synthesizeUserAgent({
|
|
342
|
+
os_name,
|
|
343
|
+
os_version,
|
|
344
|
+
device_model,
|
|
345
|
+
device_type,
|
|
346
|
+
}),
|
|
252
347
|
app_name: ExpoApplication?.applicationName || "",
|
|
253
348
|
app_version: ExpoApplication?.nativeApplicationVersion || "",
|
|
254
349
|
app_build: ExpoApplication?.nativeBuildVersion || "",
|
|
@@ -261,14 +356,21 @@ class EventFactory implements IEventFactory {
|
|
|
261
356
|
|
|
262
357
|
// Final fallback - minimal info from Platform
|
|
263
358
|
logger.debug("No device info modules available, using Platform defaults");
|
|
359
|
+
const os_name = Platform.OS;
|
|
360
|
+
const os_version = String(Platform.Version);
|
|
264
361
|
return {
|
|
265
|
-
os_name
|
|
266
|
-
os_version
|
|
362
|
+
os_name,
|
|
363
|
+
os_version,
|
|
267
364
|
device_model: "Unknown",
|
|
268
365
|
device_manufacturer: "Unknown",
|
|
269
366
|
device_name: "Unknown Device",
|
|
270
367
|
device_type: "mobile",
|
|
271
|
-
user_agent:
|
|
368
|
+
user_agent: synthesizeUserAgent({
|
|
369
|
+
os_name,
|
|
370
|
+
os_version,
|
|
371
|
+
device_model: "Unknown",
|
|
372
|
+
device_type: "mobile",
|
|
373
|
+
}),
|
|
272
374
|
app_name: "",
|
|
273
375
|
app_version: "",
|
|
274
376
|
app_build: "",
|
|
@@ -335,14 +437,14 @@ class EventFactory implements IEventFactory {
|
|
|
335
437
|
};
|
|
336
438
|
|
|
337
439
|
commonEventData.anonymous_id = generateAnonymousId(LOCAL_ANONYMOUS_ID_KEY);
|
|
440
|
+
commonEventData.session_id = getSessionId();
|
|
338
441
|
|
|
339
442
|
// Handle address - convert undefined to null for consistency
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
}
|
|
443
|
+
// Try EVM first, then Solana fallback (chainId is not always present here).
|
|
444
|
+
const validAddress = formoEvent.address
|
|
445
|
+
? validateAddress(formoEvent.address)
|
|
446
|
+
: undefined;
|
|
447
|
+
commonEventData.address = validAddress ?? null;
|
|
346
448
|
|
|
347
449
|
const processedEvent = mergeDeepRight(
|
|
348
450
|
formoEvent as Record<string, unknown>,
|
|
@@ -385,8 +487,12 @@ class EventFactory implements IEventFactory {
|
|
|
385
487
|
): Promise<IFormoEvent> {
|
|
386
488
|
const props = { ...(properties ?? {}), name, ...(category && { category }) };
|
|
387
489
|
|
|
388
|
-
// Map screen name to page-equivalent context fields
|
|
389
|
-
//
|
|
490
|
+
// Map screen name to page-equivalent context fields so mobile screens flow
|
|
491
|
+
// through the same analytics as web page views. The screen name is emitted
|
|
492
|
+
// as-is in the app:// URL; the ingestion pipeline derives `origin` (from the
|
|
493
|
+
// app identifier in context — app_name / app_bundle_id) and `page_path` (by
|
|
494
|
+
// stripping the app:// scheme), so the SDK deliberately does NOT encode a
|
|
495
|
+
// host here (see backend mobile page-event handling, P-2070).
|
|
390
496
|
// User-supplied context values take precedence (spread last).
|
|
391
497
|
const screenContext: IFormoEventContext = {
|
|
392
498
|
page_title: name,
|
|
@@ -501,7 +607,6 @@ class EventFactory implements IEventFactory {
|
|
|
501
607
|
chainId: ChainID | undefined,
|
|
502
608
|
address: Address,
|
|
503
609
|
message: string,
|
|
504
|
-
signatureHash?: string,
|
|
505
610
|
properties?: IFormoEventProperties,
|
|
506
611
|
context?: IFormoEventContext
|
|
507
612
|
): Promise<IFormoEvent> {
|
|
@@ -510,7 +615,6 @@ class EventFactory implements IEventFactory {
|
|
|
510
615
|
status,
|
|
511
616
|
...(chainId !== undefined && chainId !== null && { chainId }),
|
|
512
617
|
message,
|
|
513
|
-
...(signatureHash && { signatureHash }),
|
|
514
618
|
...properties,
|
|
515
619
|
},
|
|
516
620
|
address,
|
|
@@ -648,7 +752,6 @@ class EventFactory implements IEventFactory {
|
|
|
648
752
|
event.chainId,
|
|
649
753
|
event.address,
|
|
650
754
|
event.message,
|
|
651
|
-
event.signatureHash,
|
|
652
755
|
event.properties,
|
|
653
756
|
event.context
|
|
654
757
|
);
|
|
@@ -680,10 +783,7 @@ class EventFactory implements IEventFactory {
|
|
|
680
783
|
|
|
681
784
|
// Set address if not already set by the specific event generator
|
|
682
785
|
if (formoEvent.address === undefined || formoEvent.address === null) {
|
|
683
|
-
|
|
684
|
-
formoEvent.address = validAddress
|
|
685
|
-
? toChecksumAddress(validAddress)
|
|
686
|
-
: null;
|
|
786
|
+
formoEvent.address = address ? validateAddress(address) ?? null : null;
|
|
687
787
|
}
|
|
688
788
|
formoEvent.user_id = userId || null;
|
|
689
789
|
|