react-native-nitro-auth 0.1.3 → 0.1.5

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.
Files changed (66) hide show
  1. package/README.md +62 -13
  2. package/android/build.gradle +8 -3
  3. package/android/src/main/cpp/PlatformAuth+Android.cpp +14 -3
  4. package/android/src/main/java/com/auth/AuthAdapter.kt +100 -3
  5. package/cpp/HybridAuth.cpp +64 -13
  6. package/cpp/HybridAuth.hpp +10 -0
  7. package/cpp/PlatformAuth.hpp +2 -1
  8. package/ios/PlatformAuth+iOS.mm +22 -4
  9. package/lib/commonjs/Auth.web.js +91 -23
  10. package/lib/commonjs/Auth.web.js.map +1 -1
  11. package/lib/commonjs/AuthStorage.nitro.js +6 -0
  12. package/lib/commonjs/AuthStorage.nitro.js.map +1 -0
  13. package/lib/commonjs/index.js +12 -0
  14. package/lib/commonjs/index.js.map +1 -1
  15. package/lib/commonjs/index.web.js +12 -0
  16. package/lib/commonjs/index.web.js.map +1 -1
  17. package/lib/commonjs/ui/social-button.js +2 -2
  18. package/lib/commonjs/ui/social-button.js.map +1 -1
  19. package/lib/commonjs/ui/social-button.web.js +2 -2
  20. package/lib/commonjs/ui/social-button.web.js.map +1 -1
  21. package/lib/commonjs/utils/logger.js +17 -0
  22. package/lib/commonjs/utils/logger.js.map +1 -0
  23. package/lib/module/Auth.web.js +91 -23
  24. package/lib/module/Auth.web.js.map +1 -1
  25. package/lib/module/AuthStorage.nitro.js +4 -0
  26. package/lib/module/AuthStorage.nitro.js.map +1 -0
  27. package/lib/module/index.js +1 -0
  28. package/lib/module/index.js.map +1 -1
  29. package/lib/module/index.web.js +1 -0
  30. package/lib/module/index.web.js.map +1 -1
  31. package/lib/module/ui/social-button.js +2 -2
  32. package/lib/module/ui/social-button.js.map +1 -1
  33. package/lib/module/ui/social-button.web.js +2 -2
  34. package/lib/module/ui/social-button.web.js.map +1 -1
  35. package/lib/module/utils/logger.js +13 -0
  36. package/lib/module/utils/logger.js.map +1 -0
  37. package/lib/typescript/Auth.nitro.d.ts +5 -0
  38. package/lib/typescript/Auth.nitro.d.ts.map +1 -1
  39. package/lib/typescript/Auth.web.d.ts +9 -1
  40. package/lib/typescript/Auth.web.d.ts.map +1 -1
  41. package/lib/typescript/AuthStorage.nitro.d.ts +19 -0
  42. package/lib/typescript/AuthStorage.nitro.d.ts.map +1 -0
  43. package/lib/typescript/index.d.ts +1 -0
  44. package/lib/typescript/index.d.ts.map +1 -1
  45. package/lib/typescript/index.web.d.ts +1 -0
  46. package/lib/typescript/index.web.d.ts.map +1 -1
  47. package/lib/typescript/ui/social-button.d.ts.map +1 -1
  48. package/lib/typescript/ui/social-button.web.d.ts.map +1 -1
  49. package/lib/typescript/utils/logger.d.ts +8 -0
  50. package/lib/typescript/utils/logger.d.ts.map +1 -0
  51. package/nitrogen/generated/android/NitroAuth+autolinking.cmake +1 -0
  52. package/nitrogen/generated/shared/c++/HybridAuthSpec.cpp +3 -0
  53. package/nitrogen/generated/shared/c++/HybridAuthSpec.hpp +7 -0
  54. package/nitrogen/generated/shared/c++/HybridAuthStorageAdapterSpec.cpp +23 -0
  55. package/nitrogen/generated/shared/c++/HybridAuthStorageAdapterSpec.hpp +65 -0
  56. package/nitrogen/generated/shared/c++/LoginOptions.hpp +6 -2
  57. package/package.json +3 -4
  58. package/react-native-nitro-auth.podspec +1 -1
  59. package/src/Auth.nitro.ts +6 -0
  60. package/src/Auth.web.ts +114 -24
  61. package/src/AuthStorage.nitro.ts +17 -0
  62. package/src/index.ts +1 -0
  63. package/src/index.web.ts +1 -0
  64. package/src/ui/social-button.tsx +3 -3
  65. package/src/ui/social-button.web.tsx +3 -3
  66. package/src/utils/logger.ts +11 -0
