@usergist/feedback-react-native 0.2.0-beta.1 → 0.2.0-beta.3
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/CHANGELOG.md +19 -0
- package/README.md +5 -3
- package/dist/UserGist.d.ts +6 -0
- package/dist/UserGist.d.ts.map +1 -1
- package/dist/UserGist.js +139 -83
- package/dist/UserGist.js.map +1 -1
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/internal/context.d.ts +1 -1
- package/dist/internal/context.js +1 -1
- package/dist/internal/engine.d.ts +6 -0
- package/dist/internal/engine.d.ts.map +1 -1
- package/dist/internal/engine.js +88 -33
- package/dist/internal/engine.js.map +1 -1
- package/dist/internal/identity-lifecycle.d.ts +16 -0
- package/dist/internal/identity-lifecycle.d.ts.map +1 -0
- package/dist/internal/identity-lifecycle.js +96 -0
- package/dist/internal/identity-lifecycle.js.map +1 -0
- package/dist/internal/mutation-queue.d.ts.map +1 -1
- package/dist/internal/mutation-queue.js +12 -2
- package/dist/internal/mutation-queue.js.map +1 -1
- package/dist/internal/push-subscription.d.ts +11 -0
- package/dist/internal/push-subscription.d.ts.map +1 -0
- package/dist/internal/push-subscription.js +20 -0
- package/dist/internal/push-subscription.js.map +1 -0
- package/dist/internal/session-revocations.d.ts +5 -0
- package/dist/internal/session-revocations.d.ts.map +1 -0
- package/dist/internal/session-revocations.js +58 -0
- package/dist/internal/session-revocations.js.map +1 -0
- package/dist/internal/storage.d.ts +2 -0
- package/dist/internal/storage.d.ts.map +1 -1
- package/dist/internal/storage.js +75 -60
- package/dist/internal/storage.js.map +1 -1
- package/dist/internal/transport.d.ts +7 -2
- package/dist/internal/transport.d.ts.map +1 -1
- package/dist/internal/transport.js +25 -7
- package/dist/internal/transport.js.map +1 -1
- package/dist/internal/user-state.d.ts +2 -1
- package/dist/internal/user-state.d.ts.map +1 -1
- package/dist/internal/user-state.js +3 -2
- package/dist/internal/user-state.js.map +1 -1
- package/package.json +2 -2
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,24 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.2.0-beta.3 — durable instruction receipts
|
|
4
|
+
|
|
5
|
+
- Save instruction delivery state before requesting display, preventing replays after a failed storage write or interrupted delivery.
|
|
6
|
+
- Recheck the active identity after saving a receipt so an account change cannot display a stale instruction.
|
|
7
|
+
- Add regression coverage for concurrent delivery, repeated SDK recreation, offline acknowledgements, and failed receipt persistence.
|
|
8
|
+
- Maximum-impressions enforcement also requires the coordinated API update. Expo remains on the prerelease `next` channel.
|
|
9
|
+
|
|
10
|
+
## 0.2.0-beta.2 — identity lifecycle
|
|
11
|
+
|
|
12
|
+
- Serialize explicit token invalidation with registration, remove invalidated retry candidates, and preserve consent-based re-enable behavior.
|
|
13
|
+
- Confirmed identity state and asynchronous completion, with backend token renewal and retained account identity after expiration.
|
|
14
|
+
- Property set/unset using the active session; profile PII follows the app's server allowlist, while event filtering remains in place.
|
|
15
|
+
- Installation-bound credentials, anonymous ownership proof, and canonical profile adoption on identify.
|
|
16
|
+
- Local account reset with cancellation and independent durable logout cleanup; stale responses cannot restore the old account.
|
|
17
|
+
- Push subscription state reflects server acknowledgement; OS tokens survive restart and retry after consent, connectivity, or identity changes.
|
|
18
|
+
|
|
19
|
+
Requires the coordinated backend lifecycle deployment. See the [identity integration guide](https://usergist.com/docs/integrations/identity) for backend requirements and account-switching guidance.
|
|
20
|
+
|
|
21
|
+
|
|
3
22
|
## 0.2.0-beta.1
|
|
4
23
|
|
|
5
24
|
- Add startup presentation readiness: initialize with `presentationPaused`, then call `resumePresentation()` after the loaded screen is ready.
|
package/README.md
CHANGED
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
# @usergist/feedback-react-native
|
|
2
2
|
|
|
3
|
+
For account IDs, backend-verified guests, token expiry, property updates, and logout, see [the identity integration guide](https://usergist.com/docs/integrations/identity). The identity lifecycle APIs require SDK **0.2.0-beta.2** and the coordinated backend update; verify the installed version before copying examples into an older app.
|
|
4
|
+
|
|
5
|
+
|
|
3
6
|
Production userGist SDK for React Native and the behavioral reference for the
|
|
4
7
|
iOS, Android, and Flutter packages. Use the dashboard's SDK setup flow to
|
|
5
8
|
verify authentication and ingestion. The userGist APNs and FCM paths have
|
|
6
9
|
passed end-to-end physical-device validation; each host app still needs its own
|
|
7
|
-
provider credentials, identifiers, native callback setup, and
|
|
8
|
-
acceptance test.
|
|
10
|
+
provider credentials, identifiers, native callback setup, and confirmation that a test notification arrives.
|
|
9
11
|
|
|
10
12
|
## Expo
|
|
11
13
|
|
|
@@ -102,7 +104,7 @@ AppRegistry.registerComponent('app', () => App)
|
|
|
102
104
|
| `await UserGist.identifyAsync(userId, props?, subjectToken)` | Backward-compatible async identity API returning `synced`, `queued`, or `rejected`. |
|
|
103
105
|
| `UserGist.track(name, props?)` | Enqueues a stable event id and immediately evaluates only server-authorized client-side campaigns; all other decisions remain server-authoritative. |
|
|
104
106
|
| `await UserGist.setConsent({ analytics?, feedback?, push?, survey? })` | Persists and synchronizes the transition, refreshes targeting rules, then resolves with `true`; returns `false` when synchronization fails. |
|
|
105
|
-
| `await UserGist.reset()` | Cancels in-flight, clears queue, rotates anonymous id, wipes caches, and resolves after
|
|
107
|
+
| `await UserGist.reset()` | Cancels in-flight, clears queue, rotates anonymous id, wipes caches, and resolves after local cleanup; remote logout and new-session setup retry independently. |
|
|
106
108
|
| `UserGist.setThemeOverrides(theme)` | Global theme applied under per-prompt theme. |
|
|
107
109
|
| `UserGist.flush()` | Best-effort flush. |
|
|
108
110
|
| `UserGist.setDebug(boolean)` | Toggle the debug trace logger at runtime. |
|
package/dist/UserGist.d.ts
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { setPushSubscriptionStateHandler } from './internal/push-subscription.js';
|
|
2
|
+
import { setIdentityStateHandler, setSubjectTokenProvider, getIdentityState } from './internal/identity-lifecycle.js';
|
|
1
3
|
import type { Consent, EventPropertyValue, PromptTheme, SdkConfig, SurveyAnswerRecord, SurveyAnswerValue, SurveyAttemptSource, SurveyCampaignWithFlow, SurveySummary, CreateSurveyAttemptResponse, JsonAction, InAppCtaAction } from '@usergist/sdk-core/mobile';
|
|
2
4
|
import { logTrace, getTraces, type SdkDiagnostic } from './internal/debug.js';
|
|
3
5
|
import type { ConsentState, IdentityState, ResolvedConfig, ResponseEmission, ShowPromptPayload } from './internal/types.js';
|
|
@@ -65,6 +67,10 @@ export declare const UserGist: {
|
|
|
65
67
|
readonly resumePresentation: () => void;
|
|
66
68
|
readonly __internal_presentationGate: () => import("@usergist/sdk-core/mobile").PresentationGate;
|
|
67
69
|
readonly initAsync: (config: SdkConfig, initialIdentity?: InitialIdentity) => Promise<IdentifyResult>;
|
|
70
|
+
readonly setPushSubscriptionStateHandler: typeof setPushSubscriptionStateHandler;
|
|
71
|
+
readonly setIdentityStateHandler: typeof setIdentityStateHandler;
|
|
72
|
+
readonly setSubjectTokenProvider: typeof setSubjectTokenProvider;
|
|
73
|
+
readonly getIdentityState: typeof getIdentityState;
|
|
68
74
|
readonly identify: (userId: string, properties?: Record<string, EventPropertyValue>, subjectToken?: string) => void;
|
|
69
75
|
readonly identifyAsync: (userId: string, properties?: Record<string, EventPropertyValue>, subjectToken?: string) => Promise<IdentifyResult>;
|
|
70
76
|
/** Update the current user, including anonymous users. Durable and retried on reconnect. */
|
package/dist/UserGist.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"UserGist.d.ts","sourceRoot":"","sources":["../src/UserGist.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"UserGist.d.ts","sourceRoot":"","sources":["../src/UserGist.ts"],"names":[],"mappings":"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"}
|
package/dist/UserGist.js
CHANGED
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
import { drainRevocations, hasPendingRevocations } from './internal/session-revocations.js';
|
|
2
|
+
import { setPushSubscriptionStateHandler, pushSubscriptionChanged } from './internal/push-subscription.js';
|
|
3
|
+
import { cancelIdentityRecovery, identityChanged, setIdentityStateHandler, setSubjectTokenProvider, getIdentityState } from './internal/identity-lifecycle.js';
|
|
1
4
|
import { userPropertiesUpdateSchema } from '@usergist/sdk-core/mobile';
|
|
2
5
|
import { hydratePushDedupe } from './internal/push-dedupe.js';
|
|
3
6
|
import { REQUEST_COMMENTED_EVENT_NAME, REQUEST_COMMENT_EDITED_EVENT_NAME, REQUEST_COMMENT_DELETED_EVENT_NAME, } from '@usergist/sdk-core/mobile';
|
|
@@ -89,6 +92,20 @@ function ensureEngine(config) {
|
|
|
89
92
|
// A host-owned invitation is not a survey start. Only automatic rendering
|
|
90
93
|
// requests a session bundled with the delivery authorization.
|
|
91
94
|
engine = createEngine(config, () => !surveyHandlers.onInvite);
|
|
95
|
+
const pushEngine = engine;
|
|
96
|
+
pushEngine.retryPushRegistration = async () => {
|
|
97
|
+
if (pushEngine.resetting)
|
|
98
|
+
return;
|
|
99
|
+
const saved = await pushEngine.storage.getJson(STORAGE_KEYS.pushDevice);
|
|
100
|
+
if (!saved)
|
|
101
|
+
return;
|
|
102
|
+
pushEngine.pushTokenAvailable = true;
|
|
103
|
+
if (pushEngine !== engine || pushEngine.resetting)
|
|
104
|
+
return;
|
|
105
|
+
pushSubscriptionChanged(pushEngine);
|
|
106
|
+
if (pushEngine.consent.allowsPush())
|
|
107
|
+
await registerPushDevice(saved.token, saved.platform, { environment: saved.environment }, true);
|
|
108
|
+
};
|
|
92
109
|
surveyStore = createSurveyStore(config.writeKey, () => engine.identity.get());
|
|
93
110
|
return engine;
|
|
94
111
|
}
|
|
@@ -286,6 +303,10 @@ export const UserGist = {
|
|
|
286
303
|
return 'rejected';
|
|
287
304
|
}
|
|
288
305
|
},
|
|
306
|
+
setPushSubscriptionStateHandler,
|
|
307
|
+
setIdentityStateHandler,
|
|
308
|
+
setSubjectTokenProvider,
|
|
309
|
+
getIdentityState,
|
|
289
310
|
identify(userId, properties, subjectToken) {
|
|
290
311
|
void UserGist.identifyAsync(userId, properties, subjectToken);
|
|
291
312
|
},
|
|
@@ -296,8 +317,9 @@ export const UserGist = {
|
|
|
296
317
|
return 'rejected';
|
|
297
318
|
}
|
|
298
319
|
const e = requireEngine();
|
|
320
|
+
const generation = e.resetGeneration;
|
|
299
321
|
await ensureHydrated(e);
|
|
300
|
-
if (e.resetting)
|
|
322
|
+
if (e.resetting || e.resetGeneration !== generation)
|
|
301
323
|
return 'rejected';
|
|
302
324
|
const identity = e.identity.get();
|
|
303
325
|
const pendingIdentity = e.mutations.peek();
|
|
@@ -309,9 +331,12 @@ export const UserGist = {
|
|
|
309
331
|
return 'rejected';
|
|
310
332
|
}
|
|
311
333
|
const cleanProps = e.consent.allowsAnalytics()
|
|
312
|
-
?
|
|
334
|
+
? (properties && Object.keys(properties).length
|
|
335
|
+
? userPropertiesUpdateSchema.parse({ mutationId: generateEventId(), set: properties }).set
|
|
336
|
+
: undefined)
|
|
313
337
|
: undefined;
|
|
314
338
|
if (transition === 'already_identified' &&
|
|
339
|
+
(!subjectToken || subjectToken === e.subjectToken) &&
|
|
315
340
|
(!cleanProps || Object.keys(cleanProps).length === 0)) {
|
|
316
341
|
return 'synced';
|
|
317
342
|
}
|
|
@@ -319,6 +344,7 @@ export const UserGist = {
|
|
|
319
344
|
reportError('identify requires a server-minted subject token');
|
|
320
345
|
return 'rejected';
|
|
321
346
|
}
|
|
347
|
+
identityChanged(e, 'identifying');
|
|
322
348
|
const mutationId = await e.mutations.enqueue('identify', 'essential', {
|
|
323
349
|
subjectToken,
|
|
324
350
|
anonymousId: identity.anonymousId,
|
|
@@ -326,7 +352,10 @@ export const UserGist = {
|
|
|
326
352
|
...(cleanProps ? { properties: cleanProps } : {}),
|
|
327
353
|
}, `identify:${userId}`);
|
|
328
354
|
const result = await flushMutations(e);
|
|
355
|
+
if (e.resetting || e.resetGeneration !== generation)
|
|
356
|
+
return 'rejected';
|
|
329
357
|
if (result.permanentlyRejectedIds.has(mutationId)) {
|
|
358
|
+
identityChanged(e, 'rejected');
|
|
330
359
|
reportError('identify was rejected by the server');
|
|
331
360
|
return 'rejected';
|
|
332
361
|
}
|
|
@@ -410,7 +439,7 @@ export const UserGist = {
|
|
|
410
439
|
if (e.resetting || next.version !== e.consent.get().version)
|
|
411
440
|
return false;
|
|
412
441
|
if (e.lastPushToken)
|
|
413
|
-
await
|
|
442
|
+
await invalidatePushDevice(e.lastPushToken, true);
|
|
414
443
|
await disableNativePushForConsent(e, next.version);
|
|
415
444
|
}
|
|
416
445
|
if (e.resetting || next.version !== e.consent.get().version)
|
|
@@ -434,6 +463,9 @@ export const UserGist = {
|
|
|
434
463
|
reportError('transport.consent failed', err);
|
|
435
464
|
return false;
|
|
436
465
|
}
|
|
466
|
+
pushSubscriptionChanged(e);
|
|
467
|
+
if (next.push)
|
|
468
|
+
void e.retryPushRegistration?.().catch(error => reportError('push registration deferred', error));
|
|
437
469
|
if (next.feedback || next.survey) {
|
|
438
470
|
await refreshTargetingRules(e, true);
|
|
439
471
|
}
|
|
@@ -450,10 +482,14 @@ export const UserGist = {
|
|
|
450
482
|
reset() {
|
|
451
483
|
try {
|
|
452
484
|
const e = requireEngine();
|
|
453
|
-
if (
|
|
454
|
-
return resetPromise
|
|
485
|
+
if (resetPromise)
|
|
486
|
+
return resetPromise;
|
|
455
487
|
e.resetting = true;
|
|
488
|
+
identityChanged(e, 'resetting');
|
|
489
|
+
pushSubscriptionChanged(e);
|
|
456
490
|
e.resetGeneration += 1;
|
|
491
|
+
e.transport.cancelAll();
|
|
492
|
+
cancelIdentityRecovery(e);
|
|
457
493
|
e.presentation.invalidate();
|
|
458
494
|
requestsCache = null;
|
|
459
495
|
lastEnablePushOptions = null;
|
|
@@ -461,18 +497,15 @@ export const UserGist = {
|
|
|
461
497
|
const operation = (async () => {
|
|
462
498
|
await ensureHydrated(e);
|
|
463
499
|
await syncNativePushState(e, false);
|
|
464
|
-
|
|
465
|
-
if (e.lastPushToken)
|
|
466
|
-
await UserGist.invalidatePushToken(e.lastPushToken);
|
|
467
|
-
await UserGistPushNative.disablePush().catch(() => undefined);
|
|
500
|
+
void UserGistPushNative.disablePush().catch(() => undefined);
|
|
468
501
|
await clearAllState(e);
|
|
469
502
|
await surveyStore?.clear();
|
|
470
503
|
await hydratePushDedupe(e.config.writeKey, e.identity.get().anonymousId);
|
|
471
504
|
})();
|
|
472
505
|
const finalized = operation
|
|
473
|
-
.
|
|
506
|
+
.then(() => { e.resetting = false; pushSubscriptionChanged(e); })
|
|
507
|
+
.catch((err) => { identityChanged(e, 'reset-failed'); reportError('reset failed', err); throw err; })
|
|
474
508
|
.finally(() => {
|
|
475
|
-
e.resetting = false;
|
|
476
509
|
if (resetPromise === finalized)
|
|
477
510
|
resetPromise = null;
|
|
478
511
|
});
|
|
@@ -581,80 +614,10 @@ export const UserGist = {
|
|
|
581
614
|
}
|
|
582
615
|
},
|
|
583
616
|
async registerPushToken(token, platform, opts) {
|
|
584
|
-
|
|
585
|
-
if (!token)
|
|
586
|
-
return;
|
|
587
|
-
const e = requireEngine();
|
|
588
|
-
await ensureHydrated(e);
|
|
589
|
-
if (!e.consent.allowsPush() || e.resetting)
|
|
590
|
-
return;
|
|
591
|
-
const generation = e.resetGeneration;
|
|
592
|
-
await serializePushRegistration(async () => {
|
|
593
|
-
if (e.resetting ||
|
|
594
|
-
generation !== e.resetGeneration ||
|
|
595
|
-
!e.consent.allowsPush())
|
|
596
|
-
return;
|
|
597
|
-
const id = e.identity.get();
|
|
598
|
-
const environment = opts?.environment ??
|
|
599
|
-
(await UserGistPushNative.defaultEnvironment()) ??
|
|
600
|
-
(e.config.environment === 'production' ? 'production' : 'sandbox');
|
|
601
|
-
const registrationKey = [
|
|
602
|
-
id.anonymousId,
|
|
603
|
-
id.externalId ?? '',
|
|
604
|
-
platform,
|
|
605
|
-
environment,
|
|
606
|
-
token,
|
|
607
|
-
].join(':');
|
|
608
|
-
if (e.lastPushRegistrationKey === registrationKey &&
|
|
609
|
-
Date.now() - e.lastPushRegistrationAt < 24 * 60 * 60_000)
|
|
610
|
-
return;
|
|
611
|
-
if (e.resetting ||
|
|
612
|
-
generation !== e.resetGeneration ||
|
|
613
|
-
!e.consent.allowsPush())
|
|
614
|
-
return;
|
|
615
|
-
// Persist before the request so logout can invalidate a token even when
|
|
616
|
-
// the response is lost or the process exits after the server accepts it.
|
|
617
|
-
e.lastPushToken = token;
|
|
618
|
-
await e.storage.setJson(STORAGE_KEYS.pushToken, token);
|
|
619
|
-
await e.transport.pushRegisterToken({
|
|
620
|
-
anonymousId: id.anonymousId,
|
|
621
|
-
externalId: id.externalId ?? null,
|
|
622
|
-
token,
|
|
623
|
-
platform,
|
|
624
|
-
environment,
|
|
625
|
-
language: undefined,
|
|
626
|
-
timezone: Intl.DateTimeFormat().resolvedOptions().timeZone,
|
|
627
|
-
appVersion: undefined,
|
|
628
|
-
sdkVersion: `rn-${USERGIST_SDK_VERSION}`,
|
|
629
|
-
optIn: true,
|
|
630
|
-
});
|
|
631
|
-
e.lastPushToken = token;
|
|
632
|
-
e.lastPushRegistrationKey = registrationKey;
|
|
633
|
-
e.lastPushRegistrationAt = Date.now();
|
|
634
|
-
debugLog('push token registered with server');
|
|
635
|
-
});
|
|
636
|
-
}
|
|
637
|
-
catch (err) {
|
|
638
|
-
reportError('registerPushToken failed', err);
|
|
639
|
-
}
|
|
617
|
+
await registerPushDevice(token, platform, opts);
|
|
640
618
|
},
|
|
641
619
|
async invalidatePushToken(token) {
|
|
642
|
-
|
|
643
|
-
if (!token)
|
|
644
|
-
return;
|
|
645
|
-
const e = requireEngine();
|
|
646
|
-
await ensureHydrated(e);
|
|
647
|
-
const id = e.identity.get();
|
|
648
|
-
e.lastPushRegistrationKey = null;
|
|
649
|
-
e.lastPushRegistrationAt = 0;
|
|
650
|
-
await e.transport.pushInvalidateToken({
|
|
651
|
-
anonymousId: id.anonymousId,
|
|
652
|
-
token,
|
|
653
|
-
});
|
|
654
|
-
}
|
|
655
|
-
catch (err) {
|
|
656
|
-
reportError('invalidatePushToken failed', err);
|
|
657
|
-
}
|
|
620
|
+
await invalidatePushDevice(token);
|
|
658
621
|
},
|
|
659
622
|
/**
|
|
660
623
|
* Re-bind the latest registered device token to a newly-identified user.
|
|
@@ -1618,4 +1581,97 @@ export const UserGist = {
|
|
|
1618
1581
|
}
|
|
1619
1582
|
},
|
|
1620
1583
|
};
|
|
1584
|
+
/** Registration and invalidation share an ordered lane. Automatic retries may
|
|
1585
|
+
* consume a retained token, but must never recreate an invalidated candidate. */
|
|
1586
|
+
async function registerPushDevice(token, platform, opts, retry = false) {
|
|
1587
|
+
try {
|
|
1588
|
+
if (!token)
|
|
1589
|
+
return;
|
|
1590
|
+
const e = requireEngine();
|
|
1591
|
+
if (e.resetting)
|
|
1592
|
+
return;
|
|
1593
|
+
const generation = e.resetGeneration;
|
|
1594
|
+
await serializePushRegistration(async () => {
|
|
1595
|
+
await ensureHydrated(e);
|
|
1596
|
+
if (e.resetting || generation !== e.resetGeneration)
|
|
1597
|
+
return;
|
|
1598
|
+
const environment = opts?.environment ?? (await UserGistPushNative.defaultEnvironment()) ??
|
|
1599
|
+
(e.config.environment === 'production' ? 'production' : 'sandbox');
|
|
1600
|
+
if (e.resetting || generation !== e.resetGeneration)
|
|
1601
|
+
return;
|
|
1602
|
+
const descriptor = { token, platform, environment };
|
|
1603
|
+
const stored = await e.storage.getJson(STORAGE_KEYS.pushDevice);
|
|
1604
|
+
if (JSON.stringify(stored) !== JSON.stringify(descriptor)) {
|
|
1605
|
+
if (retry)
|
|
1606
|
+
return;
|
|
1607
|
+
await e.storage.setJsonStrict(STORAGE_KEYS.pushDevice, descriptor);
|
|
1608
|
+
}
|
|
1609
|
+
e.pushTokenAvailable = true;
|
|
1610
|
+
pushSubscriptionChanged(e);
|
|
1611
|
+
if (!e.consent.allowsPush())
|
|
1612
|
+
return;
|
|
1613
|
+
await drainRevocations(e);
|
|
1614
|
+
if (await hasPendingRevocations(e) || e.resetting || generation !== e.resetGeneration || !e.consent.allowsPush())
|
|
1615
|
+
return;
|
|
1616
|
+
const id = e.identity.get();
|
|
1617
|
+
const registrationKey = [id.anonymousId, id.externalId ?? '', platform, environment, token].join(':');
|
|
1618
|
+
if (e.lastPushRegistrationKey === registrationKey && Date.now() - e.lastPushRegistrationAt < 24 * 60 * 60_000)
|
|
1619
|
+
return;
|
|
1620
|
+
// Persist before delivery so logout still owns a token if its response is lost.
|
|
1621
|
+
e.lastPushToken = token;
|
|
1622
|
+
await e.storage.setJson(STORAGE_KEYS.pushToken, token);
|
|
1623
|
+
if (e.resetting || generation !== e.resetGeneration || !e.consent.allowsPush())
|
|
1624
|
+
return;
|
|
1625
|
+
const registration = await e.transport.pushRegisterToken({
|
|
1626
|
+
anonymousId: id.anonymousId, externalId: id.externalId ?? null,
|
|
1627
|
+
token, platform, environment, timezone: Intl.DateTimeFormat().resolvedOptions().timeZone,
|
|
1628
|
+
sdkVersion: `rn-${USERGIST_SDK_VERSION}`, optIn: true,
|
|
1629
|
+
});
|
|
1630
|
+
if (e.resetting || generation !== e.resetGeneration || !e.consent.allowsPush())
|
|
1631
|
+
return;
|
|
1632
|
+
if (!(registration && typeof registration === 'object' && 'registered' in registration && registration.registered === true)) {
|
|
1633
|
+
pushSubscriptionChanged(e);
|
|
1634
|
+
return;
|
|
1635
|
+
}
|
|
1636
|
+
e.lastPushRegistrationKey = registrationKey;
|
|
1637
|
+
e.lastPushRegistrationAt = Date.now();
|
|
1638
|
+
pushSubscriptionChanged(e);
|
|
1639
|
+
debugLog('push token registered with server');
|
|
1640
|
+
});
|
|
1641
|
+
}
|
|
1642
|
+
catch (err) {
|
|
1643
|
+
reportError('registerPushToken failed', err);
|
|
1644
|
+
}
|
|
1645
|
+
}
|
|
1646
|
+
async function invalidatePushDevice(token, retainDevice = false) {
|
|
1647
|
+
try {
|
|
1648
|
+
if (!token)
|
|
1649
|
+
return;
|
|
1650
|
+
const e = requireEngine();
|
|
1651
|
+
const generation = e.resetGeneration;
|
|
1652
|
+
await serializePushRegistration(async () => {
|
|
1653
|
+
await ensureHydrated(e);
|
|
1654
|
+
if (e.resetting || generation !== e.resetGeneration)
|
|
1655
|
+
return;
|
|
1656
|
+
const saved = await e.storage.getJson(STORAGE_KEYS.pushDevice);
|
|
1657
|
+
if (saved?.token === token) {
|
|
1658
|
+
// Retire the automatic retry candidate before invalidating it remotely.
|
|
1659
|
+
if (!retainDevice)
|
|
1660
|
+
await e.storage.setJsonStrict(STORAGE_KEYS.pushDevice, null);
|
|
1661
|
+
e.pushTokenAvailable = retainDevice;
|
|
1662
|
+
e.lastPushRegistrationKey = null;
|
|
1663
|
+
e.lastPushRegistrationAt = 0;
|
|
1664
|
+
}
|
|
1665
|
+
if (e.lastPushToken === token) {
|
|
1666
|
+
await e.storage.setJsonStrict(STORAGE_KEYS.pushToken, null);
|
|
1667
|
+
e.lastPushToken = null;
|
|
1668
|
+
}
|
|
1669
|
+
pushSubscriptionChanged(e);
|
|
1670
|
+
await e.transport.pushInvalidateToken({ anonymousId: e.identity.get().anonymousId, token });
|
|
1671
|
+
});
|
|
1672
|
+
}
|
|
1673
|
+
catch (err) {
|
|
1674
|
+
reportError('invalidatePushToken failed', err);
|
|
1675
|
+
}
|
|
1676
|
+
}
|
|
1621
1677
|
//# sourceMappingURL=UserGist.js.map
|