@sendoracloud/sdk-react-native 1.27.0 → 1.29.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/dist/index.d.cts CHANGED
@@ -221,10 +221,19 @@ declare class Storage {
221
221
  * user_id is preserved on success. Throws
222
222
  * EmailAlreadyTakenError on 409. Otherwise calls
223
223
  * /auth-service/signup as a fresh account.
224
- * signIn(email, password) — POST /auth-service/login. Wipes local
225
- * identity (anonId rotated, userId cleared, tokens dropped)
226
- * BEFORE the network call so any track() fired during the
227
- * round-trip can't attach to the prior identity.
224
+ * signIn(email, password) — POST /auth-service/login.
225
+ *
226
+ * HARD INVARIANT — a failed auth attempt leaves the caller exactly as
227
+ * it found them. Every credentialed path captures the anonymous
228
+ * refresh token into a local (for the device-takeover hint), performs
229
+ * its network call, validates the response, and only THEN clears the
230
+ * old identity and persists the new one. Clearing first would drop the
231
+ * refresh token — for an anonymous user the ONLY durable handle on the
232
+ * account — so any failure after that point (offline, 5xx, a mistyped
233
+ * OTP, a cancelled IdP callback) would orphan the account permanently.
234
+ * A track() fired during the round-trip therefore attaches to the
235
+ * still-anonymous identity, which is correct: the user is not
236
+ * identified yet, and the backend reattributes it via the takeover.
228
237
  *
229
238
  * All public auth ops are serialized through a single-flight chain
230
239
  * so a UI double-submit can't mint two anonymous users or interleave
@@ -321,9 +330,40 @@ type LinkedIdentitiesResponse = {
321
330
  identities: LinkedIdentity[];
322
331
  hasPassword: boolean;
323
332
  };
333
+ /**
334
+ * Closed set of auth failure categories (1.28.0). Branch on `kind` instead of
335
+ * string-matching the ~20 raw `code`s the backend and transport can produce.
336
+ *
337
+ * Pairs with the hard guarantee this release introduces: **a failed auth
338
+ * attempt never changes the local session.** An offline sign-in, a mistyped
339
+ * OTP, a dismissed Game Center sheet and a 429 all leave `getUserSync()` and
340
+ * the stored refresh token exactly as they were.
341
+ */
342
+ type AuthErrorKind = "network" | "server" | "rate_limited" | "invalid_credential" | "account_locked" | "credential_in_use" | "already_identified" | "cancelled" | "config" | "unknown";
324
343
  declare class AuthError extends Error {
325
344
  code: string;
326
- constructor(code: string, message: string);
345
+ /**
346
+ * Category of the failure — the field to branch on. See `AuthErrorKind`.
347
+ * Derived from `code` (+ HTTP status when known); never affects `code`,
348
+ * which stays exactly what shipped before 1.28.0.
349
+ */
350
+ readonly kind: AuthErrorKind;
351
+ /** True when retrying the SAME input can plausibly succeed later. */
352
+ readonly retryable: boolean;
353
+ /**
354
+ * Seconds to wait before retrying, when the server told us (429 backoff, or
355
+ * an ACCOUNT_LOCKED cool-off). Absent means "no server-provided hint" — for
356
+ * `account_locked` specifically, absent means the lock does NOT expire on
357
+ * its own and needs support.
358
+ */
359
+ readonly retryAfterSeconds?: number;
360
+ /** HTTP status when the failure came from a response (absent when offline). */
361
+ readonly status?: number;
362
+ constructor(code: string, message: string, opts?: {
363
+ status?: number;
364
+ retryAfterSeconds?: number;
365
+ kind?: AuthErrorKind;
366
+ });
327
367
  }
328
368
  interface AuthHooks {
329
369
  /** Storage shared with the parent SDK so re-hydration is consistent. */
@@ -366,6 +406,40 @@ interface DeletionCancelledEvent {
366
406
  /** Local clock at the time the SDK observed the event. */
367
407
  at: Date;
368
408
  }
409
+ /**
410
+ * Why the local session ended (1.28.0). Before this, a session that died in
411
+ * the background emitted NOTHING — an app could not tell a deliberate sign-out
412
+ * apart from an expired refresh token, and only discovered the difference when
413
+ * `getAccessToken()` started returning null.
414
+ *
415
+ * - `user` — the app called `signOut()`.
416
+ * - `session_expired` — the server rejected the stored refresh token (revoked,
417
+ * expired, rotated away). Transient network failures and
418
+ * rate limits do NOT produce this.
419
+ * - `account_deleted` — `deleteAccount()` succeeded.
420
+ */
421
+ type AuthSignedOutReason = "user" | "session_expired" | "account_deleted";
422
+ /**
423
+ * A single auth-state transition (1.28.0). Subscribe with
424
+ * `onAuthStateChanged` — one stream covering everything that used to need
425
+ * separate listeners (or had none at all).
426
+ */
427
+ type AuthStateChange = {
428
+ event: "signed_in";
429
+ user: AuthUser;
430
+ } | {
431
+ event: "signed_out";
432
+ user: null;
433
+ reason: AuthSignedOutReason;
434
+ } | {
435
+ event: "device_takeover";
436
+ user: AuthUser | null;
437
+ retiredAnonUserId: string;
438
+ } | {
439
+ event: "deletion_cancelled";
440
+ user: AuthUser | null;
441
+ };
442
+ type AuthStateListener = (change: AuthStateChange) => void;
369
443
  declare class Auth {
370
444
  private hooks;
371
445
  private user;
@@ -388,6 +462,7 @@ declare class Auth {
388
462
  private refreshCooldownUntil;
389
463
  private takeoverListeners;
390
464
  private deletionCancelledListeners;
465
+ private authStateListeners;
391
466
  private lastDeletionCancelled;
392
467
  private lastTakeover;
393
468
  /**
@@ -413,6 +488,11 @@ declare class Auth {
413
488
  */
414
489
  private readyPromise;
415
490
  private resolveReady;
491
+ /**
492
+ * True once `hydrate()` has run. Distinguishes "no session restored YET"
493
+ * from "genuinely signed out" for `onAuthStateChanged`'s replay-on-subscribe.
494
+ */
495
+ private hydrated;
416
496
  constructor(hooks: AuthHooks);
417
497
  /**
418
498
  * Re-hydrate session from storage. Called by the parent SDK during
@@ -449,6 +529,31 @@ declare class Auth {
449
529
  * + logged in dev mode. Auth state never depends on listener success.
450
530
  */
451
531
  onDeviceTakeover(listener: (evt: DeviceTakeoverEvent) => void): () => void;
532
+ /**
533
+ * Subscribe to every auth-state transition (1.28.0) — the single stream that
534
+ * answers "what happened to my session?". Firebase `onAuthStateChanged` /
535
+ * Supabase `onAuthStateChange` parity.
536
+ *
537
+ * The reason it exists: a session that dies in the BACKGROUND (the server
538
+ * rejected the stored refresh token) used to emit no signal whatsoever, so
539
+ * an app could not distinguish it from a deliberate sign-out and only
540
+ * noticed when `getAccessToken()` began returning null. That transition is
541
+ * now `{ event: "signed_out", reason: "session_expired" }`.
542
+ *
543
+ * Fires the CURRENT state immediately on subscribe once `init()` has
544
+ * hydrated (a `signed_in` when a session was restored from disk — including
545
+ * offline, since hydrate is disk-only), so a subscriber never misses the
546
+ * state it started in. Nothing is emitted for a signed-out cold start.
547
+ *
548
+ * A failed sign-in emits NOTHING: the session is unchanged, so there is no
549
+ * transition to report — the rejected promise is the whole story.
550
+ *
551
+ * Listeners are best-effort; a throwing listener is swallowed (dev-logged)
552
+ * and never affects auth state. Returns an unsubscribe function.
553
+ */
554
+ onAuthStateChanged(listener: AuthStateListener): () => void;
555
+ /** Fan a state change out to subscribers. Never throws. */
556
+ private emitAuthState;
452
557
  /**
453
558
  * Inspect the most recent device-takeover event observed by the
454
559
  * SDK. Cleared on signOut. Returns null when no takeover has
@@ -506,9 +611,25 @@ declare class Auth {
506
611
  getAccessToken(): Promise<string | null>;
507
612
  /** Sync read — returns whatever's cached even if expired. Prefer the async variant. */
508
613
  getAccessTokenSync(): string | null;
614
+ /**
615
+ * Mint (or return) an anonymous session.
616
+ *
617
+ * Reuses the existing anonymous user when there already is one — the same
618
+ * short-circuit Firebase's `signInAnonymously` performs. Without it, an app
619
+ * that calls this defensively on every cold launch (the most natural thing
620
+ * to write) mints a fresh `user_id` each time, and `persist()` overwrites
621
+ * the stored refresh token — the previous anonymous account's only durable
622
+ * handle — with no takeover, no webhook and no state event. That is the same
623
+ * silent progress loss as a failed sign-in wiping the session, except it
624
+ * happens on a *healthy* network.
625
+ *
626
+ * Pass `forceNew: true` to deliberately abandon the current anonymous
627
+ * session and mint a separate one.
628
+ */
509
629
  signInAnonymously(opts?: {
510
630
  name?: string;
511
631
  metadata?: Record<string, unknown>;
632
+ forceNew?: boolean;
512
633
  }): Promise<AuthUser>;
513
634
  /**
514
635
  * Create an email/password account.
@@ -882,6 +1003,29 @@ declare class Auth {
882
1003
  }>;
883
1004
  private callAuth;
884
1005
  private persist;
1006
+ /**
1007
+ * Drop the local session.
1008
+ *
1009
+ * `reason` drives the `onAuthStateChanged` emission: a real sign-out reason
1010
+ * emits `signed_out`, while `"replaced"` (the internal pre-`persist()` clear
1011
+ * on a SUCCESSFUL sign-in) emits nothing — subscribers see one `signed_in`,
1012
+ * not a spurious logout/login pair.
1013
+ *
1014
+ * ⚠ Never call this before a fallible network request. A failed sign-in must
1015
+ * leave the caller exactly as it found them; for an anonymous session the
1016
+ * refresh token dropped here is the ONLY durable handle on the account, so a
1017
+ * pre-call wipe that is not followed by a successful `persist()` orphans the
1018
+ * account permanently (offline: deterministically). Capture the anon refresh
1019
+ * into a local, make the call, and wipe only after the response validates.
1020
+ */
1021
+ /**
1022
+ * True when `sent` is still the refresh token on disk — i.e. nothing
1023
+ * replaced or cleared the session while a request carrying it was in
1024
+ * flight. Guards both directions of the refresh race: installing a rotated
1025
+ * token over a session that has since been signed out or replaced, and
1026
+ * wiping a fresh session because an OLD token was rejected.
1027
+ */
1028
+ private tokenStillCurrent;
885
1029
  private wipeLocalIdentity;
886
1030
  }
887
1031
 
@@ -1664,6 +1808,12 @@ declare class SendoraSDK {
1664
1808
  * Clear identity + rotate the anonymous id. Call on logout. Awaits
1665
1809
  * the AsyncStorage writes so a caller who kills the app immediately
1666
1810
  * after doesn't leave stale identity on disk.
1811
+ *
1812
+ * Signs out through `auth` rather than just clearing storage: `clearAll()`
1813
+ * removes the auth keys too, so doing it directly left `Auth` holding an
1814
+ * in-memory user and reporting itself signed in while its refresh token was
1815
+ * already gone — with the server-side session never revoked and no
1816
+ * `onAuthStateChanged` emission telling the app the session had ended.
1667
1817
  */
1668
1818
  reset(): Promise<void>;
1669
1819
  /** Tear down auto-track listeners. Call in test harnesses. */
@@ -1673,4 +1823,4 @@ declare class SendoraSDK {
1673
1823
  }
1674
1824
  declare const SendoraCloud: SendoraSDK;
1675
1825
 
1676
- export { AlreadyIdentifiedError, type AttachLinkingApiOptions, Auth, AuthError, type AuthTokens, type AuthUser, CredentialInUseError, EmailAlreadyTakenError, type IdentifyTraits, type LinkCreateInput, type LinkCreateResult, type LinkData, LinkError, type LinkErrorCode, type LinkMatchInput, type LinkOpenedEvent, type LinkOpenedHandler, type LinkStats, type LinkedIdentitiesResponse, type LinkedIdentity, Links, type PushTokenReceipt, type PushTokenRegistration, SendoraCloud, type SendoraConfig, type TrackProperties, computeDeviceFingerprint, SendoraCloud as default, extractShortcodeFromUrl, getPlayInstallReferrer };
1826
+ export { AlreadyIdentifiedError, type AttachLinkingApiOptions, Auth, AuthError, type AuthErrorKind, type AuthSignedOutReason, type AuthStateChange, type AuthTokens, type AuthUser, CredentialInUseError, type DeletionCancelledEvent, type DeviceTakeoverEvent, EmailAlreadyTakenError, type IdentifyTraits, type LinkCreateInput, type LinkCreateResult, type LinkData, LinkError, type LinkErrorCode, type LinkMatchInput, type LinkOpenedEvent, type LinkOpenedHandler, type LinkStats, type LinkedIdentitiesResponse, type LinkedIdentity, Links, type PushTokenReceipt, type PushTokenRegistration, SendoraCloud, type SendoraConfig, type TrackProperties, computeDeviceFingerprint, SendoraCloud as default, extractShortcodeFromUrl, getPlayInstallReferrer };
package/dist/index.d.ts CHANGED
@@ -221,10 +221,19 @@ declare class Storage {
221
221
  * user_id is preserved on success. Throws
222
222
  * EmailAlreadyTakenError on 409. Otherwise calls
223
223
  * /auth-service/signup as a fresh account.
224
- * signIn(email, password) — POST /auth-service/login. Wipes local
225
- * identity (anonId rotated, userId cleared, tokens dropped)
226
- * BEFORE the network call so any track() fired during the
227
- * round-trip can't attach to the prior identity.
224
+ * signIn(email, password) — POST /auth-service/login.
225
+ *
226
+ * HARD INVARIANT — a failed auth attempt leaves the caller exactly as
227
+ * it found them. Every credentialed path captures the anonymous
228
+ * refresh token into a local (for the device-takeover hint), performs
229
+ * its network call, validates the response, and only THEN clears the
230
+ * old identity and persists the new one. Clearing first would drop the
231
+ * refresh token — for an anonymous user the ONLY durable handle on the
232
+ * account — so any failure after that point (offline, 5xx, a mistyped
233
+ * OTP, a cancelled IdP callback) would orphan the account permanently.
234
+ * A track() fired during the round-trip therefore attaches to the
235
+ * still-anonymous identity, which is correct: the user is not
236
+ * identified yet, and the backend reattributes it via the takeover.
228
237
  *
229
238
  * All public auth ops are serialized through a single-flight chain
230
239
  * so a UI double-submit can't mint two anonymous users or interleave
@@ -321,9 +330,40 @@ type LinkedIdentitiesResponse = {
321
330
  identities: LinkedIdentity[];
322
331
  hasPassword: boolean;
323
332
  };
333
+ /**
334
+ * Closed set of auth failure categories (1.28.0). Branch on `kind` instead of
335
+ * string-matching the ~20 raw `code`s the backend and transport can produce.
336
+ *
337
+ * Pairs with the hard guarantee this release introduces: **a failed auth
338
+ * attempt never changes the local session.** An offline sign-in, a mistyped
339
+ * OTP, a dismissed Game Center sheet and a 429 all leave `getUserSync()` and
340
+ * the stored refresh token exactly as they were.
341
+ */
342
+ type AuthErrorKind = "network" | "server" | "rate_limited" | "invalid_credential" | "account_locked" | "credential_in_use" | "already_identified" | "cancelled" | "config" | "unknown";
324
343
  declare class AuthError extends Error {
325
344
  code: string;
326
- constructor(code: string, message: string);
345
+ /**
346
+ * Category of the failure — the field to branch on. See `AuthErrorKind`.
347
+ * Derived from `code` (+ HTTP status when known); never affects `code`,
348
+ * which stays exactly what shipped before 1.28.0.
349
+ */
350
+ readonly kind: AuthErrorKind;
351
+ /** True when retrying the SAME input can plausibly succeed later. */
352
+ readonly retryable: boolean;
353
+ /**
354
+ * Seconds to wait before retrying, when the server told us (429 backoff, or
355
+ * an ACCOUNT_LOCKED cool-off). Absent means "no server-provided hint" — for
356
+ * `account_locked` specifically, absent means the lock does NOT expire on
357
+ * its own and needs support.
358
+ */
359
+ readonly retryAfterSeconds?: number;
360
+ /** HTTP status when the failure came from a response (absent when offline). */
361
+ readonly status?: number;
362
+ constructor(code: string, message: string, opts?: {
363
+ status?: number;
364
+ retryAfterSeconds?: number;
365
+ kind?: AuthErrorKind;
366
+ });
327
367
  }
328
368
  interface AuthHooks {
329
369
  /** Storage shared with the parent SDK so re-hydration is consistent. */
@@ -366,6 +406,40 @@ interface DeletionCancelledEvent {
366
406
  /** Local clock at the time the SDK observed the event. */
367
407
  at: Date;
368
408
  }
409
+ /**
410
+ * Why the local session ended (1.28.0). Before this, a session that died in
411
+ * the background emitted NOTHING — an app could not tell a deliberate sign-out
412
+ * apart from an expired refresh token, and only discovered the difference when
413
+ * `getAccessToken()` started returning null.
414
+ *
415
+ * - `user` — the app called `signOut()`.
416
+ * - `session_expired` — the server rejected the stored refresh token (revoked,
417
+ * expired, rotated away). Transient network failures and
418
+ * rate limits do NOT produce this.
419
+ * - `account_deleted` — `deleteAccount()` succeeded.
420
+ */
421
+ type AuthSignedOutReason = "user" | "session_expired" | "account_deleted";
422
+ /**
423
+ * A single auth-state transition (1.28.0). Subscribe with
424
+ * `onAuthStateChanged` — one stream covering everything that used to need
425
+ * separate listeners (or had none at all).
426
+ */
427
+ type AuthStateChange = {
428
+ event: "signed_in";
429
+ user: AuthUser;
430
+ } | {
431
+ event: "signed_out";
432
+ user: null;
433
+ reason: AuthSignedOutReason;
434
+ } | {
435
+ event: "device_takeover";
436
+ user: AuthUser | null;
437
+ retiredAnonUserId: string;
438
+ } | {
439
+ event: "deletion_cancelled";
440
+ user: AuthUser | null;
441
+ };
442
+ type AuthStateListener = (change: AuthStateChange) => void;
369
443
  declare class Auth {
370
444
  private hooks;
371
445
  private user;
@@ -388,6 +462,7 @@ declare class Auth {
388
462
  private refreshCooldownUntil;
389
463
  private takeoverListeners;
390
464
  private deletionCancelledListeners;
465
+ private authStateListeners;
391
466
  private lastDeletionCancelled;
392
467
  private lastTakeover;
393
468
  /**
@@ -413,6 +488,11 @@ declare class Auth {
413
488
  */
414
489
  private readyPromise;
415
490
  private resolveReady;
491
+ /**
492
+ * True once `hydrate()` has run. Distinguishes "no session restored YET"
493
+ * from "genuinely signed out" for `onAuthStateChanged`'s replay-on-subscribe.
494
+ */
495
+ private hydrated;
416
496
  constructor(hooks: AuthHooks);
417
497
  /**
418
498
  * Re-hydrate session from storage. Called by the parent SDK during
@@ -449,6 +529,31 @@ declare class Auth {
449
529
  * + logged in dev mode. Auth state never depends on listener success.
450
530
  */
451
531
  onDeviceTakeover(listener: (evt: DeviceTakeoverEvent) => void): () => void;
532
+ /**
533
+ * Subscribe to every auth-state transition (1.28.0) — the single stream that
534
+ * answers "what happened to my session?". Firebase `onAuthStateChanged` /
535
+ * Supabase `onAuthStateChange` parity.
536
+ *
537
+ * The reason it exists: a session that dies in the BACKGROUND (the server
538
+ * rejected the stored refresh token) used to emit no signal whatsoever, so
539
+ * an app could not distinguish it from a deliberate sign-out and only
540
+ * noticed when `getAccessToken()` began returning null. That transition is
541
+ * now `{ event: "signed_out", reason: "session_expired" }`.
542
+ *
543
+ * Fires the CURRENT state immediately on subscribe once `init()` has
544
+ * hydrated (a `signed_in` when a session was restored from disk — including
545
+ * offline, since hydrate is disk-only), so a subscriber never misses the
546
+ * state it started in. Nothing is emitted for a signed-out cold start.
547
+ *
548
+ * A failed sign-in emits NOTHING: the session is unchanged, so there is no
549
+ * transition to report — the rejected promise is the whole story.
550
+ *
551
+ * Listeners are best-effort; a throwing listener is swallowed (dev-logged)
552
+ * and never affects auth state. Returns an unsubscribe function.
553
+ */
554
+ onAuthStateChanged(listener: AuthStateListener): () => void;
555
+ /** Fan a state change out to subscribers. Never throws. */
556
+ private emitAuthState;
452
557
  /**
453
558
  * Inspect the most recent device-takeover event observed by the
454
559
  * SDK. Cleared on signOut. Returns null when no takeover has
@@ -506,9 +611,25 @@ declare class Auth {
506
611
  getAccessToken(): Promise<string | null>;
507
612
  /** Sync read — returns whatever's cached even if expired. Prefer the async variant. */
508
613
  getAccessTokenSync(): string | null;
614
+ /**
615
+ * Mint (or return) an anonymous session.
616
+ *
617
+ * Reuses the existing anonymous user when there already is one — the same
618
+ * short-circuit Firebase's `signInAnonymously` performs. Without it, an app
619
+ * that calls this defensively on every cold launch (the most natural thing
620
+ * to write) mints a fresh `user_id` each time, and `persist()` overwrites
621
+ * the stored refresh token — the previous anonymous account's only durable
622
+ * handle — with no takeover, no webhook and no state event. That is the same
623
+ * silent progress loss as a failed sign-in wiping the session, except it
624
+ * happens on a *healthy* network.
625
+ *
626
+ * Pass `forceNew: true` to deliberately abandon the current anonymous
627
+ * session and mint a separate one.
628
+ */
509
629
  signInAnonymously(opts?: {
510
630
  name?: string;
511
631
  metadata?: Record<string, unknown>;
632
+ forceNew?: boolean;
512
633
  }): Promise<AuthUser>;
513
634
  /**
514
635
  * Create an email/password account.
@@ -882,6 +1003,29 @@ declare class Auth {
882
1003
  }>;
883
1004
  private callAuth;
884
1005
  private persist;
1006
+ /**
1007
+ * Drop the local session.
1008
+ *
1009
+ * `reason` drives the `onAuthStateChanged` emission: a real sign-out reason
1010
+ * emits `signed_out`, while `"replaced"` (the internal pre-`persist()` clear
1011
+ * on a SUCCESSFUL sign-in) emits nothing — subscribers see one `signed_in`,
1012
+ * not a spurious logout/login pair.
1013
+ *
1014
+ * ⚠ Never call this before a fallible network request. A failed sign-in must
1015
+ * leave the caller exactly as it found them; for an anonymous session the
1016
+ * refresh token dropped here is the ONLY durable handle on the account, so a
1017
+ * pre-call wipe that is not followed by a successful `persist()` orphans the
1018
+ * account permanently (offline: deterministically). Capture the anon refresh
1019
+ * into a local, make the call, and wipe only after the response validates.
1020
+ */
1021
+ /**
1022
+ * True when `sent` is still the refresh token on disk — i.e. nothing
1023
+ * replaced or cleared the session while a request carrying it was in
1024
+ * flight. Guards both directions of the refresh race: installing a rotated
1025
+ * token over a session that has since been signed out or replaced, and
1026
+ * wiping a fresh session because an OLD token was rejected.
1027
+ */
1028
+ private tokenStillCurrent;
885
1029
  private wipeLocalIdentity;
886
1030
  }
887
1031
 
@@ -1664,6 +1808,12 @@ declare class SendoraSDK {
1664
1808
  * Clear identity + rotate the anonymous id. Call on logout. Awaits
1665
1809
  * the AsyncStorage writes so a caller who kills the app immediately
1666
1810
  * after doesn't leave stale identity on disk.
1811
+ *
1812
+ * Signs out through `auth` rather than just clearing storage: `clearAll()`
1813
+ * removes the auth keys too, so doing it directly left `Auth` holding an
1814
+ * in-memory user and reporting itself signed in while its refresh token was
1815
+ * already gone — with the server-side session never revoked and no
1816
+ * `onAuthStateChanged` emission telling the app the session had ended.
1667
1817
  */
1668
1818
  reset(): Promise<void>;
1669
1819
  /** Tear down auto-track listeners. Call in test harnesses. */
@@ -1673,4 +1823,4 @@ declare class SendoraSDK {
1673
1823
  }
1674
1824
  declare const SendoraCloud: SendoraSDK;
1675
1825
 
1676
- export { AlreadyIdentifiedError, type AttachLinkingApiOptions, Auth, AuthError, type AuthTokens, type AuthUser, CredentialInUseError, EmailAlreadyTakenError, type IdentifyTraits, type LinkCreateInput, type LinkCreateResult, type LinkData, LinkError, type LinkErrorCode, type LinkMatchInput, type LinkOpenedEvent, type LinkOpenedHandler, type LinkStats, type LinkedIdentitiesResponse, type LinkedIdentity, Links, type PushTokenReceipt, type PushTokenRegistration, SendoraCloud, type SendoraConfig, type TrackProperties, computeDeviceFingerprint, SendoraCloud as default, extractShortcodeFromUrl, getPlayInstallReferrer };
1826
+ export { AlreadyIdentifiedError, type AttachLinkingApiOptions, Auth, AuthError, type AuthErrorKind, type AuthSignedOutReason, type AuthStateChange, type AuthTokens, type AuthUser, CredentialInUseError, type DeletionCancelledEvent, type DeviceTakeoverEvent, EmailAlreadyTakenError, type IdentifyTraits, type LinkCreateInput, type LinkCreateResult, type LinkData, LinkError, type LinkErrorCode, type LinkMatchInput, type LinkOpenedEvent, type LinkOpenedHandler, type LinkStats, type LinkedIdentitiesResponse, type LinkedIdentity, Links, type PushTokenReceipt, type PushTokenRegistration, SendoraCloud, type SendoraConfig, type TrackProperties, computeDeviceFingerprint, SendoraCloud as default, extractShortcodeFromUrl, getPlayInstallReferrer };