@@ -0,0 +1,23 @@
1
+ ///
2
+ /// HybridAuthStorageAdapterSpec.cpp
3
+ /// This file was generated by nitrogen. DO NOT MODIFY THIS FILE.
4
+ /// https://github.com/mrousavy/nitro
5
+ /// Copyright © 2025 Marc Rousavy @ Margelo
6
+ ///
7
+
8
+ #include "HybridAuthStorageAdapterSpec.hpp"
9
+
10
+ namespace margelo::nitro::NitroAuth {
11
+
12
+ void HybridAuthStorageAdapterSpec::loadHybridMethods() {
13
+ // load base methods/properties
14
+ HybridObject::loadHybridMethods();
15
+ // load custom methods/properties
16
+ registerHybrids(this, [](Prototype& prototype) {
17
+ prototype.registerHybridMethod("save", &HybridAuthStorageAdapterSpec::save);
18
+ prototype.registerHybridMethod("load", &HybridAuthStorageAdapterSpec::load);
19
+ prototype.registerHybridMethod("remove", &HybridAuthStorageAdapterSpec::remove);
20
+ });
21
+ }
22
+
23
+ } // namespace margelo::nitro::NitroAuth
@@ -0,0 +1,65 @@
1
+ ///
2
+ /// HybridAuthStorageAdapterSpec.hpp
3
+ /// This file was generated by nitrogen. DO NOT MODIFY THIS FILE.
4
+ /// https://github.com/mrousavy/nitro
5
+ /// Copyright © 2025 Marc Rousavy @ Margelo
6
+ ///
7
+
8
+ #pragma once
9
+
10
+ #if __has_include(<NitroModules/HybridObject.hpp>)
11
+ #include <NitroModules/HybridObject.hpp>
12
+ #else
13
+ #error NitroModules cannot be found! Are you sure you installed NitroModules properly?
14
+ #endif
15
+
16
+
17
+
18
+ #include <string>
19
+ #include <optional>
20
+
21
+ namespace margelo::nitro::NitroAuth {
22
+
23
+ using namespace margelo::nitro;
24
+
25
+ /**
26
+ * An abstract base class for `AuthStorageAdapter`
27
+ * Inherit this class to create instances of `HybridAuthStorageAdapterSpec` in C++.
28
+ * You must explicitly call `HybridObject`'s constructor yourself, because it is virtual.
29
+ * @example
30
+ * ```cpp
31
+ * class HybridAuthStorageAdapter: public HybridAuthStorageAdapterSpec {
32
+ * public:
33
+ * HybridAuthStorageAdapter(...): HybridObject(TAG) { ... }
34
+ * // ...
35
+ * };
36
+ * ```
37
+ */
38
+ class HybridAuthStorageAdapterSpec: public virtual HybridObject {
39
+ public:
40
+ // Constructor
41
+ explicit HybridAuthStorageAdapterSpec(): HybridObject(TAG) { }
42
+
43
+ // Destructor
44
+ ~HybridAuthStorageAdapterSpec() override = default;
45
+
46
+ public:
47
+ // Properties
48
+
49
+
50
+ public:
51
+ // Methods
52
+ virtual void save(const std::string& key, const std::string& value) = 0;
53
+ virtual std::optional<std::string> load(const std::string& key) = 0;
54
+ virtual void remove(const std::string& key) = 0;
55
+
56
+ protected:
57
+ // Hybrid Setup
58
+ void loadHybridMethods() override;
59
+
60
+ protected:
61
+ // Tag for logging
62
+ static constexpr auto TAG = "AuthStorageAdapter";
63
+ };
64
+
65
+ } // namespace margelo::nitro::NitroAuth
@@ -38,10 +38,11 @@ namespace margelo::nitro::NitroAuth {
38
38
  public:
39
39
  std::optional<std::vector<std::string>> scopes SWIFT_PRIVATE;
40
40
  std::optional<std::string> loginHint SWIFT_PRIVATE;
41
+ std::optional<bool> useOneTap SWIFT_PRIVATE;
41
42
 
42
43
  public:
43
44
  LoginOptions() = default;
44
- explicit LoginOptions(std::optional<std::vector<std::string>> scopes, std::optional<std::string> loginHint): scopes(scopes), loginHint(loginHint) {}
45
+ explicit LoginOptions(std::optional<std::vector<std::string>> scopes, std::optional<std::string> loginHint, std::optional<bool> useOneTap): scopes(scopes), loginHint(loginHint), useOneTap(useOneTap) {}
45
46
  };
