@posthog/react-native-plugin 2.2.4 → 2.3.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/android/build.gradle +1 -1
- package/android/src/main/java/com/posthogreactnativeplugin/PosthogReactNativePluginModule.kt +289 -0
- package/ios/PosthogReactNativePlugin-Bridging-Header.h +1 -0
- package/ios/PosthogReactNativePlugin.mm +28 -1
- package/ios/PosthogReactNativePlugin.swift +165 -1
- package/lib/commonjs/index.js +79 -1
- package/lib/commonjs/index.js.map +1 -1
- package/lib/module/index.js +74 -2
- package/lib/module/index.js.map +1 -1
- package/lib/typescript/commonjs/src/index.d.ts +47 -0
- package/lib/typescript/commonjs/src/index.d.ts.map +1 -1
- package/lib/typescript/module/src/index.d.ts +47 -0
- package/lib/typescript/module/src/index.d.ts.map +1 -1
- package/package.json +1 -2
- package/posthog-react-native-plugin.podspec +1 -1
- package/src/index.tsx +107 -1
package/android/build.gradle
CHANGED
|
@@ -85,6 +85,6 @@ dependencies {
|
|
|
85
85
|
//noinspection GradleDynamicVersion
|
|
86
86
|
implementation "com.facebook.react:react-native:+"
|
|
87
87
|
implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
|
|
88
|
-
implementation "com.posthog:posthog-android:3.
|
|
88
|
+
implementation "com.posthog:posthog-android:3.58.0"
|
|
89
89
|
}
|
|
90
90
|
|
package/android/src/main/java/com/posthogreactnativeplugin/PosthogReactNativePluginModule.kt
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
package com.posthogreactnativeplugin
|
|
2
2
|
|
|
3
|
+
import android.content.Intent
|
|
3
4
|
import android.util.Log
|
|
5
|
+
import com.facebook.react.bridge.Arguments
|
|
4
6
|
import com.facebook.react.bridge.Promise
|
|
5
7
|
import com.facebook.react.bridge.ReactApplicationContext
|
|
6
8
|
import com.facebook.react.bridge.ReactContextBaseJavaModule
|
|
@@ -8,6 +10,7 @@ import com.facebook.react.bridge.ReactMethod
|
|
|
8
10
|
import com.facebook.react.bridge.ReadableMap
|
|
9
11
|
import com.facebook.react.bridge.UiThreadUtil
|
|
10
12
|
import com.facebook.react.common.JavascriptException
|
|
13
|
+
import com.facebook.react.modules.core.DeviceEventManagerModule
|
|
11
14
|
import com.posthog.PostHog
|
|
12
15
|
import com.posthog.PostHogConfig
|
|
13
16
|
import com.posthog.android.PostHogAndroid
|
|
@@ -42,6 +45,7 @@ class PosthogReactNativePluginModule(
|
|
|
42
45
|
decideReplayConfig = getMap(sessionReplayConfig, "decideReplayConfig"),
|
|
43
46
|
nativeErrorTrackingAutocapture = getBoolean(errorTrackingConfig, "nativeAutocapture", false),
|
|
44
47
|
exceptionStepsConfig = getMap(errorTrackingConfig, "exceptionSteps"),
|
|
48
|
+
pushConfig = getMap(pluginConfig, "push"),
|
|
45
49
|
promise = promise,
|
|
46
50
|
)
|
|
47
51
|
}
|
|
@@ -63,6 +67,7 @@ class PosthogReactNativePluginModule(
|
|
|
63
67
|
decideReplayConfig = decideReplayConfig,
|
|
64
68
|
nativeErrorTrackingAutocapture = false,
|
|
65
69
|
exceptionStepsConfig = null,
|
|
70
|
+
pushConfig = null,
|
|
66
71
|
promise = promise,
|
|
67
72
|
)
|
|
68
73
|
}
|
|
@@ -76,6 +81,7 @@ class PosthogReactNativePluginModule(
|
|
|
76
81
|
decideReplayConfig: ReadableMap?,
|
|
77
82
|
nativeErrorTrackingAutocapture: Boolean,
|
|
78
83
|
exceptionStepsConfig: ReadableMap?,
|
|
84
|
+
pushConfig: ReadableMap?,
|
|
79
85
|
promise: Promise,
|
|
80
86
|
) {
|
|
81
87
|
val initRunnable =
|
|
@@ -92,6 +98,9 @@ class PosthogReactNativePluginModule(
|
|
|
92
98
|
val anonymousId = getString(sdkOptions, "anonymousId", "")
|
|
93
99
|
val theSdkVersion = getString(sdkOptions, "sdkVersion", "")
|
|
94
100
|
val theFlushAt = getInt(sdkOptions, "flushAt", DEFAULT_FLUSH_AT)
|
|
101
|
+
val theOptOut = getBoolean(sdkOptions, "optOut", false)
|
|
102
|
+
// Default true: an older JS layer that never sends this keeps native's own fetch.
|
|
103
|
+
val thePreloadFeatureFlags = getBoolean(sdkOptions, "preloadFeatureFlags", true)
|
|
95
104
|
|
|
96
105
|
// Forward custom headers (e.g. Authorization for a reverse proxy) so the native SDK
|
|
97
106
|
// attaches them to the requests it sends directly (session replay, crash uploads).
|
|
@@ -104,6 +113,8 @@ class PosthogReactNativePluginModule(
|
|
|
104
113
|
val config =
|
|
105
114
|
PostHogAndroidConfig(apiKey, host).apply {
|
|
106
115
|
debug = debugValue
|
|
116
|
+
optOut = theOptOut
|
|
117
|
+
preloadFeatureFlags = thePreloadFeatureFlags
|
|
107
118
|
captureDeepLinks = false
|
|
108
119
|
captureApplicationLifecycleEvents = false
|
|
109
120
|
captureScreenViews = false
|
|
@@ -153,6 +164,25 @@ class PosthogReactNativePluginModule(
|
|
|
153
164
|
snapshotEndpoint = endpoint
|
|
154
165
|
}
|
|
155
166
|
|
|
167
|
+
// Only set when present: the legacy start() path predates push, and there the
|
|
168
|
+
// native defaults (both true) must win, matching posthog-android on its own.
|
|
169
|
+
if (hasKey(pushConfig, "capturePushNotificationSubscriptions")) {
|
|
170
|
+
capturePushNotificationSubscriptions =
|
|
171
|
+
getBoolean(pushConfig, "capturePushNotificationSubscriptions", true)
|
|
172
|
+
}
|
|
173
|
+
if (hasKey(pushConfig, "capturePushNotificationOpened")) {
|
|
174
|
+
capturePushNotificationOpened = getBoolean(pushConfig, "capturePushNotificationOpened", true)
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
// Installed only when JS asked for it: an uninvited bridging provider would
|
|
178
|
+
// change how the native SDK handles a 401 on the subscription call.
|
|
179
|
+
if (getBoolean(pushConfig, "pushIdentityProviderEnabled", false)) {
|
|
180
|
+
pushModule = this@PosthogReactNativePluginModule
|
|
181
|
+
pushIdentityProvider = { distinctId, appId, completion ->
|
|
182
|
+
requestPushIdentityToken(distinctId, appId, completion)
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
|
|
156
186
|
if (theSdkVersion.isNotEmpty()) {
|
|
157
187
|
sdkName = "posthog-react-native"
|
|
158
188
|
sdkVersion = theSdkVersion
|
|
@@ -161,6 +191,8 @@ class PosthogReactNativePluginModule(
|
|
|
161
191
|
PostHogAndroid.setup(context, config)
|
|
162
192
|
|
|
163
193
|
setIdentify(config.cachePreferences, distinctId, anonymousId)
|
|
194
|
+
|
|
195
|
+
captureColdStartPushOpenIfNeeded(config)
|
|
164
196
|
} catch (e: Throwable) {
|
|
165
197
|
logError(method, e)
|
|
166
198
|
} finally {
|
|
@@ -228,6 +260,50 @@ class PosthogReactNativePluginModule(
|
|
|
228
260
|
}
|
|
229
261
|
}
|
|
230
262
|
|
|
263
|
+
// Calls the native SDK rather than writing preferences like identify() does: reset() is what
|
|
264
|
+
// unregisters the logged-out user's push subscription and re-registers under the new identity.
|
|
265
|
+
@ReactMethod
|
|
266
|
+
fun reset(
|
|
267
|
+
distinctId: String,
|
|
268
|
+
anonymousId: String,
|
|
269
|
+
promise: Promise,
|
|
270
|
+
) {
|
|
271
|
+
try {
|
|
272
|
+
PostHog.reset()
|
|
273
|
+
// Native reset() mints its own anonymous id; overwrite it with the JS one so the two
|
|
274
|
+
// SDKs stay on the same identity. Must run after reset(), which needs the pre-reset
|
|
275
|
+
// distinctId to know which subscription to unregister. Known gap (as on iOS): native's
|
|
276
|
+
// async push re-registration can read the identity before this write lands and register
|
|
277
|
+
// under a throwaway id; retryPending() converges it on the next flush.
|
|
278
|
+
setIdentify(PostHog.getConfig<PostHogConfig>()?.cachePreferences, distinctId, anonymousId)
|
|
279
|
+
} catch (e: Throwable) {
|
|
280
|
+
logError("reset", e)
|
|
281
|
+
} finally {
|
|
282
|
+
promise.resolve(null)
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
// Runtime consent changes must reach native: it persists its own opt-out flag and only reads
|
|
287
|
+
// the JS value at setup(), so a refreshed FCM token could otherwise auto-register after the
|
|
288
|
+
// user opted out. optIn() also resumes deferred push work on the next flush.
|
|
289
|
+
@ReactMethod
|
|
290
|
+
fun setOptOut(
|
|
291
|
+
optOut: Boolean,
|
|
292
|
+
promise: Promise,
|
|
293
|
+
) {
|
|
294
|
+
try {
|
|
295
|
+
if (optOut) {
|
|
296
|
+
PostHog.optOut()
|
|
297
|
+
} else {
|
|
298
|
+
PostHog.optIn()
|
|
299
|
+
}
|
|
300
|
+
} catch (e: Throwable) {
|
|
301
|
+
logError("setOptOut", e)
|
|
302
|
+
} finally {
|
|
303
|
+
promise.resolve(null)
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
|
|
231
307
|
private fun setIdentify(
|
|
232
308
|
cachePreferences: PostHogPreferences?,
|
|
233
309
|
distinctId: String,
|
|
@@ -333,15 +409,228 @@ class PosthogReactNativePluginModule(
|
|
|
333
409
|
Log.println(Log.ERROR, POSTHOG_TAG, "Method $method, error: $error")
|
|
334
410
|
}
|
|
335
411
|
|
|
412
|
+
// These reject instead of this module's usual swallow-and-resolve convention: a failed
|
|
413
|
+
// registration is a distinct signal, not a silent success. The JS layer's public methods
|
|
414
|
+
// never throw, so the rejection is what gives it something to log.
|
|
415
|
+
@ReactMethod
|
|
416
|
+
fun registerPushNotificationToken(
|
|
417
|
+
deviceToken: String?,
|
|
418
|
+
appId: String?,
|
|
419
|
+
promise: Promise,
|
|
420
|
+
) {
|
|
421
|
+
try {
|
|
422
|
+
if (deviceToken.isNullOrBlank()) {
|
|
423
|
+
// A blank token is dropped silently by the native SDK, so surface it here
|
|
424
|
+
// instead of reporting false success.
|
|
425
|
+
promise.reject(
|
|
426
|
+
PUSH_ERROR_CODE,
|
|
427
|
+
"registerPushNotificationToken: deviceToken is blank; token not registered.",
|
|
428
|
+
)
|
|
429
|
+
return
|
|
430
|
+
}
|
|
431
|
+
val resolvedAppId = appId?.trim()?.takeIf { it.isNotEmpty() } ?: firebaseProjectId
|
|
432
|
+
if (resolvedAppId.isNullOrEmpty()) {
|
|
433
|
+
val message =
|
|
434
|
+
"registerPushNotificationToken: no appId provided and no Firebase project id " +
|
|
435
|
+
"could be resolved, skipping. Pass appId explicitly if this app does not use Firebase."
|
|
436
|
+
Log.w(POSTHOG_TAG, message)
|
|
437
|
+
promise.reject(PUSH_ERROR_CODE, message)
|
|
438
|
+
return
|
|
439
|
+
}
|
|
440
|
+
PostHog.registerPushNotificationToken(deviceToken, resolvedAppId)
|
|
441
|
+
promise.resolve(null)
|
|
442
|
+
} catch (e: Throwable) {
|
|
443
|
+
logError("registerPushNotificationToken", e)
|
|
444
|
+
promise.reject(PUSH_ERROR_CODE, e)
|
|
445
|
+
}
|
|
446
|
+
}
|
|
447
|
+
|
|
448
|
+
@ReactMethod
|
|
449
|
+
fun unregisterPushNotificationToken(promise: Promise) {
|
|
450
|
+
try {
|
|
451
|
+
PostHog.unregisterPushNotificationToken()
|
|
452
|
+
promise.resolve(null)
|
|
453
|
+
} catch (e: Throwable) {
|
|
454
|
+
logError("unregisterPushNotificationToken", e)
|
|
455
|
+
promise.reject(PUSH_ERROR_CODE, e)
|
|
456
|
+
}
|
|
457
|
+
}
|
|
458
|
+
|
|
459
|
+
@ReactMethod
|
|
460
|
+
fun capturePushNotificationOpened(
|
|
461
|
+
properties: ReadableMap,
|
|
462
|
+
promise: Promise,
|
|
463
|
+
) {
|
|
464
|
+
try {
|
|
465
|
+
// subtitle is iOS-only; posthog-android's capturePushNotificationOpened has no
|
|
466
|
+
// subtitle parameter, so JS's value is dropped here.
|
|
467
|
+
val title = if (hasKey(properties, "title")) properties.getString("title") else null
|
|
468
|
+
val body = if (hasKey(properties, "body")) properties.getString("body") else null
|
|
469
|
+
val payload = if (hasKey(properties, "payload")) properties.getMap("payload")?.toHashMap() else null
|
|
470
|
+
val action = if (hasKey(properties, "action")) properties.getString("action") else null
|
|
471
|
+
PostHog.capturePushNotificationOpened(title, body, payload, action)
|
|
472
|
+
promise.resolve(null)
|
|
473
|
+
} catch (e: Throwable) {
|
|
474
|
+
logError("capturePushNotificationOpened", e)
|
|
475
|
+
promise.reject(PUSH_ERROR_CODE, e)
|
|
476
|
+
}
|
|
477
|
+
}
|
|
478
|
+
|
|
479
|
+
// posthog-android's open-capture integration registers ActivityLifecycleCallbacks during
|
|
480
|
+
// setup(), which the bridge reaches only after the launch Activity was created — so the
|
|
481
|
+
// cold-start tray tap it exists for is the one creation it can never observe here. Read
|
|
482
|
+
// the launch intent directly, then strip the marker so the integration (or a re-run)
|
|
483
|
+
// can't capture the same tap again from this intent object.
|
|
484
|
+
private fun captureColdStartPushOpenIfNeeded(config: PostHogAndroidConfig) {
|
|
485
|
+
if (!config.capturePushNotificationOpened) {
|
|
486
|
+
return
|
|
487
|
+
}
|
|
488
|
+
val intent = currentActivity?.intent ?: return
|
|
489
|
+
// A relaunch from recents redelivers the original tray intent to a fresh activity;
|
|
490
|
+
// capturing it would count a days-old tap as a new open.
|
|
491
|
+
if (intent.flags and Intent.FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY != 0) {
|
|
492
|
+
return
|
|
493
|
+
}
|
|
494
|
+
try {
|
|
495
|
+
intent.getStringExtra(GOOGLE_MESSAGE_ID) ?: return
|
|
496
|
+
// Unmarshalling extras throws BadParcelableException on a Parcelable class this
|
|
497
|
+
// classloader lacks; read before stripping the marker so a failed read leaves the
|
|
498
|
+
// intent as the native integration expects it.
|
|
499
|
+
val payload =
|
|
500
|
+
intent.extras?.let { bundle ->
|
|
501
|
+
bundle.keySet().associateWith { key ->
|
|
502
|
+
@Suppress("DEPRECATION")
|
|
503
|
+
bundle.get(key)
|
|
504
|
+
}
|
|
505
|
+
}
|
|
506
|
+
intent.removeExtra(GOOGLE_MESSAGE_ID)
|
|
507
|
+
PostHog.capturePushNotificationOpened(null, null, payload, null)
|
|
508
|
+
} catch (e: Throwable) {
|
|
509
|
+
logError("capturePushNotificationOpened", e)
|
|
510
|
+
}
|
|
511
|
+
}
|
|
512
|
+
|
|
513
|
+
@ReactMethod
|
|
514
|
+
fun providePushIdentityToken(
|
|
515
|
+
requestId: String?,
|
|
516
|
+
token: String?,
|
|
517
|
+
promise: Promise,
|
|
518
|
+
) {
|
|
519
|
+
try {
|
|
520
|
+
if (requestId != null) {
|
|
521
|
+
pushIdentityCompletions.remove(requestId)?.invoke(token)
|
|
522
|
+
}
|
|
523
|
+
} catch (e: Throwable) {
|
|
524
|
+
logError("providePushIdentityToken", e)
|
|
525
|
+
} finally {
|
|
526
|
+
promise.resolve(null)
|
|
527
|
+
}
|
|
528
|
+
}
|
|
529
|
+
|
|
530
|
+
// Required by NativeEventEmitter on the old architecture; events are broadcast via
|
|
531
|
+
// RCTDeviceEventEmitter, so there is nothing to do here.
|
|
532
|
+
@ReactMethod
|
|
533
|
+
fun addListener(eventName: String?) = Unit
|
|
534
|
+
|
|
535
|
+
@ReactMethod
|
|
536
|
+
fun removeListeners(count: Int) = Unit
|
|
537
|
+
|
|
538
|
+
override fun invalidate() {
|
|
539
|
+
if (pushModule === this) {
|
|
540
|
+
// Decline mints fast after teardown instead of stalling the native 10s watchdog.
|
|
541
|
+
pushModule = null
|
|
542
|
+
}
|
|
543
|
+
super.invalidate()
|
|
544
|
+
}
|
|
545
|
+
|
|
336
546
|
companion object {
|
|
337
547
|
const val NAME = "PosthogReactNativePlugin"
|
|
338
548
|
const val POSTHOG_TAG = "PostHog"
|
|
339
549
|
|
|
550
|
+
// FCM stamps this extra on the tray-tap launch intent; mirrors posthog-android's
|
|
551
|
+
// PostHogActivityLifecycleCallbackIntegration.
|
|
552
|
+
private const val GOOGLE_MESSAGE_ID = "google.message_id"
|
|
553
|
+
|
|
340
554
|
// Default session replay configuration values
|
|
341
555
|
const val DEFAULT_MASK_ALL_TEXT_INPUTS = true
|
|
342
556
|
const val DEFAULT_MASK_ALL_IMAGES = true
|
|
343
557
|
const val DEFAULT_CAPTURE_LOG = true
|
|
344
558
|
const val DEFAULT_FLUSH_AT = 20
|
|
345
559
|
const val DEFAULT_THROTTLE_DELAY_MS = 1000
|
|
560
|
+
|
|
561
|
+
private const val PUSH_ERROR_CODE = "PosthogReactNativePluginError"
|
|
562
|
+
private const val PUSH_IDENTITY_EVENT = "PostHogPushIdentityRequest"
|
|
563
|
+
private const val PUSH_IDENTITY_REPLY_TTL_MS = 15_000L
|
|
564
|
+
|
|
565
|
+
// Modules die on every bridge reload, so the provider closure resolves the live
|
|
566
|
+
// module through this static reference at call time, not a captured setup-time one.
|
|
567
|
+
@Volatile
|
|
568
|
+
private var pushModule: PosthogReactNativePluginModule? = null
|
|
569
|
+
|
|
570
|
+
private val pushIdentityCompletions = java.util.concurrent.ConcurrentHashMap<String, (String?) -> Unit>()
|
|
571
|
+
|
|
572
|
+
private fun requestPushIdentityToken(
|
|
573
|
+
distinctId: String,
|
|
574
|
+
appId: String,
|
|
575
|
+
completion: (String?) -> Unit,
|
|
576
|
+
) {
|
|
577
|
+
val module = pushModule
|
|
578
|
+
val context = module?.reactApplicationContext
|
|
579
|
+
if (module == null || context == null || !context.hasActiveReactInstance()) {
|
|
580
|
+
declinePushIdentity(completion, "no React instance attached")
|
|
581
|
+
return
|
|
582
|
+
}
|
|
583
|
+
val requestId = UUID.randomUUID().toString()
|
|
584
|
+
pushIdentityCompletions[requestId] = completion
|
|
585
|
+
try {
|
|
586
|
+
val params =
|
|
587
|
+
Arguments.createMap().apply {
|
|
588
|
+
putString("requestId", requestId)
|
|
589
|
+
putString("distinctId", distinctId)
|
|
590
|
+
putString("appId", appId)
|
|
591
|
+
}
|
|
592
|
+
context
|
|
593
|
+
.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter::class.java)
|
|
594
|
+
.emit(PUSH_IDENTITY_EVENT, params)
|
|
595
|
+
} catch (e: Throwable) {
|
|
596
|
+
pushIdentityCompletions.remove(requestId)
|
|
597
|
+
declinePushIdentity(completion, "failed to reach JS: ${e.message}")
|
|
598
|
+
return
|
|
599
|
+
}
|
|
600
|
+
// The native SDK's own 10s mint watchdog handles the fallback; this only drops the
|
|
601
|
+
// entry so a late JS reply is ignored and the completion doesn't leak.
|
|
602
|
+
UiThreadUtil.runOnUiThread({ pushIdentityCompletions.remove(requestId) }, PUSH_IDENTITY_REPLY_TTL_MS)
|
|
603
|
+
}
|
|
604
|
+
|
|
605
|
+
// A null identity token sends the request unauthenticated, which a project requiring
|
|
606
|
+
// identity verification rejects server-side. Log the reason so that failure is
|
|
607
|
+
// greppable and distinct from a host that deliberately returned null.
|
|
608
|
+
private fun declinePushIdentity(
|
|
609
|
+
completion: (String?) -> Unit,
|
|
610
|
+
reason: String,
|
|
611
|
+
) {
|
|
612
|
+
Log.w(POSTHOG_TAG, "Push subscription will be sent unauthenticated: $reason")
|
|
613
|
+
completion(null)
|
|
614
|
+
}
|
|
615
|
+
|
|
616
|
+
@Volatile private var cachedFirebaseProjectId: String? = null
|
|
617
|
+
|
|
618
|
+
// No Firebase dependency here, so the project id is looked up reflectively and any
|
|
619
|
+
// failure (class missing, Firebase not initialized) is swallowed. Only a successful lookup
|
|
620
|
+
// is cached: getInstance() throws until Firebase initializes, so memoizing the null would
|
|
621
|
+
// strand every later token-refresh call with no resolvable appId for the process lifetime.
|
|
622
|
+
private val firebaseProjectId: String?
|
|
623
|
+
get() =
|
|
624
|
+
cachedFirebaseProjectId
|
|
625
|
+
?: try {
|
|
626
|
+
val firebaseAppClass = Class.forName("com.google.firebase.FirebaseApp")
|
|
627
|
+
val firebaseApp = firebaseAppClass.getMethod("getInstance").invoke(null)
|
|
628
|
+
val options = firebaseAppClass.getMethod("getOptions").invoke(firebaseApp)
|
|
629
|
+
(options?.javaClass?.getMethod("getProjectId")?.invoke(options) as? String)?.also {
|
|
630
|
+
cachedFirebaseProjectId = it
|
|
631
|
+
}
|
|
632
|
+
} catch (e: Throwable) {
|
|
633
|
+
null
|
|
634
|
+
}
|
|
346
635
|
}
|
|
347
636
|
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
#import <React/RCTBridgeModule.h>
|
|
2
|
+
#import <React/RCTEventEmitter.h>
|
|
2
3
|
|
|
3
|
-
@interface RCT_EXTERN_MODULE(PosthogReactNativePlugin,
|
|
4
|
+
@interface RCT_EXTERN_MODULE(PosthogReactNativePlugin, RCTEventEmitter)
|
|
4
5
|
|
|
5
6
|
RCT_EXTERN_METHOD(setup:(NSString)sessionId
|
|
6
7
|
withSdkOptions:(NSDictionary)sdkOptions
|
|
@@ -42,6 +43,32 @@ RCT_EXTERN_METHOD(addExceptionStep:(NSString)message
|
|
|
42
43
|
withResolver:(RCTPromiseResolveBlock)resolve
|
|
43
44
|
withRejecter:(RCTPromiseRejectBlock)reject)
|
|
44
45
|
|
|
46
|
+
RCT_EXTERN_METHOD(reset:(NSString)distinctId
|
|
47
|
+
withAnonymousId:(NSString)anonymousId
|
|
48
|
+
withResolver:(RCTPromiseResolveBlock)resolve
|
|
49
|
+
withRejecter:(RCTPromiseRejectBlock)reject)
|
|
50
|
+
|
|
51
|
+
RCT_EXTERN_METHOD(registerPushNotificationToken:(NSString)deviceToken
|
|
52
|
+
withAppId:(NSString)appId
|
|
53
|
+
withResolver:(RCTPromiseResolveBlock)resolve
|
|
54
|
+
withRejecter:(RCTPromiseRejectBlock)reject)
|
|
55
|
+
|
|
56
|
+
RCT_EXTERN_METHOD(unregisterPushNotificationToken:(RCTPromiseResolveBlock)resolve
|
|
57
|
+
withRejecter:(RCTPromiseRejectBlock)reject)
|
|
58
|
+
|
|
59
|
+
RCT_EXTERN_METHOD(setOptOut:(BOOL)optOut
|
|
60
|
+
withResolver:(RCTPromiseResolveBlock)resolve
|
|
61
|
+
withRejecter:(RCTPromiseRejectBlock)reject)
|
|
62
|
+
|
|
63
|
+
RCT_EXTERN_METHOD(capturePushNotificationOpened:(NSDictionary)properties
|
|
64
|
+
withResolver:(RCTPromiseResolveBlock)resolve
|
|
65
|
+
withRejecter:(RCTPromiseRejectBlock)reject)
|
|
66
|
+
|
|
67
|
+
RCT_EXTERN_METHOD(providePushIdentityToken:(NSString)requestId
|
|
68
|
+
withToken:(NSString)token
|
|
69
|
+
withResolver:(RCTPromiseResolveBlock)resolve
|
|
70
|
+
withRejecter:(RCTPromiseRejectBlock)reject)
|
|
71
|
+
|
|
45
72
|
+ (BOOL)requiresMainQueueSetup
|
|
46
73
|
{
|
|
47
74
|
return NO;
|
|
@@ -46,10 +46,40 @@ private func isReactNativeFatalJsError(_ event: PostHogEvent) -> Bool {
|
|
|
46
46
|
}
|
|
47
47
|
}
|
|
48
48
|
|
|
49
|
+
// A nil identity token sends the request unauthenticated, which a project requiring
|
|
50
|
+
// identity verification rejects server-side. Log the reason so that failure is greppable
|
|
51
|
+
// and distinct from a host that deliberately returned nil.
|
|
52
|
+
private func declinePushIdentity(_ completion: (String?) -> Void, _ reason: String) {
|
|
53
|
+
hedgeLog("Push subscription will be sent unauthenticated: \(reason)")
|
|
54
|
+
completion(nil)
|
|
55
|
+
}
|
|
56
|
+
|
|
49
57
|
@objc(PosthogReactNativePlugin)
|
|
50
|
-
class PosthogReactNativePlugin:
|
|
58
|
+
class PosthogReactNativePlugin: RCTEventEmitter {
|
|
51
59
|
private var config: PostHogConfig?
|
|
52
60
|
|
|
61
|
+
private static let pushIdentityEvent = "PostHogPushIdentityRequest"
|
|
62
|
+
|
|
63
|
+
// This module dies on every bridge reload, so the provider closure resolves the live
|
|
64
|
+
// module through this static weak reference at call time, not a captured setup-time one.
|
|
65
|
+
private static weak var pushInstance: PosthogReactNativePlugin?
|
|
66
|
+
|
|
67
|
+
// Main-thread confined, like the rest of the identity-request bookkeeping below.
|
|
68
|
+
private var hasPushListeners = false
|
|
69
|
+
private var pushIdentityCompletions: [String: (String?) -> Void] = [:]
|
|
70
|
+
|
|
71
|
+
override func supportedEvents() -> [String]! {
|
|
72
|
+
[PosthogReactNativePlugin.pushIdentityEvent]
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
override func startObserving() {
|
|
76
|
+
DispatchQueue.main.async { self.hasPushListeners = true }
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
override func stopObserving() {
|
|
80
|
+
DispatchQueue.main.async { self.hasPushListeners = false }
|
|
81
|
+
}
|
|
82
|
+
|
|
53
83
|
@objc(setup:withSdkOptions:withPluginConfig:withResolver:withRejecter:)
|
|
54
84
|
func setup(
|
|
55
85
|
sessionId: String, sdkOptions: [String: Any], pluginConfig: [String: Any],
|
|
@@ -68,6 +98,7 @@ class PosthogReactNativePlugin: NSObject {
|
|
|
68
98
|
decideReplayConfig: sessionReplayConfig["decideReplayConfig"] as? [String: Any] ?? [:],
|
|
69
99
|
nativeErrorTrackingAutocapture: errorTrackingConfig["nativeAutocapture"] as? Bool ?? false,
|
|
70
100
|
exceptionStepsConfig: exceptionStepsConfig,
|
|
101
|
+
pushConfig: pluginConfig["push"] as? [String: Any] ?? [:],
|
|
71
102
|
resolve: resolve
|
|
72
103
|
)
|
|
73
104
|
}
|
|
@@ -87,6 +118,7 @@ class PosthogReactNativePlugin: NSObject {
|
|
|
87
118
|
decideReplayConfig: decideReplayConfig,
|
|
88
119
|
nativeErrorTrackingAutocapture: false,
|
|
89
120
|
exceptionStepsConfig: [:],
|
|
121
|
+
pushConfig: [:],
|
|
90
122
|
resolve: resolve
|
|
91
123
|
)
|
|
92
124
|
}
|
|
@@ -100,6 +132,7 @@ class PosthogReactNativePlugin: NSObject {
|
|
|
100
132
|
decideReplayConfig: [String: Any],
|
|
101
133
|
nativeErrorTrackingAutocapture: Bool,
|
|
102
134
|
exceptionStepsConfig: [String: Any],
|
|
135
|
+
pushConfig: [String: Any],
|
|
103
136
|
resolve: RCTPromiseResolveBlock
|
|
104
137
|
) {
|
|
105
138
|
if sessionId.isEmpty {
|
|
@@ -193,6 +226,11 @@ class PosthogReactNativePlugin: NSObject {
|
|
|
193
226
|
let flushAt = sdkOptions["flushAt"] as? Int ?? 20
|
|
194
227
|
config.flushAt = flushAt
|
|
195
228
|
|
|
229
|
+
config.optOut = sdkOptions["optOut"] as? Bool ?? false
|
|
230
|
+
// JS owns flags; it tells us when the native preload would be a duplicate. posthog-ios
|
|
231
|
+
// has no remoteConfig switch to mirror — it deprecated the option and always loads.
|
|
232
|
+
config.preloadFeatureFlags = sdkOptions["preloadFeatureFlags"] as? Bool ?? true
|
|
233
|
+
|
|
196
234
|
// Forward custom headers (e.g. Authorization for a reverse proxy) so the native SDK
|
|
197
235
|
// attaches them to the requests it sends directly (session replay, crash uploads).
|
|
198
236
|
// Keep only string values so a stray non-string doesn't drop every header (matches Android).
|
|
@@ -205,6 +243,40 @@ class PosthogReactNativePlugin: NSObject {
|
|
|
205
243
|
postHogVersion = sdkVersion
|
|
206
244
|
}
|
|
207
245
|
|
|
246
|
+
// Only set when present: the legacy start() path predates push, and there the
|
|
247
|
+
// native defaults (both true) must win, matching posthog-ios on its own.
|
|
248
|
+
if let capturePushSubscriptions = pushConfig["capturePushNotificationSubscriptions"] as? Bool {
|
|
249
|
+
config.capturePushNotificationSubscriptions = capturePushSubscriptions
|
|
250
|
+
}
|
|
251
|
+
if let capturePushOpened = pushConfig["capturePushNotificationOpened"] as? Bool {
|
|
252
|
+
config.capturePushNotificationOpened = capturePushOpened
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
// Installed only when JS asked for it: an uninvited bridging provider would change
|
|
256
|
+
// how the native SDK handles a 401 on the subscription call.
|
|
257
|
+
if pushConfig["pushIdentityProviderEnabled"] as? Bool == true {
|
|
258
|
+
PosthogReactNativePlugin.pushInstance = self
|
|
259
|
+
config.pushIdentityProvider = { distinctId, appId, completion in
|
|
260
|
+
DispatchQueue.main.async {
|
|
261
|
+
guard let instance = PosthogReactNativePlugin.pushInstance, instance.hasPushListeners else {
|
|
262
|
+
declinePushIdentity(completion, "no JS listener attached")
|
|
263
|
+
return
|
|
264
|
+
}
|
|
265
|
+
let requestId = UUID().uuidString
|
|
266
|
+
instance.pushIdentityCompletions[requestId] = completion
|
|
267
|
+
instance.sendEvent(
|
|
268
|
+
withName: PosthogReactNativePlugin.pushIdentityEvent,
|
|
269
|
+
body: ["requestId": requestId, "distinctId": distinctId, "appId": appId]
|
|
270
|
+
)
|
|
271
|
+
// The native SDK's own 10s mint watchdog handles the fallback; this only
|
|
272
|
+
// drops the entry so a late JS reply is ignored and the closure doesn't leak.
|
|
273
|
+
DispatchQueue.main.asyncAfter(deadline: .now() + 15) { [weak instance] in
|
|
274
|
+
instance?.pushIdentityCompletions.removeValue(forKey: requestId)
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
|
|
208
280
|
PostHogSDK.shared.setup(config)
|
|
209
281
|
|
|
210
282
|
self.config = config
|
|
@@ -265,6 +337,23 @@ class PosthogReactNativePlugin: NSObject {
|
|
|
265
337
|
resolve(nil)
|
|
266
338
|
}
|
|
267
339
|
|
|
340
|
+
// Calls the native SDK rather than writing storage like identify() does: reset() is what
|
|
341
|
+
// unregisters the logged-out user's push subscription and re-registers under the new identity.
|
|
342
|
+
@objc(reset:withAnonymousId:withResolver:withRejecter:)
|
|
343
|
+
func reset(
|
|
344
|
+
distinctId: String, anonymousId: String, resolve: RCTPromiseResolveBlock,
|
|
345
|
+
reject _: RCTPromiseRejectBlock
|
|
346
|
+
) {
|
|
347
|
+
PostHogSDK.shared.reset()
|
|
348
|
+
// Native reset() mints its own anonymous id; overwrite it with the JS one so the two SDKs
|
|
349
|
+
// stay on the same identity. Must run after reset(), which needs the pre-reset distinctId
|
|
350
|
+
// to know which subscription to unregister.
|
|
351
|
+
if let storageManager = config?.storageManager {
|
|
352
|
+
setIdentify(storageManager, distinctId: distinctId, anonymousId: anonymousId)
|
|
353
|
+
}
|
|
354
|
+
resolve(nil)
|
|
355
|
+
}
|
|
356
|
+
|
|
268
357
|
private func setIdentify(
|
|
269
358
|
_ storageManager: PostHogStorageManager, distinctId: String, anonymousId: String
|
|
270
359
|
) {
|
|
@@ -276,6 +365,21 @@ class PosthogReactNativePlugin: NSObject {
|
|
|
276
365
|
}
|
|
277
366
|
}
|
|
278
367
|
|
|
368
|
+
// Runtime consent changes must reach native: it persists its own opt-out flag and only
|
|
369
|
+
// reads the JS value at setup(), so a refreshed APNs token could otherwise auto-register
|
|
370
|
+
// after the user opted out. optIn() also reinstalls the integrations opt-out removed.
|
|
371
|
+
@objc(setOptOut:withResolver:withRejecter:)
|
|
372
|
+
func setOptOut(
|
|
373
|
+
optOut: Bool, resolve: RCTPromiseResolveBlock, reject _: RCTPromiseRejectBlock
|
|
374
|
+
) {
|
|
375
|
+
if optOut {
|
|
376
|
+
PostHogSDK.shared.optOut()
|
|
377
|
+
} else {
|
|
378
|
+
PostHogSDK.shared.optIn()
|
|
379
|
+
}
|
|
380
|
+
resolve(nil)
|
|
381
|
+
}
|
|
382
|
+
|
|
279
383
|
@objc(startRecording:withResolver:withRejecter:)
|
|
280
384
|
func startRecording(
|
|
281
385
|
resumeCurrent: Bool, resolve: RCTPromiseResolveBlock, reject _: RCTPromiseRejectBlock
|
|
@@ -306,4 +410,64 @@ class PosthogReactNativePlugin: NSObject {
|
|
|
306
410
|
PostHogSDK.shared.addExceptionStep(message, properties: properties)
|
|
307
411
|
resolve(nil)
|
|
308
412
|
}
|
|
413
|
+
|
|
414
|
+
@objc(registerPushNotificationToken:withAppId:withResolver:withRejecter:)
|
|
415
|
+
func registerPushNotificationToken(
|
|
416
|
+
deviceToken: String, appId: String?, resolve: RCTPromiseResolveBlock,
|
|
417
|
+
reject: RCTPromiseRejectBlock
|
|
418
|
+
) {
|
|
419
|
+
#if os(iOS)
|
|
420
|
+
// A blank token is dropped silently by the native SDK, so surface it here
|
|
421
|
+
// instead of reporting false success.
|
|
422
|
+
if deviceToken.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty {
|
|
423
|
+
reject("PosthogReactNativePluginError", "registerPushNotificationToken: deviceToken is blank; token not registered.", nil)
|
|
424
|
+
return
|
|
425
|
+
}
|
|
426
|
+
PostHogSDK.shared.registerPushNotificationToken(deviceToken, appId: appId)
|
|
427
|
+
resolve(nil)
|
|
428
|
+
#else
|
|
429
|
+
// posthog-ios push registration is iOS-only (the backend rejects the macos platform).
|
|
430
|
+
_ = reject
|
|
431
|
+
hedgeLog("registerPushNotificationToken is not supported on macOS; token not registered.")
|
|
432
|
+
resolve(nil)
|
|
433
|
+
#endif
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
@objc(unregisterPushNotificationToken:withRejecter:)
|
|
437
|
+
func unregisterPushNotificationToken(resolve: RCTPromiseResolveBlock, reject _: RCTPromiseRejectBlock) {
|
|
438
|
+
#if os(iOS)
|
|
439
|
+
PostHogSDK.shared.unregisterPushNotificationToken()
|
|
440
|
+
#else
|
|
441
|
+
hedgeLog("unregisterPushNotificationToken is not supported on macOS; nothing to unregister.")
|
|
442
|
+
#endif
|
|
443
|
+
resolve(nil)
|
|
444
|
+
}
|
|
445
|
+
|
|
446
|
+
@objc(capturePushNotificationOpened:withResolver:withRejecter:)
|
|
447
|
+
func capturePushNotificationOpened(
|
|
448
|
+
properties: [String: Any], resolve: RCTPromiseResolveBlock, reject _: RCTPromiseRejectBlock
|
|
449
|
+
) {
|
|
450
|
+
PostHogSDK.shared.capturePushNotificationOpened(
|
|
451
|
+
title: properties["title"] as? String,
|
|
452
|
+
subtitle: properties["subtitle"] as? String,
|
|
453
|
+
body: properties["body"] as? String,
|
|
454
|
+
payload: properties["payload"] as? [String: Any],
|
|
455
|
+
action: properties["action"] as? String
|
|
456
|
+
)
|
|
457
|
+
resolve(nil)
|
|
458
|
+
}
|
|
459
|
+
|
|
460
|
+
@objc(providePushIdentityToken:withToken:withResolver:withRejecter:)
|
|
461
|
+
func providePushIdentityToken(
|
|
462
|
+
requestId: String, token: String?, resolve: RCTPromiseResolveBlock,
|
|
463
|
+
reject _: RCTPromiseRejectBlock
|
|
464
|
+
) {
|
|
465
|
+
DispatchQueue.main.async { [weak self] in
|
|
466
|
+
guard let completion = self?.pushIdentityCompletions.removeValue(forKey: requestId) else {
|
|
467
|
+
return
|
|
468
|
+
}
|
|
469
|
+
completion(token)
|
|
470
|
+
}
|
|
471
|
+
resolve(nil)
|
|
472
|
+
}
|
|
309
473
|
}
|
package/lib/commonjs/index.js
CHANGED
|
@@ -4,15 +4,21 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
4
4
|
value: true
|
|
5
5
|
});
|
|
6
6
|
exports.addExceptionStep = addExceptionStep;
|
|
7
|
+
exports.capturePushNotificationOpened = capturePushNotificationOpened;
|
|
7
8
|
exports.default = void 0;
|
|
8
9
|
exports.endSession = endSession;
|
|
9
10
|
exports.identify = identify;
|
|
10
11
|
exports.isEnabled = isEnabled;
|
|
12
|
+
exports.registerPushNotificationToken = registerPushNotificationToken;
|
|
13
|
+
exports.reset = reset;
|
|
14
|
+
exports.setOptOut = setOptOut;
|
|
15
|
+
exports.setPushIdentityProvider = setPushIdentityProvider;
|
|
11
16
|
exports.setup = setup;
|
|
12
17
|
exports.start = start;
|
|
13
18
|
exports.startRecording = startRecording;
|
|
14
19
|
exports.startSession = startSession;
|
|
15
20
|
exports.stopRecording = stopRecording;
|
|
21
|
+
exports.unregisterPushNotificationToken = unregisterPushNotificationToken;
|
|
16
22
|
var _reactNative = require("react-native");
|
|
17
23
|
const LINKING_ERROR = `The package '@posthog/react-native-plugin' doesn't seem to be linked. Make sure: \n\n` + _reactNative.Platform.select({
|
|
18
24
|
ios: "- You have run 'pod install'\n",
|
|
@@ -41,6 +47,15 @@ function isEnabled() {
|
|
|
41
47
|
function identify(distinctId, anonymousId) {
|
|
42
48
|
return PosthogReactNativePlugin.identify(distinctId, anonymousId);
|
|
43
49
|
}
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Resets the native SDK's identity on logout. Unlike {@link identify}, this calls the native
|
|
53
|
+
* SDK's own `reset()`, which unregisters the logged-out user's push subscription and
|
|
54
|
+
* re-registers it under the new anonymous id.
|
|
55
|
+
*/
|
|
56
|
+
function reset(distinctId, anonymousId) {
|
|
57
|
+
return PosthogReactNativePlugin.reset(distinctId, anonymousId);
|
|
58
|
+
}
|
|
44
59
|
function startRecording(resumeCurrent) {
|
|
45
60
|
return PosthogReactNativePlugin.startRecording(resumeCurrent);
|
|
46
61
|
}
|
|
@@ -50,6 +65,63 @@ function stopRecording() {
|
|
|
50
65
|
function addExceptionStep(message, properties) {
|
|
51
66
|
return PosthogReactNativePlugin.addExceptionStep(message, properties ?? {});
|
|
52
67
|
}
|
|
68
|
+
function registerPushNotificationToken(deviceToken, appId) {
|
|
69
|
+
return PosthogReactNativePlugin.registerPushNotificationToken(deviceToken, appId);
|
|
70
|
+
}
|
|
71
|
+
function unregisterPushNotificationToken() {
|
|
72
|
+
return PosthogReactNativePlugin.unregisterPushNotificationToken();
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Propagates a runtime consent change to the native SDK, which otherwise only reads the JS
|
|
77
|
+
* opt-out flag at setup() and could auto-register a refreshed push token after optOut().
|
|
78
|
+
*/
|
|
79
|
+
function setOptOut(optOut) {
|
|
80
|
+
return PosthogReactNativePlugin.setOptOut(optOut);
|
|
81
|
+
}
|
|
82
|
+
function capturePushNotificationOpened(properties) {
|
|
83
|
+
return PosthogReactNativePlugin.capturePushNotificationOpened(properties);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* Mints a signed identity-verification token for a push subscription request.
|
|
88
|
+
* Return null to send the request without an identity token.
|
|
89
|
+
*/
|
|
90
|
+
|
|
91
|
+
const PUSH_IDENTITY_EVENT = 'PostHogPushIdentityRequest';
|
|
92
|
+
let pushIdentitySubscription;
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* Installs the JS side of the push identity-provider bridge. The native SDK asks for a
|
|
96
|
+
* token via a `PostHogPushIdentityRequest` event; the reply is routed back with
|
|
97
|
+
* `providePushIdentityToken`, keyed by the request id so late replies are ignored.
|
|
98
|
+
*
|
|
99
|
+
* Install before setup() with `push.pushIdentityProviderEnabled` set, so the native
|
|
100
|
+
* config gets its bridging provider at SDK initialization. Any provider failure
|
|
101
|
+
* degrades to a null token — an unauthenticated request — never a stalled mint.
|
|
102
|
+
*/
|
|
103
|
+
function setPushIdentityProvider(provider) {
|
|
104
|
+
pushIdentitySubscription?.remove();
|
|
105
|
+
// Via the proxy, not raw NativeModules: an unlinked module would build an emitter over
|
|
106
|
+
// undefined and throw a generic RN error inside the SDK's init try, taking replay down with it.
|
|
107
|
+
const emitter = new _reactNative.NativeEventEmitter(PosthogReactNativePlugin);
|
|
108
|
+
pushIdentitySubscription = emitter.addListener(PUSH_IDENTITY_EVENT, async request => {
|
|
109
|
+
let token = null;
|
|
110
|
+
try {
|
|
111
|
+
const minted = await provider(request.distinctId, request.appId);
|
|
112
|
+
token = typeof minted === 'string' ? minted : null;
|
|
113
|
+
} catch (e) {
|
|
114
|
+
// eslint-disable-next-line no-console
|
|
115
|
+
console.warn(`[PostHog] pushIdentityProvider threw: ${e}. Push subscription will be sent unauthenticated.`);
|
|
116
|
+
}
|
|
117
|
+
try {
|
|
118
|
+
await PosthogReactNativePlugin.providePushIdentityToken(request.requestId, token);
|
|
119
|
+
} catch (e) {
|
|
120
|
+
// eslint-disable-next-line no-console
|
|
121
|
+
console.warn(`[PostHog] Failed to deliver push identity token to native: ${e}`);
|
|
122
|
+
}
|
|
123
|
+
});
|
|
124
|
+
}
|
|
53
125
|
const PostHogReactNativePlugin = {
|
|
54
126
|
setup,
|
|
55
127
|
start,
|
|
@@ -57,9 +129,15 @@ const PostHogReactNativePlugin = {
|
|
|
57
129
|
endSession,
|
|
58
130
|
isEnabled,
|
|
59
131
|
identify,
|
|
132
|
+
reset,
|
|
60
133
|
startRecording,
|
|
61
134
|
stopRecording,
|
|
62
|
-
addExceptionStep
|
|
135
|
+
addExceptionStep,
|
|
136
|
+
registerPushNotificationToken,
|
|
137
|
+
unregisterPushNotificationToken,
|
|
138
|
+
setOptOut,
|
|
139
|
+
capturePushNotificationOpened,
|
|
140
|
+
setPushIdentityProvider
|
|
63
141
|
};
|
|
64
142
|
var _default = exports.default = PostHogReactNativePlugin;
|
|
65
143
|
//# sourceMappingURL=index.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":["_reactNative","require","LINKING_ERROR","Platform","select","ios","default","PosthogReactNativePlugin","NativeModules","Proxy","get","Error","setup","sessionId","sdkOptions","pluginConfig","start","sdkReplayConfig","decideReplayConfig","startSession","endSession","isEnabled","identify","distinctId","anonymousId","startRecording","resumeCurrent","stopRecording","addExceptionStep","message","properties","PostHogReactNativePlugin","_default","exports"],"sourceRoot":"../../src","sources":["index.tsx"],"mappings":"
|
|
1
|
+
{"version":3,"names":["_reactNative","require","LINKING_ERROR","Platform","select","ios","default","PosthogReactNativePlugin","NativeModules","Proxy","get","Error","setup","sessionId","sdkOptions","pluginConfig","start","sdkReplayConfig","decideReplayConfig","startSession","endSession","isEnabled","identify","distinctId","anonymousId","reset","startRecording","resumeCurrent","stopRecording","addExceptionStep","message","properties","registerPushNotificationToken","deviceToken","appId","unregisterPushNotificationToken","setOptOut","optOut","capturePushNotificationOpened","PUSH_IDENTITY_EVENT","pushIdentitySubscription","setPushIdentityProvider","provider","remove","emitter","NativeEventEmitter","addListener","request","token","minted","e","console","warn","providePushIdentityToken","requestId","PostHogReactNativePlugin","_default","exports"],"sourceRoot":"../../src","sources":["index.tsx"],"mappings":"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","ignoreList":[]}
|
package/lib/module/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
|
|
3
|
-
import { NativeModules, Platform } from 'react-native';
|
|
3
|
+
import { NativeEventEmitter, NativeModules, Platform } from 'react-native';
|
|
4
4
|
const LINKING_ERROR = `The package '@posthog/react-native-plugin' doesn't seem to be linked. Make sure: \n\n` + Platform.select({
|
|
5
5
|
ios: "- You have run 'pod install'\n",
|
|
6
6
|
default: ''
|
|
@@ -28,6 +28,15 @@ export function isEnabled() {
|
|
|
28
28
|
export function identify(distinctId, anonymousId) {
|
|
29
29
|
return PosthogReactNativePlugin.identify(distinctId, anonymousId);
|
|
30
30
|
}
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Resets the native SDK's identity on logout. Unlike {@link identify}, this calls the native
|
|
34
|
+
* SDK's own `reset()`, which unregisters the logged-out user's push subscription and
|
|
35
|
+
* re-registers it under the new anonymous id.
|
|
36
|
+
*/
|
|
37
|
+
export function reset(distinctId, anonymousId) {
|
|
38
|
+
return PosthogReactNativePlugin.reset(distinctId, anonymousId);
|
|
39
|
+
}
|
|
31
40
|
export function startRecording(resumeCurrent) {
|
|
32
41
|
return PosthogReactNativePlugin.startRecording(resumeCurrent);
|
|
33
42
|
}
|
|
@@ -37,6 +46,63 @@ export function stopRecording() {
|
|
|
37
46
|
export function addExceptionStep(message, properties) {
|
|
38
47
|
return PosthogReactNativePlugin.addExceptionStep(message, properties ?? {});
|
|
39
48
|
}
|
|
49
|
+
export function registerPushNotificationToken(deviceToken, appId) {
|
|
50
|
+
return PosthogReactNativePlugin.registerPushNotificationToken(deviceToken, appId);
|
|
51
|
+
}
|
|
52
|
+
export function unregisterPushNotificationToken() {
|
|
53
|
+
return PosthogReactNativePlugin.unregisterPushNotificationToken();
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Propagates a runtime consent change to the native SDK, which otherwise only reads the JS
|
|
58
|
+
* opt-out flag at setup() and could auto-register a refreshed push token after optOut().
|
|
59
|
+
*/
|
|
60
|
+
export function setOptOut(optOut) {
|
|
61
|
+
return PosthogReactNativePlugin.setOptOut(optOut);
|
|
62
|
+
}
|
|
63
|
+
export function capturePushNotificationOpened(properties) {
|
|
64
|
+
return PosthogReactNativePlugin.capturePushNotificationOpened(properties);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Mints a signed identity-verification token for a push subscription request.
|
|
69
|
+
* Return null to send the request without an identity token.
|
|
70
|
+
*/
|
|
71
|
+
|
|
72
|
+
const PUSH_IDENTITY_EVENT = 'PostHogPushIdentityRequest';
|
|
73
|
+
let pushIdentitySubscription;
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Installs the JS side of the push identity-provider bridge. The native SDK asks for a
|
|
77
|
+
* token via a `PostHogPushIdentityRequest` event; the reply is routed back with
|
|
78
|
+
* `providePushIdentityToken`, keyed by the request id so late replies are ignored.
|
|
79
|
+
*
|
|
80
|
+
* Install before setup() with `push.pushIdentityProviderEnabled` set, so the native
|
|
81
|
+
* config gets its bridging provider at SDK initialization. Any provider failure
|
|
82
|
+
* degrades to a null token — an unauthenticated request — never a stalled mint.
|
|
83
|
+
*/
|
|
84
|
+
export function setPushIdentityProvider(provider) {
|
|
85
|
+
pushIdentitySubscription?.remove();
|
|
86
|
+
// Via the proxy, not raw NativeModules: an unlinked module would build an emitter over
|
|
87
|
+
// undefined and throw a generic RN error inside the SDK's init try, taking replay down with it.
|
|
88
|
+
const emitter = new NativeEventEmitter(PosthogReactNativePlugin);
|
|
89
|
+
pushIdentitySubscription = emitter.addListener(PUSH_IDENTITY_EVENT, async request => {
|
|
90
|
+
let token = null;
|
|
91
|
+
try {
|
|
92
|
+
const minted = await provider(request.distinctId, request.appId);
|
|
93
|
+
token = typeof minted === 'string' ? minted : null;
|
|
94
|
+
} catch (e) {
|
|
95
|
+
// eslint-disable-next-line no-console
|
|
96
|
+
console.warn(`[PostHog] pushIdentityProvider threw: ${e}. Push subscription will be sent unauthenticated.`);
|
|
97
|
+
}
|
|
98
|
+
try {
|
|
99
|
+
await PosthogReactNativePlugin.providePushIdentityToken(request.requestId, token);
|
|
100
|
+
} catch (e) {
|
|
101
|
+
// eslint-disable-next-line no-console
|
|
102
|
+
console.warn(`[PostHog] Failed to deliver push identity token to native: ${e}`);
|
|
103
|
+
}
|
|
104
|
+
});
|
|
105
|
+
}
|
|
40
106
|
const PostHogReactNativePlugin = {
|
|
41
107
|
setup,
|
|
42
108
|
start,
|
|
@@ -44,9 +110,15 @@ const PostHogReactNativePlugin = {
|
|
|
44
110
|
endSession,
|
|
45
111
|
isEnabled,
|
|
46
112
|
identify,
|
|
113
|
+
reset,
|
|
47
114
|
startRecording,
|
|
48
115
|
stopRecording,
|
|
49
|
-
addExceptionStep
|
|
116
|
+
addExceptionStep,
|
|
117
|
+
registerPushNotificationToken,
|
|
118
|
+
unregisterPushNotificationToken,
|
|
119
|
+
setOptOut,
|
|
120
|
+
capturePushNotificationOpened,
|
|
121
|
+
setPushIdentityProvider
|
|
50
122
|
};
|
|
51
123
|
export default PostHogReactNativePlugin;
|
|
52
124
|
//# sourceMappingURL=index.js.map
|
package/lib/module/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":["NativeModules","Platform","LINKING_ERROR","select","ios","default","PosthogReactNativePlugin","Proxy","get","Error","setup","sessionId","sdkOptions","pluginConfig","start","sdkReplayConfig","decideReplayConfig","startSession","endSession","isEnabled","identify","distinctId","anonymousId","startRecording","resumeCurrent","stopRecording","addExceptionStep","message","properties","PostHogReactNativePlugin"],"sourceRoot":"../../src","sources":["index.tsx"],"mappings":";;AAAA,SAASA,aAAa,EAAEC,QAAQ,QAAQ,cAAc;
|
|
1
|
+
{"version":3,"names":["NativeEventEmitter","NativeModules","Platform","LINKING_ERROR","select","ios","default","PosthogReactNativePlugin","Proxy","get","Error","setup","sessionId","sdkOptions","pluginConfig","start","sdkReplayConfig","decideReplayConfig","startSession","endSession","isEnabled","identify","distinctId","anonymousId","reset","startRecording","resumeCurrent","stopRecording","addExceptionStep","message","properties","registerPushNotificationToken","deviceToken","appId","unregisterPushNotificationToken","setOptOut","optOut","capturePushNotificationOpened","PUSH_IDENTITY_EVENT","pushIdentitySubscription","setPushIdentityProvider","provider","remove","emitter","addListener","request","token","minted","e","console","warn","providePushIdentityToken","requestId","PostHogReactNativePlugin"],"sourceRoot":"../../src","sources":["index.tsx"],"mappings":"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","ignoreList":[]}
|
|
@@ -14,9 +14,21 @@ export interface PostHogReactNativePluginErrorTrackingConfig {
|
|
|
14
14
|
nativeAutocapture?: boolean;
|
|
15
15
|
exceptionSteps?: PostHogReactNativePluginExceptionStepsConfig;
|
|
16
16
|
}
|
|
17
|
+
export interface PostHogReactNativePluginPushConfig {
|
|
18
|
+
capturePushNotificationSubscriptions?: boolean;
|
|
19
|
+
capturePushNotificationOpened?: boolean;
|
|
20
|
+
/**
|
|
21
|
+
* A provider callback can't cross the bridge, so this only tells native whether to
|
|
22
|
+
* install the bridging provider at all — installing one the host didn't ask for
|
|
23
|
+
* would change how the native SDK handles a 401 on the subscription call.
|
|
24
|
+
* Pair with {@link setPushIdentityProvider} before calling setup().
|
|
25
|
+
*/
|
|
26
|
+
pushIdentityProviderEnabled?: boolean;
|
|
27
|
+
}
|
|
17
28
|
export interface PostHogReactNativePluginConfig {
|
|
18
29
|
sessionReplay?: PostHogReactNativePluginSessionReplayConfig;
|
|
19
30
|
errorTracking?: PostHogReactNativePluginErrorTrackingConfig;
|
|
31
|
+
push?: PostHogReactNativePluginPushConfig;
|
|
20
32
|
}
|
|
21
33
|
export declare function setup(sessionId: string, sdkOptions: PostHogReactNativePluginMap, pluginConfig?: PostHogReactNativePluginConfig): Promise<void>;
|
|
22
34
|
export declare function start(sessionId: string, sdkOptions: PostHogReactNativePluginMap, sdkReplayConfig: PostHogReactNativePluginMap, decideReplayConfig: PostHogReactNativePluginMap): Promise<void>;
|
|
@@ -24,9 +36,38 @@ export declare function startSession(sessionId: string): Promise<void>;
|
|
|
24
36
|
export declare function endSession(): Promise<void>;
|
|
25
37
|
export declare function isEnabled(): Promise<boolean>;
|
|
26
38
|
export declare function identify(distinctId: string, anonymousId: string): Promise<void>;
|
|
39
|
+
/**
|
|
40
|
+
* Resets the native SDK's identity on logout. Unlike {@link identify}, this calls the native
|
|
41
|
+
* SDK's own `reset()`, which unregisters the logged-out user's push subscription and
|
|
42
|
+
* re-registers it under the new anonymous id.
|
|
43
|
+
*/
|
|
44
|
+
export declare function reset(distinctId: string, anonymousId: string): Promise<void>;
|
|
27
45
|
export declare function startRecording(resumeCurrent: boolean): Promise<void>;
|
|
28
46
|
export declare function stopRecording(): Promise<void>;
|
|
29
47
|
export declare function addExceptionStep(message: string, properties?: PostHogReactNativePluginMap): Promise<void>;
|
|
48
|
+
export declare function registerPushNotificationToken(deviceToken: string, appId: string | null): Promise<void>;
|
|
49
|
+
export declare function unregisterPushNotificationToken(): Promise<void>;
|
|
50
|
+
/**
|
|
51
|
+
* Propagates a runtime consent change to the native SDK, which otherwise only reads the JS
|
|
52
|
+
* opt-out flag at setup() and could auto-register a refreshed push token after optOut().
|
|
53
|
+
*/
|
|
54
|
+
export declare function setOptOut(optOut: boolean): Promise<void>;
|
|
55
|
+
export declare function capturePushNotificationOpened(properties: PostHogReactNativePluginMap): Promise<void>;
|
|
56
|
+
/**
|
|
57
|
+
* Mints a signed identity-verification token for a push subscription request.
|
|
58
|
+
* Return null to send the request without an identity token.
|
|
59
|
+
*/
|
|
60
|
+
export type PostHogPushIdentityProvider = (distinctId: string, appId: string) => Promise<string | null>;
|
|
61
|
+
/**
|
|
62
|
+
* Installs the JS side of the push identity-provider bridge. The native SDK asks for a
|
|
63
|
+
* token via a `PostHogPushIdentityRequest` event; the reply is routed back with
|
|
64
|
+
* `providePushIdentityToken`, keyed by the request id so late replies are ignored.
|
|
65
|
+
*
|
|
66
|
+
* Install before setup() with `push.pushIdentityProviderEnabled` set, so the native
|
|
67
|
+
* config gets its bridging provider at SDK initialization. Any provider failure
|
|
68
|
+
* degrades to a null token — an unauthenticated request — never a stalled mint.
|
|
69
|
+
*/
|
|
70
|
+
export declare function setPushIdentityProvider(provider: PostHogPushIdentityProvider): void;
|
|
30
71
|
export interface PostHogReactNativePluginModule {
|
|
31
72
|
setup: (sessionId: string, sdkOptions: PostHogReactNativePluginMap, pluginConfig?: PostHogReactNativePluginConfig) => Promise<void>;
|
|
32
73
|
/**
|
|
@@ -37,9 +78,15 @@ export interface PostHogReactNativePluginModule {
|
|
|
37
78
|
endSession: () => Promise<void>;
|
|
38
79
|
isEnabled: () => Promise<boolean>;
|
|
39
80
|
identify: (distinctId: string, anonymousId: string) => Promise<void>;
|
|
81
|
+
reset: (distinctId: string, anonymousId: string) => Promise<void>;
|
|
40
82
|
startRecording: (resumeCurrent: boolean) => Promise<void>;
|
|
41
83
|
stopRecording: () => Promise<void>;
|
|
42
84
|
addExceptionStep: (message: string, properties?: PostHogReactNativePluginMap) => Promise<void>;
|
|
85
|
+
registerPushNotificationToken: (deviceToken: string, appId: string | null) => Promise<void>;
|
|
86
|
+
unregisterPushNotificationToken: () => Promise<void>;
|
|
87
|
+
setOptOut: (optOut: boolean) => Promise<void>;
|
|
88
|
+
capturePushNotificationOpened: (properties: PostHogReactNativePluginMap) => Promise<void>;
|
|
89
|
+
setPushIdentityProvider: (provider: PostHogPushIdentityProvider) => void;
|
|
43
90
|
}
|
|
44
91
|
declare const PostHogReactNativePlugin: PostHogReactNativePluginModule;
|
|
45
92
|
export default PostHogReactNativePlugin;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/index.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/index.tsx"],"names":[],"mappings":"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"}
|
|
@@ -14,9 +14,21 @@ export interface PostHogReactNativePluginErrorTrackingConfig {
|
|
|
14
14
|
nativeAutocapture?: boolean;
|
|
15
15
|
exceptionSteps?: PostHogReactNativePluginExceptionStepsConfig;
|
|
16
16
|
}
|
|
17
|
+
export interface PostHogReactNativePluginPushConfig {
|
|
18
|
+
capturePushNotificationSubscriptions?: boolean;
|
|
19
|
+
capturePushNotificationOpened?: boolean;
|
|
20
|
+
/**
|
|
21
|
+
* A provider callback can't cross the bridge, so this only tells native whether to
|
|
22
|
+
* install the bridging provider at all — installing one the host didn't ask for
|
|
23
|
+
* would change how the native SDK handles a 401 on the subscription call.
|
|
24
|
+
* Pair with {@link setPushIdentityProvider} before calling setup().
|
|
25
|
+
*/
|
|
26
|
+
pushIdentityProviderEnabled?: boolean;
|
|
27
|
+
}
|
|
17
28
|
export interface PostHogReactNativePluginConfig {
|
|
18
29
|
sessionReplay?: PostHogReactNativePluginSessionReplayConfig;
|
|
19
30
|
errorTracking?: PostHogReactNativePluginErrorTrackingConfig;
|
|
31
|
+
push?: PostHogReactNativePluginPushConfig;
|
|
20
32
|
}
|
|
21
33
|
export declare function setup(sessionId: string, sdkOptions: PostHogReactNativePluginMap, pluginConfig?: PostHogReactNativePluginConfig): Promise<void>;
|
|
22
34
|
export declare function start(sessionId: string, sdkOptions: PostHogReactNativePluginMap, sdkReplayConfig: PostHogReactNativePluginMap, decideReplayConfig: PostHogReactNativePluginMap): Promise<void>;
|
|
@@ -24,9 +36,38 @@ export declare function startSession(sessionId: string): Promise<void>;
|
|
|
24
36
|
export declare function endSession(): Promise<void>;
|
|
25
37
|
export declare function isEnabled(): Promise<boolean>;
|
|
26
38
|
export declare function identify(distinctId: string, anonymousId: string): Promise<void>;
|
|
39
|
+
/**
|
|
40
|
+
* Resets the native SDK's identity on logout. Unlike {@link identify}, this calls the native
|
|
41
|
+
* SDK's own `reset()`, which unregisters the logged-out user's push subscription and
|
|
42
|
+
* re-registers it under the new anonymous id.
|
|
43
|
+
*/
|
|
44
|
+
export declare function reset(distinctId: string, anonymousId: string): Promise<void>;
|
|
27
45
|
export declare function startRecording(resumeCurrent: boolean): Promise<void>;
|
|
28
46
|
export declare function stopRecording(): Promise<void>;
|
|
29
47
|
export declare function addExceptionStep(message: string, properties?: PostHogReactNativePluginMap): Promise<void>;
|
|
48
|
+
export declare function registerPushNotificationToken(deviceToken: string, appId: string | null): Promise<void>;
|
|
49
|
+
export declare function unregisterPushNotificationToken(): Promise<void>;
|
|
50
|
+
/**
|
|
51
|
+
* Propagates a runtime consent change to the native SDK, which otherwise only reads the JS
|
|
52
|
+
* opt-out flag at setup() and could auto-register a refreshed push token after optOut().
|
|
53
|
+
*/
|
|
54
|
+
export declare function setOptOut(optOut: boolean): Promise<void>;
|
|
55
|
+
export declare function capturePushNotificationOpened(properties: PostHogReactNativePluginMap): Promise<void>;
|
|
56
|
+
/**
|
|
57
|
+
* Mints a signed identity-verification token for a push subscription request.
|
|
58
|
+
* Return null to send the request without an identity token.
|
|
59
|
+
*/
|
|
60
|
+
export type PostHogPushIdentityProvider = (distinctId: string, appId: string) => Promise<string | null>;
|
|
61
|
+
/**
|
|
62
|
+
* Installs the JS side of the push identity-provider bridge. The native SDK asks for a
|
|
63
|
+
* token via a `PostHogPushIdentityRequest` event; the reply is routed back with
|
|
64
|
+
* `providePushIdentityToken`, keyed by the request id so late replies are ignored.
|
|
65
|
+
*
|
|
66
|
+
* Install before setup() with `push.pushIdentityProviderEnabled` set, so the native
|
|
67
|
+
* config gets its bridging provider at SDK initialization. Any provider failure
|
|
68
|
+
* degrades to a null token — an unauthenticated request — never a stalled mint.
|
|
69
|
+
*/
|
|
70
|
+
export declare function setPushIdentityProvider(provider: PostHogPushIdentityProvider): void;
|
|
30
71
|
export interface PostHogReactNativePluginModule {
|
|
31
72
|
setup: (sessionId: string, sdkOptions: PostHogReactNativePluginMap, pluginConfig?: PostHogReactNativePluginConfig) => Promise<void>;
|
|
32
73
|
/**
|
|
@@ -37,9 +78,15 @@ export interface PostHogReactNativePluginModule {
|
|
|
37
78
|
endSession: () => Promise<void>;
|
|
38
79
|
isEnabled: () => Promise<boolean>;
|
|
39
80
|
identify: (distinctId: string, anonymousId: string) => Promise<void>;
|
|
81
|
+
reset: (distinctId: string, anonymousId: string) => Promise<void>;
|
|
40
82
|
startRecording: (resumeCurrent: boolean) => Promise<void>;
|
|
41
83
|
stopRecording: () => Promise<void>;
|
|
42
84
|
addExceptionStep: (message: string, properties?: PostHogReactNativePluginMap) => Promise<void>;
|
|
85
|
+
registerPushNotificationToken: (deviceToken: string, appId: string | null) => Promise<void>;
|
|
86
|
+
unregisterPushNotificationToken: () => Promise<void>;
|
|
87
|
+
setOptOut: (optOut: boolean) => Promise<void>;
|
|
88
|
+
capturePushNotificationOpened: (properties: PostHogReactNativePluginMap) => Promise<void>;
|
|
89
|
+
setPushIdentityProvider: (provider: PostHogPushIdentityProvider) => void;
|
|
43
90
|
}
|
|
44
91
|
declare const PostHogReactNativePlugin: PostHogReactNativePluginModule;
|
|
45
92
|
export default PostHogReactNativePlugin;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/index.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/index.tsx"],"names":[],"mappings":"AAoBA,MAAM,MAAM,2BAA2B,GAAG;IAAE,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAA;CAAE,CAAA;AAEhE,MAAM,WAAW,2CAA2C;IAC1D,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB,eAAe,CAAC,EAAE,2BAA2B,CAAA;IAC7C,kBAAkB,CAAC,EAAE,2BAA2B,CAAA;CACjD;AAED,MAAM,WAAW,4CAA4C;IAC3D,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAA;CAClB;AAED,MAAM,WAAW,2CAA2C;IAC1D,iBAAiB,CAAC,EAAE,OAAO,CAAA;IAC3B,cAAc,CAAC,EAAE,4CAA4C,CAAA;CAC9D;AAED,MAAM,WAAW,kCAAkC;IACjD,oCAAoC,CAAC,EAAE,OAAO,CAAA;IAC9C,6BAA6B,CAAC,EAAE,OAAO,CAAA;IACvC;;;;;OAKG;IACH,2BAA2B,CAAC,EAAE,OAAO,CAAA;CACtC;AAED,MAAM,WAAW,8BAA8B;IAC7C,aAAa,CAAC,EAAE,2CAA2C,CAAA;IAC3D,aAAa,CAAC,EAAE,2CAA2C,CAAA;IAC3D,IAAI,CAAC,EAAE,kCAAkC,CAAA;CAC1C;AAED,wBAAgB,KAAK,CACnB,SAAS,EAAE,MAAM,EACjB,UAAU,EAAE,2BAA2B,EACvC,YAAY,GAAE,8BAAmC,GAChD,OAAO,CAAC,IAAI,CAAC,CAEf;AAED,wBAAgB,KAAK,CACnB,SAAS,EAAE,MAAM,EACjB,UAAU,EAAE,2BAA2B,EACvC,eAAe,EAAE,2BAA2B,EAC5C,kBAAkB,EAAE,2BAA2B,GAC9C,OAAO,CAAC,IAAI,CAAC,CAEf;AAED,wBAAgB,YAAY,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAE7D;AAED,wBAAgB,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC,CAE1C;AAED,wBAAgB,SAAS,IAAI,OAAO,CAAC,OAAO,CAAC,CAE5C;AAED,wBAAgB,QAAQ,CAAC,UAAU,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAE/E;AAED;;;;GAIG;AACH,wBAAgB,KAAK,CAAC,UAAU,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAE5E;AAED,wBAAgB,cAAc,CAAC,aAAa,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC,CAEpE;AAED,wBAAgB,aAAa,IAAI,OAAO,CAAC,IAAI,CAAC,CAE7C;AAED,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,MAAM,EAAE,UAAU,CAAC,EAAE,2BAA2B,GAAG,OAAO,CAAC,IAAI,CAAC,CAEzG;AAED,wBAAgB,6BAA6B,CAAC,WAAW,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAEtG;AAED,wBAAgB,+BAA+B,IAAI,OAAO,CAAC,IAAI,CAAC,CAE/D;AAED;;;GAGG;AACH,wBAAgB,SAAS,CAAC,MAAM,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC,CAExD;AAED,wBAAgB,6BAA6B,CAAC,UAAU,EAAE,2BAA2B,GAAG,OAAO,CAAC,IAAI,CAAC,CAEpG;AAED;;;GAGG;AACH,MAAM,MAAM,2BAA2B,GAAG,CAAC,UAAU,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAAA;AAMvG;;;;;;;;GAQG;AACH,wBAAgB,uBAAuB,CAAC,QAAQ,EAAE,2BAA2B,GAAG,IAAI,CAwBnF;AAED,MAAM,WAAW,8BAA8B;IAC7C,KAAK,EAAE,CACL,SAAS,EAAE,MAAM,EACjB,UAAU,EAAE,2BAA2B,EACvC,YAAY,CAAC,EAAE,8BAA8B,KAC1C,OAAO,CAAC,IAAI,CAAC,CAAA;IAElB;;OAEG;IACH,KAAK,EAAE,CACL,SAAS,EAAE,MAAM,EACjB,UAAU,EAAE,2BAA2B,EACvC,eAAe,EAAE,2BAA2B,EAC5C,kBAAkB,EAAE,2BAA2B,KAC5C,OAAO,CAAC,IAAI,CAAC,CAAA;IAElB,YAAY,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAA;IAElD,UAAU,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAA;IAE/B,SAAS,EAAE,MAAM,OAAO,CAAC,OAAO,CAAC,CAAA;IAEjC,QAAQ,EAAE,CAAC,UAAU,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAA;IAEpE,KAAK,EAAE,CAAC,UAAU,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAA;IAEjE,cAAc,EAAE,CAAC,aAAa,EAAE,OAAO,KAAK,OAAO,CAAC,IAAI,CAAC,CAAA;IAEzD,aAAa,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAA;IAElC,gBAAgB,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,UAAU,CAAC,EAAE,2BAA2B,KAAK,OAAO,CAAC,IAAI,CAAC,CAAA;IAE9F,6BAA6B,EAAE,CAAC,WAAW,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI,KAAK,OAAO,CAAC,IAAI,CAAC,CAAA;IAE3F,+BAA+B,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAA;IAEpD,SAAS,EAAE,CAAC,MAAM,EAAE,OAAO,KAAK,OAAO,CAAC,IAAI,CAAC,CAAA;IAE7C,6BAA6B,EAAE,CAAC,UAAU,EAAE,2BAA2B,KAAK,OAAO,CAAC,IAAI,CAAC,CAAA;IAEzF,uBAAuB,EAAE,CAAC,QAAQ,EAAE,2BAA2B,KAAK,IAAI,CAAA;CACzE;AAED,QAAA,MAAM,wBAAwB,EAAE,8BAgB/B,CAAA;AAED,eAAe,wBAAwB,CAAA"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@posthog/react-native-plugin",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.3.0",
|
|
4
4
|
"description": "PostHog React Native plugin for iOS and Android integrations",
|
|
5
5
|
"source": "./src/index.tsx",
|
|
6
6
|
"main": "./lib/commonjs/index.js",
|
|
@@ -69,7 +69,6 @@
|
|
|
69
69
|
"react-native": "*"
|
|
70
70
|
},
|
|
71
71
|
"jest": {
|
|
72
|
-
"preset": "react-native",
|
|
73
72
|
"modulePathIgnorePatterns": [
|
|
74
73
|
"<rootDir>/lib/"
|
|
75
74
|
],
|
|
@@ -6,7 +6,7 @@ folly_compiler_flags = '-DFOLLY_NO_CONFIG -DFOLLY_MOBILE=1 -DFOLLY_USE_LIBCPP=1
|
|
|
6
6
|
# Single source of truth for the posthog-ios native dependency version.
|
|
7
7
|
# Used by both the SPM and CocoaPods resolution paths below; bump this
|
|
8
8
|
# line when picking up a new posthog-ios release.
|
|
9
|
-
posthog_ios_version = '3.69.
|
|
9
|
+
posthog_ios_version = '3.69.2'
|
|
10
10
|
|
|
11
11
|
Pod::Spec.new do |s|
|
|
12
12
|
s.name = "posthog-react-native-plugin"
|
package/src/index.tsx
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import { NativeModules, Platform } from 'react-native'
|
|
1
|
+
import { NativeEventEmitter, NativeModules, Platform } from 'react-native'
|
|
2
|
+
import type { EmitterSubscription } from 'react-native'
|
|
2
3
|
|
|
3
4
|
const LINKING_ERROR =
|
|
4
5
|
`The package '@posthog/react-native-plugin' doesn't seem to be linked. Make sure: \n\n` +
|
|
@@ -35,9 +36,22 @@ export interface PostHogReactNativePluginErrorTrackingConfig {
|
|
|
35
36
|
exceptionSteps?: PostHogReactNativePluginExceptionStepsConfig
|
|
36
37
|
}
|
|
37
38
|
|
|
39
|
+
export interface PostHogReactNativePluginPushConfig {
|
|
40
|
+
capturePushNotificationSubscriptions?: boolean
|
|
41
|
+
capturePushNotificationOpened?: boolean
|
|
42
|
+
/**
|
|
43
|
+
* A provider callback can't cross the bridge, so this only tells native whether to
|
|
44
|
+
* install the bridging provider at all — installing one the host didn't ask for
|
|
45
|
+
* would change how the native SDK handles a 401 on the subscription call.
|
|
46
|
+
* Pair with {@link setPushIdentityProvider} before calling setup().
|
|
47
|
+
*/
|
|
48
|
+
pushIdentityProviderEnabled?: boolean
|
|
49
|
+
}
|
|
50
|
+
|
|
38
51
|
export interface PostHogReactNativePluginConfig {
|
|
39
52
|
sessionReplay?: PostHogReactNativePluginSessionReplayConfig
|
|
40
53
|
errorTracking?: PostHogReactNativePluginErrorTrackingConfig
|
|
54
|
+
push?: PostHogReactNativePluginPushConfig
|
|
41
55
|
}
|
|
42
56
|
|
|
43
57
|
export function setup(
|
|
@@ -73,6 +87,15 @@ export function identify(distinctId: string, anonymousId: string): Promise<void>
|
|
|
73
87
|
return PosthogReactNativePlugin.identify(distinctId, anonymousId)
|
|
74
88
|
}
|
|
75
89
|
|
|
90
|
+
/**
|
|
91
|
+
* Resets the native SDK's identity on logout. Unlike {@link identify}, this calls the native
|
|
92
|
+
* SDK's own `reset()`, which unregisters the logged-out user's push subscription and
|
|
93
|
+
* re-registers it under the new anonymous id.
|
|
94
|
+
*/
|
|
95
|
+
export function reset(distinctId: string, anonymousId: string): Promise<void> {
|
|
96
|
+
return PosthogReactNativePlugin.reset(distinctId, anonymousId)
|
|
97
|
+
}
|
|
98
|
+
|
|
76
99
|
export function startRecording(resumeCurrent: boolean): Promise<void> {
|
|
77
100
|
return PosthogReactNativePlugin.startRecording(resumeCurrent)
|
|
78
101
|
}
|
|
@@ -85,6 +108,71 @@ export function addExceptionStep(message: string, properties?: PostHogReactNativ
|
|
|
85
108
|
return PosthogReactNativePlugin.addExceptionStep(message, properties ?? {})
|
|
86
109
|
}
|
|
87
110
|
|
|
111
|
+
export function registerPushNotificationToken(deviceToken: string, appId: string | null): Promise<void> {
|
|
112
|
+
return PosthogReactNativePlugin.registerPushNotificationToken(deviceToken, appId)
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
export function unregisterPushNotificationToken(): Promise<void> {
|
|
116
|
+
return PosthogReactNativePlugin.unregisterPushNotificationToken()
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
/**
|
|
120
|
+
* Propagates a runtime consent change to the native SDK, which otherwise only reads the JS
|
|
121
|
+
* opt-out flag at setup() and could auto-register a refreshed push token after optOut().
|
|
122
|
+
*/
|
|
123
|
+
export function setOptOut(optOut: boolean): Promise<void> {
|
|
124
|
+
return PosthogReactNativePlugin.setOptOut(optOut)
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
export function capturePushNotificationOpened(properties: PostHogReactNativePluginMap): Promise<void> {
|
|
128
|
+
return PosthogReactNativePlugin.capturePushNotificationOpened(properties)
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* Mints a signed identity-verification token for a push subscription request.
|
|
133
|
+
* Return null to send the request without an identity token.
|
|
134
|
+
*/
|
|
135
|
+
export type PostHogPushIdentityProvider = (distinctId: string, appId: string) => Promise<string | null>
|
|
136
|
+
|
|
137
|
+
const PUSH_IDENTITY_EVENT = 'PostHogPushIdentityRequest'
|
|
138
|
+
|
|
139
|
+
let pushIdentitySubscription: EmitterSubscription | undefined
|
|
140
|
+
|
|
141
|
+
/**
|
|
142
|
+
* Installs the JS side of the push identity-provider bridge. The native SDK asks for a
|
|
143
|
+
* token via a `PostHogPushIdentityRequest` event; the reply is routed back with
|
|
144
|
+
* `providePushIdentityToken`, keyed by the request id so late replies are ignored.
|
|
145
|
+
*
|
|
146
|
+
* Install before setup() with `push.pushIdentityProviderEnabled` set, so the native
|
|
147
|
+
* config gets its bridging provider at SDK initialization. Any provider failure
|
|
148
|
+
* degrades to a null token — an unauthenticated request — never a stalled mint.
|
|
149
|
+
*/
|
|
150
|
+
export function setPushIdentityProvider(provider: PostHogPushIdentityProvider): void {
|
|
151
|
+
pushIdentitySubscription?.remove()
|
|
152
|
+
// Via the proxy, not raw NativeModules: an unlinked module would build an emitter over
|
|
153
|
+
// undefined and throw a generic RN error inside the SDK's init try, taking replay down with it.
|
|
154
|
+
const emitter = new NativeEventEmitter(PosthogReactNativePlugin)
|
|
155
|
+
pushIdentitySubscription = emitter.addListener(
|
|
156
|
+
PUSH_IDENTITY_EVENT,
|
|
157
|
+
async (request: { requestId: string; distinctId: string; appId: string }) => {
|
|
158
|
+
let token: string | null = null
|
|
159
|
+
try {
|
|
160
|
+
const minted = await provider(request.distinctId, request.appId)
|
|
161
|
+
token = typeof minted === 'string' ? minted : null
|
|
162
|
+
} catch (e) {
|
|
163
|
+
// eslint-disable-next-line no-console
|
|
164
|
+
console.warn(`[PostHog] pushIdentityProvider threw: ${e}. Push subscription will be sent unauthenticated.`)
|
|
165
|
+
}
|
|
166
|
+
try {
|
|
167
|
+
await PosthogReactNativePlugin.providePushIdentityToken(request.requestId, token)
|
|
168
|
+
} catch (e) {
|
|
169
|
+
// eslint-disable-next-line no-console
|
|
170
|
+
console.warn(`[PostHog] Failed to deliver push identity token to native: ${e}`)
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
)
|
|
174
|
+
}
|
|
175
|
+
|
|
88
176
|
export interface PostHogReactNativePluginModule {
|
|
89
177
|
setup: (
|
|
90
178
|
sessionId: string,
|
|
@@ -110,11 +198,23 @@ export interface PostHogReactNativePluginModule {
|
|
|
110
198
|
|
|
111
199
|
identify: (distinctId: string, anonymousId: string) => Promise<void>
|
|
112
200
|
|
|
201
|
+
reset: (distinctId: string, anonymousId: string) => Promise<void>
|
|
202
|
+
|
|
113
203
|
startRecording: (resumeCurrent: boolean) => Promise<void>
|
|
114
204
|
|
|
115
205
|
stopRecording: () => Promise<void>
|
|
116
206
|
|
|
117
207
|
addExceptionStep: (message: string, properties?: PostHogReactNativePluginMap) => Promise<void>
|
|
208
|
+
|
|
209
|
+
registerPushNotificationToken: (deviceToken: string, appId: string | null) => Promise<void>
|
|
210
|
+
|
|
211
|
+
unregisterPushNotificationToken: () => Promise<void>
|
|
212
|
+
|
|
213
|
+
setOptOut: (optOut: boolean) => Promise<void>
|
|
214
|
+
|
|
215
|
+
capturePushNotificationOpened: (properties: PostHogReactNativePluginMap) => Promise<void>
|
|
216
|
+
|
|
217
|
+
setPushIdentityProvider: (provider: PostHogPushIdentityProvider) => void
|
|
118
218
|
}
|
|
119
219
|
|
|
120
220
|
const PostHogReactNativePlugin: PostHogReactNativePluginModule = {
|
|
@@ -124,9 +224,15 @@ const PostHogReactNativePlugin: PostHogReactNativePluginModule = {
|
|
|
124
224
|
endSession,
|
|
125
225
|
isEnabled,
|
|
126
226
|
identify,
|
|
227
|
+
reset,
|
|
127
228
|
startRecording,
|
|
128
229
|
stopRecording,
|
|
129
230
|
addExceptionStep,
|
|
231
|
+
registerPushNotificationToken,
|
|
232
|
+
unregisterPushNotificationToken,
|
|
233
|
+
setOptOut,
|
|
234
|
+
capturePushNotificationOpened,
|
|
235
|
+
setPushIdentityProvider,
|
|
130
236
|
}
|
|
131
237
|
|
|
132
238
|
export default PostHogReactNativePlugin
|