@sendoracloud/sdk-react-native 0.7.0 → 0.9.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
@@ -355,6 +355,59 @@ var Auth = class {
355
355
  return parsed.data.user;
356
356
  });
357
357
  }
358
+ /**
359
+ * Verify an IdP-issued credential (authorization code OR id_token)
360
+ * and mint a Sendora session. Customer's app handles the IdP
361
+ * dance — typically via expo-auth-session / react-native-app-auth
362
+ * — then hands the result here. See web SDK for full provider
363
+ * matrix; mirrors that surface 1:1.
364
+ */
365
+ loginSocial(input) {
366
+ return this.serialize(async () => {
367
+ if (this.user !== null) await this.wipeLocalIdentity();
368
+ const res = await post(
369
+ { apiUrl: this.hooks.apiUrl, publicKey: this.hooks.publicKey, debug: this.hooks.debug },
370
+ "/api/v1/auth-service/login/social",
371
+ input
372
+ );
373
+ if (!res) throw new AuthError("NETWORK_ERROR", "Network request failed");
374
+ let parsed;
375
+ try {
376
+ parsed = await res.json();
377
+ } catch {
378
+ throw new AuthError("PARSE_ERROR", `HTTP ${res.status}`);
379
+ }
380
+ if (!res.ok || !parsed.success || !isAuthApiResponse(parsed.data)) {
381
+ throw new AuthError(
382
+ parsed.error?.code ?? "SOCIAL_LOGIN_FAILED",
383
+ parsed.error?.message ?? "Social login failed"
384
+ );
385
+ }
386
+ this.persist(parsed.data);
387
+ return parsed.data.user;
388
+ });
389
+ }
390
+ signInWithGoogle(code, redirectUri) {
391
+ return this.loginSocial({ provider: "google", code, redirectUri });
392
+ }
393
+ signInWithGitHub(code, redirectUri) {
394
+ return this.loginSocial({ provider: "github", code, redirectUri });
395
+ }
396
+ signInWithApple(input) {
397
+ return this.loginSocial({ provider: "apple", ...input });
398
+ }
399
+ signInWithMicrosoft(code, redirectUri) {
400
+ return this.loginSocial({ provider: "microsoft", code, redirectUri });
401
+ }
402
+ signInWithLinkedIn(code, redirectUri) {
403
+ return this.loginSocial({ provider: "linkedin", code, redirectUri });
404
+ }
405
+ signInWithFacebook(code, redirectUri) {
406
+ return this.loginSocial({ provider: "facebook", code, redirectUri });
407
+ }
408
+ signInWithDiscord(code, redirectUri) {
409
+ return this.loginSocial({ provider: "discord", code, redirectUri });
410
+ }
358
411
  /**
359
412
  * Exchange the MFA challenge token from `signIn` for a real session
360
413
  * by submitting a TOTP or recovery code from the user's authenticator.
@@ -391,6 +444,77 @@ var Auth = class {
391
444
  });
392
445
  }
393
446
  // ============================================================
447
+ // EMAIL OTP (6-digit cross-device code)
448
+ // ============================================================
449
+ async sendEmailOtp(email) {
450
+ const res = await post(
451
+ { apiUrl: this.hooks.apiUrl, publicKey: this.hooks.publicKey, debug: this.hooks.debug },
452
+ "/api/v1/auth-service/email-otp/request",
453
+ { email }
454
+ );
455
+ if (!res || !res.ok) {
456
+ throw new AuthError("EMAIL_OTP_REQUEST_FAILED", "Failed to send code");
457
+ }
458
+ }
459
+ verifyEmailOtp(email, code) {
460
+ return this.serialize(async () => {
461
+ if (this.user !== null) await this.wipeLocalIdentity();
462
+ const data = await this.callAuth("/api/v1/auth-service/email-otp/verify", { email, code });
463
+ this.persist(data);
464
+ return data.user;
465
+ });
466
+ }
467
+ // ============================================================
468
+ // PASSWORD RESET + EMAIL VERIFICATION
469
+ // ============================================================
470
+ /** Trigger password-reset email. Resolves on 204 even when address is unknown (anti-enumeration). */
471
+ async requestPasswordReset(email) {
472
+ const res = await post(
473
+ { apiUrl: this.hooks.apiUrl, publicKey: this.hooks.publicKey, debug: this.hooks.debug },
474
+ "/api/v1/auth-service/password/forgot",
475
+ { email }
476
+ );
477
+ if (!res || !res.ok) {
478
+ throw new AuthError("PASSWORD_RESET_REQUEST_FAILED", "Failed to send reset email");
479
+ }
480
+ }
481
+ /** Pair the reset-email token with the new password to complete the reset. */
482
+ async resetPassword(token, newPassword) {
483
+ const res = await post(
484
+ { apiUrl: this.hooks.apiUrl, publicKey: this.hooks.publicKey, debug: this.hooks.debug },
485
+ "/api/v1/auth-service/password/reset",
486
+ { token, newPassword }
487
+ );
488
+ if (!res || !res.ok) {
489
+ throw new AuthError("PASSWORD_RESET_FAILED", "Reset failed");
490
+ }
491
+ }
492
+ /** Verify the email-address token from the link Sendora sent on signup. */
493
+ async verifyEmail(token) {
494
+ const res = await post(
495
+ { apiUrl: this.hooks.apiUrl, publicKey: this.hooks.publicKey, debug: this.hooks.debug },
496
+ "/api/v1/auth-service/email/verify",
497
+ { token }
498
+ );
499
+ if (!res || !res.ok) {
500
+ throw new AuthError("EMAIL_VERIFICATION_FAILED", "Verification failed");
501
+ }
502
+ }
503
+ /** Re-send the email-verification email for the currently-signed-in user. */
504
+ async sendVerificationEmail() {
505
+ const headers = this.bearerHeaders();
506
+ if (!headers) throw new AuthError("UNAUTHORIZED", "Sign in before requesting a verification email");
507
+ const res = await post(
508
+ { apiUrl: this.hooks.apiUrl, publicKey: this.hooks.publicKey, debug: this.hooks.debug },
509
+ "/api/v1/auth-service/email/verify/resend",
510
+ {},
511
+ headers
512
+ );
513
+ if (!res || !res.ok) {
514
+ throw new AuthError("VERIFICATION_RESEND_FAILED", "Failed to send verification email");
515
+ }
516
+ }
517
+ // ============================================================
394
518
  // TOTP MFA — enrollment management (Bearer-authenticated)
