@amplytools/react-native-amply-sdk 0.14.0 → 0.15.1
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/AmplyReactNative.podspec +1 -1
- package/README.md +41 -0
- package/android/build.gradle +1 -1
- package/android/src/main/java/tools/amply/sdk/reactnative/AmplyModule.kt +22 -0
- package/android/src/main/java/tools/amply/sdk/reactnative/core/AmplyClient.kt +11 -0
- package/android/src/main/java/tools/amply/sdk/reactnative/core/DefaultAmplyClient.kt +29 -0
- package/android/src/main/java/tools/amply/sdk/reactnative/model/CampaignTouchPayload.kt +12 -0
- package/android/src/newarch/java/tools/amply/sdk/reactnative/NativeAmplyModuleSpec.java +8 -0
- package/android/src/newarch/jni/AmplyReactNative-generated.cpp +12 -0
- package/dist/cjs/campaignTouch.js +44 -0
- package/dist/cjs/campaignTouch.js.map +1 -0
- package/dist/cjs/hooks/useAmplySystemEvents.js +60 -0
- package/dist/cjs/hooks/useAmplySystemEvents.js.map +1 -0
- package/dist/cjs/index.js +723 -0
- package/dist/cjs/index.js.map +1 -0
- package/dist/cjs/nativeModule.js +55 -0
- package/dist/cjs/nativeModule.js.map +1 -0
- package/dist/cjs/nativeSpecs/NativeAmplyModule.js +5 -0
- package/dist/cjs/nativeSpecs/NativeAmplyModule.js.map +1 -0
- package/dist/cjs/systemEventUtils.js +47 -0
- package/dist/cjs/systemEventUtils.js.map +1 -0
- package/dist/cjs/systemEvents.js +27 -0
- package/dist/cjs/systemEvents.js.map +1 -0
- package/dist/src/campaignTouch.d.ts +36 -0
- package/dist/src/campaignTouch.d.ts.map +1 -0
- package/dist/src/campaignTouch.js +39 -0
- package/dist/src/index.d.ts +35 -0
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +120 -0
- package/dist/src/nativeSpecs/NativeAmplyModule.d.ts +28 -0
- package/dist/src/nativeSpecs/NativeAmplyModule.d.ts.map +1 -1
- package/dist/src/systemEventUtils.d.ts.map +1 -1
- package/dist/src/systemEventUtils.js +3 -1
- package/docs/ARCHITECTURE.md +28 -19
- package/docs/DEVELOPMENT.md +2 -1
- package/ios/Sources/AmplyReactNative/AmplyModule.mm +56 -0
- package/ios/Sources/AmplyReactNative/AmplyReactNative/AmplyReactNative-generated.mm +14 -0
- package/ios/Sources/AmplyReactNative/AmplyReactNative/AmplyReactNative.h +4 -0
- package/package.json +12 -6
- package/scripts/check-package.js +159 -0
- package/src/campaignTouch.ts +74 -0
- package/src/index.ts +124 -0
- package/src/nativeSpecs/NativeAmplyModule.ts +29 -0
- package/src/systemEventUtils.ts +3 -1
- package/dist/index.js +0 -272
- package/dist/index.js.map +0 -1
- package/dist/index.mjs +0 -234
- package/dist/index.mjs.map +0 -1
- package/dist/plugin/index.d.ts +0 -6
- package/dist/plugin/index.d.ts.map +0 -1
- package/dist/plugin/index.js +0 -186
- package/dist/plugin/index.js.map +0 -1
- package/dist/plugin/index.mjs +0 -169
- package/dist/plugin/index.mjs.map +0 -1
- package/dist/plugin/withAmply.d.ts +0 -12
- package/dist/plugin/withAmply.d.ts.map +0 -1
- package/dist/src/__tests__/appLanguage.test.d.ts +0 -43
- package/dist/src/__tests__/appLanguage.test.d.ts.map +0 -1
- package/dist/src/__tests__/appLanguage.test.js +0 -211
- package/dist/src/__tests__/campaignResolved.test.d.ts +0 -2
- package/dist/src/__tests__/campaignResolved.test.d.ts.map +0 -1
- package/dist/src/__tests__/campaignResolved.test.js +0 -208
- package/dist/src/__tests__/gateRegistrationLifecycle.test.d.ts +0 -2
- package/dist/src/__tests__/gateRegistrationLifecycle.test.d.ts.map +0 -1
- package/dist/src/__tests__/gateRegistrationLifecycle.test.js +0 -215
- package/dist/src/__tests__/index.test.d.ts +0 -2
- package/dist/src/__tests__/index.test.d.ts.map +0 -1
- package/dist/src/__tests__/index.test.js +0 -204
- package/dist/src/__tests__/systemEventUtils.test.d.ts +0 -2
- package/dist/src/__tests__/systemEventUtils.test.d.ts.map +0 -1
- package/dist/src/__tests__/systemEventUtils.test.js +0 -56
- package/dist/tsconfig.tsbuildinfo +0 -1
- package/plugin/tsconfig.tsbuildinfo +0 -1
- package/src/__tests__/appLanguage.test.ts +0 -296
- package/src/__tests__/campaignResolved.test.ts +0 -294
- package/src/__tests__/gateRegistrationLifecycle.test.ts +0 -281
- package/src/__tests__/index.test.ts +0 -258
- package/src/__tests__/systemEventUtils.test.ts +0 -75
package/AmplyReactNative.podspec
CHANGED
package/README.md
CHANGED
|
@@ -13,6 +13,7 @@ React Native TurboModule bridge for the Amply SDK. Enables event tracking, deepl
|
|
|
13
13
|
| Debug/Logging | ✅ | Android, iOS |
|
|
14
14
|
| Custom properties | ✅ | Android, iOS |
|
|
15
15
|
| User identification | ✅ | Android, iOS |
|
|
16
|
+
| Last campaign touch (attribution in your analytics) | ✅ | Android, iOS |
|
|
16
17
|
|
|
17
18
|
## Requirements
|
|
18
19
|
|
|
@@ -75,6 +76,46 @@ const unsubscribe = await Amply.addDeepLinkListener((event) => {
|
|
|
75
76
|
});
|
|
76
77
|
```
|
|
77
78
|
|
|
79
|
+
### Debug launch
|
|
80
|
+
|
|
81
|
+
Amply can open a campaign on a real device from a link or QR code made in the dashboard, so you
|
|
82
|
+
can click through it inside your app. The link uses your app's URL scheme, so the app has to pass
|
|
83
|
+
incoming links to Amply:
|
|
84
|
+
|
|
85
|
+
```typescript
|
|
86
|
+
import {Linking} from 'react-native';
|
|
87
|
+
import Amply from '@amplytools/react-native-amply-sdk';
|
|
88
|
+
|
|
89
|
+
const forward = (url: string | null) => {
|
|
90
|
+
if (url && Amply.handleUrl(url)) {
|
|
91
|
+
return; // an Amply link: Amply took it, do not route it
|
|
92
|
+
}
|
|
93
|
+
// ...your own link handling
|
|
94
|
+
};
|
|
95
|
+
|
|
96
|
+
Linking.getInitialURL().then(forward);
|
|
97
|
+
Linking.addEventListener('url', ({url}) => forward(url));
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
`handleUrl` returns `true` when Amply recognised the link as its own, and `false` for any other
|
|
101
|
+
link (it never throws). It is fine to call it before `initialize` finishes, as on a cold start: an Amply link that arrives early is held (the newest one) and opened as soon as `initialize` succeeds; it is dropped if `initialize` fails. A
|
|
102
|
+
campaign launched this way is not counted in statistics.
|
|
103
|
+
|
|
104
|
+
With Expo Router, links are routed before your code sees them, so forward only from
|
|
105
|
+
`app/+native-intent.tsx` (and do not also forward with `Linking` above). An Amply link reaches the
|
|
106
|
+
SDK instead of the not-found screen, and every other link is routed as usual:
|
|
107
|
+
|
|
108
|
+
```typescript
|
|
109
|
+
import Amply from '@amplytools/react-native-amply-sdk';
|
|
110
|
+
|
|
111
|
+
export function redirectSystemPath({path}: {path: string; initial: boolean}) {
|
|
112
|
+
if (Amply.handleUrl(path)) {
|
|
113
|
+
return '/'; // an Amply link: Amply took it
|
|
114
|
+
}
|
|
115
|
+
return path;
|
|
116
|
+
}
|
|
117
|
+
```
|
|
118
|
+
|
|
78
119
|
### About the keys
|
|
79
120
|
|
|
80
121
|
`apiKeySecret` ships inside your app: the SDK signs every request with it on the device. Keep it
|
package/android/build.gradle
CHANGED
|
@@ -15,7 +15,7 @@ buildscript {
|
|
|
15
15
|
apply plugin: 'com.android.library'
|
|
16
16
|
apply plugin: 'org.jetbrains.kotlin.android'
|
|
17
17
|
|
|
18
|
-
def amplySdkVersion = project.findProperty('amplySdkVersion') ?: System.getenv('AMPLY_SDK_VERSION') ?: '0.
|
|
18
|
+
def amplySdkVersion = project.findProperty('amplySdkVersion') ?: System.getenv('AMPLY_SDK_VERSION') ?: '0.15.0'
|
|
19
19
|
group = 'tools.amply'
|
|
20
20
|
version = amplySdkVersion
|
|
21
21
|
|
|
@@ -5,6 +5,7 @@ import tools.amply.sdk.reactnative.core.AmplyClient
|
|
|
5
5
|
import tools.amply.sdk.reactnative.core.DefaultAmplyClient
|
|
6
6
|
import tools.amply.sdk.reactnative.core.GateDecision
|
|
7
7
|
import tools.amply.sdk.reactnative.model.AmplyInitializationOptions
|
|
8
|
+
import tools.amply.sdk.reactnative.model.CampaignTouchPayload
|
|
8
9
|
import tools.amply.sdk.reactnative.model.DataSetType
|
|
9
10
|
import tools.amply.sdk.reactnative.model.DataSetType.EventParam
|
|
10
11
|
import tools.amply.sdk.reactnative.model.DataSetType.Events
|
|
@@ -153,6 +154,16 @@ class AmplyModule(reactContext: ReactApplicationContext) :
|
|
|
153
154
|
}
|
|
154
155
|
}
|
|
155
156
|
|
|
157
|
+
override fun getLastCampaignTouch(withinMs: Double, promise: Promise) {
|
|
158
|
+
scope.launch {
|
|
159
|
+
try {
|
|
160
|
+
promise.resolve(client.getLastCampaignTouch(withinMs.toLong())?.toWritableMap())
|
|
161
|
+
} catch (throwable: Throwable) {
|
|
162
|
+
promise.reject(CAMPAIGN_TOUCH_ERROR, throwable)
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
|
|
156
167
|
override fun getDataSetSnapshot(type: ReadableMap, promise: Promise) {
|
|
157
168
|
val datasetType = try {
|
|
158
169
|
type.toDataSetType()
|
|
@@ -199,6 +210,8 @@ class AmplyModule(reactContext: ReactApplicationContext) :
|
|
|
199
210
|
client.setAppLanguage(tag)
|
|
200
211
|
}
|
|
201
212
|
|
|
213
|
+
override fun handleUrl(url: String): Boolean = client.handleUrl(url)
|
|
214
|
+
|
|
202
215
|
override fun setLogLevel(level: String) {
|
|
203
216
|
val newLevel = LogLevel.fromString(level)
|
|
204
217
|
client.setLogLevel(newLevel)
|
|
@@ -427,6 +440,14 @@ class AmplyModule(reactContext: ReactApplicationContext) :
|
|
|
427
440
|
putMap("properties", properties.toWritableMap())
|
|
428
441
|
}
|
|
429
442
|
|
|
443
|
+
private fun CampaignTouchPayload.toWritableMap(): WritableMap =
|
|
444
|
+
Arguments.createMap().apply {
|
|
445
|
+
putString("campaignId", campaignId)
|
|
446
|
+
putString("campaignName", campaignName)
|
|
447
|
+
putString("kind", kind)
|
|
448
|
+
putDouble("atMs", atMs.toDouble())
|
|
449
|
+
}
|
|
450
|
+
|
|
430
451
|
private fun List<EventEnvelope>.toWritableArray(): WritableArray {
|
|
431
452
|
val array = Arguments.createArray()
|
|
432
453
|
forEach { event ->
|
|
@@ -530,6 +551,7 @@ class AmplyModule(reactContext: ReactApplicationContext) :
|
|
|
530
551
|
private const val ARGUMENT_ERROR = "AMP_INVALID_ARGUMENT"
|
|
531
552
|
private const val TRACK_ERROR = "AMP_TRACK_FAILED"
|
|
532
553
|
private const val EVENTS_ERROR = "AMP_EVENTS_FAILED"
|
|
554
|
+
private const val CAMPAIGN_TOUCH_ERROR = "AMP_CAMPAIGN_TOUCH_FAILED"
|
|
533
555
|
private const val DATASET_ERROR = "AMP_DATASET_FAILED"
|
|
534
556
|
private const val CUSTOM_PROP_ERROR = "AMP_CUSTOM_PROP_FAILED"
|
|
535
557
|
}
|
|
@@ -2,6 +2,7 @@ package tools.amply.sdk.reactnative.core
|
|
|
2
2
|
|
|
3
3
|
import android.app.Activity
|
|
4
4
|
import tools.amply.sdk.reactnative.model.AmplyInitializationOptions
|
|
5
|
+
import tools.amply.sdk.reactnative.model.CampaignTouchPayload
|
|
5
6
|
import tools.amply.sdk.reactnative.model.DataSetType
|
|
6
7
|
import tools.amply.sdk.reactnative.model.DeepLinkPayload
|
|
7
8
|
import tools.amply.sdk.reactnative.model.EventEnvelope
|
|
@@ -65,6 +66,13 @@ interface AmplyClient {
|
|
|
65
66
|
|
|
66
67
|
suspend fun getRecentEvents(limit: Int): List<EventEnvelope>
|
|
67
68
|
|
|
69
|
+
/**
|
|
70
|
+
* The SDK's `getLastCampaignTouch(withinMs)`: the newest campaign touch at most [withinMs] ago
|
|
71
|
+
* (clamped by the SDK to [0, 30 days]). Null when there is none, and also before
|
|
72
|
+
* initialisation — the SDK answers null there rather than throwing, and so does the bridge.
|
|
73
|
+
*/
|
|
74
|
+
suspend fun getLastCampaignTouch(withinMs: Long): CampaignTouchPayload?
|
|
75
|
+
|
|
68
76
|
suspend fun getDataSetSnapshot(type: DataSetType): Map<String, Any?>
|
|
69
77
|
|
|
70
78
|
fun registerDeepLinkListener()
|
|
@@ -74,6 +82,9 @@ interface AmplyClient {
|
|
|
74
82
|
|
|
75
83
|
fun setAppLanguage(tag: String?)
|
|
76
84
|
|
|
85
|
+
/** True when the SDK recognised [url] as its own and took it over; false otherwise or when not initialised. */
|
|
86
|
+
fun handleUrl(url: String): Boolean
|
|
87
|
+
|
|
77
88
|
fun setLogLevel(level: LogLevel)
|
|
78
89
|
fun getLogLevel(): LogLevel
|
|
79
90
|
|
|
@@ -5,6 +5,7 @@ import android.app.Application
|
|
|
5
5
|
import android.os.Handler
|
|
6
6
|
import android.os.Looper
|
|
7
7
|
import tools.amply.sdk.reactnative.model.AmplyInitializationOptions
|
|
8
|
+
import tools.amply.sdk.reactnative.model.CampaignTouchPayload
|
|
8
9
|
import tools.amply.sdk.reactnative.model.DataSetType
|
|
9
10
|
import tools.amply.sdk.reactnative.model.DeepLinkPayload
|
|
10
11
|
import tools.amply.sdk.reactnative.model.EventEnvelope
|
|
@@ -30,6 +31,8 @@ import tools.amply.sdk.actions.CampaignPresenter
|
|
|
30
31
|
import tools.amply.sdk.actions.CampaignResolution
|
|
31
32
|
import tools.amply.sdk.actions.CampaignResult
|
|
32
33
|
import tools.amply.sdk.actions.DeepLinkListener
|
|
34
|
+
import tools.amply.sdk.campaigns.CampaignTouch
|
|
35
|
+
import tools.amply.sdk.campaigns.CampaignTouchKind
|
|
33
36
|
import tools.amply.sdk.core.GateDecision as KmpGateDecision
|
|
34
37
|
import tools.amply.sdk.core.ProceedReason as KmpProceedReason
|
|
35
38
|
import tools.amply.sdk.config.AmplyConfig
|
|
@@ -291,6 +294,26 @@ class DefaultAmplyClient(
|
|
|
291
294
|
}
|
|
292
295
|
}
|
|
293
296
|
|
|
297
|
+
override suspend fun getLastCampaignTouch(withinMs: Long): CampaignTouchPayload? {
|
|
298
|
+
// Not requireInstance(): "not initialised" is an answer here (null), as it is in the SDK.
|
|
299
|
+
val instance = amplyInstance ?: return null
|
|
300
|
+
return withContext(Dispatchers.IO) {
|
|
301
|
+
instance.getLastCampaignTouch(withinMs)?.toPayload()
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
private fun CampaignTouch.toPayload(): CampaignTouchPayload = CampaignTouchPayload(
|
|
306
|
+
campaignId = campaignId,
|
|
307
|
+
campaignName = campaignName,
|
|
308
|
+
// Exhaustive on purpose: a kind added to the SDK must fail this build, not reach JS as a
|
|
309
|
+
// value the TS type does not admit.
|
|
310
|
+
kind = when (kind) {
|
|
311
|
+
CampaignTouchKind.SHOWN -> "shown"
|
|
312
|
+
CampaignTouchKind.ENGAGED -> "engaged"
|
|
313
|
+
},
|
|
314
|
+
atMs = atMs,
|
|
315
|
+
)
|
|
316
|
+
|
|
294
317
|
override suspend fun getDataSetSnapshot(type: DataSetType): Map<String, Any?> {
|
|
295
318
|
val instance = requireInstance()
|
|
296
319
|
val nativeType = type.toNativeDataSetType()
|
|
@@ -400,6 +423,12 @@ class DefaultAmplyClient(
|
|
|
400
423
|
}
|
|
401
424
|
}
|
|
402
425
|
|
|
426
|
+
override fun handleUrl(url: String): Boolean {
|
|
427
|
+
// Not buffered: a link is only meaningful to a live SDK, and the answer is needed right now.
|
|
428
|
+
val instance = amplyInstance ?: return false
|
|
429
|
+
return instance.handleUrl(url)
|
|
430
|
+
}
|
|
431
|
+
|
|
403
432
|
override fun setCustomProperty(key: String, value: Any) {
|
|
404
433
|
synchronized(propertyLock) {
|
|
405
434
|
val instance = amplyInstance
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
package tools.amply.sdk.reactnative.model
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* The bridge's copy of the SDK's `CampaignTouch`, with [kind] already in its JS spelling
|
|
5
|
+
* (`"shown"` / `"engaged"`).
|
|
6
|
+
*/
|
|
7
|
+
data class CampaignTouchPayload(
|
|
8
|
+
val campaignId: String,
|
|
9
|
+
val campaignName: String,
|
|
10
|
+
val kind: String,
|
|
11
|
+
val atMs: Long,
|
|
12
|
+
)
|
|
@@ -78,6 +78,10 @@ public abstract class NativeAmplyModuleSpec extends ReactContextBaseJavaModule i
|
|
|
78
78
|
@DoNotStrip
|
|
79
79
|
public abstract void getRecentEvents(double limit, Promise promise);
|
|
80
80
|
|
|
81
|
+
@ReactMethod
|
|
82
|
+
@DoNotStrip
|
|
83
|
+
public abstract void getLastCampaignTouch(double withinMs, Promise promise);
|
|
84
|
+
|
|
81
85
|
@ReactMethod
|
|
82
86
|
@DoNotStrip
|
|
83
87
|
public abstract void getDataSetSnapshot(ReadableMap type, Promise promise);
|
|
@@ -94,6 +98,10 @@ public abstract class NativeAmplyModuleSpec extends ReactContextBaseJavaModule i
|
|
|
94
98
|
@DoNotStrip
|
|
95
99
|
public abstract void setAppLanguage(@Nullable String tag);
|
|
96
100
|
|
|
101
|
+
@ReactMethod(isBlockingSynchronousMethod = true)
|
|
102
|
+
@DoNotStrip
|
|
103
|
+
public abstract boolean handleUrl(String url);
|
|
104
|
+
|
|
97
105
|
@ReactMethod
|
|
98
106
|
@DoNotStrip
|
|
99
107
|
public abstract void setLogLevel(String level);
|
|
@@ -52,6 +52,11 @@ static facebook::jsi::Value __hostFunction_NativeAmplyModuleSpecJSI_getRecentEve
|
|
|
52
52
|
return static_cast<JavaTurboModule &>(turboModule).invokeJavaMethod(rt, PromiseKind, "getRecentEvents", "(DLcom/facebook/react/bridge/Promise;)V", args, count, cachedMethodId);
|
|
53
53
|
}
|
|
54
54
|
|
|
55
|
+
static facebook::jsi::Value __hostFunction_NativeAmplyModuleSpecJSI_getLastCampaignTouch(facebook::jsi::Runtime& rt, TurboModule &turboModule, const facebook::jsi::Value* args, size_t count) {
|
|
56
|
+
static jmethodID cachedMethodId = nullptr;
|
|
57
|
+
return static_cast<JavaTurboModule &>(turboModule).invokeJavaMethod(rt, PromiseKind, "getLastCampaignTouch", "(DLcom/facebook/react/bridge/Promise;)V", args, count, cachedMethodId);
|
|
58
|
+
}
|
|
59
|
+
|
|
55
60
|
static facebook::jsi::Value __hostFunction_NativeAmplyModuleSpecJSI_getDataSetSnapshot(facebook::jsi::Runtime& rt, TurboModule &turboModule, const facebook::jsi::Value* args, size_t count) {
|
|
56
61
|
static jmethodID cachedMethodId = nullptr;
|
|
57
62
|
return static_cast<JavaTurboModule &>(turboModule).invokeJavaMethod(rt, PromiseKind, "getDataSetSnapshot", "(Lcom/facebook/react/bridge/ReadableMap;Lcom/facebook/react/bridge/Promise;)V", args, count, cachedMethodId);
|
|
@@ -72,6 +77,11 @@ static facebook::jsi::Value __hostFunction_NativeAmplyModuleSpecJSI_setAppLangua
|
|
|
72
77
|
return static_cast<JavaTurboModule &>(turboModule).invokeJavaMethod(rt, VoidKind, "setAppLanguage", "(Ljava/lang/String;)V", args, count, cachedMethodId);
|
|
73
78
|
}
|
|
74
79
|
|
|
80
|
+
static facebook::jsi::Value __hostFunction_NativeAmplyModuleSpecJSI_handleUrl(facebook::jsi::Runtime& rt, TurboModule &turboModule, const facebook::jsi::Value* args, size_t count) {
|
|
81
|
+
static jmethodID cachedMethodId = nullptr;
|
|
82
|
+
return static_cast<JavaTurboModule &>(turboModule).invokeJavaMethod(rt, BooleanKind, "handleUrl", "(Ljava/lang/String;)Z", args, count, cachedMethodId);
|
|
83
|
+
}
|
|
84
|
+
|
|
75
85
|
static facebook::jsi::Value __hostFunction_NativeAmplyModuleSpecJSI_setLogLevel(facebook::jsi::Runtime& rt, TurboModule &turboModule, const facebook::jsi::Value* args, size_t count) {
|
|
76
86
|
static jmethodID cachedMethodId = nullptr;
|
|
77
87
|
return static_cast<JavaTurboModule &>(turboModule).invokeJavaMethod(rt, VoidKind, "setLogLevel", "(Ljava/lang/String;)V", args, count, cachedMethodId);
|
|
@@ -122,10 +132,12 @@ NativeAmplyModuleSpecJSI::NativeAmplyModuleSpecJSI(const JavaTurboModule::InitPa
|
|
|
122
132
|
methodMap_["registerGate"] = MethodMetadata {3, __hostFunction_NativeAmplyModuleSpecJSI_registerGate};
|
|
123
133
|
methodMap_["unregisterGate"] = MethodMetadata {1, __hostFunction_NativeAmplyModuleSpecJSI_unregisterGate};
|
|
124
134
|
methodMap_["getRecentEvents"] = MethodMetadata {1, __hostFunction_NativeAmplyModuleSpecJSI_getRecentEvents};
|
|
135
|
+
methodMap_["getLastCampaignTouch"] = MethodMetadata {1, __hostFunction_NativeAmplyModuleSpecJSI_getLastCampaignTouch};
|
|
125
136
|
methodMap_["getDataSetSnapshot"] = MethodMetadata {1, __hostFunction_NativeAmplyModuleSpecJSI_getDataSetSnapshot};
|
|
126
137
|
methodMap_["registerDeepLinkListener"] = MethodMetadata {0, __hostFunction_NativeAmplyModuleSpecJSI_registerDeepLinkListener};
|
|
127
138
|
methodMap_["setUserId"] = MethodMetadata {1, __hostFunction_NativeAmplyModuleSpecJSI_setUserId};
|
|
128
139
|
methodMap_["setAppLanguage"] = MethodMetadata {1, __hostFunction_NativeAmplyModuleSpecJSI_setAppLanguage};
|
|
140
|
+
methodMap_["handleUrl"] = MethodMetadata {1, __hostFunction_NativeAmplyModuleSpecJSI_handleUrl};
|
|
129
141
|
methodMap_["setLogLevel"] = MethodMetadata {1, __hostFunction_NativeAmplyModuleSpecJSI_setLogLevel};
|
|
130
142
|
methodMap_["getLogLevel"] = MethodMetadata {0, __hostFunction_NativeAmplyModuleSpecJSI_getLogLevel};
|
|
131
143
|
methodMap_["setCustomProperties"] = MethodMetadata {1, __hostFunction_NativeAmplyModuleSpecJSI_setCustomProperties};
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.assertValidWithinMs = assertValidWithinMs;
|
|
4
|
+
exports.toCampaignTouch = toCampaignTouch;
|
|
5
|
+
/** Thrown (as a rejection) by `getLastCampaignTouch` for a window that is not a usable number. */
|
|
6
|
+
function assertValidWithinMs(withinMs) {
|
|
7
|
+
if (typeof withinMs !== 'number' || !Number.isFinite(withinMs) || withinMs < 0) {
|
|
8
|
+
throw new RangeError(`[Amply] getLastCampaignTouch: withinMs must be a finite number >= 0, got ${String(withinMs)}`);
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
function toKind(raw) {
|
|
12
|
+
if (typeof raw !== 'string') {
|
|
13
|
+
return null;
|
|
14
|
+
}
|
|
15
|
+
const lowered = raw.toLowerCase();
|
|
16
|
+
return lowered === 'shown' || lowered === 'engaged' ? lowered : null;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Narrows what the native bridge resolved to the public type. Anything it cannot read as a
|
|
20
|
+
* touch becomes null with a warning: the caller asked "was there a campaign", and a payload this
|
|
21
|
+
* bridge does not understand is not one it can vouch for.
|
|
22
|
+
*/
|
|
23
|
+
function toCampaignTouch(payload) {
|
|
24
|
+
if (payload == null) {
|
|
25
|
+
return null;
|
|
26
|
+
}
|
|
27
|
+
const kind = toKind(payload.kind);
|
|
28
|
+
const isReadable = kind !== null &&
|
|
29
|
+
typeof payload.campaignId === 'string' &&
|
|
30
|
+
payload.campaignId.length > 0 &&
|
|
31
|
+
typeof payload.atMs === 'number' &&
|
|
32
|
+
Number.isFinite(payload.atMs);
|
|
33
|
+
if (!isReadable) {
|
|
34
|
+
console.warn('[Amply] getLastCampaignTouch: ignoring an unreadable native payload', payload);
|
|
35
|
+
return null;
|
|
36
|
+
}
|
|
37
|
+
return {
|
|
38
|
+
campaignId: payload.campaignId,
|
|
39
|
+
campaignName: typeof payload.campaignName === 'string' ? payload.campaignName : '',
|
|
40
|
+
kind,
|
|
41
|
+
atMs: payload.atMs,
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
//# sourceMappingURL=campaignTouch.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"campaignTouch.js","sourceRoot":"","sources":["../../src/campaignTouch.ts"],"names":[],"mappings":";;AA+BA,kDAMC;AAeD,0CAqBC;AA3CD,kGAAkG;AAClG,SAAgB,mBAAmB,CAAC,QAAiB;IACnD,IAAI,OAAO,QAAQ,KAAK,QAAQ,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,QAAQ,CAAC,IAAI,QAAQ,GAAG,CAAC,EAAE,CAAC;QAC/E,MAAM,IAAI,UAAU,CAClB,4EAA4E,MAAM,CAAC,QAAQ,CAAC,EAAE,CAC/F,CAAC;IACJ,CAAC;AACH,CAAC;AAED,SAAS,MAAM,CAAC,GAAY;IAC1B,IAAI,OAAO,GAAG,KAAK,QAAQ,EAAE,CAAC;QAC5B,OAAO,IAAI,CAAC;IACd,CAAC;IACD,MAAM,OAAO,GAAG,GAAG,CAAC,WAAW,EAAE,CAAC;IAClC,OAAO,OAAO,KAAK,OAAO,IAAI,OAAO,KAAK,SAAS,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC;AACvE,CAAC;AAED;;;;GAIG;AACH,SAAgB,eAAe,CAAC,OAAgD;IAC9E,IAAI,OAAO,IAAI,IAAI,EAAE,CAAC;QACpB,OAAO,IAAI,CAAC;IACd,CAAC;IACD,MAAM,IAAI,GAAG,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;IAClC,MAAM,UAAU,GACd,IAAI,KAAK,IAAI;QACb,OAAO,OAAO,CAAC,UAAU,KAAK,QAAQ;QACtC,OAAO,CAAC,UAAU,CAAC,MAAM,GAAG,CAAC;QAC7B,OAAO,OAAO,CAAC,IAAI,KAAK,QAAQ;QAChC,MAAM,CAAC,QAAQ,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;IAChC,IAAI,CAAC,UAAU,EAAE,CAAC;QAChB,OAAO,CAAC,IAAI,CAAC,qEAAqE,EAAE,OAAO,CAAC,CAAC;QAC7F,OAAO,IAAI,CAAC;IACd,CAAC;IACD,OAAO;QACL,UAAU,EAAE,OAAO,CAAC,UAAU;QAC9B,YAAY,EAAE,OAAO,OAAO,CAAC,YAAY,KAAK,QAAQ,CAAC,CAAC,CAAC,OAAO,CAAC,YAAY,CAAC,CAAC,CAAC,EAAE;QAClF,IAAI;QACJ,IAAI,EAAE,OAAO,CAAC,IAAI;KACnB,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.useAmplySystemEvents = useAmplySystemEvents;
|
|
4
|
+
const react_1 = require("react");
|
|
5
|
+
const systemEvents_1 = require("../systemEvents");
|
|
6
|
+
function useAmplySystemEvents(options = {}) {
|
|
7
|
+
const { maxEntries = 50, dedupe = true, onEvent } = options;
|
|
8
|
+
const [events, setEvents] = (0, react_1.useState)([]);
|
|
9
|
+
const seenKeysRef = (0, react_1.useRef)(new Set());
|
|
10
|
+
const handlerRef = (0, react_1.useRef)(onEvent);
|
|
11
|
+
(0, react_1.useEffect)(() => {
|
|
12
|
+
handlerRef.current = onEvent;
|
|
13
|
+
}, [onEvent]);
|
|
14
|
+
(0, react_1.useEffect)(() => {
|
|
15
|
+
let unsubscribe;
|
|
16
|
+
let isMounted = true;
|
|
17
|
+
(0, systemEvents_1.addSystemEventListener)(event => {
|
|
18
|
+
var _a;
|
|
19
|
+
if (!isMounted) {
|
|
20
|
+
return;
|
|
21
|
+
}
|
|
22
|
+
if (dedupe) {
|
|
23
|
+
const key = `${event.name}-${event.timestamp}`;
|
|
24
|
+
if (seenKeysRef.current.has(key)) {
|
|
25
|
+
return;
|
|
26
|
+
}
|
|
27
|
+
seenKeysRef.current.add(key);
|
|
28
|
+
}
|
|
29
|
+
(_a = handlerRef.current) === null || _a === void 0 ? void 0 : _a.call(handlerRef, event);
|
|
30
|
+
setEvents(prev => {
|
|
31
|
+
const next = [...prev, event];
|
|
32
|
+
if (next.length > maxEntries) {
|
|
33
|
+
next.splice(0, next.length - maxEntries);
|
|
34
|
+
}
|
|
35
|
+
return next;
|
|
36
|
+
});
|
|
37
|
+
})
|
|
38
|
+
.then(unsub => {
|
|
39
|
+
if (!isMounted) {
|
|
40
|
+
unsub();
|
|
41
|
+
}
|
|
42
|
+
else {
|
|
43
|
+
unsubscribe = unsub;
|
|
44
|
+
}
|
|
45
|
+
})
|
|
46
|
+
.catch(error => {
|
|
47
|
+
console.warn('[Amply] system event listener error', error);
|
|
48
|
+
});
|
|
49
|
+
return () => {
|
|
50
|
+
isMounted = false;
|
|
51
|
+
unsubscribe === null || unsubscribe === void 0 ? void 0 : unsubscribe();
|
|
52
|
+
};
|
|
53
|
+
}, [dedupe, maxEntries]);
|
|
54
|
+
const reset = (0, react_1.useCallback)(() => {
|
|
55
|
+
seenKeysRef.current.clear();
|
|
56
|
+
setEvents([]);
|
|
57
|
+
}, []);
|
|
58
|
+
return { events, reset };
|
|
59
|
+
}
|
|
60
|
+
//# sourceMappingURL=useAmplySystemEvents.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useAmplySystemEvents.js","sourceRoot":"","sources":["../../../src/hooks/useAmplySystemEvents.ts"],"names":[],"mappings":";;AAeA,oDA2DC;AA1ED,iCAA+D;AAE/D,kDAAuD;AAavD,SAAgB,oBAAoB,CAClC,UAAuC,EAAE;IAEzC,MAAM,EAAC,UAAU,GAAG,EAAE,EAAE,MAAM,GAAG,IAAI,EAAE,OAAO,EAAC,GAAG,OAAO,CAAC;IAC1D,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,GAAG,IAAA,gBAAQ,EAAgB,EAAE,CAAC,CAAC;IACxD,MAAM,WAAW,GAAG,IAAA,cAAM,EAAc,IAAI,GAAG,EAAE,CAAC,CAAC;IACnD,MAAM,UAAU,GAAG,IAAA,cAAM,EAAiB,OAAO,CAAC,CAAC;IAEnD,IAAA,iBAAS,EAAC,GAAG,EAAE;QACb,UAAU,CAAC,OAAO,GAAG,OAAO,CAAC;IAC/B,CAAC,EAAE,CAAC,OAAO,CAAC,CAAC,CAAC;IAEd,IAAA,iBAAS,EAAC,GAAG,EAAE;QACb,IAAI,WAAqC,CAAC;QAC1C,IAAI,SAAS,GAAG,IAAI,CAAC;QAErB,IAAA,qCAAsB,EAAC,KAAK,CAAC,EAAE;;YAC7B,IAAI,CAAC,SAAS,EAAE,CAAC;gBACf,OAAO;YACT,CAAC;YACD,IAAI,MAAM,EAAE,CAAC;gBACX,MAAM,GAAG,GAAG,GAAG,KAAK,CAAC,IAAI,IAAI,KAAK,CAAC,SAAS,EAAE,CAAC;gBAC/C,IAAI,WAAW,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC;oBACjC,OAAO;gBACT,CAAC;gBACD,WAAW,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;YAC/B,CAAC;YACD,MAAA,UAAU,CAAC,OAAO,2DAAG,KAAK,CAAC,CAAC;YAC5B,SAAS,CAAC,IAAI,CAAC,EAAE;gBACf,MAAM,IAAI,GAAG,CAAC,GAAG,IAAI,EAAE,KAAK,CAAC,CAAC;gBAC9B,IAAI,IAAI,CAAC,MAAM,GAAG,UAAU,EAAE,CAAC;oBAC7B,IAAI,CAAC,MAAM,CAAC,CAAC,EAAE,IAAI,CAAC,MAAM,GAAG,UAAU,CAAC,CAAC;gBAC3C,CAAC;gBACD,OAAO,IAAI,CAAC;YACd,CAAC,CAAC,CAAC;QACL,CAAC,CAAC;aACC,IAAI,CAAC,KAAK,CAAC,EAAE;YACZ,IAAI,CAAC,SAAS,EAAE,CAAC;gBACf,KAAK,EAAE,CAAC;YACV,CAAC;iBAAM,CAAC;gBACN,WAAW,GAAG,KAAK,CAAC;YACtB,CAAC;QACH,CAAC,CAAC;aACD,KAAK,CAAC,KAAK,CAAC,EAAE;YACb,OAAO,CAAC,IAAI,CAAC,qCAAqC,EAAE,KAAK,CAAC,CAAC;QAC7D,CAAC,CAAC,CAAC;QAEL,OAAO,GAAG,EAAE;YACV,SAAS,GAAG,KAAK,CAAC;YAClB,WAAW,aAAX,WAAW,uBAAX,WAAW,EAAI,CAAC;QAClB,CAAC,CAAC;IACJ,CAAC,EAAE,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC,CAAC;IAEzB,MAAM,KAAK,GAAG,IAAA,mBAAW,EAAC,GAAG,EAAE;QAC7B,WAAW,CAAC,OAAO,CAAC,KAAK,EAAE,CAAC;QAC5B,SAAS,CAAC,EAAE,CAAC,CAAC;IAChB,CAAC,EAAE,EAAE,CAAC,CAAC;IAEP,OAAO,EAAC,MAAM,EAAE,KAAK,EAAC,CAAC;AACzB,CAAC"}
|