46
47
 
47
48
  } // namespace margelo::nitro::NitroAuth
@@ -55,13 +56,15 @@ namespace margelo::nitro {
55
56
  jsi::Object obj = arg.asObject(runtime);
56
57
  return margelo::nitro::NitroAuth::LoginOptions(
57
58
  JSIConverter<std::optional<std::vector<std::string>>>::fromJSI(runtime, obj.getProperty(runtime, "scopes")),
58
- JSIConverter<std::optional<std::string>>::fromJSI(runtime, obj.getProperty(runtime, "loginHint"))
59
+ JSIConverter<std::optional<std::string>>::fromJSI(runtime, obj.getProperty(runtime, "loginHint")),
60
+ JSIConverter<std::optional<bool>>::fromJSI(runtime, obj.getProperty(runtime, "useOneTap"))
59
61
  );
60
62
  }
61
63
  static inline jsi::Value toJSI(jsi::Runtime& runtime, const margelo::nitro::NitroAuth::LoginOptions& arg) {
62
64
  jsi::Object obj(runtime);
63
65
  obj.setProperty(runtime, "scopes", JSIConverter<std::optional<std::vector<std::string>>>::toJSI(runtime, arg.scopes));
64
66
  obj.setProperty(runtime, "loginHint", JSIConverter<std::optional<std::string>>::toJSI(runtime, arg.loginHint));
67
+ obj.setProperty(runtime, "useOneTap", JSIConverter<std::optional<bool>>::toJSI(runtime, arg.useOneTap));
65
68
  return obj;
66
69
  }
67
70
  static inline bool canConvert(jsi::Runtime& runtime, const jsi::Value& value) {
@@ -74,6 +77,7 @@ namespace margelo::nitro {
74
77
  }
75
78
  if (!JSIConverter<std::optional<std::vector<std::string>>>::canConvert(runtime, obj.getProperty(runtime, "scopes"))) return false;
76
79
  if (!JSIConverter<std::optional<std::string>>::canConvert(runtime, obj.getProperty(runtime, "loginHint"))) return false;
80
+ if (!JSIConverter<std::optional<bool>>::canConvert(runtime, obj.getProperty(runtime, "useOneTap"))) return false;
77
81
  return true;
78
82
  }
79
83
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-native-nitro-auth",
3
- "version": "0.1.3",
3
+ "version": "0.1.5",
4
4
  "description": "High-performance authentication library for React Native with Google Sign-In and Apple Sign-In support, powered by Nitro Modules (JSI)",
5
5
  "main": "lib/commonjs/index.js",
6
6
  "module": "lib/module/index.js",
@@ -78,9 +78,8 @@
78
78
  "devDependencies": {
79
79
  "@expo/config-plugins": "^54.0.4",
80
80
  "@react-native/babel-preset": "^0.81.0",
81
- "@testing-library/react": "^16.3.1",
82
- "@testing-library/react-hooks": "^8.0.1",
83
- "@testing-library/react-native": "^13.3.3",
81
+ "@testing-library/react": "^16.1.0",
82
+ "jest-environment-jsdom": "^29.7.0",
84
83
  "react": "19.1.0",
85
84
  "react-native": "0.81.5",
86
85
  "react-native-nitro-modules": "^0.32.0",
@@ -33,7 +33,7 @@ Pod::Spec.new do |s|
33
33
  }
34
34
 
35
35
  s.dependency "React-Core"