395
519
  // ============================================================
396
520
  async enrollMfa() {
package/dist/index.d.cts CHANGED
@@ -137,6 +137,39 @@ declare class Auth {
137
137
  mfaChallengeToken: string;
138
138
  userId: string;
139
139
  }>;
140
+ /**
141
+ * Verify an IdP-issued credential (authorization code OR id_token)
142
+ * and mint a Sendora session. Customer's app handles the IdP
143
+ * dance — typically via expo-auth-session / react-native-app-auth
144
+ * — then hands the result here. See web SDK for full provider
145
+ * matrix; mirrors that surface 1:1.
146
+ */
147
+ loginSocial(input: {
148
+ provider: "google" | "github" | "apple" | "microsoft" | "linkedin" | "facebook" | "twitter" | "discord";
149
+ code?: string;
150
+ idToken?: string;
151
+ redirectUri?: string;
152
+ codeVerifier?: string;
153
+ appleName?: {
154
+ firstName?: string;
155
+ lastName?: string;
156
+ };
157
+ }): Promise<AuthUser>;
158
+ signInWithGoogle(code: string, redirectUri: string): Promise<AuthUser>;
159
+ signInWithGitHub(code: string, redirectUri: string): Promise<AuthUser>;
160
+ signInWithApple(input: {
161
+ idToken?: string;
162
+ code?: string;
163
+ redirectUri?: string;
164
+ appleName?: {
165
+ firstName?: string;
166
+ lastName?: string;
167
+ };
168
+ }): Promise<AuthUser>;
169
+ signInWithMicrosoft(code: string, redirectUri: string): Promise<AuthUser>;
170
+ signInWithLinkedIn(code: string, redirectUri: string): Promise<AuthUser>;
171
+ signInWithFacebook(code: string, redirectUri: string): Promise<AuthUser>;
172
+ signInWithDiscord(code: string, redirectUri: string): Promise<AuthUser>;
140
173
  /**
141
174
  * Exchange the MFA challenge token from `signIn` for a real session
142
175
  * by submitting a TOTP or recovery code from the user's authenticator.
@@ -144,6 +177,16 @@ declare class Auth {
144
177
  challengeMfa(mfaChallengeToken: string, code: string): Promise<AuthUser>;
145
178
  sendMagicLink(email: string): Promise<void>;
146
179
  verifyMagicLink(token: string): Promise<AuthUser>;
180
+ sendEmailOtp(email: string): Promise<void>;
181
+ verifyEmailOtp(email: string, code: string): Promise<AuthUser>;
182
+ /** Trigger password-reset email. Resolves on 204 even when address is unknown (anti-enumeration). */
183
+ requestPasswordReset(email: string): Promise<void>;
184
+ /** Pair the reset-email token with the new password to complete the reset. */
185
+ resetPassword(token: string, newPassword: string): Promise<void>;
186
+ /** Verify the email-address token from the link Sendora sent on signup. */
187
+ verifyEmail(token: string): Promise<void>;
188
+ /** Re-send the email-verification email for the currently-signed-in user. */
189
+ sendVerificationEmail(): Promise<void>;
147
190
  enrollMfa(): Promise<{
148
191
  secret: string;
149
192
  otpauthUrl: string;
package/dist/index.d.ts CHANGED
@@ -137,6 +137,39 @@ declare class Auth {
137
137
  mfaChallengeToken: string;
138
138
  userId: string;
139
139
  }>;
140
+ /**
141
+ * Verify an IdP-issued credential (authorization code OR id_token)
142
+ * and mint a Sendora session. Customer's app handles the IdP
143
+ * dance — typically via expo-auth-session / react-native-app-auth
144
+ * — then hands the result here. See web SDK for full provider
145
+ * matrix; mirrors that surface 1:1.
146
+ */
147
+ loginSocial(input: {
148
+ provider: "google" | "github" | "apple" | "microsoft" | "linkedin" | "facebook" | "twitter" | "discord";
149
+ code?: string;
150
+ idToken?: string;
151
+ redirectUri?: string;
152
+ codeVerifier?: string;
153
+ appleName?: {
154
+ firstName?: string;
155
+ lastName?: string;
156
+ };
157
+ }): Promise<AuthUser>;
158
+ signInWithGoogle(code: string, redirectUri: string): Promise<AuthUser>;
159
+ signInWithGitHub(code: string, redirectUri: string): Promise<AuthUser>;
160
+ signInWithApple(input: {
161
+ idToken?: string;
162
+ code?: string;
163
+ redirectUri?: string;
164
+ appleName?: {
165
+ firstName?: string;
166
+ lastName?: string;
167
+ };
168
+ }): Promise<AuthUser>;
169
+ signInWithMicrosoft(code: string, redirectUri: string): Promise<AuthUser>;
170
+ signInWithLinkedIn(code: string, redirectUri: string): Promise<AuthUser>;
171
+ signInWithFacebook(code: string, redirectUri: string): Promise<AuthUser>;
172
+ signInWithDiscord(code: string, redirectUri: string): Promise<AuthUser>;
140
173
  /**
141
174
  * Exchange the MFA challenge token from `signIn` for a real session
142
175
  * by submitting a TOTP or recovery code from the user's authenticator.
@@ -144,6 +177,16 @@ declare class Auth {
144
177
  challengeMfa(mfaChallengeToken: string, code: string): Promise<AuthUser>;
145
178
  sendMagicLink(email: string): Promise<void>;
146
179
  verifyMagicLink(token: string): Promise<AuthUser>;
180
+ sendEmailOtp(email: string): Promise<void>;
181
+ verifyEmailOtp(email: string, code: string): Promise<AuthUser>;
182
+ /** Trigger password-reset email. Resolves on 204 even when address is unknown (anti-enumeration). */
183
+ requestPasswordReset(email: string): Promise<void>;
184
+ /** Pair the reset-email token with the new password to complete the reset. */
185
+ resetPassword(token: string, newPassword: string): Promise<void>;
186
+ /** Verify the email-address token from the link Sendora sent on signup. */
187
+ verifyEmail(token: string): Promise<void>;
188
+ /** Re-send the email-verification email for the currently-signed-in user. */
189
+ sendVerificationEmail(): Promise<void>;
147
190
  enrollMfa(): Promise<{
148
191
  secret: string;
149
192
  otpauthUrl: string;
package/dist/index.js CHANGED
@@ -315,6 +315,59 @@ var Auth = class {
315
315
  return parsed.data.user;
316
316
  });
317
317
  }
318
+ /**
319
+ * Verify an IdP-issued credential (authorization code OR id_token)
320
+ * and mint a Sendora session. Customer's app handles the IdP
321
+ * dance — typically via expo-auth-session / react-native-app-auth
322
+ * — then hands the result here. See web SDK for full provider
323
+ * matrix; mirrors that surface 1:1.
324
+ */
325
+ loginSocial(input) {
326
+ return this.serialize(async () => {
327
+ if (this.user !== null) await this.wipeLocalIdentity();
328
+ const res = await post(
329
+ { apiUrl: this.hooks.apiUrl, publicKey: this.hooks.publicKey, debug: this.hooks.debug },
330
+ "/api/v1/auth-service/login/social",
331
+ input
332
+ );
333
+ if (!res) throw new AuthError("NETWORK_ERROR", "Network request failed");
334
+ let parsed;
335
+ try {
336
+ parsed = await res.json();
337
+ } catch {
338
+ throw new AuthError("PARSE_ERROR", `HTTP ${res.status}`);
339
+ }
340
+ if (!res.ok || !parsed.success || !isAuthApiResponse(parsed.data)) {
341
+ throw new AuthError(
342
+ parsed.error?.code ?? "SOCIAL_LOGIN_FAILED",
343
+ parsed.error?.message ?? "Social login failed"
344
+ );
345
+ }
346
+ this.persist(parsed.data);
347
+ return parsed.data.user;
348
+ });
349
+ }
350
+ signInWithGoogle(code, redirectUri) {
351
+ return this.loginSocial({ provider: "google", code, redirectUri });
352
+ }
353
+ signInWithGitHub(code, redirectUri) {
354
+ return this.loginSocial({ provider: "github", code, redirectUri });
355
+ }
356
+ signInWithApple(input) {
357
+ return this.loginSocial({ provider: "apple", ...input });
358
+ }
359
+ signInWithMicrosoft(code, redirectUri) {
360
+ return this.loginSocial({ provider: "microsoft", code, redirectUri });
361
+ }
362
+ signInWithLinkedIn(code, redirectUri) {
363
+ return this.loginSocial({ provider: "linkedin", code, redirectUri });
364
+ }
365
+ signInWithFacebook(code, redirectUri) {
366
+ return this.loginSocial({ provider: "facebook", code, redirectUri });
367
+ }
368
+ signInWithDiscord(code, redirectUri) {
369
+ return this.loginSocial({ provider: "discord", code, redirectUri });
370
+ }
318
371
  /**
319
372
  * Exchange the MFA challenge token from `signIn` for a real session
320
373
  * by submitting a TOTP or recovery code from the user's authenticator.
@@ -351,6 +404,77 @@ var Auth = class {
351
404
  });
352
405
  }
353
406
  // ============================================================
407
+ // EMAIL OTP (6-digit cross-device code)
408
+ // ============================================================
409
+ async sendEmailOtp(email) {
410
+ const res = await post(
411
+ { apiUrl: this.hooks.apiUrl, publicKey: this.hooks.publicKey, debug: this.hooks.debug },
412
+ "/api/v1/auth-service/email-otp/request",
413
+ { email }
414
+ );
415
+ if (!res || !res.ok) {
416
+ throw new AuthError("EMAIL_OTP_REQUEST_FAILED", "Failed to send code");
417
+ }
418
+ }
419
+ verifyEmailOtp(email, code) {
420
+ return this.serialize(async () => {
421
+ if (this.user !== null) await this.wipeLocalIdentity();
422
+ const data = await this.callAuth("/api/v1/auth-service/email-otp/verify", { email, code });
423
+ this.persist(data);
424
+ return data.user;
425
+ });
426
+ }
427
+ // ============================================================
428
+ // PASSWORD RESET + EMAIL VERIFICATION
429
+ // ============================================================
430
+ /** Trigger password-reset email. Resolves on 204 even when address is unknown (anti-enumeration). */
431
+ async requestPasswordReset(email) {
432
+ const res = await post(
433
+ { apiUrl: this.hooks.apiUrl, publicKey: this.hooks.publicKey, debug: this.hooks.debug },
434
+ "/api/v1/auth-service/password/forgot",
435
+ { email }
436
+ );
437
+ if (!res || !res.ok) {
438
+ throw new AuthError("PASSWORD_RESET_REQUEST_FAILED", "Failed to send reset email");
439
+ }
440
+ }
441
+ /** Pair the reset-email token with the new password to complete the reset. */
442
+ async resetPassword(token, newPassword) {
443
+ const res = await post(
444
+ { apiUrl: this.hooks.apiUrl, publicKey: this.hooks.publicKey, debug: this.hooks.debug },
445
+ "/api/v1/auth-service/password/reset",
446
+ { token, newPassword }
447
+ );
448
+ if (!res || !res.ok) {
449
+ throw new AuthError("PASSWORD_RESET_FAILED", "Reset failed");
450
+ }
451
+ }
452
+ /** Verify the email-address token from the link Sendora sent on signup. */
453
+ async verifyEmail(token) {
454
+ const res = await post(
455
+ { apiUrl: this.hooks.apiUrl, publicKey: this.hooks.publicKey, debug: this.hooks.debug },
456
+ "/api/v1/auth-service/email/verify",
457
+ { token }
458
+ );
459
+ if (!res || !res.ok) {
460
+ throw new AuthError("EMAIL_VERIFICATION_FAILED", "Verification failed");
461
+ }
462
+ }
463
+ /** Re-send the email-verification email for the currently-signed-in user. */
464
+ async sendVerificationEmail() {
465
+ const headers = this.bearerHeaders();
466
+ if (!headers) throw new AuthError("UNAUTHORIZED", "Sign in before requesting a verification email");
467
+ const res = await post(
468
+ { apiUrl: this.hooks.apiUrl, publicKey: this.hooks.publicKey, debug: this.hooks.debug },
469
+ "/api/v1/auth-service/email/verify/resend",
470
+ {},
471
+ headers
472
+ );
473
+ if (!res || !res.ok) {
474
+ throw new AuthError("VERIFICATION_RESEND_FAILED", "Failed to send verification email");
475
+ }
476
+ }
477
+ // ============================================================
354
478
  // TOTP MFA — enrollment management (Bearer-authenticated)
355
479
  // ============================================================
356
480
  async enrollMfa() {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sendoracloud/sdk-react-native",
3
- "version": "0.7.0",
3
+ "version": "0.9.0",
4
4
  "description": "Sendora Cloud React Native + Expo SDK — analytics, identity, push-token registration, auth. Expo Go compatible, no native modules beyond AsyncStorage.",
5
5
  "type": "module",
6
6
  "main": "./dist/index.cjs",