@sendoracloud/sdk-react-native 1.25.0 → 1.27.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.cjs CHANGED
@@ -202,7 +202,7 @@ var Storage = class {
202
202
  // package.json
203
203
  var package_default = {
204
204
  name: "@sendoracloud/sdk-react-native",
205
- version: "1.25.0",
205
+ version: "1.27.0",
206
206
  description: "Sendora Cloud React Native + Expo SDK \u2014 analytics, identity, push-token registration, auth (incl. Game Center / Play Games), deep links (Branch / Firebase Dynamic Links parity). Auth + analytics + deep links work in Expo Go; push-token registration and the no-arg Game Center / Play Games sign-in require a Dev Client (EAS Build or `npx expo prebuild`).",
207
207
  type: "module",
208
208
  main: "./dist/index.cjs",
@@ -510,6 +510,8 @@ var Auth = class {
510
510
  this.refreshFailureCount = 0;
511
511
  this.refreshCooldownUntil = 0;
512
512
  this.takeoverListeners = /* @__PURE__ */ new Set();
513
+ this.deletionCancelledListeners = /* @__PURE__ */ new Set();
514
+ this.lastDeletionCancelled = null;
513
515
  this.lastTakeover = null;
514
516
  /**
515
517
  * Anon refresh token captured at `signIn()` time, stashed keyed to the
@@ -622,6 +624,36 @@ var Auth = class {
622
624
  }
623
625
  }
624
626
  }
627
+ /**
628
+ * Subscribe to deletion-cancelled events (s58.269): fires when a sign-in
629
+ * cancelled a pending self-service account deletion within its grace window
630
+ * (the account is restored, same user_id). Use it to show "your account
631
+ * deletion was cancelled" + reconcile local state. Fires from signIn /
632
+ * loginSocial / signInWithGameCenter / signInWithPlayGames. Returns an
633
+ * unsubscribe function; listener errors are swallowed (best-effort).
634
+ */
635
+ onDeletionCancelled(listener) {
636
+ this.deletionCancelledListeners.add(listener);
637
+ return () => {
638
+ this.deletionCancelledListeners.delete(listener);
639
+ };
640
+ }
641
+ /** The most recent deletion-cancelled event this session, or null. Cleared on signOut. */
642
+ getLastDeletionCancelled() {
643
+ return this.lastDeletionCancelled;
644
+ }
645
+ /** Internal — fan out deletion-cancelled to subscribers + cache the latest. */
646
+ fireDeletionCancelled(userId) {
647
+ const evt = { userId, at: /* @__PURE__ */ new Date() };
648
+ this.lastDeletionCancelled = evt;
649
+ for (const fn of this.deletionCancelledListeners) {
650
+ try {
651
+ fn(evt);
652
+ } catch (err) {
653
+ if (this.hooks.debug) console.warn("[sendoracloud] onDeletionCancelled listener threw", err);
654
+ }
655
+ }
656
+ }
625
657
  /**
626
658
  * Returns a VALID (non-expired) access token, or null.
627
659
  *
@@ -952,6 +984,36 @@ var Auth = class {
952
984
  this.user = user;
953
985
  this.hooks.storage.set(USER_KEY, JSON.stringify(user));
954
986
  }
987
+ /**
988
+ * List the auth methods/identities linked to the current account (ADR-030
989
+ * read side, s58.270). Returns every social/gaming identity on this account
990
+ * plus a `hasPassword` flag — the cross-device / reinstall-durable source of
991
+ * truth for a "Connected: Game Center · Google" UI (an on-device tracker
992
+ * misses a link made on another device). Bearer-gated network read (NOT a
993
+ * cache read — `getUserSync()` only holds the primary `signupMethod`/
994
+ * `lastLoginMethod`). Resolves a FRESH access token first (mirrors
995
+ * `deleteAccount`). Firebase `user.providerData` / Supabase `user.identities`.
996
+ */
997
+ async listLinkedIdentities() {
998
+ const token = await this.getAccessToken();
999
+ if (!token) throw new AuthError("NOT_SIGNED_IN", "Sign in before listing linked identities");
1000
+ const res = await getJson(
1001
+ { apiUrl: this.hooks.apiUrl, publicKey: this.hooks.publicKey, debug: this.hooks.debug },
1002
+ "/api/v1/auth-service/me/identities",
1003
+ { Authorization: `Bearer ${token}` }
1004
+ );
1005
+ if (!res || !res.ok) throw new AuthError("NETWORK_ERROR", "Failed to list linked identities");
1006
+ let parsed;
1007
+ try {
1008
+ parsed = await res.json();
1009
+ } catch {
1010
+ throw new AuthError("PARSE_ERROR", `HTTP ${res.status}`);
1011
+ }
1012
+ if (!parsed.success || !parsed.data) {
1013
+ throw new AuthError(parsed.error?.code ?? "IDENTITIES_FAILED", parsed.error?.message ?? "Failed to list linked identities");
1014
+ }
1015
+ return { identities: parsed.data.identities ?? [], hasPassword: Boolean(parsed.data.hasPassword) };
1016
+ }
955
1017
  /**
956
1018
  * Shared gaming-identity sign-in. Mirrors `loginSocial`'s anon-takeover +
957
1019
  * ADR-025 link-in-place handling: reads the anon refresh BEFORE wiping local
@@ -1599,12 +1661,16 @@ var Auth = class {
1599
1661
  if (data.retiredAnonUserId) {
1600
1662
  this.fireDeviceTakeover(data.retiredAnonUserId, data.user.id);
1601
1663
  }
1664
+ if (data.reactivatedFromDeletion) {
1665
+ this.fireDeletionCancelled(data.user.id);
1666
+ }
1602
1667
  }
1603
1668
  async wipeLocalIdentity() {
1604
1669
  this.user = null;
1605
1670
  this.accessToken = null;
1606
1671
  this.accessExpiresAt = 0;
1607
1672
  this.lastTakeover = null;
1673
+ this.lastDeletionCancelled = null;
1608
1674
  this.pendingAnonTakeover = null;
1609
1675
  this.hooks.storage.remove(USER_KEY);
1610
1676
  this.hooks.storage.remove(TOKEN_KEY);
package/dist/index.d.cts CHANGED
@@ -310,6 +310,17 @@ declare class AlreadyIdentifiedError extends Error {
310
310
  declare class CredentialInUseError extends Error {
311
311
  constructor(message?: string);
312
312
  }
313
+ /** One credential linked to an account (ADR-030 read side, s58.270). */
314
+ type LinkedIdentity = {
315
+ provider: string;
316
+ email: string | null;
317
+ linkedAt: string;
318
+ };
319
+ /** Response of `auth.listLinkedIdentities()` — the full connected-account set. */
320
+ type LinkedIdentitiesResponse = {
321
+ identities: LinkedIdentity[];
322
+ hasPassword: boolean;
323
+ };
313
324
  declare class AuthError extends Error {
314
325
  code: string;
315
326
  constructor(code: string, message: string);
@@ -344,6 +355,17 @@ interface DeviceTakeoverEvent {
344
355
  /** Local clock at the time the SDK observed the event. */
345
356
  at: Date;
346
357
  }
358
+ /**
359
+ * Detail handed to `onDeletionCancelled` subscribers (s58.269). Fires once
360
+ * per sign-in that cancelled a pending self-service deletion within grace —
361
+ * the account is restored with the SAME user_id.
362
+ */
363
+ interface DeletionCancelledEvent {
364
+ /** The restored user_id (unchanged — this is a status flip, not a remap). */
365
+ userId: string;
366
+ /** Local clock at the time the SDK observed the event. */
367
+ at: Date;
368
+ }
347
369
  declare class Auth {
348
370
  private hooks;
349
371
  private user;
@@ -365,6 +387,8 @@ declare class Auth {
365
387
  private refreshFailureCount;
366
388
  private refreshCooldownUntil;
367
389
  private takeoverListeners;
390
+ private deletionCancelledListeners;
391
+ private lastDeletionCancelled;
368
392
  private lastTakeover;
369
393
  /**
370
394
  * Anon refresh token captured at `signIn()` time, stashed keyed to the
@@ -434,6 +458,19 @@ declare class Auth {
434
458
  getLastDeviceTakeover(): DeviceTakeoverEvent | null;
435
459
  /** Internal — fan out to subscribers + cache the latest. */
436
460
  private fireDeviceTakeover;
461
+ /**
462
+ * Subscribe to deletion-cancelled events (s58.269): fires when a sign-in
463
+ * cancelled a pending self-service account deletion within its grace window
464
+ * (the account is restored, same user_id). Use it to show "your account
465
+ * deletion was cancelled" + reconcile local state. Fires from signIn /
466
+ * loginSocial / signInWithGameCenter / signInWithPlayGames. Returns an
467
+ * unsubscribe function; listener errors are swallowed (best-effort).
468
+ */
469
+ onDeletionCancelled(listener: (evt: DeletionCancelledEvent) => void): () => void;
470
+ /** The most recent deletion-cancelled event this session, or null. Cleared on signOut. */
471
+ getLastDeletionCancelled(): DeletionCancelledEvent | null;
472
+ /** Internal — fan out deletion-cancelled to subscribers + cache the latest. */
473
+ private fireDeletionCancelled;
437
474
  /**
438
475
  * Returns a VALID (non-expired) access token, or null.
439
476
  *
@@ -650,6 +687,17 @@ declare class Auth {
650
687
  * user object + its storage copy are updated (no token/identity rotation).
651
688
  */
652
689
  private updateLocalUser;
690
+ /**
691
+ * List the auth methods/identities linked to the current account (ADR-030
692
+ * read side, s58.270). Returns every social/gaming identity on this account
693
+ * plus a `hasPassword` flag — the cross-device / reinstall-durable source of
694
+ * truth for a "Connected: Game Center · Google" UI (an on-device tracker
695
+ * misses a link made on another device). Bearer-gated network read (NOT a
696
+ * cache read — `getUserSync()` only holds the primary `signupMethod`/
697
+ * `lastLoginMethod`). Resolves a FRESH access token first (mirrors
698
+ * `deleteAccount`). Firebase `user.providerData` / Supabase `user.identities`.
699
+ */
700
+ listLinkedIdentities(): Promise<LinkedIdentitiesResponse>;
653
701
  /**
654
702
  * Shared gaming-identity sign-in. Mirrors `loginSocial`'s anon-takeover +
655
703
  * ADR-025 link-in-place handling: reads the anon refresh BEFORE wiping local
@@ -1625,4 +1673,4 @@ declare class SendoraSDK {
1625
1673
  }
1626
1674
  declare const SendoraCloud: SendoraSDK;
1627
1675
 
1628
- 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, Links, type PushTokenReceipt, type PushTokenRegistration, SendoraCloud, type SendoraConfig, type TrackProperties, computeDeviceFingerprint, SendoraCloud as default, extractShortcodeFromUrl, getPlayInstallReferrer };
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 };
package/dist/index.d.ts CHANGED
@@ -310,6 +310,17 @@ declare class AlreadyIdentifiedError extends Error {
310
310
  declare class CredentialInUseError extends Error {
311
311
  constructor(message?: string);
312
312
  }
313
+ /** One credential linked to an account (ADR-030 read side, s58.270). */
314
+ type LinkedIdentity = {
315
+ provider: string;
316
+ email: string | null;
317
+ linkedAt: string;
318
+ };
319
+ /** Response of `auth.listLinkedIdentities()` — the full connected-account set. */
320
+ type LinkedIdentitiesResponse = {
321
+ identities: LinkedIdentity[];
322
+ hasPassword: boolean;
323
+ };
313
324
  declare class AuthError extends Error {
314
325
  code: string;
315
326
  constructor(code: string, message: string);
@@ -344,6 +355,17 @@ interface DeviceTakeoverEvent {
344
355
  /** Local clock at the time the SDK observed the event. */
345
356
  at: Date;
346
357
  }
358
+ /**
359
+ * Detail handed to `onDeletionCancelled` subscribers (s58.269). Fires once
360
+ * per sign-in that cancelled a pending self-service deletion within grace —
361
+ * the account is restored with the SAME user_id.
362
+ */
363
+ interface DeletionCancelledEvent {
364
+ /** The restored user_id (unchanged — this is a status flip, not a remap). */
365
+ userId: string;
366
+ /** Local clock at the time the SDK observed the event. */
367
+ at: Date;
368
+ }
347
369
  declare class Auth {
348
370
  private hooks;
349
371
  private user;
@@ -365,6 +387,8 @@ declare class Auth {
365
387
  private refreshFailureCount;
366
388
  private refreshCooldownUntil;
367
389
  private takeoverListeners;
390
+ private deletionCancelledListeners;
391
+ private lastDeletionCancelled;
368
392
  private lastTakeover;
369
393
  /**
370
394
  * Anon refresh token captured at `signIn()` time, stashed keyed to the
@@ -434,6 +458,19 @@ declare class Auth {
434
458
  getLastDeviceTakeover(): DeviceTakeoverEvent | null;
435
459
  /** Internal — fan out to subscribers + cache the latest. */
436
460
  private fireDeviceTakeover;
461
+ /**
462
+ * Subscribe to deletion-cancelled events (s58.269): fires when a sign-in
463
+ * cancelled a pending self-service account deletion within its grace window
464
+ * (the account is restored, same user_id). Use it to show "your account
465
+ * deletion was cancelled" + reconcile local state. Fires from signIn /
466
+ * loginSocial / signInWithGameCenter / signInWithPlayGames. Returns an
467
+ * unsubscribe function; listener errors are swallowed (best-effort).
468
+ */
469
+ onDeletionCancelled(listener: (evt: DeletionCancelledEvent) => void): () => void;
470
+ /** The most recent deletion-cancelled event this session, or null. Cleared on signOut. */
471
+ getLastDeletionCancelled(): DeletionCancelledEvent | null;
472
+ /** Internal — fan out deletion-cancelled to subscribers + cache the latest. */
473
+ private fireDeletionCancelled;
437
474
  /**
438
475
  * Returns a VALID (non-expired) access token, or null.
439
476
  *
@@ -650,6 +687,17 @@ declare class Auth {
650
687
  * user object + its storage copy are updated (no token/identity rotation).
651
688
  */
652
689
  private updateLocalUser;
690
+ /**
691
+ * List the auth methods/identities linked to the current account (ADR-030
692
+ * read side, s58.270). Returns every social/gaming identity on this account
693
+ * plus a `hasPassword` flag — the cross-device / reinstall-durable source of
694
+ * truth for a "Connected: Game Center · Google" UI (an on-device tracker
695
+ * misses a link made on another device). Bearer-gated network read (NOT a
696
+ * cache read — `getUserSync()` only holds the primary `signupMethod`/
697
+ * `lastLoginMethod`). Resolves a FRESH access token first (mirrors
698
+ * `deleteAccount`). Firebase `user.providerData` / Supabase `user.identities`.
699
+ */
700
+ listLinkedIdentities(): Promise<LinkedIdentitiesResponse>;
653
701
  /**
654
702
  * Shared gaming-identity sign-in. Mirrors `loginSocial`'s anon-takeover +
655
703
  * ADR-025 link-in-place handling: reads the anon refresh BEFORE wiping local
@@ -1625,4 +1673,4 @@ declare class SendoraSDK {
1625
1673
  }
1626
1674
  declare const SendoraCloud: SendoraSDK;
1627
1675
 
1628
- 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, Links, type PushTokenReceipt, type PushTokenRegistration, SendoraCloud, type SendoraConfig, type TrackProperties, computeDeviceFingerprint, SendoraCloud as default, extractShortcodeFromUrl, getPlayInstallReferrer };
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 };
package/dist/index.js CHANGED
@@ -157,7 +157,7 @@ var Storage = class {
157
157
  // package.json
158
158
  var package_default = {
159
159
  name: "@sendoracloud/sdk-react-native",
160
- version: "1.25.0",
160
+ version: "1.27.0",
161
161
  description: "Sendora Cloud React Native + Expo SDK \u2014 analytics, identity, push-token registration, auth (incl. Game Center / Play Games), deep links (Branch / Firebase Dynamic Links parity). Auth + analytics + deep links work in Expo Go; push-token registration and the no-arg Game Center / Play Games sign-in require a Dev Client (EAS Build or `npx expo prebuild`).",
162
162
  type: "module",
163
163
  main: "./dist/index.cjs",
@@ -465,6 +465,8 @@ var Auth = class {
465
465
  this.refreshFailureCount = 0;
466
466
  this.refreshCooldownUntil = 0;
467
467
  this.takeoverListeners = /* @__PURE__ */ new Set();
468
+ this.deletionCancelledListeners = /* @__PURE__ */ new Set();
469
+ this.lastDeletionCancelled = null;
468
470
  this.lastTakeover = null;
469
471
  /**
470
472
  * Anon refresh token captured at `signIn()` time, stashed keyed to the
@@ -577,6 +579,36 @@ var Auth = class {
577
579
  }
578
580
  }
579
581
  }
582
+ /**
583
+ * Subscribe to deletion-cancelled events (s58.269): fires when a sign-in
584
+ * cancelled a pending self-service account deletion within its grace window
585
+ * (the account is restored, same user_id). Use it to show "your account
586
+ * deletion was cancelled" + reconcile local state. Fires from signIn /
587
+ * loginSocial / signInWithGameCenter / signInWithPlayGames. Returns an
588
+ * unsubscribe function; listener errors are swallowed (best-effort).
589
+ */
590
+ onDeletionCancelled(listener) {
591
+ this.deletionCancelledListeners.add(listener);
592
+ return () => {
593
+ this.deletionCancelledListeners.delete(listener);
594
+ };
595
+ }
596
+ /** The most recent deletion-cancelled event this session, or null. Cleared on signOut. */
597
+ getLastDeletionCancelled() {
598
+ return this.lastDeletionCancelled;
599
+ }
600
+ /** Internal — fan out deletion-cancelled to subscribers + cache the latest. */
601
+ fireDeletionCancelled(userId) {
602
+ const evt = { userId, at: /* @__PURE__ */ new Date() };
603
+ this.lastDeletionCancelled = evt;
604
+ for (const fn of this.deletionCancelledListeners) {
605
+ try {
606
+ fn(evt);
607
+ } catch (err) {
608
+ if (this.hooks.debug) console.warn("[sendoracloud] onDeletionCancelled listener threw", err);
609
+ }
610
+ }
611
+ }
580
612
  /**
581
613
  * Returns a VALID (non-expired) access token, or null.
582
614
  *
@@ -907,6 +939,36 @@ var Auth = class {
907
939
  this.user = user;
908
940
  this.hooks.storage.set(USER_KEY, JSON.stringify(user));
909
941
  }
942
+ /**
943
+ * List the auth methods/identities linked to the current account (ADR-030
944
+ * read side, s58.270). Returns every social/gaming identity on this account
945
+ * plus a `hasPassword` flag — the cross-device / reinstall-durable source of
946
+ * truth for a "Connected: Game Center · Google" UI (an on-device tracker
947
+ * misses a link made on another device). Bearer-gated network read (NOT a
948
+ * cache read — `getUserSync()` only holds the primary `signupMethod`/
949
+ * `lastLoginMethod`). Resolves a FRESH access token first (mirrors
950
+ * `deleteAccount`). Firebase `user.providerData` / Supabase `user.identities`.
951
+ */
952
+ async listLinkedIdentities() {
953
+ const token = await this.getAccessToken();
954
+ if (!token) throw new AuthError("NOT_SIGNED_IN", "Sign in before listing linked identities");
955
+ const res = await getJson(
956
+ { apiUrl: this.hooks.apiUrl, publicKey: this.hooks.publicKey, debug: this.hooks.debug },
957
+ "/api/v1/auth-service/me/identities",
958
+ { Authorization: `Bearer ${token}` }
959
+ );
960
+ if (!res || !res.ok) throw new AuthError("NETWORK_ERROR", "Failed to list linked identities");
961
+ let parsed;
962
+ try {
963
+ parsed = await res.json();
964
+ } catch {
965
+ throw new AuthError("PARSE_ERROR", `HTTP ${res.status}`);
966
+ }
967
+ if (!parsed.success || !parsed.data) {
968
+ throw new AuthError(parsed.error?.code ?? "IDENTITIES_FAILED", parsed.error?.message ?? "Failed to list linked identities");
969
+ }
970
+ return { identities: parsed.data.identities ?? [], hasPassword: Boolean(parsed.data.hasPassword) };
971
+ }
910
972
  /**
911
973
  * Shared gaming-identity sign-in. Mirrors `loginSocial`'s anon-takeover +
912
974
  * ADR-025 link-in-place handling: reads the anon refresh BEFORE wiping local
@@ -1554,12 +1616,16 @@ var Auth = class {
1554
1616
  if (data.retiredAnonUserId) {
1555
1617
  this.fireDeviceTakeover(data.retiredAnonUserId, data.user.id);
1556
1618
  }
1619
+ if (data.reactivatedFromDeletion) {
1620
+ this.fireDeletionCancelled(data.user.id);
1621
+ }
1557
1622
  }
1558
1623
  async wipeLocalIdentity() {
1559
1624
  this.user = null;
1560
1625
  this.accessToken = null;
1561
1626
  this.accessExpiresAt = 0;
1562
1627
  this.lastTakeover = null;
1628
+ this.lastDeletionCancelled = null;
1563
1629
  this.pendingAnonTakeover = null;
1564
1630
  this.hooks.storage.remove(USER_KEY);
1565
1631
  this.hooks.storage.remove(TOKEN_KEY);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sendoracloud/sdk-react-native",
3
- "version": "1.25.0",
3
+ "version": "1.27.0",
4
4
  "description": "Sendora Cloud React Native + Expo SDK — analytics, identity, push-token registration, auth (incl. Game Center / Play Games), deep links (Branch / Firebase Dynamic Links parity). Auth + analytics + deep links work in Expo Go; push-token registration and the no-arg Game Center / Play Games sign-in require a Dev Client (EAS Build or `npx expo prebuild`).",
5
5
  "type": "module",
6
6
  "main": "./dist/index.cjs",