36
- s.dependency "GoogleSignIn"
36
+ s.dependency "GoogleSignIn", "~> 8.0"
37
37
 
38
38
  load 'nitrogen/generated/ios/NitroAuth+autolinking.rb'
39
39
  add_nitrogen_files(s)
package/src/Auth.nitro.ts CHANGED
@@ -1,5 +1,7 @@
1
1
  import type { HybridObject } from "react-native-nitro-modules";
2
2
 
3
+ import type { AuthStorageAdapter } from "./AuthStorage.nitro";
4
+
3
5
  export type AuthProvider = "google" | "apple";
4
6
 
5
7
  export type AuthErrorCode =
@@ -12,6 +14,7 @@ export type AuthErrorCode =
12
14
  export interface LoginOptions {
13
15
  scopes?: string[];
14
16
  loginHint?: string;
17
+ useOneTap?: boolean;
15
18
  }
16
19
 
17
20
  export interface AuthTokens {
@@ -48,4 +51,7 @@ export interface Auth extends HybridObject<{ ios: "c++"; android: "c++" }> {
48
51
  onAuthStateChanged(
49
52
  callback: (user: AuthUser | undefined) => void
50
53
  ): () => void;
54
+ onTokensRefreshed(callback: (tokens: AuthTokens) => void): () => void;
55
+ setLoggingEnabled(enabled: boolean): void;
56
+ setStorageAdapter(adapter: AuthStorageAdapter | undefined): void;
51
57
  }
package/src/Auth.web.ts CHANGED
@@ -1,4 +1,12 @@
1
- import type { Auth, AuthUser, AuthProvider, LoginOptions } from "./Auth.nitro";
1
+ import type {
2
+ Auth,
3
+ AuthUser,
4
+ AuthProvider,
5
+ LoginOptions,
6
+ AuthTokens,
7
+ } from "./Auth.nitro";
8
+ import type { AuthStorageAdapter } from "./AuthStorage.nitro";
9
+ import { logger } from "./utils/logger";
2
10
 
3
11
  const CACHE_KEY = "nitro_auth_user";
4
12
  const SCOPES_KEY = "nitro_auth_scopes";
@@ -17,26 +25,47 @@ class AuthWeb implements Auth {
17
25
  private _currentUser: AuthUser | undefined;
18
26
  private _grantedScopes: string[] = [];
19
27
  private _listeners: ((user: AuthUser | undefined) => void)[] = [];
28
+ private _tokenListeners: ((tokens: AuthTokens) => void)[] = [];
29
+ private _storageAdapter: AuthStorageAdapter | undefined;
20
30
 
21
31
  constructor() {
22
- const cached = localStorage.getItem(CACHE_KEY);
32
+ this.loadFromCache();
33
+ }
34
+
35
+ private loadFromCache() {
36
+ const cached = this._storageAdapter
37
+ ? this._storageAdapter.load(CACHE_KEY)
38
+ : localStorage.getItem(CACHE_KEY);
39
+
23
40
  if (cached) {
24
41
  try {
25
42
  this._currentUser = JSON.parse(cached);
26
43
  } catch {
27
- localStorage.removeItem(CACHE_KEY);
44
+ this.removeFromCache(CACHE_KEY);
28
45
  }
29
46
  }
30
- const scopes = localStorage.getItem(SCOPES_KEY);
47
+
48
+ const scopes = this._storageAdapter
49
+ ? this._storageAdapter.load(SCOPES_KEY)
50
+ : localStorage.getItem(SCOPES_KEY);
51
+
31
52
  if (scopes) {
32
53
  try {
33
54
  this._grantedScopes = JSON.parse(scopes);
34
55
  } catch {
35
- localStorage.removeItem(SCOPES_KEY);
56
+ this.removeFromCache(SCOPES_KEY);
36
57
  }
37
58
  }
38
59
  }
39
60
 
61
+ private removeFromCache(key: string) {
62
+ if (this._storageAdapter) {
63
+ this._storageAdapter.remove(key);
64
+ } else {
65
+ localStorage.removeItem(key);
66
+ }
67
+ }
68
+
40
69
  get currentUser(): AuthUser | undefined {
41
70
  return this._currentUser;
42
71
  }
@@ -59,6 +88,13 @@ class AuthWeb implements Auth {
59
88
  };
60
89
  }
61
90
 
91
+ onTokensRefreshed(callback: (tokens: AuthTokens) => void): () => void {
92
+ this._tokenListeners.push(callback);
93
+ return () => {
94
+ this._tokenListeners = this._tokenListeners.filter((l) => l !== callback);
95
+ };
96
+ }
97
+
62
98
  private notify() {
63
99
  this._listeners.forEach((l) => l(this._currentUser));
64
100
  }
@@ -66,13 +102,18 @@ class AuthWeb implements Auth {
66
102
  async login(provider: AuthProvider, options?: LoginOptions): Promise<void> {
67
103
  const scopes = options?.scopes ?? DEFAULT_SCOPES;
68
104
  const loginHint = options?.loginHint;
105
+ logger.log(`Starting login with ${provider}`, { scopes });
69
106
  try {
70
107
  if (provider === "google") {
71
- return await this.loginGoogle(scopes, loginHint);
108
+ await this.loginGoogle(scopes, loginHint);
109
+ } else {
110
+ await this.loginApple();
72
111
  }
73
- return await this.loginApple();
112
+ logger.log(`Login successful with ${provider}`);
74
113
  } catch (e: unknown) {
75
- throw this.mapError(e);
114
+ const error = this.mapError(e);
115
+ logger.error(`Login failed for ${provider}:`, error.message);
116
+ throw error;
76
117
  }
77
118
  }
78
119
 
@@ -83,17 +124,28 @@ class AuthWeb implements Auth {
83
124
  if (this._currentUser.provider !== "google") {
84
125
  throw new Error("Scope management only supported for Google");
85
126
  }
127
+ logger.log("Requesting additional scopes:", scopes);
86
128
  const newScopes = [...new Set([...this._grantedScopes, ...scopes])];
87
129
  return this.loginGoogle(newScopes).catch((e) => {
88
- throw this.mapError(e);
130
+ const error = this.mapError(e);
131
+ logger.error("Requesting scopes failed:", error.message);
132
+ throw error;
89
133
  });
90
134
  }
91
135
 
92
136
  async revokeScopes(scopes: string[]): Promise<void> {
137
+ logger.log("Revoking scopes:", scopes);
93
138
  this._grantedScopes = this._grantedScopes.filter(
94
139
  (s) => !scopes.includes(s)
95
140
  );
96
- localStorage.setItem(SCOPES_KEY, JSON.stringify(this._grantedScopes));
141
+ if (this._storageAdapter) {
142
+ this._storageAdapter.save(
143
+ SCOPES_KEY,
144
+ JSON.stringify(this._grantedScopes)
145
+ );
146
+ } else {
147
+ localStorage.setItem(SCOPES_KEY, JSON.stringify(this._grantedScopes));
148
+ }
97
149
  if (this._currentUser) {
98
150
  this._currentUser.scopes = this._grantedScopes;
99
151
  this.updateUser(this._currentUser);
@@ -104,6 +156,7 @@ class AuthWeb implements Auth {
104
156
  if (this._currentUser?.expirationTime) {
105
157
  const now = Date.now();
106
158
  if (now + 300000 > this._currentUser.expirationTime) {
159
+ logger.log("Token about to expire, refreshing...");
107
160
  await this.refreshToken();
108
161
  }
109
162
  }
@@ -117,27 +170,38 @@ class AuthWeb implements Auth {
117
170
  if (this._currentUser.provider !== "google") {
118
171
  throw new Error("Token refresh only supported for Google");
119
172
  }
173
+ logger.log("Refreshing tokens...");
120
174
  await this.loginGoogle(
121
175
  this._grantedScopes.length > 0 ? this._grantedScopes : DEFAULT_SCOPES
122
176
  );
123
- return {
177
+ const tokens = {
124
178
  accessToken: this._currentUser.accessToken,
125
179
  idToken: this._currentUser.idToken,
126
180
  };
181
+ this._tokenListeners.forEach((l) => l(tokens));
182
+ return tokens;
127
183
  }
128
184
 
129
185
  private mapError(error: unknown): Error {
130
- const msg = (error as any)?.message?.toLowerCase() ?? "";
186
+ if (error instanceof Error) {
187
+ const msg = error.message.toLowerCase();
188
+ if (msg.includes("cancel") || msg.includes("popup_closed")) {
189
+ return new Error("cancelled");
190
+ }
191
+ if (msg.includes("network")) {
192
+ return new Error("network_error");
193
+ }
194
+ if (msg.includes("client id") || msg.includes("config")) {
195
+ return new Error("configuration_error");
196
+ }
197
+ return error;
198
+ }
199
+
200
+ const msg = String(error).toLowerCase();
131
201
  if (msg.includes("cancel") || msg.includes("popup_closed")) {
132
202
  return new Error("cancelled");
133
203
  }
134
- if (msg.includes("network")) {
135
- return new Error("network_error");
136
- }
137
- if (msg.includes("client id") || msg.includes("config")) {
138
- return new Error("configuration_error");
139
- }
140
- return error as Error;
204
+ return new Error(String(error));
141
205
  }
142
206
 
143
207
  private async loginGoogle(
@@ -158,9 +222,13 @@ class AuthWeb implements Auth {
158
222
  const authUrl = new URL("https://accounts.google.com/o/oauth2/v2/auth");
159
223
  authUrl.searchParams.set("client_id", clientId);
160
224
  authUrl.searchParams.set("redirect_uri", redirectUri);
161
- authUrl.searchParams.set("response_type", "id_token token");
225
+ // Requesting code alongside tokens for server-side verification if needed
226
+ authUrl.searchParams.set("response_type", "id_token token code");
162
227
  authUrl.searchParams.set("scope", scopes.join(" "));
163
228
  authUrl.searchParams.set("nonce", Math.random().toString(36).slice(2));
229
+ authUrl.searchParams.set("access_type", "offline"); // Needed for server auth code flow
230
+ authUrl.searchParams.set("prompt", "consent"); // Force consent to get refresh token/code sometimes
231
+
164
232
  if (loginHint) {
165
233
  authUrl.searchParams.set("login_hint", loginHint);
166
234
  }
@@ -199,15 +267,21 @@ class AuthWeb implements Auth {
199
267
  const idToken = params.get("id_token");
200
268
  const accessToken = params.get("access_token");
201
269
  const expiresIn = params.get("expires_in");
270
+ const code = params.get("code");
202
271
 
203
272
  if (idToken) {
204
273
  this._grantedScopes = scopes;
205
- localStorage.setItem(SCOPES_KEY, JSON.stringify(scopes));
274
+ if (this._storageAdapter) {
275
+ this._storageAdapter.save(SCOPES_KEY, JSON.stringify(scopes));
276
+ } else {
277
+ localStorage.setItem(SCOPES_KEY, JSON.stringify(scopes));
278
+ }
206
279
 
207
280
  const user: AuthUser = {
208
281
  provider: "google",
209
282
  idToken,
210
283
  accessToken: accessToken ?? undefined,
284
+ serverAuthCode: code ?? undefined,
211
285
  scopes,
212
286
  expirationTime: expiresIn
213
287
  ? Date.now() + parseInt(expiresIn) * 1000
@@ -289,17 +363,33 @@ class AuthWeb implements Auth {
289
363
  logout(): void {
290
364
  this._currentUser = undefined;
291
365
  this._grantedScopes = [];
292
- localStorage.removeItem(CACHE_KEY);
293
- localStorage.removeItem(SCOPES_KEY);
366
+ this.removeFromCache(CACHE_KEY);
367
+ this.removeFromCache(SCOPES_KEY);
294
368
  this.notify();
295
369
  }
296
370
 
297
371
  private updateUser(user: AuthUser) {
298
372
  this._currentUser = user;
299
- localStorage.setItem(CACHE_KEY, JSON.stringify(user));
373
+ if (this._storageAdapter) {
374
+ this._storageAdapter.save(CACHE_KEY, JSON.stringify(user));
375
+ } else {
376
+ localStorage.setItem(CACHE_KEY, JSON.stringify(user));
377
+ }
300
378
  this.notify();
301
379
  }
302
380
 
381
+ setLoggingEnabled(enabled: boolean): void {
382
+ logger.setEnabled(enabled);
383
+ }
384
+
385
+ setStorageAdapter(adapter: AuthStorageAdapter | undefined): void {
386
+ this._storageAdapter = adapter;
387
+ if (adapter) {
388
+ this.loadFromCache();
389
+ this.notify();
390
+ }
391
+ }
392
+
303
393
  name = "Auth";
304
394
  dispose() {}
305
395
  equals(other: any) {
@@ -0,0 +1,17 @@
1
+ import type { HybridObject } from "react-native-nitro-modules";
2
+
3
+ export interface AuthStorageAdapter
4
+ extends HybridObject<{ ios: "c++"; android: "c++" }> {
5
+ /**
6
+ * Called to save a value to the custom storage.
7
+ */
8
+ save(key: string, value: string): void;
9
+ /**
10
+ * Called to load a value from the custom storage.
11
+ */
12
+ load(key: string): string | undefined;
13
+ /**
14
+ * Called to remove a value from the custom storage.
15
+ */
16
+ remove(key: string): void;
17
+ }
package/src/index.ts CHANGED
@@ -1,4 +1,5 @@
1
1
  export * from "./Auth.nitro";
2
+ export * from "./AuthStorage.nitro";
2
3
  export * from "./ui/social-button";
3
4
  export * from "./use-auth";
4
5
  export { AuthService } from "./service";
package/src/index.web.ts CHANGED
@@ -1,4 +1,5 @@
1
1
  export * from "./Auth.nitro";
2
+ export * from "./AuthStorage.nitro";
2
3
  export * from "./ui/social-button.web";
3
4
  export * from "./use-auth";
4
5
  export { AuthService } from "./service.web";
@@ -23,10 +23,9 @@ interface SocialButtonProps {
23
23
  onPress?: () => void;
24
24
  }
25
25
 
26
- async function performLogin(provider: AuthProvider): Promise<AuthUser | null> {
26
+ async function performLogin(provider: AuthProvider): Promise<void> {
27
27
  const auth = NitroModules.createHybridObject<Auth>("Auth");
28
28
  await auth.login(provider);
29
- return auth.currentUser ?? null;
30
29
  }
31
30
 
32
31
  export const SocialButton: React.FC<SocialButtonProps> = ({
@@ -50,8 +49,9 @@ export const SocialButton: React.FC<SocialButtonProps> = ({
50
49
  }
51
50
  setLoading(true);
52
51
  performLogin(provider)
53
- .then((user) => {
52
+ .then(() => {
54
53
  setLoading(false);
54
+ const user = NitroModules.createHybridObject<Auth>("Auth").currentUser;
55
55
  if (user) onSuccess?.(user);
56
56
  })
57
57
  .catch((e) => {
@@ -23,9 +23,8 @@ interface SocialButtonProps {
23
23
  onPress?: () => void;
24
24
  }
25
25
 
26
- async function performLogin(provider: AuthProvider): Promise<AuthUser | null> {
26
+ async function performLogin(provider: AuthProvider): Promise<void> {
27
27
  await AuthModule.login(provider);
28
- return AuthModule.currentUser ?? null;
29
28
  }
30
29
 
31
30
  export const SocialButton: React.FC<SocialButtonProps> = ({
@@ -49,8 +48,9 @@ export const SocialButton: React.FC<SocialButtonProps> = ({
49
48
  }
50
49
  setLoading(true);
51
50
  performLogin(provider)
52
- .then((user) => {
51
+ .then(() => {
53
52
  setLoading(false);
53
+ const user = AuthModule.currentUser;
54
54
  if (user) onSuccess?.(user);
55
55
  })
56
56
  .catch((e) => {
@@ -0,0 +1,11 @@
1
+ let enabled = false;
2
+
3
+ export const logger = {
4
+ setEnabled: (value: boolean) => {
5
+ enabled = value;
6
+ },
7
+ log: (...args: any[]) => enabled && console.log("[NitroAuth]", ...args),
8
+ warn: (...args: any[]) => enabled && console.warn("[NitroAuth]", ...args),
9
+ error: (...args: any[]) => enabled && console.error("[NitroAuth]", ...args),
10
+ debug: (...args: any[]) => enabled && console.debug("[NitroAuth]", ...args),
11
+ };