@goliapkg/sentori-react-native 6.4.0 → 7.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/android/src/main/java-core/com/sentori/SentoriConfig.kt +1 -1
- package/android/src/main/java-core/com/sentori/SentoriPush.kt +61 -23
- package/android/src/test/java-core/com/sentori/SentoriPushTest.kt +70 -1
- package/lib/push.d.ts +1 -1
- package/lib/push.d.ts.map +1 -1
- package/lib/push.js +49 -17
- package/lib/push.js.map +1 -1
- package/lib/transport.js +1 -1
- package/package.json +2 -2
- package/src/__tests__/iron-rule.test.ts +118 -0
- package/src/__tests__/push.test.ts +152 -7
- package/src/push.ts +49 -18
- package/src/transport.ts +1 -1
|
@@ -273,17 +273,24 @@ object SentoriPush {
|
|
|
273
273
|
*/
|
|
274
274
|
private fun identityChanged(appContext: Context) {
|
|
275
275
|
val config = SentoriConfig.current ?: return
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
276
|
+
// Everything, including the preference reads, on the worker.
|
|
277
|
+
// `Sentori.user` is synchronous and is called from wherever
|
|
278
|
+
// the host signs someone in — usually the main thread — and
|
|
279
|
+
// reading preferences there is disk I/O on the thread that
|
|
280
|
+
// draws frames. Warm in practice, since this listener is only
|
|
281
|
+
// installed after a registration has already touched them; on
|
|
282
|
+
// the worker it cannot be anything else.
|
|
283
|
+
worker.execute {
|
|
284
|
+
val prefs = appContext.getSharedPreferences(PREFS, Context.MODE_PRIVATE)
|
|
285
|
+
val token = prefs.getString(TOKEN_KEY, null) ?: return@execute
|
|
286
|
+
if (prefs.getString(HANDLE_KEY, null) == null) return@execute
|
|
279
287
|
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
288
|
+
// `Sentori.user` is a verb an app may call on every screen,
|
|
289
|
+
// and one request per call is not free to a host.
|
|
290
|
+
val identity = "${SentoriScope.userKey}\u0000${SentoriScope.traits}"
|
|
291
|
+
if (identity == lastSentIdentity) return@execute
|
|
292
|
+
lastSentIdentity = identity
|
|
285
293
|
|
|
286
|
-
worker.execute {
|
|
287
294
|
when (val r = registerWithServer(appContext, token, config)) {
|
|
288
295
|
is Result.Success -> rememberHandle(appContext, r.handle, token)
|
|
289
296
|
is Result.Failure -> {
|
|
@@ -319,6 +326,9 @@ object SentoriPush {
|
|
|
319
326
|
}
|
|
320
327
|
}
|
|
321
328
|
|
|
329
|
+
/** Hand one drained batch to the host's callbacks, for tests. */
|
|
330
|
+
internal fun drainForTests(state: Map<String, Any?>) = flush(state)
|
|
331
|
+
|
|
322
332
|
/** This installation's id, minted on first use and kept after. */
|
|
323
333
|
internal fun installId(ctx: Context): String {
|
|
324
334
|
val prefs = ctx.applicationContext.getSharedPreferences(PREFS, Context.MODE_PRIVATE)
|
|
@@ -350,7 +360,12 @@ object SentoriPush {
|
|
|
350
360
|
"push register failed (${result.reason.reason}): ${result.message}",
|
|
351
361
|
)
|
|
352
362
|
}
|
|
353
|
-
|
|
363
|
+
// The host's callback is the host's code. A registration that
|
|
364
|
+
// succeeded must not be undone by what the host does with the
|
|
365
|
+
// news, and this runs on the single worker thread — an
|
|
366
|
+
// exception here takes the thread, and with it every push
|
|
367
|
+
// request the process makes afterwards.
|
|
368
|
+
safely("register callback") { completion(result) }
|
|
354
369
|
}
|
|
355
370
|
|
|
356
371
|
private fun finishRegister(
|
|
@@ -439,7 +454,7 @@ object SentoriPush {
|
|
|
439
454
|
val ok =
|
|
440
455
|
try {
|
|
441
456
|
conn =
|
|
442
|
-
URL("${config.ingestUrl}/v1/push/
|
|
457
|
+
URL("${config.ingestUrl}/v1/push/devices/$handle").openConnection()
|
|
443
458
|
as HttpURLConnection
|
|
444
459
|
conn.requestMethod = "DELETE"
|
|
445
460
|
conn.setRequestProperty("Authorization", "Bearer ${config.token}")
|
|
@@ -507,7 +522,7 @@ object SentoriPush {
|
|
|
507
522
|
var conn: HttpURLConnection? = null
|
|
508
523
|
return try {
|
|
509
524
|
conn =
|
|
510
|
-
URL("${config.ingestUrl}/v1/push/
|
|
525
|
+
URL("${config.ingestUrl}/v1/push/devices").openConnection() as HttpURLConnection
|
|
511
526
|
conn.requestMethod = "POST"
|
|
512
527
|
conn.setRequestProperty("Content-Type", "application/json")
|
|
513
528
|
conn.setRequestProperty("Authorization", "Bearer ${config.token}")
|
|
@@ -527,15 +542,9 @@ object SentoriPush {
|
|
|
527
542
|
// The handle is the `device_tokens` row id, a bare
|
|
528
543
|
// uuid. The RN SDK parsed it as an `ipt_*` string no
|
|
529
544
|
// server has ever returned.
|
|
530
|
-
//
|
|
531
|
-
// server shipped under. Reading the new one first and
|
|
532
|
-
// falling back matters in one direction that is easy
|
|
533
|
-
// to miss: a self-hosted deployment upgrades on its
|
|
534
|
-
// own schedule, so an SDK newer than its server is an
|
|
535
|
-
// ordinary state, and an SDK that only knew the new
|
|
536
|
-
// name would fail every registration against it.
|
|
545
|
+
// The address, by its one name.
|
|
537
546
|
val json = JSONObject(text)
|
|
538
|
-
val handle = json.optString("spToken")
|
|
547
|
+
val handle = json.optString("spToken")
|
|
539
548
|
if (handle.isNullOrEmpty()) {
|
|
540
549
|
Result.Failure(Failure.SERVER_REJECTED, "server returned no device token id")
|
|
541
550
|
} else {
|
|
@@ -558,7 +567,11 @@ object SentoriPush {
|
|
|
558
567
|
if (drainTask != null) return
|
|
559
568
|
drainTask =
|
|
560
569
|
worker.scheduleWithFixedDelay(
|
|
561
|
-
|
|
570
|
+
// Belt as well as braces: `flush` contains the
|
|
571
|
+
// host's code, and this contains everything else,
|
|
572
|
+
// because a task that throws is a task the
|
|
573
|
+
// executor never runs again.
|
|
574
|
+
{ safely("drain") { flush(SentoriPushNotifications.drainState()) } },
|
|
562
575
|
1,
|
|
563
576
|
1,
|
|
564
577
|
TimeUnit.SECONDS,
|
|
@@ -567,11 +580,36 @@ object SentoriPush {
|
|
|
567
580
|
}
|
|
568
581
|
|
|
569
582
|
@Suppress("UNCHECKED_CAST")
|
|
583
|
+
/**
|
|
584
|
+
* Hand a drained batch to the host, without letting the host reach
|
|
585
|
+
* back.
|
|
586
|
+
*
|
|
587
|
+
* Push is allowed to fail silently; it is never allowed to make
|
|
588
|
+
* the host app fail. The handlers are the host's own code running
|
|
589
|
+
* inside our loop, and the loop is a `scheduleWithFixedDelay` —
|
|
590
|
+
* where an exception out of the task makes the executor **cancel
|
|
591
|
+
* every future run**, silently. One throwing `onMessage` ended
|
|
592
|
+
* push delivery for the life of the process, and nothing anywhere
|
|
593
|
+
* said so.
|
|
594
|
+
*/
|
|
570
595
|
private fun flush(state: Map<String, Any?>) {
|
|
571
596
|
val (message, tap) = synchronized(lock) { onMessage to onTap }
|
|
572
597
|
if (message == null && tap == null) return
|
|
573
|
-
(state["notifications"] as? List<Map<String, Any?>>)?.forEach {
|
|
574
|
-
|
|
598
|
+
(state["notifications"] as? List<Map<String, Any?>>)?.forEach {
|
|
599
|
+
safely("onMessage") { message?.invoke(it) }
|
|
600
|
+
}
|
|
601
|
+
(state["taps"] as? List<Map<String, Any?>>)?.forEach {
|
|
602
|
+
safely("onTap") { tap?.invoke(it) }
|
|
603
|
+
}
|
|
604
|
+
}
|
|
605
|
+
|
|
606
|
+
/** Run the host's own code without letting it reach back into ours. */
|
|
607
|
+
private inline fun safely(what: String, body: () -> Unit) {
|
|
608
|
+
try {
|
|
609
|
+
body()
|
|
610
|
+
} catch (t: Throwable) {
|
|
611
|
+
android.util.Log.w("sentori", "push $what threw — carrying on", t)
|
|
612
|
+
}
|
|
575
613
|
}
|
|
576
614
|
|
|
577
615
|
internal fun resetForTests() {
|
|
@@ -525,7 +525,7 @@ class SentoriPushTest {
|
|
|
525
525
|
}
|
|
526
526
|
bodies.add(String(body, 0, read, Charsets.UTF_8))
|
|
527
527
|
val payload =
|
|
528
|
-
"""{"spToken":"019ff000-0000-7000-8000-000000000001","
|
|
528
|
+
"""{"spToken":"019ff000-0000-7000-8000-000000000001","isNew":false}"""
|
|
529
529
|
c.getOutputStream().write(
|
|
530
530
|
("HTTP/1.1 202 Accepted\r\nContent-Type: application/json\r\n" +
|
|
531
531
|
"Content-Length: ${payload.toByteArray().size}\r\n" +
|
|
@@ -704,4 +704,73 @@ class SentoriPushTest {
|
|
|
704
704
|
assertEquals(0, rec.bodies.size)
|
|
705
705
|
}
|
|
706
706
|
}
|
|
707
|
+
|
|
708
|
+
/**
|
|
709
|
+
* Push is allowed to fail silently. It is never allowed to make
|
|
710
|
+
* the host app fail.
|
|
711
|
+
*
|
|
712
|
+
* The host's own handlers are the sharp edge: they are its code
|
|
713
|
+
* and they run inside our loop. Worse here than anywhere — the
|
|
714
|
+
* drain is a `scheduleWithFixedDelay`, and an exception out of a
|
|
715
|
+
* scheduled task makes the executor **cancel every future run**,
|
|
716
|
+
* silently. One throwing `onMessage` used to end push delivery for
|
|
717
|
+
* the life of the process, with nothing anywhere to say so.
|
|
718
|
+
*/
|
|
719
|
+
@Test
|
|
720
|
+
fun aThrowingHandlerDoesNotStopDelivery() {
|
|
721
|
+
val ctx = ApplicationProvider.getApplicationContext<android.content.Context>()
|
|
722
|
+
SentoriConfig.set(
|
|
723
|
+
SentoriConfig(token = "st_test", ingestUrl = "http://127.0.0.1:9",
|
|
724
|
+
release = "app@1.0.0", environment = "test"),
|
|
725
|
+
)
|
|
726
|
+
val seen = mutableListOf<String>()
|
|
727
|
+
val latch = CountDownLatch(1)
|
|
728
|
+
SentoriPush.register(
|
|
729
|
+
ctx,
|
|
730
|
+
activity = null,
|
|
731
|
+
timeoutMs = 200,
|
|
732
|
+
onMessage = {
|
|
733
|
+
seen.add(it["title"] as? String ?: "?")
|
|
734
|
+
if (it["title"] == "one") error("the host threw")
|
|
735
|
+
},
|
|
736
|
+
onTap = { seen.add("tap") },
|
|
737
|
+
) { latch.countDown() }
|
|
738
|
+
assertTrue(latch.await(30, TimeUnit.SECONDS))
|
|
739
|
+
|
|
740
|
+
// One bad handler must not swallow the rest of the batch.
|
|
741
|
+
SentoriPush.drainForTests(
|
|
742
|
+
mapOf(
|
|
743
|
+
"notifications" to listOf(
|
|
744
|
+
mapOf("title" to "one"),
|
|
745
|
+
mapOf("title" to "two"),
|
|
746
|
+
),
|
|
747
|
+
"taps" to listOf(mapOf<String, Any?>("tapped" to true)),
|
|
748
|
+
),
|
|
749
|
+
)
|
|
750
|
+
assertEquals(listOf("one", "two", "tap"), seen)
|
|
751
|
+
|
|
752
|
+
// And the next batch still arrives, which is what would have
|
|
753
|
+
// been lost when the executor cancelled the task.
|
|
754
|
+
SentoriPush.drainForTests(
|
|
755
|
+
mapOf("notifications" to listOf(mapOf("title" to "three")), "taps" to null),
|
|
756
|
+
)
|
|
757
|
+
assertEquals(listOf("one", "two", "tap", "three"), seen)
|
|
758
|
+
}
|
|
759
|
+
|
|
760
|
+
/** A host whose completion throws must not take the worker with it. */
|
|
761
|
+
@Test
|
|
762
|
+
fun aThrowingCompletionIsContained() {
|
|
763
|
+
val ctx = ApplicationProvider.getApplicationContext<android.content.Context>()
|
|
764
|
+
SentoriConfig.set(
|
|
765
|
+
SentoriConfig(token = "st_test", ingestUrl = "http://127.0.0.1:9",
|
|
766
|
+
release = "app@1.0.0", environment = "test"),
|
|
767
|
+
)
|
|
768
|
+
val second = CountDownLatch(1)
|
|
769
|
+
SentoriPush.register(ctx, activity = null, timeoutMs = 200) { error("the host threw") }
|
|
770
|
+
Thread.sleep(300)
|
|
771
|
+
// The worker is a single thread. If the first completion took
|
|
772
|
+
// it down, nothing after it ever runs.
|
|
773
|
+
SentoriPush.register(ctx, activity = null, timeoutMs = 200) { second.countDown() }
|
|
774
|
+
assertTrue("the worker did not survive a throwing completion", second.await(30, TimeUnit.SECONDS))
|
|
775
|
+
}
|
|
707
776
|
}
|
package/lib/push.d.ts
CHANGED
|
@@ -80,7 +80,7 @@ export type PushNotificationPayload = {
|
|
|
80
80
|
*/
|
|
81
81
|
export declare function register(opts?: PushRegisterOptions): Promise<PushRegisterResult>;
|
|
82
82
|
/**
|
|
83
|
-
* Revoke the cached handle (DELETE /v1/push/
|
|
83
|
+
* Revoke the cached handle (DELETE /v1/push/devices/{ipt}) +
|
|
84
84
|
* unregister locally. Idempotent — repeat calls are no-ops.
|
|
85
85
|
*/
|
|
86
86
|
export declare function unregister(): Promise<void>;
|
package/lib/push.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"push.d.ts","sourceRoot":"","sources":["../src/push.ts"],"names":[],"mappings":"AAqCA,OAAO,EAEL,aAAa,EAEb,qBAAqB,EAEtB,MAAM,aAAa,CAAA;AAsCpB,MAAM,MAAM,mBAAmB,GAAG;IAChC;;;;;;mEAM+D;IAC/D,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;IAClC;kDAC8C;IAC9C,SAAS,CAAC,EAAE,CAAC,OAAO,EAAE,uBAAuB,KAAK,IAAI,CAAA;IACtD,sDAAsD;IACtD,KAAK,CAAC,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,CAAA;IAC/B;iEAC6D;IAC7D,OAAO,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAA;IAC/B;;yBAEqB;IACrB,OAAO,CAAC,EAAE,CAAC,GAAG,EAAE,KAAK,KAAK,IAAI,CAAA;IAC9B;;;kBAGc;IACd,cAAc,CAAC,EAAE,MAAM,CAAA;CACxB,CAAA;AAED;;;;;;;;;;;;;;GAcG;AACH,MAAM,MAAM,mBAAmB,GAC3B,iBAAiB,GACjB,cAAc,GACd,mBAAmB,GACnB,iBAAiB,GACjB,eAAe,CAAA;AAEnB;;;;mCAImC;AACnC,MAAM,MAAM,kBAAkB,GAC1B;IACE,EAAE,EAAE,IAAI,CAAA;IACR;;oDAEgD;IAChD,GAAG,EAAE,MAAM,CAAA;CACZ,GACD;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,mBAAmB,CAAA;CAAE,CAAA;AAE/D,MAAM,MAAM,uBAAuB,GAAG;IACpC,EAAE,CAAC,EAAE,MAAM,CAAA;IACX,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;IAClC,UAAU,CAAC,EAAE,MAAM,CAAA;CACpB,CAAA;AAED;;;;;;;;;;GAUG;AACH,wBAAsB,QAAQ,CAAC,IAAI,GAAE,mBAAwB,GAAG,OAAO,CAAC,kBAAkB,CAAC,
|
|
1
|
+
{"version":3,"file":"push.d.ts","sourceRoot":"","sources":["../src/push.ts"],"names":[],"mappings":"AAqCA,OAAO,EAEL,aAAa,EAEb,qBAAqB,EAEtB,MAAM,aAAa,CAAA;AAsCpB,MAAM,MAAM,mBAAmB,GAAG;IAChC;;;;;;mEAM+D;IAC/D,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;IAClC;kDAC8C;IAC9C,SAAS,CAAC,EAAE,CAAC,OAAO,EAAE,uBAAuB,KAAK,IAAI,CAAA;IACtD,sDAAsD;IACtD,KAAK,CAAC,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,CAAA;IAC/B;iEAC6D;IAC7D,OAAO,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAA;IAC/B;;yBAEqB;IACrB,OAAO,CAAC,EAAE,CAAC,GAAG,EAAE,KAAK,KAAK,IAAI,CAAA;IAC9B;;;kBAGc;IACd,cAAc,CAAC,EAAE,MAAM,CAAA;CACxB,CAAA;AAED;;;;;;;;;;;;;;GAcG;AACH,MAAM,MAAM,mBAAmB,GAC3B,iBAAiB,GACjB,cAAc,GACd,mBAAmB,GACnB,iBAAiB,GACjB,eAAe,CAAA;AAEnB;;;;mCAImC;AACnC,MAAM,MAAM,kBAAkB,GAC1B;IACE,EAAE,EAAE,IAAI,CAAA;IACR;;oDAEgD;IAChD,GAAG,EAAE,MAAM,CAAA;CACZ,GACD;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,mBAAmB,CAAA;CAAE,CAAA;AAE/D,MAAM,MAAM,uBAAuB,GAAG;IACpC,EAAE,CAAC,EAAE,MAAM,CAAA;IACX,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;IAClC,UAAU,CAAC,EAAE,MAAM,CAAA;CACpB,CAAA;AAED;;;;;;;;;;GAUG;AACH,wBAAsB,QAAQ,CAAC,IAAI,GAAE,mBAAwB,GAAG,OAAO,CAAC,kBAAkB,CAAC,CA6C1F;AAmDD;;;GAGG;AACH,wBAAsB,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC,CAoBhD;AAED;4DAC4D;AAC5D,wBAAgB,YAAY,IAAI,IAAI,GAAG,MAAM,CAE5C;AAED,sDAAsD;AACtD,OAAO,EAAE,aAAa,IAAI,SAAS,EAAE,qBAAqB,IAAI,iBAAiB,EAAE,CAAA;AA+RjF;oEACoE;AACpE,wBAAgB,iBAAiB,CAAC,SAAS,EAAE,IAAI,GAAG,MAAM,GAAG,IAAI,CAEhE;AA4HD;;+DAE+D;AAC/D,wBAAgB,eAAe,IAAI,IAAI,CAWtC;AAID;qCACqC;AACrC,wBAAgB,qBAAqB,CAAC,CAAC,EAAE,KAAK,GAAG,SAAS,GAAG,SAAS,GAAG,IAAI,GAAG,IAAI,CAEnF"}
|
package/lib/push.js
CHANGED
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
// asynchronously and lands in the native buffer.
|
|
11
11
|
// 3. Poll `pushDrainState()` at 200 ms ticks for up to 8 s waiting
|
|
12
12
|
// for the token.
|
|
13
|
-
// 4. POST `/v1/push/
|
|
13
|
+
// 4. POST `/v1/push/devices` with `kind: 'apns' | 'fcm'` — the
|
|
14
14
|
// server's field name; sending `provider` here earned a 422 for
|
|
15
15
|
// every registration this SDK ever attempted — plus
|
|
16
16
|
// `nativeToken`, `userKey`, and `env` on iOS only (FCM is a
|
|
@@ -97,7 +97,11 @@ export async function register(opts = {}) {
|
|
|
97
97
|
_lastNativeToken = token;
|
|
98
98
|
_lastOptions = opts;
|
|
99
99
|
void persistIpt(ipt);
|
|
100
|
-
|
|
100
|
+
// The registration reached the server and came back with a handle.
|
|
101
|
+
// What the host does with it afterwards is not our outcome — this
|
|
102
|
+
// used to sit inside the try, so a throwing `onToken` reported a
|
|
103
|
+
// successful registration as `server-rejected`.
|
|
104
|
+
safely('onToken', () => opts.onToken?.(ipt));
|
|
101
105
|
bindBufferDrain(opts.onMessage, opts.onTap);
|
|
102
106
|
// From here on, signing in or out updates the row by itself.
|
|
103
107
|
onIdentityChange(reRegisterAfterIdentityChange);
|
|
@@ -113,7 +117,10 @@ export async function register(opts = {}) {
|
|
|
113
117
|
* wants a callback, hand back the reason. */
|
|
114
118
|
function fail(opts, reason, message) {
|
|
115
119
|
logger.warn('push', `register failed (${reason}):`, message);
|
|
116
|
-
|
|
120
|
+
// `register()` never throws is the contract, and this is the one
|
|
121
|
+
// path that hands the host an error to look at — so it is also the
|
|
122
|
+
// one place where the host's own code could have broken it.
|
|
123
|
+
safely('onError', () => opts.onError?.(new Error(message)));
|
|
117
124
|
return { ok: false, message, reason };
|
|
118
125
|
}
|
|
119
126
|
/**
|
|
@@ -151,7 +158,7 @@ class PushRegisterError extends Error {
|
|
|
151
158
|
}
|
|
152
159
|
}
|
|
153
160
|
/**
|
|
154
|
-
* Revoke the cached handle (DELETE /v1/push/
|
|
161
|
+
* Revoke the cached handle (DELETE /v1/push/devices/{ipt}) +
|
|
155
162
|
* unregister locally. Idempotent — repeat calls are no-ops.
|
|
156
163
|
*/
|
|
157
164
|
export async function unregister() {
|
|
@@ -159,7 +166,7 @@ export async function unregister() {
|
|
|
159
166
|
const ipt = _cachedIpt ?? (await readPersistedIpt());
|
|
160
167
|
if (cfg && ipt) {
|
|
161
168
|
try {
|
|
162
|
-
await fetch(joinUrl(cfg.ingestUrl, `/v1/push/
|
|
169
|
+
await fetch(joinUrl(cfg.ingestUrl, `/v1/push/devices/${ipt}`), {
|
|
163
170
|
method: 'DELETE',
|
|
164
171
|
headers: { authorization: `Bearer ${cfg.token}` },
|
|
165
172
|
});
|
|
@@ -255,7 +262,7 @@ async function registerWithServer(cfg, nativeToken, opts) {
|
|
|
255
262
|
const traits = currentUserTraits();
|
|
256
263
|
if (traits != null)
|
|
257
264
|
body.traits = traits;
|
|
258
|
-
const res = await fetch(joinUrl(cfg.ingestUrl, '/v1/push/
|
|
265
|
+
const res = await fetch(joinUrl(cfg.ingestUrl, '/v1/push/devices'), {
|
|
259
266
|
method: 'POST',
|
|
260
267
|
headers: {
|
|
261
268
|
authorization: `Bearer ${cfg.token}`,
|
|
@@ -264,16 +271,16 @@ async function registerWithServer(cfg, nativeToken, opts) {
|
|
|
264
271
|
body: JSON.stringify(body),
|
|
265
272
|
});
|
|
266
273
|
if (!res.ok) {
|
|
267
|
-
throw new PushRegisterError('server-rejected', `/v1/push/
|
|
274
|
+
throw new PushRegisterError('server-rejected', `/v1/push/devices HTTP ${res.status}`);
|
|
268
275
|
}
|
|
269
276
|
// The handle is the device_tokens row id — a uuid, which is what
|
|
270
277
|
// the revoke and send routes take. It was parsed here as an
|
|
271
278
|
// `ipt_*` string that no server has ever returned.
|
|
272
279
|
const json = (await res.json());
|
|
273
|
-
if (typeof json.
|
|
280
|
+
if (typeof json.spToken !== 'string' || json.spToken.length === 0) {
|
|
274
281
|
throw new PushRegisterError('server-rejected', 'server did not return a device token id');
|
|
275
282
|
}
|
|
276
|
-
return json.
|
|
283
|
+
return json.spToken;
|
|
277
284
|
}
|
|
278
285
|
function bindBufferDrain(onMessage, onTap) {
|
|
279
286
|
_onMessage = onMessage;
|
|
@@ -300,9 +307,18 @@ function teardownBufferDrain() {
|
|
|
300
307
|
_ackQueue = [];
|
|
301
308
|
}
|
|
302
309
|
async function pumpOnce() {
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
310
|
+
// Nothing in a tick may reject. The caller is `void pumpOnce()` on
|
|
311
|
+
// an interval, so a rejection here is an unhandled rejection in the
|
|
312
|
+
// host's process — a red box in development, and on some setups
|
|
313
|
+
// worse — for something the host is entitled to have fail quietly.
|
|
314
|
+
try {
|
|
315
|
+
const state = await pushDrainState();
|
|
316
|
+
flushBuffered(state.notifications, state.taps);
|
|
317
|
+
await reportRotationIfAny(state.token);
|
|
318
|
+
}
|
|
319
|
+
catch (e) {
|
|
320
|
+
logger.warn('push', 'a drain tick failed — the next one still runs', e);
|
|
321
|
+
}
|
|
306
322
|
}
|
|
307
323
|
/// Tell the server when the vendor has handed the app a different
|
|
308
324
|
/// token from the one it registered with.
|
|
@@ -345,17 +361,33 @@ async function reportRotationIfAny(token) {
|
|
|
345
361
|
logger.warn('push', 'reporting a rotated token failed', e);
|
|
346
362
|
}
|
|
347
363
|
}
|
|
364
|
+
/// Run the host's own code without letting it reach back into ours.
|
|
365
|
+
///
|
|
366
|
+
/// A push that does not arrive is a product decision the host can live
|
|
367
|
+
/// with. An exception out of an SDK it merely opted into is not — and
|
|
368
|
+
/// the host's handlers are the sharp edge here: they are its code,
|
|
369
|
+
/// they run inside our loop, and JavaScript throws for a living. One
|
|
370
|
+
/// throwing handler used to take the rest of the batch with it, then
|
|
371
|
+
/// the tick, then every later tick as an unhandled rejection.
|
|
372
|
+
function safely(what, fn) {
|
|
373
|
+
try {
|
|
374
|
+
fn();
|
|
375
|
+
}
|
|
376
|
+
catch (e) {
|
|
377
|
+
logger.warn('push', `${what} threw — carrying on`, e);
|
|
378
|
+
}
|
|
379
|
+
}
|
|
348
380
|
function flushBuffered(notifications, taps) {
|
|
349
381
|
for (const raw of notifications) {
|
|
350
382
|
// v2.26 — Observability link-through (rule #4). If the server
|
|
351
383
|
// injected `_sentori.msgId` in v2.25+, drop a `push` breadcrumb,
|
|
352
384
|
// emit `sentori.push.received` track, and queue the ack.
|
|
353
|
-
autoCorrelate(raw, 'received');
|
|
354
|
-
_onMessage?.(coerceNotification(raw));
|
|
385
|
+
safely('autoCorrelate', () => autoCorrelate(raw, 'received'));
|
|
386
|
+
safely('onMessage', () => _onMessage?.(coerceNotification(raw)));
|
|
355
387
|
}
|
|
356
388
|
for (const raw of taps) {
|
|
357
|
-
autoCorrelate(raw, 'opened');
|
|
358
|
-
_onTap?.(raw.userInfo ?? raw);
|
|
389
|
+
safely('autoCorrelate', () => autoCorrelate(raw, 'opened'));
|
|
390
|
+
safely('onTap', () => _onTap?.(raw.userInfo ?? raw));
|
|
359
391
|
}
|
|
360
392
|
}
|
|
361
393
|
/** v2.26 — process one drained notification or tap for downstream
|
|
@@ -415,7 +447,7 @@ async function drainAckQueue() {
|
|
|
415
447
|
// the user flow.
|
|
416
448
|
for (const msgId of batch) {
|
|
417
449
|
try {
|
|
418
|
-
await fetch(joinUrl(cfg.ingestUrl, `/v1/push/
|
|
450
|
+
await fetch(joinUrl(cfg.ingestUrl, `/v1/push/deliveries/${msgId}/ack`), {
|
|
419
451
|
body: JSON.stringify({ eventType: 'received', sessionId: _sessionId }),
|
|
420
452
|
headers: {
|
|
421
453
|
authorization: `Bearer ${cfg.token}`,
|
package/lib/push.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"push.js","sourceRoot":"","sources":["../src/push.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"push.js","sourceRoot":"","sources":["../src/push.ts"],"names":[],"mappings":"AAAA,iEAAiE;AACjE,yBAAyB;AACzB,EAAE;AACF,QAAQ;AACR,gEAAgE;AAChE,oCAAoC;AACpC,2CAA2C;AAC3C,kEAAkE;AAClE,qEAAqE;AACrE,sDAAsD;AACtD,qEAAqE;AACrE,sBAAsB;AACtB,iEAAiE;AACjE,qEAAqE;AACrE,yDAAyD;AACzD,iEAAiE;AACjE,yDAAyD;AACzD,2DAA2D;AAC3D,4CAA4C;AAC5C,qEAAqE;AACrE,8DAA8D;AAC9D,8DAA8D;AAE9D,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAA;AAE3D,OAAO,EAAE,cAAc,EAAE,iBAAiB,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAA;AAYhF,OAAO,EACL,cAAc,EACd,aAAa,EACb,YAAY,IAAI,kBAAkB,EAClC,qBAAqB,EACrB,cAAc,IAAI,oBAAoB,GACvC,MAAM,aAAa,CAAA;AAEpB,MAAM,WAAW,GAAG,kBAAkB,CAAA;AACtC,+BAA+B;AAC/B,GAAG;AACH,oEAAoE;AACpE,sEAAsE;AACtE,sEAAsE;AACtE,mEAAmE;AACnE,qEAAqE;AACrE,MAAM,WAAW,GAAG,sBAAsB,CAAA;AAE1C,IAAI,UAAU,GAAkB,IAAI,CAAA;AACpC,qEAAqE;AACrE,4DAA4D;AAC5D,IAAI,gBAAgB,GAAkB,IAAI,CAAA;AAC1C,IAAI,YAAY,GAAwB,EAAE,CAAA;AAC1C,mEAAmE;AACnE,oEAAoE;AACpE,qEAAqE;AACrE,IAAI,iBAAiB,GAAkB,IAAI,CAAA;AAC3C,IAAI,UAAU,GAAkB,IAAI,CAAA;AACpC,IAAI,cAAc,GAA0C,IAAI,CAAA;AAChE,IAAI,qBAAqB,GAAkC,IAAI,CAAA;AAC/D,IAAI,aAAa,GAAG,KAAK,CAAA;AAEzB,IAAI,UAAU,GAAqC,SAAS,CAAA;AAC5D,IAAI,MAAM,GAAiC,SAAS,CAAA;AAEpD,iEAAiE;AACjE,kEAAkE;AAClE,4DAA4D;AAC5D,sDAAsD;AACtD,MAAM,qBAAqB,GAAG,IAAI,CAAA;AAClC,IAAI,SAAS,GAAa,EAAE,CAAA;AAC5B,IAAI,iBAAiB,GAA0C,IAAI,CAAA;AACnE,IAAI,UAAU,GAAkB,IAAI,CAAA;AA6EpC;;;;;;;;;;GAUG;AACH,MAAM,CAAC,KAAK,UAAU,QAAQ,CAAC,IAAI,GAAwB,EAAE;IAC3D,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,mBAAmB,EAAE,CAAA;QACjC,IAAI,CAAC,GAAG,EAAE,CAAC;YACT,OAAO,IAAI,CAAC,IAAI,EAAE,iBAAiB,EAAE,4BAA4B,CAAC,CAAA;QACpE,CAAC;QACD,qDAAqD;QACrD,iEAAiE;QACjE,8DAA8D;QAC9D,wDAAwD;QACxD,oBAAoB;QACpB,UAAU,GAAG,IAAI,CAAC,SAAS,CAAA;QAC3B,MAAM,GAAG,IAAI,CAAC,KAAK,CAAA;QACnB,MAAM,MAAM,GAAG,MAAM,qBAAqB,EAAE,CAAA;QAC5C,+DAA+D;QAC/D,6DAA6D;QAC7D,+DAA+D;QAC/D,yBAAyB;QACzB,IAAI,MAAM,IAAI,IAAI,EAAE,CAAC;YACnB,OAAO,IAAI,CAAC,IAAI,EAAE,cAAc,EAAE,qCAAqC,CAAC,CAAA;QAC1E,CAAC;QACD,IAAI,MAAM,KAAK,SAAS,IAAI,MAAM,KAAK,aAAa,IAAI,MAAM,KAAK,WAAW,EAAE,CAAC;YAC/E,OAAO,IAAI,CAAC,IAAI,EAAE,mBAAmB,EAAE,oBAAoB,MAAM,GAAG,CAAC,CAAA;QACvE,CAAC;QACD,kBAAkB,EAAE,CAAA;QACpB,MAAM,KAAK,GAAG,MAAM,YAAY,CAAC,IAAI,CAAC,cAAc,IAAI,IAAI,CAAC,CAAA;QAC7D,MAAM,GAAG,GAAG,MAAM,kBAAkB,CAAC,GAAG,EAAE,KAAK,EAAE,IAAI,CAAC,CAAA;QACtD,UAAU,GAAG,GAAG,CAAA;QAChB,gBAAgB,GAAG,KAAK,CAAA;QACxB,YAAY,GAAG,IAAI,CAAA;QACnB,KAAK,UAAU,CAAC,GAAG,CAAC,CAAA;QACpB,mEAAmE;QACnE,kEAAkE;QAClE,iEAAiE;QACjE,gDAAgD;QAChD,MAAM,CAAC,SAAS,EAAE,GAAG,EAAE,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC,GAAG,CAAC,CAAC,CAAA;QAC5C,eAAe,CAAC,IAAI,CAAC,SAAS,EAAE,IAAI,CAAC,KAAK,CAAC,CAAA;QAC3C,6DAA6D;QAC7D,gBAAgB,CAAC,6BAA6B,CAAC,CAAA;QAC/C,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,GAAG,EAAE,CAAA;IAC1B,CAAC;IAAC,OAAO,CAAC,EAAE,CAAC;QACX,MAAM,GAAG,GAAG,CAAC,YAAY,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAA;QACzD,MAAM,MAAM,GAAG,CAAC,YAAY,iBAAiB,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,iBAAiB,CAAA;QAC5E,OAAO,IAAI,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,CAAC,OAAO,CAAC,CAAA;IACxC,CAAC;AACH,CAAC;AAED;8CAC8C;AAC9C,SAAS,IAAI,CACX,IAAyB,EACzB,MAA2B,EAC3B,OAAe;IAEf,MAAM,CAAC,IAAI,CAAC,MAAM,EAAE,oBAAoB,MAAM,IAAI,EAAE,OAAO,CAAC,CAAA;IAC5D,iEAAiE;IACjE,mEAAmE;IACnE,4DAA4D;IAC5D,MAAM,CAAC,SAAS,EAAE,GAAG,EAAE,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC,IAAI,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,CAAA;IAC3D,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,OAAO,EAAE,MAAM,EAAE,CAAA;AACvC,CAAC;AAED;;;;;;;GAOG;AACH,SAAS,6BAA6B;IACpC,MAAM,KAAK,GAAG,gBAAgB,CAAA;IAC9B,MAAM,GAAG,GAAG,mBAAmB,EAAE,CAAA;IACjC,IAAI,KAAK,IAAI,IAAI,IAAI,GAAG,IAAI,IAAI;QAAE,OAAM;IACxC,MAAM,QAAQ,GAAG,IAAI,CAAC,SAAS,CAAC,CAAC,cAAc,EAAE,IAAI,IAAI,EAAE,iBAAiB,EAAE,IAAI,IAAI,CAAC,CAAC,CAAA;IACxF,IAAI,QAAQ,KAAK,iBAAiB;QAAE,OAAM;IAC1C,iBAAiB,GAAG,QAAQ,CAAA;IAC5B,KAAK,kBAAkB,CAAC,GAAG,EAAE,KAAK,EAAE,YAAY,CAAC,CAAC,KAAK,CAAC,CAAC,CAAU,EAAE,EAAE;QACrE,kEAAkE;QAClE,mDAAmD;QACnD,iBAAiB,GAAG,IAAI,CAAA;QACxB,MAAM,CAAC,IAAI,CAAC,MAAM,EAAE,4CAA4C,EAAE,CAAC,CAAC,CAAA;IACtE,CAAC,CAAC,CAAA;AACJ,CAAC;AAED;+DAC+D;AAC/D,MAAM,iBAAkB,SAAQ,KAAK;IAC1B,MAAM,CAAqB;IACpC,YAAY,MAA2B,EAAE,OAAe;QACtD,KAAK,CAAC,OAAO,CAAC,CAAA;QACd,IAAI,CAAC,IAAI,GAAG,mBAAmB,CAAA;QAC/B,IAAI,CAAC,MAAM,GAAG,MAAM,CAAA;IACtB,CAAC;CACF;AAED;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,UAAU;IAC9B,MAAM,GAAG,GAAG,mBAAmB,EAAE,CAAA;IACjC,MAAM,GAAG,GAAG,UAAU,IAAI,CAAC,MAAM,gBAAgB,EAAE,CAAC,CAAA;IACpD,IAAI,GAAG,IAAI,GAAG,EAAE,CAAC;QACf,IAAI,CAAC;YACH,MAAM,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,SAAS,EAAE,oBAAoB,GAAG,EAAE,CAAC,EAAE;gBAC7D,MAAM,EAAE,QAAQ;gBAChB,OAAO,EAAE,EAAE,aAAa,EAAE,UAAU,GAAG,CAAC,KAAK,EAAE,EAAE;aAClD,CAAC,CAAA;QACJ,CAAC;QAAC,OAAO,CAAC,EAAE,CAAC;YACX,MAAM,CAAC,IAAI,CAAC,MAAM,EAAE,iCAAiC,EAAE,CAAC,CAAC,CAAA;QAC3D,CAAC;IACH,CAAC;IACD,oBAAoB,EAAE,CAAA;IACtB,gBAAgB,CAAC,SAAS,CAAC,CAAA;IAC3B,gBAAgB,GAAG,IAAI,CAAA;IACvB,iBAAiB,GAAG,IAAI,CAAA;IACxB,UAAU,GAAG,IAAI,CAAA;IACjB,KAAK,iBAAiB,EAAE,CAAA;IACxB,mBAAmB,EAAE,CAAA;AACvB,CAAC;AAED;4DAC4D;AAC5D,MAAM,UAAU,YAAY;IAC1B,OAAO,UAAU,CAAA;AACnB,CAAC;AAED,sDAAsD;AACtD,OAAO,EAAE,aAAa,IAAI,SAAS,EAAE,qBAAqB,IAAI,iBAAiB,EAAE,CAAA;AAMjF,SAAS,mBAAmB;IAC1B,8DAA8D;IAC9D,0DAA0D;IAC1D,IAAI,CAAC;QACH,MAAM,IAAI,GAAG,OAAO,CAAC,aAAa,CAA+C,CAAA;QACjF,OAAO,IAAI,CAAC,SAAS,EAAE,EAAE,IAAI,IAAI,CAAA;IACnC,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAA;IACb,CAAC;AACH,CAAC;AAED,KAAK,UAAU,YAAY,CAAC,SAAiB;IAC3C,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,EAAE,CAAA;IACxB,OAAO,IAAI,CAAC,GAAG,EAAE,GAAG,KAAK,GAAG,SAAS,EAAE,CAAC;QACtC,MAAM,KAAK,GAAG,MAAM,cAAc,EAAE,CAAA;QACpC,IAAI,KAAK,CAAC,KAAK,EAAE,CAAC;YAChB,MAAM,IAAI,iBAAiB,CAAC,cAAc,EAAE,2BAA2B,KAAK,CAAC,KAAK,EAAE,CAAC,CAAA;QACvF,CAAC;QACD,IAAI,KAAK,CAAC,KAAK,EAAE,CAAC;YAChB,4DAA4D;YAC5D,wDAAwD;YACxD,aAAa,CAAC,KAAK,CAAC,aAAa,EAAE,KAAK,CAAC,IAAI,CAAC,CAAA;YAC9C,OAAO,KAAK,CAAC,KAAK,CAAA;QACpB,CAAC;QACD,aAAa,CAAC,KAAK,CAAC,aAAa,EAAE,KAAK,CAAC,IAAI,CAAC,CAAA;QAC9C,MAAM,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,UAAU,CAAC,OAAO,EAAE,GAAG,CAAC,CAAC,CAAA;IAC1D,CAAC;IACD,MAAM,IAAI,iBAAiB,CAAC,eAAe,EAAE,0BAA0B,SAAS,KAAK,CAAC,CAAA;AACxF,CAAC;AAED,KAAK,UAAU,kBAAkB,CAC/B,GAAkB,EAClB,WAAmB,EACnB,IAAyB;IAEzB,qDAAqD;IACrD,6DAA6D;IAC7D,6DAA6D;IAC7D,sCAAsC;IACtC,MAAM,QAAQ,GAAG,cAAc,EAAE,CAAA;IACjC,MAAM,SAAS,GAAG,QAAQ,KAAK,SAAS,CAAA;IACxC,MAAM,GAAG,GAAG,SAAS;QACnB,CAAC,CAAC,SAAS;QACX,CAAC,CAAC,OAAO,OAAO,KAAK,WAAW,IAAI,OAAO;YACzC,CAAC,CAAC,SAAS;YACX,CAAC,CAAC,YAAY,CAAA;IAClB,+DAA+D;IAC/D,8DAA8D;IAC9D,MAAM,IAAI,GAA4B;QACpC,kEAAkE;QAClE,kEAAkE;QAClE,2BAA2B;QAC3B,SAAS,EAAE,MAAM,SAAS,EAAE;QAC5B,IAAI,EAAE,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM;QAChC,WAAW;QACX,4DAA4D;QAC5D,2DAA2D;QAC3D,uDAAuD;QACvD,OAAO,EAAE,cAAc,EAAE;KAC1B,CAAA;IACD,IAAI,GAAG,IAAI,IAAI;QAAE,IAAI,CAAC,GAAG,GAAG,GAAG,CAAA;IAC/B,gEAAgE;IAChE,mEAAmE;IACnE,iEAAiE;IACjE,oEAAoE;IACpE,oEAAoE;IACpE,qBAAqB;IACrB,IAAI,IAAI,CAAC,QAAQ,IAAI,IAAI;QAAE,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC,QAAQ,CAAA;IACxD,oEAAoE;IACpE,qEAAqE;IACrE,oEAAoE;IACpE,mCAAmC;IACnC,MAAM,MAAM,GAAG,iBAAiB,EAAE,CAAA;IAClC,IAAI,MAAM,IAAI,IAAI;QAAE,IAAI,CAAC,MAAM,GAAG,MAAM,CAAA;IACxC,MAAM,GAAG,GAAG,MAAM,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,SAAS,EAAE,kBAAkB,CAAC,EAAE;QAClE,MAAM,EAAE,MAAM;QACd,OAAO,EAAE;YACP,aAAa,EAAE,UAAU,GAAG,CAAC,KAAK,EAAE;YACpC,cAAc,EAAE,kBAAkB;SACnC;QACD,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC;KAC3B,CAAC,CAAA;IACF,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC;QACZ,MAAM,IAAI,iBAAiB,CAAC,iBAAiB,EAAE,yBAAyB,GAAG,CAAC,MAAM,EAAE,CAAC,CAAA;IACvF,CAAC;IACD,iEAAiE;IACjE,4DAA4D;IAC5D,mDAAmD;IACnD,MAAM,IAAI,GAAG,CAAC,MAAM,GAAG,CAAC,IAAI,EAAE,CAAyB,CAAA;IACvD,IAAI,OAAO,IAAI,CAAC,OAAO,KAAK,QAAQ,IAAI,IAAI,CAAC,OAAO,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAClE,MAAM,IAAI,iBAAiB,CAAC,iBAAiB,EAAE,yCAAyC,CAAC,CAAA;IAC3F,CAAC;IACD,OAAO,IAAI,CAAC,OAAO,CAAA;AACrB,CAAC;AAED,SAAS,eAAe,CACtB,SAA4C,EAC5C,KAAoC;IAEpC,UAAU,GAAG,SAAS,CAAA;IACtB,MAAM,GAAG,KAAK,CAAA;IACd,mBAAmB,EAAE,CAAA;IACrB,kBAAkB,EAAE,CAAA;IACpB,cAAc,GAAG,WAAW,CAAC,GAAG,EAAE;QAChC,IAAI,aAAa;YAAE,OAAM;QACzB,KAAK,QAAQ,EAAE,CAAA;IACjB,CAAC,EAAE,IAAI,CAAC,CAAA;AACV,CAAC;AAED,SAAS,mBAAmB;IAC1B,IAAI,cAAc,EAAE,CAAC;QACnB,aAAa,CAAC,cAAc,CAAC,CAAA;QAC7B,cAAc,GAAG,IAAI,CAAA;IACvB,CAAC;IACD,qBAAqB,EAAE,MAAM,EAAE,CAAA;IAC/B,qBAAqB,GAAG,IAAI,CAAA;IAC5B,IAAI,iBAAiB,EAAE,CAAC;QACtB,aAAa,CAAC,iBAAiB,CAAC,CAAA;QAChC,iBAAiB,GAAG,IAAI,CAAA;IAC1B,CAAC;IACD,SAAS,GAAG,EAAE,CAAA;AAChB,CAAC;AAED,KAAK,UAAU,QAAQ;IACrB,mEAAmE;IACnE,oEAAoE;IACpE,gEAAgE;IAChE,mEAAmE;IACnE,IAAI,CAAC;QACH,MAAM,KAAK,GAAG,MAAM,cAAc,EAAE,CAAA;QACpC,aAAa,CAAC,KAAK,CAAC,aAAa,EAAE,KAAK,CAAC,IAAI,CAAC,CAAA;QAC9C,MAAM,mBAAmB,CAAC,KAAK,CAAC,KAAK,CAAC,CAAA;IACxC,CAAC;IAAC,OAAO,CAAC,EAAE,CAAC;QACX,MAAM,CAAC,IAAI,CAAC,MAAM,EAAE,+CAA+C,EAAE,CAAC,CAAC,CAAA;IACzE,CAAC;AACH,CAAC;AAED,kEAAkE;AAClE,0CAA0C;AAC1C,GAAG;AACH,iEAAiE;AACjE,kEAAkE;AAClE,gEAAgE;AAChE,qEAAqE;AACrE,sEAAsE;AACtE,2DAA2D;AAC3D,sEAAsE;AACtE,SAAS;AACT,GAAG;AACH,sEAAsE;AACtE,sEAAsE;AACtE,qEAAqE;AACrE,+CAA+C;AAC/C,KAAK,UAAU,mBAAmB,CAAC,KAAyB;IAC1D,IAAI,KAAK,IAAI,IAAI,IAAI,KAAK,KAAK,EAAE,IAAI,KAAK,KAAK,gBAAgB;QAAE,OAAM;IACvE,mEAAmE;IACnE,kEAAkE;IAClE,2BAA2B;IAC3B,IAAI,gBAAgB,IAAI,IAAI;QAAE,OAAM;IACpC,MAAM,GAAG,GAAG,mBAAmB,EAAE,CAAA;IACjC,IAAI,GAAG,IAAI,IAAI;QAAE,OAAM;IACvB,MAAM,QAAQ,GAAG,gBAAgB,CAAA;IACjC,gBAAgB,GAAG,KAAK,CAAA;IACxB,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,MAAM,kBAAkB,CAAC,GAAG,EAAE,KAAK,EAAE,YAAY,CAAC,CAAA;QAC9D,UAAU,GAAG,GAAG,CAAA;QAChB,KAAK,UAAU,CAAC,GAAG,CAAC,CAAA;IACtB,CAAC;IAAC,OAAO,CAAC,EAAE,CAAC;QACX,gEAAgE;QAChE,0DAA0D;QAC1D,gBAAgB,GAAG,QAAQ,CAAA;QAC3B,MAAM,CAAC,IAAI,CAAC,MAAM,EAAE,kCAAkC,EAAE,CAAC,CAAC,CAAA;IAC5D,CAAC;AACH,CAAC;AAED,oEAAoE;AACpE,GAAG;AACH,uEAAuE;AACvE,sEAAsE;AACtE,mEAAmE;AACnE,qEAAqE;AACrE,qEAAqE;AACrE,8DAA8D;AAC9D,SAAS,MAAM,CAAC,IAAY,EAAE,EAAc;IAC1C,IAAI,CAAC;QACH,EAAE,EAAE,CAAA;IACN,CAAC;IAAC,OAAO,CAAC,EAAE,CAAC;QACX,MAAM,CAAC,IAAI,CAAC,MAAM,EAAE,GAAG,IAAI,sBAAsB,EAAE,CAAC,CAAC,CAAA;IACvD,CAAC;AACH,CAAC;AAED,SAAS,aAAa,CACpB,aAA6C,EAC7C,IAAoC;IAEpC,KAAK,MAAM,GAAG,IAAI,aAAa,EAAE,CAAC;QAChC,8DAA8D;QAC9D,iEAAiE;QACjE,yDAAyD;QACzD,MAAM,CAAC,eAAe,EAAE,GAAG,EAAE,CAAC,aAAa,CAAC,GAAG,EAAE,UAAU,CAAC,CAAC,CAAA;QAC7D,MAAM,CAAC,WAAW,EAAE,GAAG,EAAE,CAAC,UAAU,EAAE,CAAC,kBAAkB,CAAC,GAAG,CAAC,CAAC,CAAC,CAAA;IAClE,CAAC;IACD,KAAK,MAAM,GAAG,IAAI,IAAI,EAAE,CAAC;QACvB,MAAM,CAAC,eAAe,EAAE,GAAG,EAAE,CAAC,aAAa,CAAC,GAAG,EAAE,QAAQ,CAAC,CAAC,CAAA;QAC3D,MAAM,CAAC,OAAO,EAAE,GAAG,EAAE,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,QAAQ,IAAI,GAAG,CAAC,CAAC,CAAA;IACtD,CAAC;AACH,CAAC;AAED;;8DAE8D;AAC9D,SAAS,aAAa,CACpB,GAA4B,EAC5B,SAAgC;IAEhC,MAAM,QAAQ,GAAI,GAAG,CAAC,QAAgD,IAAI,GAAG,CAAA;IAC7E,MAAM,OAAO,GAAI,QAAQ,CAAC,QAAgD,IAAI,SAAS,CAAA;IACvF,MAAM,KAAK,GAAG,OAAO,OAAO,EAAE,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,SAAS,CAAA;IAC5E,IAAI,CAAC,KAAK;QAAE,OAAM;IAElB,MAAM,QAAQ,GAAG,aAAa,CAAC,GAAG,CAAC,CAAA;IACnC,MAAM,KAAK,GAAG,OAAO,GAAG,CAAC,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,SAAS,CAAA;IACnE,MAAM,IAAI,GAAG,OAAO,GAAG,CAAC,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,SAAS,CAAA;IAEhE,+DAA+D;IAC/D,6DAA6D;IAC7D,0CAA0C;IAC1C,UAAU,CAAC,MAAM,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,KAAK,EAAE,MAAM,EAAE,SAAS,KAAK,QAAQ,EAAE,QAAQ,EAAE,KAAK,EAAE,CAAC,CAAA;IAE/F,2DAA2D;IAC3D,gEAAgE;IAChE,MAAM,SAAS,GAAG,SAAS,KAAK,QAAQ,CAAC,CAAC,CAAC,qBAAqB,CAAC,CAAC,CAAC,uBAAuB,CAAA;IAC1F,4CAA4C;IAC5C,UAAU,CAAC,KAAK,CAAC,CAAA;AACnB,CAAC;AAED,SAAS,aAAa,CAAC,GAA4B;IACjD,IAAI,OAAO,GAAG,CAAC,QAAQ,KAAK,QAAQ;QAAE,OAAO,GAAG,CAAC,QAAQ,CAAA;IACzD,oEAAoE;IACpE,mEAAmE;IACnE,yBAAyB;IACzB,IAAI,GAAG,CAAC,IAAI;QAAE,OAAO,KAAK,CAAA;IAC1B,IAAI,GAAG,CAAC,QAAQ;QAAE,OAAO,MAAM,CAAA;IAC/B,OAAO,SAAS,CAAA;AAClB,CAAC;AAED,SAAS,UAAU,CAAC,KAAa;IAC/B,IAAI,SAAS,CAAC,QAAQ,CAAC,KAAK,CAAC;QAAE,OAAM;IACrC,SAAS,CAAC,IAAI,CAAC,KAAK,CAAC,CAAA;IACrB,IAAI,CAAC,iBAAiB,EAAE,CAAC;QACvB,iBAAiB,GAAG,WAAW,CAAC,GAAG,EAAE;YACnC,KAAK,aAAa,EAAE,CAAA;QACtB,CAAC,EAAE,qBAAqB,CAAC,CAAA;IAC3B,CAAC;AACH,CAAC;AAED,KAAK,UAAU,aAAa;IAC1B,IAAI,SAAS,CAAC,MAAM,KAAK,CAAC;QAAE,OAAM;IAClC,MAAM,GAAG,GAAG,mBAAmB,EAAE,CAAA;IACjC,IAAI,CAAC,GAAG;QAAE,OAAM;IAChB,MAAM,KAAK,GAAG,SAAS,CAAC,MAAM,CAAC,CAAC,EAAE,SAAS,CAAC,MAAM,CAAC,CAAA;IACnD,8DAA8D;IAC9D,8DAA8D;IAC9D,+DAA+D;IAC/D,iBAAiB;IACjB,KAAK,MAAM,KAAK,IAAI,KAAK,EAAE,CAAC;QAC1B,IAAI,CAAC;YACH,MAAM,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,SAAS,EAAE,uBAAuB,KAAK,MAAM,CAAC,EAAE;gBACtE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,SAAS,EAAE,UAAU,EAAE,SAAS,EAAE,UAAU,EAAE,CAAC;gBACtE,OAAO,EAAE;oBACP,aAAa,EAAE,UAAU,GAAG,CAAC,KAAK,EAAE;oBACpC,cAAc,EAAE,kBAAkB;iBACnC;gBACD,MAAM,EAAE,MAAM;aACf,CAAC,CAAA;QACJ,CAAC;QAAC,MAAM,CAAC;YACP,yBAAyB;QAC3B,CAAC;IACH,CAAC;AACH,CAAC;AAED;oEACoE;AACpE,MAAM,UAAU,iBAAiB,CAAC,SAAwB;IACxD,UAAU,GAAG,SAAS,CAAA;AACxB,CAAC;AAED,SAAS,kBAAkB,CAAC,GAA4B;IACtD,OAAO;QACL,EAAE,EAAE,GAAG,CAAC,EAAwB;QAChC,KAAK,EAAE,GAAG,CAAC,KAA2B;QACtC,IAAI,EAAE,GAAG,CAAC,IAA0B;QACpC,QAAQ,EAAE,GAAG,CAAC,QAA8B;QAC5C,QAAQ,EAAE,GAAG,CAAC,QAA8B;QAC5C,QAAQ,EAAE,GAAG,CAAC,QAA+C;QAC7D,UAAU,EAAE,GAAG,CAAC,UAAgC;KACjD,CAAA;AACH,CAAC;AAED,SAAS,kBAAkB;IACzB,IAAI,qBAAqB;QAAE,OAAM;IACjC,IAAI,CAAC;QACH,MAAM,EAAE,GAAG,OAAO,CAAC,cAAc,CAAkC,CAAA;QACnE,MAAM,QAAQ,GAAG,EAAE,CAAC,QAAQ,CAAA;QAC5B,IAAI,CAAC,QAAQ;YAAE,OAAM;QACrB,aAAa,GAAG,QAAQ,CAAC,YAAY,KAAK,YAAY,CAAA;QACtD,qBAAqB,GAAG,QAAQ,CAAC,gBAAgB,CAAC,QAAQ,EAAE,CAAC,KAAa,EAAE,EAAE;YAC5E,aAAa,GAAG,KAAK,KAAK,YAAY,CAAA;QACxC,CAAC,CAAC,CAAA;IACJ,CAAC;IAAC,MAAM,CAAC;QACP,0CAA0C;IAC5C,CAAC;AACH,CAAC;AAED,+DAA+D;AAC/D,GAAG;AACH,sEAAsE;AACtE,sEAAsE;AACtE,kEAAkE;AAClE,uBAAuB;AACvB,KAAK,UAAU,SAAS;IACtB,IAAI,UAAU,IAAI,IAAI;QAAE,OAAO,UAAU,CAAA;IACzC,MAAM,OAAO,GAAG,MAAM,eAAe,EAAE,CAAA;IACvC,IAAI,OAAO,EAAE,CAAC;QACZ,IAAI,CAAC;YACH,MAAM,IAAI,GAAG,MAAM,OAAO,CAAC,OAAO,CAAC,WAAW,CAAC,CAAA;YAC/C,IAAI,OAAO,IAAI,KAAK,QAAQ,IAAI,IAAI,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gBAChD,UAAU,GAAG,IAAI,CAAA;gBACjB,OAAO,IAAI,CAAA;YACb,CAAC;QACH,CAAC;QAAC,MAAM,CAAC;YACP,qDAAqD;QACvD,CAAC;IACH,CAAC;IACD,MAAM,KAAK,GAAG,QAAQ,EAAE,CAAA;IACxB,UAAU,GAAG,KAAK,CAAA;IAClB,IAAI,OAAO,EAAE,CAAC;QACZ,IAAI,CAAC;YACH,MAAM,OAAO,CAAC,OAAO,CAAC,WAAW,EAAE,KAAK,CAAC,CAAA;QAC3C,CAAC;QAAC,OAAO,CAAC,EAAE,CAAC;YACX,MAAM,CAAC,IAAI,CAAC,MAAM,EAAE,6BAA6B,EAAE,CAAC,CAAC,CAAA;QACvD,CAAC;IACH,CAAC;IACD,OAAO,KAAK,CAAA;AACd,CAAC;AAED,2CAA2C;AAC3C,GAAG;AACH,sEAAsE;AACtE,iEAAiE;AACjE,6BAA6B;AAC7B,SAAS,QAAQ;IACf,MAAM,CAAC,GAAI,UAAyD,CAAC,MAAM,CAAA;IAC3E,IAAI,OAAO,CAAC,EAAE,UAAU,KAAK,UAAU;QAAE,OAAO,CAAC,CAAC,UAAU,EAAE,CAAA;IAC9D,IAAI,GAAG,GAAG,EAAE,CAAA;IACZ,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,EAAE,EAAE,CAAC,EAAE;QAAE,GAAG,IAAI,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,EAAE,GAAG,EAAE,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAA;IAC/E,OAAO,GAAG,CAAA;AACZ,CAAC;AAED,KAAK,UAAU,UAAU,CAAC,GAAW;IACnC,MAAM,OAAO,GAAG,MAAM,eAAe,EAAE,CAAA;IACvC,IAAI,CAAC,OAAO;QAAE,OAAM;IACpB,IAAI,CAAC;QACH,MAAM,OAAO,CAAC,OAAO,CAAC,WAAW,EAAE,GAAG,CAAC,CAAA;IACzC,CAAC;IAAC,OAAO,CAAC,EAAE,CAAC;QACX,MAAM,CAAC,IAAI,CAAC,MAAM,EAAE,6BAA6B,EAAE,CAAC,CAAC,CAAA;IACvD,CAAC;AACH,CAAC;AAED,KAAK,UAAU,iBAAiB;IAC9B,MAAM,OAAO,GAAG,MAAM,eAAe,EAAE,CAAA;IACvC,IAAI,CAAC;QACH,MAAM,OAAO,EAAE,UAAU,CAAC,WAAW,CAAC,CAAA;IACxC,CAAC;IAAC,OAAO,CAAC,EAAE,CAAC;QACX,MAAM,CAAC,IAAI,CAAC,MAAM,EAAE,gCAAgC,EAAE,CAAC,CAAC,CAAA;IAC1D,CAAC;AACH,CAAC;AAED,KAAK,UAAU,gBAAgB;IAC7B,MAAM,OAAO,GAAG,MAAM,eAAe,EAAE,CAAA;IACvC,IAAI,CAAC,OAAO;QAAE,OAAO,IAAI,CAAA;IACzB,IAAI,CAAC;QACH,OAAO,MAAM,OAAO,CAAC,OAAO,CAAC,WAAW,CAAC,CAAA;IAC3C,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAA;IACb,CAAC;AACH,CAAC;AAQD,KAAK,UAAU,eAAe;IAC5B,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,OAAO,CAAC,2CAA2C,CAE9D,CAAA;QACD,OAAO,GAAG,CAAC,OAAO,IAAI,IAAI,CAAA;IAC5B,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAA;IACb,CAAC;AACH,CAAC;AAED,SAAS,OAAO,CAAC,IAAY,EAAE,IAAY;IACzC,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,GAAG,IAAI,EAAE,CAAA;AAC7C,CAAC;AAED;;+DAE+D;AAC/D,MAAM,UAAU,eAAe;IAC7B,UAAU,GAAG,IAAI,CAAA;IACjB,UAAU,GAAG,IAAI,CAAA;IACjB,UAAU,GAAG,SAAS,CAAA;IACtB,MAAM,GAAG,SAAS,CAAA;IAClB,SAAS,GAAG,EAAE,CAAA;IACd,gBAAgB,GAAG,IAAI,CAAA;IACvB,YAAY,GAAG,EAAE,CAAA;IACjB,iBAAiB,GAAG,IAAI,CAAA;IACxB,gBAAgB,CAAC,SAAS,CAAC,CAAA;IAC3B,mBAAmB,EAAE,CAAA;AACvB,CAAC;AAED,IAAI,iBAAiB,GAAyC,IAAI,CAAA;AAElE;qCACqC;AACrC,MAAM,UAAU,qBAAqB,CAAC,CAAuC;IAC3E,iBAAiB,GAAG,CAAC,CAAA;AACvB,CAAC;AAED,SAAS,cAAc;IACrB,IAAI,iBAAiB,IAAI,IAAI;QAAE,OAAO,iBAAiB,CAAA;IACvD,IAAI,CAAC;QACH,MAAM,EAAE,GAAG,OAAO,CAAC,cAAc,CAAmC,CAAA;QACpE,MAAM,EAAE,GAAG,EAAE,CAAC,QAAQ,EAAE,EAAE,CAAA;QAC1B,IAAI,EAAE,KAAK,KAAK,IAAI,EAAE,KAAK,SAAS;YAAE,OAAO,EAAE,CAAA;IACjD,CAAC;IAAC,MAAM,CAAC;QACP,8BAA8B;IAChC,CAAC;IACD,OAAO,SAAS,CAAA;AAClB,CAAC"}
|
package/lib/transport.js
CHANGED
|
@@ -15,7 +15,7 @@ const MAX_RETRY = 3;
|
|
|
15
15
|
const STORAGE_KEY = '@sentori/pending';
|
|
16
16
|
const MAX_PERSISTED = 1000;
|
|
17
17
|
// Pinned to package.json by a test — bump both together.
|
|
18
|
-
const SDK_VERSION = '
|
|
18
|
+
const SDK_VERSION = '7.0.0';
|
|
19
19
|
let _queue = [];
|
|
20
20
|
let _assertStats = new Map();
|
|
21
21
|
let _flushTimer = null;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@goliapkg/sentori-react-native",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "7.0.0",
|
|
4
4
|
"description": "Sentori SDK for React Native — JS-layer error capture, native crash handlers (iOS / Android), batched transport, fetch + react-navigation tracing.",
|
|
5
5
|
"license": "Apache-2.0 OR MIT",
|
|
6
6
|
"author": "GOLIA K.K. <takagi@golia.jp> (https://golia.jp)",
|
|
@@ -85,6 +85,6 @@
|
|
|
85
85
|
"access": "public"
|
|
86
86
|
},
|
|
87
87
|
"dependencies": {
|
|
88
|
-
"@goliapkg/sentori-core": "^
|
|
88
|
+
"@goliapkg/sentori-core": "^3.0.0"
|
|
89
89
|
}
|
|
90
90
|
}
|
|
@@ -17,6 +17,14 @@ import {
|
|
|
17
17
|
startTransport,
|
|
18
18
|
} from '../transport';
|
|
19
19
|
import { verbs } from '../verbs';
|
|
20
|
+
import { __setNativeForTests as setNative } from '../native';
|
|
21
|
+
import {
|
|
22
|
+
__resetForTests as resetPush,
|
|
23
|
+
__setPlatformForTests as setPlatform,
|
|
24
|
+
getCachedIpt,
|
|
25
|
+
register as pushRegister,
|
|
26
|
+
unregister as pushUnregister,
|
|
27
|
+
} from '../push';
|
|
20
28
|
|
|
21
29
|
const baseConfig = {
|
|
22
30
|
token: 'st_test',
|
|
@@ -126,3 +134,113 @@ describe('iron rule: init timing', () => {
|
|
|
126
134
|
expect(ms).toBeLessThan(50);
|
|
127
135
|
});
|
|
128
136
|
});
|
|
137
|
+
|
|
138
|
+
// Dimension 3, for push specifically.
|
|
139
|
+
//
|
|
140
|
+
// The rule was written down and the gate did not reach here: this file
|
|
141
|
+
// covered the five event verbs and mentioned push nowhere, while push
|
|
142
|
+
// is the surface with the most ways to go wrong — an OS permission, a
|
|
143
|
+
// vendor token, a network round trip, a background loop, and the
|
|
144
|
+
// host's own handlers running inside it.
|
|
145
|
+
//
|
|
146
|
+
// A notification that does not arrive is something the host can live
|
|
147
|
+
// with. An exception out of an SDK it merely opted into is not.
|
|
148
|
+
describe('iron rule: push never reaches the host', () => {
|
|
149
|
+
beforeEach(() => {
|
|
150
|
+
resetAll();
|
|
151
|
+
resetPush();
|
|
152
|
+
setPlatform('ios');
|
|
153
|
+
setConfig(baseConfig);
|
|
154
|
+
});
|
|
155
|
+
afterEach(() => {
|
|
156
|
+
globalThis.fetch = originalFetch;
|
|
157
|
+
setPlatform(null);
|
|
158
|
+
setNative(undefined);
|
|
159
|
+
resetPush();
|
|
160
|
+
resetAll();
|
|
161
|
+
});
|
|
162
|
+
|
|
163
|
+
const granting = {
|
|
164
|
+
pushRequestPermission: () => Promise.resolve('granted'),
|
|
165
|
+
pushGetStatus: () => Promise.resolve('granted'),
|
|
166
|
+
pushRegister: () => undefined,
|
|
167
|
+
pushUnregister: () => undefined,
|
|
168
|
+
pushDrainState: () => Promise.resolve({ notifications: [], taps: [], token: 'abc' }),
|
|
169
|
+
};
|
|
170
|
+
|
|
171
|
+
it('a server that answers 500 is an outcome, not an exception', async () => {
|
|
172
|
+
setNative(granting);
|
|
173
|
+
globalThis.fetch = (async () => new Response('boom', { status: 500 })) as typeof fetch;
|
|
174
|
+
const r = await pushRegister();
|
|
175
|
+
expect(r.ok).toBe(false);
|
|
176
|
+
});
|
|
177
|
+
|
|
178
|
+
it('a network that is down is an outcome, not an exception', async () => {
|
|
179
|
+
setNative(granting);
|
|
180
|
+
globalThis.fetch = (async () => {
|
|
181
|
+
throw new Error('offline');
|
|
182
|
+
}) as typeof fetch;
|
|
183
|
+
const r = await pushRegister();
|
|
184
|
+
expect(r.ok).toBe(false);
|
|
185
|
+
});
|
|
186
|
+
|
|
187
|
+
it('a server that answers nonsense is an outcome, not an exception', async () => {
|
|
188
|
+
setNative(granting);
|
|
189
|
+
globalThis.fetch = (async () => new Response('<html>not json</html>', { status: 200 })) as typeof fetch;
|
|
190
|
+
const r = await pushRegister();
|
|
191
|
+
expect(r.ok).toBe(false);
|
|
192
|
+
});
|
|
193
|
+
|
|
194
|
+
it('a native module that throws is an outcome, not an exception', async () => {
|
|
195
|
+
setNative({
|
|
196
|
+
...granting,
|
|
197
|
+
pushRequestPermission: () => {
|
|
198
|
+
throw new Error('bridge died');
|
|
199
|
+
},
|
|
200
|
+
});
|
|
201
|
+
const r = await pushRegister();
|
|
202
|
+
expect(r.ok).toBe(false);
|
|
203
|
+
});
|
|
204
|
+
|
|
205
|
+
it('fuzz: the push verbs accept garbage without throwing', async () => {
|
|
206
|
+
setNative(granting);
|
|
207
|
+
globalThis.fetch = (async () =>
|
|
208
|
+
new Response(JSON.stringify({ spToken: 'dev-1' }), { status: 200 })) as typeof fetch;
|
|
209
|
+
const circular: Record<string, unknown> = { a: 1 };
|
|
210
|
+
circular.self = circular;
|
|
211
|
+
const garbage = [
|
|
212
|
+
undefined,
|
|
213
|
+
null,
|
|
214
|
+
{},
|
|
215
|
+
{ metadata: circular },
|
|
216
|
+
{ metadata: { huge: 'x'.repeat(200_000) } },
|
|
217
|
+
{ onMessage: 'not a function' },
|
|
218
|
+
{ tokenTimeoutMs: -1 },
|
|
219
|
+
{ tokenTimeoutMs: Number.NaN },
|
|
220
|
+
];
|
|
221
|
+
for (const g of garbage) {
|
|
222
|
+
const r = await pushRegister(g as never);
|
|
223
|
+
expect(typeof r.ok).toBe('boolean');
|
|
224
|
+
}
|
|
225
|
+
});
|
|
226
|
+
|
|
227
|
+
it('every push verb before init is a quiet outcome', async () => {
|
|
228
|
+
resetConfig();
|
|
229
|
+
setNative(granting);
|
|
230
|
+
const r = await pushRegister();
|
|
231
|
+
expect(r).toEqual({ ok: false, message: 'sentori.init() has not run', reason: 'not-initialised' });
|
|
232
|
+
await pushUnregister();
|
|
233
|
+
expect(await getCachedIpt()).toBe(null);
|
|
234
|
+
});
|
|
235
|
+
|
|
236
|
+
it('unregister cannot fail, whatever the server does', async () => {
|
|
237
|
+
setNative(granting);
|
|
238
|
+
globalThis.fetch = (async () =>
|
|
239
|
+
new Response(JSON.stringify({ spToken: 'dev-1' }), { status: 200 })) as typeof fetch;
|
|
240
|
+
await pushRegister();
|
|
241
|
+
globalThis.fetch = (async () => {
|
|
242
|
+
throw new Error('offline');
|
|
243
|
+
}) as typeof fetch;
|
|
244
|
+
await pushUnregister();
|
|
245
|
+
});
|
|
246
|
+
});
|
|
@@ -13,6 +13,7 @@ import {
|
|
|
13
13
|
__resetForTests as resetPush,
|
|
14
14
|
__setPlatformForTests as setPlatform,
|
|
15
15
|
register,
|
|
16
|
+
unregister,
|
|
16
17
|
} from '../push';
|
|
17
18
|
import { __resetForTests as resetConfig, setConfig } from '../config';
|
|
18
19
|
import { __resetForTests as resetScope, setUser } from '../scope';
|
|
@@ -43,7 +44,7 @@ function grantingNative(over: Record<string, unknown> = {}) {
|
|
|
43
44
|
|
|
44
45
|
const realFetch = globalThis.fetch;
|
|
45
46
|
|
|
46
|
-
/** Answer /v1/push/
|
|
47
|
+
/** Answer /v1/push/devices with `body` under `status`. */
|
|
47
48
|
function stubFetch(status: number, body: unknown): void {
|
|
48
49
|
globalThis.fetch = (() =>
|
|
49
50
|
Promise.resolve({
|
|
@@ -72,7 +73,7 @@ describe('push.register', () => {
|
|
|
72
73
|
|
|
73
74
|
it('returns the device handle when the whole flow works', async () => {
|
|
74
75
|
__setNativeForTests(grantingNative());
|
|
75
|
-
stubFetch(200, {
|
|
76
|
+
stubFetch(200, { spToken: '018f0000-0000-7000-8000-000000000001', isNew: true });
|
|
76
77
|
|
|
77
78
|
const r = await register();
|
|
78
79
|
|
|
@@ -88,7 +89,7 @@ describe('push.register', () => {
|
|
|
88
89
|
return Promise.resolve({
|
|
89
90
|
ok: true,
|
|
90
91
|
status: 200,
|
|
91
|
-
json: () => Promise.resolve({
|
|
92
|
+
json: () => Promise.resolve({ spToken: 'id-1' }),
|
|
92
93
|
});
|
|
93
94
|
}) as unknown as typeof fetch;
|
|
94
95
|
|
|
@@ -107,7 +108,7 @@ describe('push.register', () => {
|
|
|
107
108
|
return Promise.resolve({
|
|
108
109
|
ok: true,
|
|
109
110
|
status: 200,
|
|
110
|
-
json: () => Promise.resolve({
|
|
111
|
+
json: () => Promise.resolve({ spToken: 'id-1' }),
|
|
111
112
|
});
|
|
112
113
|
}) as unknown as typeof fetch;
|
|
113
114
|
|
|
@@ -208,7 +209,7 @@ describe('push.register', () => {
|
|
|
208
209
|
// the life of the install — and a send aimed at that user reached
|
|
209
210
|
// nobody and reported success.
|
|
210
211
|
describe('push registration follows the person', () => {
|
|
211
|
-
/** Record every /v1/push/
|
|
212
|
+
/** Record every /v1/push/devices body, so a test can say what the
|
|
212
213
|
* server was told rather than that it was told something. */
|
|
213
214
|
function recordingFetch(): Array<Record<string, unknown>> {
|
|
214
215
|
const seen: Array<Record<string, unknown>> = [];
|
|
@@ -219,7 +220,7 @@ describe('push registration follows the person', () => {
|
|
|
219
220
|
return Promise.resolve({
|
|
220
221
|
ok: true,
|
|
221
222
|
status: 202,
|
|
222
|
-
json: () => Promise.resolve({ spToken: 'dev-1'
|
|
223
|
+
json: () => Promise.resolve({ spToken: 'dev-1' }),
|
|
223
224
|
});
|
|
224
225
|
}) as unknown as typeof fetch;
|
|
225
226
|
return seen;
|
|
@@ -321,7 +322,7 @@ describe('push survives the vendor rotating its token', () => {
|
|
|
321
322
|
return Promise.resolve({
|
|
322
323
|
ok: true,
|
|
323
324
|
status: 202,
|
|
324
|
-
json: () => Promise.resolve({ spToken: 'dev-1'
|
|
325
|
+
json: () => Promise.resolve({ spToken: 'dev-1' }),
|
|
325
326
|
});
|
|
326
327
|
}) as unknown as typeof fetch;
|
|
327
328
|
return seen;
|
|
@@ -404,3 +405,147 @@ describe('push survives the vendor rotating its token', () => {
|
|
|
404
405
|
expect(seen).toHaveLength(1);
|
|
405
406
|
});
|
|
406
407
|
});
|
|
408
|
+
|
|
409
|
+
// Push is allowed to fail silently. It is never allowed to make the
|
|
410
|
+
// host app fail — a notification that does not arrive is a product
|
|
411
|
+
// decision the host can live with; an exception out of an SDK the host
|
|
412
|
+
// merely opted into is not.
|
|
413
|
+
//
|
|
414
|
+
// The host's own handlers are the sharp edge: they are its code, they
|
|
415
|
+
// run inside our loop, and JavaScript throws for a living.
|
|
416
|
+
describe('nothing the host does can reach back into the app', () => {
|
|
417
|
+
const boom = () => {
|
|
418
|
+
throw new Error('the host threw');
|
|
419
|
+
};
|
|
420
|
+
|
|
421
|
+
/** Hands the batch over once and is empty after, the way the real
|
|
422
|
+
* native drain is — a stub that keeps re-delivering makes a second
|
|
423
|
+
* tick look like a bug in the SDK. */
|
|
424
|
+
function drainingNative(notifications: unknown[], taps: unknown[]) {
|
|
425
|
+
let drained = false;
|
|
426
|
+
return grantingNative({
|
|
427
|
+
pushDrainState: () => {
|
|
428
|
+
const batch = drained
|
|
429
|
+
? { notifications: [], taps: [] }
|
|
430
|
+
: { notifications, taps };
|
|
431
|
+
drained = true;
|
|
432
|
+
return Promise.resolve({ ...batch, token: 'abc123' });
|
|
433
|
+
},
|
|
434
|
+
});
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
function okFetch(): void {
|
|
438
|
+
globalThis.fetch = (() =>
|
|
439
|
+
Promise.resolve({
|
|
440
|
+
ok: true,
|
|
441
|
+
status: 202,
|
|
442
|
+
json: () => Promise.resolve({ spToken: 'dev-1' }),
|
|
443
|
+
})) as unknown as typeof fetch;
|
|
444
|
+
}
|
|
445
|
+
|
|
446
|
+
beforeEach(() => {
|
|
447
|
+
resetPush();
|
|
448
|
+
resetConfig();
|
|
449
|
+
resetScope();
|
|
450
|
+
setPlatform('ios');
|
|
451
|
+
setConfig(baseConfig);
|
|
452
|
+
okFetch();
|
|
453
|
+
});
|
|
454
|
+
afterEach(() => {
|
|
455
|
+
resetPush();
|
|
456
|
+
resetConfig();
|
|
457
|
+
resetScope();
|
|
458
|
+
setPlatform(null);
|
|
459
|
+
__setNativeForTests(undefined);
|
|
460
|
+
globalThis.fetch = realFetch;
|
|
461
|
+
});
|
|
462
|
+
|
|
463
|
+
it('keeps delivering after a handler throws', async () => {
|
|
464
|
+
const seen: string[] = [];
|
|
465
|
+
__setNativeForTests(
|
|
466
|
+
drainingNative(
|
|
467
|
+
[{ title: 'one' }, { title: 'two' }],
|
|
468
|
+
[{ tapped: true }],
|
|
469
|
+
),
|
|
470
|
+
);
|
|
471
|
+
const r = await register({
|
|
472
|
+
onMessage: (n) => {
|
|
473
|
+
seen.push(String(n.title));
|
|
474
|
+
// The first one throws. The second one, and the tap after it,
|
|
475
|
+
// still have to arrive: one bad handler must not swallow the
|
|
476
|
+
// rest of the batch.
|
|
477
|
+
if (n.title === 'one') boom();
|
|
478
|
+
},
|
|
479
|
+
onTap: () => seen.push('tap'),
|
|
480
|
+
});
|
|
481
|
+
expect(r.ok).toBe(true);
|
|
482
|
+
await new Promise((res) => setTimeout(res, 1400));
|
|
483
|
+
expect(seen).toEqual(['one', 'two', 'tap']);
|
|
484
|
+
});
|
|
485
|
+
|
|
486
|
+
it('keeps ticking after a handler throws', async () => {
|
|
487
|
+
let ticks = 0;
|
|
488
|
+
__setNativeForTests(
|
|
489
|
+
grantingNative({
|
|
490
|
+
pushDrainState: () => {
|
|
491
|
+
ticks += 1;
|
|
492
|
+
return Promise.resolve({
|
|
493
|
+
notifications: [{ title: 'n' }],
|
|
494
|
+
taps: [],
|
|
495
|
+
token: 'abc123',
|
|
496
|
+
});
|
|
497
|
+
},
|
|
498
|
+
}),
|
|
499
|
+
);
|
|
500
|
+
await register({ onMessage: boom });
|
|
501
|
+
const first = ticks;
|
|
502
|
+
await new Promise((res) => setTimeout(res, 2400));
|
|
503
|
+
// A throwing handler that stops the loop is worse than one that
|
|
504
|
+
// drops a notification: every later push is gone too, silently.
|
|
505
|
+
expect(ticks).toBeGreaterThan(first + 1);
|
|
506
|
+
});
|
|
507
|
+
|
|
508
|
+
it('survives a native module that rejects', async () => {
|
|
509
|
+
let ticks = 0;
|
|
510
|
+
__setNativeForTests(
|
|
511
|
+
grantingNative({
|
|
512
|
+
pushDrainState: () => {
|
|
513
|
+
ticks += 1;
|
|
514
|
+
return ticks === 1
|
|
515
|
+
? Promise.resolve({ notifications: [], taps: [], token: 'abc123' })
|
|
516
|
+
: Promise.reject(new Error('bridge died'));
|
|
517
|
+
},
|
|
518
|
+
}),
|
|
519
|
+
);
|
|
520
|
+
await register();
|
|
521
|
+
await new Promise((res) => setTimeout(res, 2400));
|
|
522
|
+
expect(ticks).toBeGreaterThan(2);
|
|
523
|
+
});
|
|
524
|
+
|
|
525
|
+
it('does not report a failure because onToken threw', async () => {
|
|
526
|
+
__setNativeForTests(grantingNative());
|
|
527
|
+
const r = await register({ onToken: boom });
|
|
528
|
+
// The registration reached the server and came back with a handle.
|
|
529
|
+
// What the host did with it afterwards is not our outcome.
|
|
530
|
+
expect(r).toEqual({ ok: true, ipt: 'dev-1' });
|
|
531
|
+
});
|
|
532
|
+
|
|
533
|
+
it('still resolves when onError throws', async () => {
|
|
534
|
+
// `register()` never throws is the documented contract, and the
|
|
535
|
+
// one path that reports failure is the one that hands the host an
|
|
536
|
+
// error to look at.
|
|
537
|
+
__setNativeForTests(
|
|
538
|
+
grantingNative({ pushRequestPermission: () => Promise.resolve('denied') }),
|
|
539
|
+
);
|
|
540
|
+
const r = await register({ onError: boom });
|
|
541
|
+
expect(r.ok).toBe(false);
|
|
542
|
+
});
|
|
543
|
+
|
|
544
|
+
it('unregister does not throw when the server is unreachable', async () => {
|
|
545
|
+
__setNativeForTests(grantingNative());
|
|
546
|
+
await register();
|
|
547
|
+
globalThis.fetch = (() => Promise.reject(new Error('offline'))) as unknown as typeof fetch;
|
|
548
|
+
// Signing out must not be something that can fail.
|
|
549
|
+
await unregister();
|
|
550
|
+
});
|
|
551
|
+
});
|
package/src/push.ts
CHANGED
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
// asynchronously and lands in the native buffer.
|
|
11
11
|
// 3. Poll `pushDrainState()` at 200 ms ticks for up to 8 s waiting
|
|
12
12
|
// for the token.
|
|
13
|
-
// 4. POST `/v1/push/
|
|
13
|
+
// 4. POST `/v1/push/devices` with `kind: 'apns' | 'fcm'` — the
|
|
14
14
|
// server's field name; sending `provider` here earned a 422 for
|
|
15
15
|
// every registration this SDK ever attempted — plus
|
|
16
16
|
// `nativeToken`, `userKey`, and `env` on iOS only (FCM is a
|
|
@@ -196,7 +196,11 @@ export async function register(opts: PushRegisterOptions = {}): Promise<PushRegi
|
|
|
196
196
|
_lastNativeToken = token
|
|
197
197
|
_lastOptions = opts
|
|
198
198
|
void persistIpt(ipt)
|
|
199
|
-
|
|
199
|
+
// The registration reached the server and came back with a handle.
|
|
200
|
+
// What the host does with it afterwards is not our outcome — this
|
|
201
|
+
// used to sit inside the try, so a throwing `onToken` reported a
|
|
202
|
+
// successful registration as `server-rejected`.
|
|
203
|
+
safely('onToken', () => opts.onToken?.(ipt))
|
|
200
204
|
bindBufferDrain(opts.onMessage, opts.onTap)
|
|
201
205
|
// From here on, signing in or out updates the row by itself.
|
|
202
206
|
onIdentityChange(reRegisterAfterIdentityChange)
|
|
@@ -216,7 +220,10 @@ function fail(
|
|
|
216
220
|
message: string,
|
|
217
221
|
): PushRegisterResult {
|
|
218
222
|
logger.warn('push', `register failed (${reason}):`, message)
|
|
219
|
-
|
|
223
|
+
// `register()` never throws is the contract, and this is the one
|
|
224
|
+
// path that hands the host an error to look at — so it is also the
|
|
225
|
+
// one place where the host's own code could have broken it.
|
|
226
|
+
safely('onError', () => opts.onError?.(new Error(message)))
|
|
220
227
|
return { ok: false, message, reason }
|
|
221
228
|
}
|
|
222
229
|
|
|
@@ -255,7 +262,7 @@ class PushRegisterError extends Error {
|
|
|
255
262
|
}
|
|
256
263
|
|
|
257
264
|
/**
|
|
258
|
-
* Revoke the cached handle (DELETE /v1/push/
|
|
265
|
+
* Revoke the cached handle (DELETE /v1/push/devices/{ipt}) +
|
|
259
266
|
* unregister locally. Idempotent — repeat calls are no-ops.
|
|
260
267
|
*/
|
|
261
268
|
export async function unregister(): Promise<void> {
|
|
@@ -263,7 +270,7 @@ export async function unregister(): Promise<void> {
|
|
|
263
270
|
const ipt = _cachedIpt ?? (await readPersistedIpt())
|
|
264
271
|
if (cfg && ipt) {
|
|
265
272
|
try {
|
|
266
|
-
await fetch(joinUrl(cfg.ingestUrl, `/v1/push/
|
|
273
|
+
await fetch(joinUrl(cfg.ingestUrl, `/v1/push/devices/${ipt}`), {
|
|
267
274
|
method: 'DELETE',
|
|
268
275
|
headers: { authorization: `Bearer ${cfg.token}` },
|
|
269
276
|
})
|
|
@@ -367,7 +374,7 @@ async function registerWithServer(
|
|
|
367
374
|
// which is what signing out sends.
|
|
368
375
|
const traits = currentUserTraits()
|
|
369
376
|
if (traits != null) body.traits = traits
|
|
370
|
-
const res = await fetch(joinUrl(cfg.ingestUrl, '/v1/push/
|
|
377
|
+
const res = await fetch(joinUrl(cfg.ingestUrl, '/v1/push/devices'), {
|
|
371
378
|
method: 'POST',
|
|
372
379
|
headers: {
|
|
373
380
|
authorization: `Bearer ${cfg.token}`,
|
|
@@ -376,16 +383,16 @@ async function registerWithServer(
|
|
|
376
383
|
body: JSON.stringify(body),
|
|
377
384
|
})
|
|
378
385
|
if (!res.ok) {
|
|
379
|
-
throw new PushRegisterError('server-rejected', `/v1/push/
|
|
386
|
+
throw new PushRegisterError('server-rejected', `/v1/push/devices HTTP ${res.status}`)
|
|
380
387
|
}
|
|
381
388
|
// The handle is the device_tokens row id — a uuid, which is what
|
|
382
389
|
// the revoke and send routes take. It was parsed here as an
|
|
383
390
|
// `ipt_*` string that no server has ever returned.
|
|
384
|
-
const json = (await res.json()) as {
|
|
385
|
-
if (typeof json.
|
|
391
|
+
const json = (await res.json()) as { spToken?: string }
|
|
392
|
+
if (typeof json.spToken !== 'string' || json.spToken.length === 0) {
|
|
386
393
|
throw new PushRegisterError('server-rejected', 'server did not return a device token id')
|
|
387
394
|
}
|
|
388
|
-
return json.
|
|
395
|
+
return json.spToken
|
|
389
396
|
}
|
|
390
397
|
|
|
391
398
|
function bindBufferDrain(
|
|
@@ -417,9 +424,17 @@ function teardownBufferDrain(): void {
|
|
|
417
424
|
}
|
|
418
425
|
|
|
419
426
|
async function pumpOnce(): Promise<void> {
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
427
|
+
// Nothing in a tick may reject. The caller is `void pumpOnce()` on
|
|
428
|
+
// an interval, so a rejection here is an unhandled rejection in the
|
|
429
|
+
// host's process — a red box in development, and on some setups
|
|
430
|
+
// worse — for something the host is entitled to have fail quietly.
|
|
431
|
+
try {
|
|
432
|
+
const state = await pushDrainState()
|
|
433
|
+
flushBuffered(state.notifications, state.taps)
|
|
434
|
+
await reportRotationIfAny(state.token)
|
|
435
|
+
} catch (e) {
|
|
436
|
+
logger.warn('push', 'a drain tick failed — the next one still runs', e)
|
|
437
|
+
}
|
|
423
438
|
}
|
|
424
439
|
|
|
425
440
|
/// Tell the server when the vendor has handed the app a different
|
|
@@ -460,6 +475,22 @@ async function reportRotationIfAny(token: string | undefined): Promise<void> {
|
|
|
460
475
|
}
|
|
461
476
|
}
|
|
462
477
|
|
|
478
|
+
/// Run the host's own code without letting it reach back into ours.
|
|
479
|
+
///
|
|
480
|
+
/// A push that does not arrive is a product decision the host can live
|
|
481
|
+
/// with. An exception out of an SDK it merely opted into is not — and
|
|
482
|
+
/// the host's handlers are the sharp edge here: they are its code,
|
|
483
|
+
/// they run inside our loop, and JavaScript throws for a living. One
|
|
484
|
+
/// throwing handler used to take the rest of the batch with it, then
|
|
485
|
+
/// the tick, then every later tick as an unhandled rejection.
|
|
486
|
+
function safely(what: string, fn: () => void): void {
|
|
487
|
+
try {
|
|
488
|
+
fn()
|
|
489
|
+
} catch (e) {
|
|
490
|
+
logger.warn('push', `${what} threw — carrying on`, e)
|
|
491
|
+
}
|
|
492
|
+
}
|
|
493
|
+
|
|
463
494
|
function flushBuffered(
|
|
464
495
|
notifications: Array<Record<string, unknown>>,
|
|
465
496
|
taps: Array<Record<string, unknown>>,
|
|
@@ -468,12 +499,12 @@ function flushBuffered(
|
|
|
468
499
|
// v2.26 — Observability link-through (rule #4). If the server
|
|
469
500
|
// injected `_sentori.msgId` in v2.25+, drop a `push` breadcrumb,
|
|
470
501
|
// emit `sentori.push.received` track, and queue the ack.
|
|
471
|
-
autoCorrelate(raw, 'received')
|
|
472
|
-
_onMessage?.(coerceNotification(raw))
|
|
502
|
+
safely('autoCorrelate', () => autoCorrelate(raw, 'received'))
|
|
503
|
+
safely('onMessage', () => _onMessage?.(coerceNotification(raw)))
|
|
473
504
|
}
|
|
474
505
|
for (const raw of taps) {
|
|
475
|
-
autoCorrelate(raw, 'opened')
|
|
476
|
-
_onTap?.(raw.userInfo ?? raw)
|
|
506
|
+
safely('autoCorrelate', () => autoCorrelate(raw, 'opened'))
|
|
507
|
+
safely('onTap', () => _onTap?.(raw.userInfo ?? raw))
|
|
477
508
|
}
|
|
478
509
|
}
|
|
479
510
|
|
|
@@ -536,7 +567,7 @@ async function drainAckQueue(): Promise<void> {
|
|
|
536
567
|
// the user flow.
|
|
537
568
|
for (const msgId of batch) {
|
|
538
569
|
try {
|
|
539
|
-
await fetch(joinUrl(cfg.ingestUrl, `/v1/push/
|
|
570
|
+
await fetch(joinUrl(cfg.ingestUrl, `/v1/push/deliveries/${msgId}/ack`), {
|
|
540
571
|
body: JSON.stringify({ eventType: 'received', sessionId: _sessionId }),
|
|
541
572
|
headers: {
|
|
542
573
|
authorization: `Bearer ${cfg.token}`,
|
package/src/transport.ts
CHANGED
|
@@ -20,7 +20,7 @@ const STORAGE_KEY = '@sentori/pending';
|
|
|
20
20
|
const MAX_PERSISTED = 1000;
|
|
21
21
|
|
|
22
22
|
// Pinned to package.json by a test — bump both together.
|
|
23
|
-
const SDK_VERSION = '
|
|
23
|
+
const SDK_VERSION = '7.0.0';
|
|
24
24
|
|
|
25
25
|
let _queue: WireEvent[] = [];
|
|
26
26
|
let _assertStats = new Map<string, AssertStat>();
|