@authon/react-native 0.1.22 → 0.2.1

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
@@ -1,7 +1,9 @@
1
1
  "use strict";
2
+ var __create = Object.create;
2
3
  var __defProp = Object.defineProperty;
3
4
  var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
5
  var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
5
7
  var __hasOwnProp = Object.prototype.hasOwnProperty;
6
8
  var __export = (target, all) => {
7
9
  for (var name in all)
@@ -15,6 +17,14 @@ var __copyProps = (to, from, except, desc) => {
15
17
  }
16
18
  return to;
17
19
  };
20
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
+ // If the importer is in node compatibility mode or this is not an ESM
22
+ // file that has been converted to a CommonJS file using a Babel-
23
+ // compatible transform (i.e. "__esModule" has not been set), then set
24
+ // "default" to the CommonJS "module.exports" for node compatibility.
25
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
+ mod
27
+ ));
18
28
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
29
 
20
30
  // src/index.ts
@@ -23,6 +33,9 @@ __export(index_exports, {
23
33
  AuthonContext: () => AuthonContext,
24
34
  AuthonMobileClient: () => AuthonMobileClient,
25
35
  AuthonProvider: () => AuthonProvider,
36
+ ProviderIcon: () => ProviderIcon,
37
+ SocialButton: () => SocialButton,
38
+ SocialButtons: () => SocialButtons,
26
39
  useAuthon: () => useAuthon,
27
40
  useUser: () => useUser
28
41
  });
@@ -38,7 +51,14 @@ var AuthonMobileClient = class {
38
51
  apiUrl;
39
52
  publishableKey;
40
53
  tokens = null;
54
+ user = null;
41
55
  storage = null;
56
+ refreshTimer = null;
57
+ listeners = /* @__PURE__ */ new Map();
58
+ // Cached provider/branding data
59
+ _providers = [];
60
+ _branding = null;
61
+ _initialized = false;
42
62
  constructor(config) {
43
63
  this.publishableKey = config.publishableKey;
44
64
  this.apiUrl = (config.apiUrl || DEFAULT_API_URL).replace(/\/$/, "");
@@ -46,6 +66,7 @@ var AuthonMobileClient = class {
46
66
  setStorage(storage) {
47
67
  this.storage = storage;
48
68
  }
69
+ // ── Initialization ──
49
70
  async initialize() {
50
71
  if (!this.storage) return null;
51
72
  const stored = await this.storage.getItem(STORAGE_KEY);
@@ -54,6 +75,7 @@ var AuthonMobileClient = class {
54
75
  const tokens = JSON.parse(stored);
55
76
  if (tokens.expiresAt > Date.now()) {
56
77
  this.tokens = tokens;
78
+ this.scheduleRefresh(tokens.expiresAt);
57
79
  return tokens;
58
80
  }
59
81
  return await this.refreshToken(tokens.refreshToken);
@@ -62,17 +84,39 @@ var AuthonMobileClient = class {
62
84
  return null;
63
85
  }
64
86
  }
87
+ /** Fetch providers + branding from API (lazy, cached) */
88
+ async ensureInitialized() {
89
+ if (this._initialized) return;
90
+ try {
91
+ const [branding, providersRes] = await Promise.all([
92
+ this.request("GET", "/v1/auth/branding"),
93
+ this.request("GET", "/v1/auth/providers")
94
+ ]);
95
+ this._branding = branding;
96
+ this._providers = providersRes.providers;
97
+ this._initialized = true;
98
+ } catch (err) {
99
+ this.emit("error", err instanceof Error ? err : new Error(String(err)));
100
+ }
101
+ }
102
+ // ── Auth ──
65
103
  async signIn(params) {
66
104
  const res = await this.request("POST", "/v1/auth/signin", params);
67
105
  this.tokens = this.toTokenPair(res);
106
+ this.user = res.user;
68
107
  await this.persistTokens();
69
- return this.tokens;
108
+ this.scheduleRefresh(this.tokens.expiresAt);
109
+ this.emit("signedIn", res.user);
110
+ return { tokens: this.tokens, user: res.user };
70
111
  }
71
112
  async signUp(params) {
72
113
  const res = await this.request("POST", "/v1/auth/signup", params);
73
114
  this.tokens = this.toTokenPair(res);
115
+ this.user = res.user;
74
116
  await this.persistTokens();
75
- return this.tokens;
117
+ this.scheduleRefresh(this.tokens.expiresAt);
118
+ this.emit("signedIn", res.user);
119
+ return { tokens: this.tokens, user: res.user };
76
120
  }
77
121
  async signOut() {
78
122
  if (this.tokens) {
@@ -81,19 +125,23 @@ var AuthonMobileClient = class {
81
125
  } catch {
82
126
  }
83
127
  }
84
- this.tokens = null;
85
- if (this.storage) {
86
- await this.storage.removeItem(STORAGE_KEY);
87
- }
128
+ this.clearSession();
129
+ this.emit("signedOut");
88
130
  }
89
131
  async getUser() {
90
132
  if (!this.tokens) return null;
91
133
  try {
92
- return await this.request("GET", "/v1/auth/me");
134
+ const user = await this.request("GET", "/v1/auth/me");
135
+ this.user = user;
136
+ return user;
93
137
  } catch {
94
138
  return null;
95
139
  }
96
140
  }
141
+ getCachedUser() {
142
+ return this.user;
143
+ }
144
+ // ── Token management ──
97
145
  async refreshToken(refreshToken) {
98
146
  const token = refreshToken || this.tokens?.refreshToken;
99
147
  if (!token) return null;
@@ -107,13 +155,15 @@ var AuthonMobileClient = class {
107
155
  body: JSON.stringify({ refreshToken: token })
108
156
  });
109
157
  if (!res.ok) {
110
- this.tokens = null;
111
- if (this.storage) await this.storage.removeItem(STORAGE_KEY);
158
+ this.clearSession();
112
159
  return null;
113
160
  }
114
161
  const data = await res.json();
115
162
  this.tokens = this.toTokenPair(data);
163
+ this.user = data.user;
116
164
  await this.persistTokens();
165
+ this.scheduleRefresh(this.tokens.expiresAt);
166
+ this.emit("tokenRefreshed");
117
167
  return this.tokens;
118
168
  } catch {
119
169
  return null;
@@ -125,6 +175,98 @@ var AuthonMobileClient = class {
125
175
  isAuthenticated() {
126
176
  return this.tokens !== null && this.tokens.expiresAt > Date.now();
127
177
  }
178
+ // ── OAuth ──
179
+ async getProviders() {
180
+ await this.ensureInitialized();
181
+ return this._providers;
182
+ }
183
+ async getBranding() {
184
+ await this.ensureInitialized();
185
+ return this._branding;
186
+ }
187
+ async getOAuthUrl(provider, redirectUri) {
188
+ const params = new URLSearchParams({ redirectUri, flow: "redirect" });
189
+ return await this.request(
190
+ "GET",
191
+ `/v1/auth/oauth/${provider}/url?${params.toString()}`
192
+ );
193
+ }
194
+ async pollOAuth(state) {
195
+ try {
196
+ const res = await fetch(
197
+ `${this.apiUrl}/v1/auth/oauth/poll?state=${encodeURIComponent(state)}`,
198
+ { headers: { "x-api-key": this.publishableKey } }
199
+ );
200
+ if (!res.ok) return null;
201
+ const data = await res.json();
202
+ if (data.status === "completed" && data.accessToken) {
203
+ return data;
204
+ }
205
+ return null;
206
+ } catch {
207
+ return null;
208
+ }
209
+ }
210
+ /** Poll for OAuth completion (3 minute timeout, matching JS SDK) */
211
+ async completeOAuth(state) {
212
+ const maxAttempts = 360;
213
+ for (let i = 0; i < maxAttempts; i++) {
214
+ const result = await this.pollOAuth(state);
215
+ if (result) {
216
+ this.tokens = this.toTokenPair(result);
217
+ this.user = result.user;
218
+ await this.persistTokens();
219
+ this.scheduleRefresh(this.tokens.expiresAt);
220
+ this.emit("signedIn", result.user);
221
+ return { tokens: this.tokens, user: result.user };
222
+ }
223
+ await new Promise((r) => setTimeout(r, 500));
224
+ }
225
+ throw new Error("OAuth timeout");
226
+ }
227
+ getApiUrl() {
228
+ return this.apiUrl;
229
+ }
230
+ // ── Event system ──
231
+ on(event, listener) {
232
+ if (!this.listeners.has(event)) this.listeners.set(event, /* @__PURE__ */ new Set());
233
+ const set = this.listeners.get(event);
234
+ set.add(listener);
235
+ return () => set.delete(listener);
236
+ }
237
+ emit(event, ...args) {
238
+ this.listeners.get(event)?.forEach((fn) => fn(...args));
239
+ }
240
+ // ── Cleanup ──
241
+ destroy() {
242
+ this.clearRefreshTimer();
243
+ this.listeners.clear();
244
+ }
245
+ // ── Private ──
246
+ clearSession() {
247
+ this.tokens = null;
248
+ this.user = null;
249
+ this.clearRefreshTimer();
250
+ if (this.storage) {
251
+ this.storage.removeItem(STORAGE_KEY).catch(() => {
252
+ });
253
+ }
254
+ }
255
+ clearRefreshTimer() {
256
+ if (this.refreshTimer) {
257
+ clearTimeout(this.refreshTimer);
258
+ this.refreshTimer = null;
259
+ }
260
+ }
261
+ /** Schedule auto-refresh 60 seconds before token expiry (like JS SDK) */
262
+ scheduleRefresh(expiresAt) {
263
+ this.clearRefreshTimer();
264
+ const refreshIn = Math.max(expiresAt - Date.now() - 6e4, 3e4);
265
+ this.refreshTimer = setTimeout(() => {
266
+ this.refreshToken().catch(() => {
267
+ });
268
+ }, refreshIn);
269
+ }
128
270
  async persistTokens() {
129
271
  if (this.storage && this.tokens) {
130
272
  await this.storage.setItem(STORAGE_KEY, JSON.stringify(this.tokens));
@@ -152,7 +294,8 @@ var AuthonMobileClient = class {
152
294
  });
153
295
  if (!res.ok) {
154
296
  const error = await res.json().catch(() => ({ message: res.statusText }));
155
- throw new Error(error.message || `Request failed with status ${res.status}`);
297
+ const msg = Array.isArray(error.message) ? error.message[0] : error.message || `Request failed with status ${res.status}`;
298
+ throw new Error(msg);
156
299
  }
157
300
  const text = await res.text();
158
301
  return text ? JSON.parse(text) : void 0;
@@ -172,6 +315,8 @@ function AuthonProvider({ children, storage, ...config }) {
172
315
  accessToken: null
173
316
  });
174
317
  const [user, setUser] = (0, import_react.useState)(null);
318
+ const [providers, setProviders] = (0, import_react.useState)([]);
319
+ const [branding, setBranding] = (0, import_react.useState)(null);
175
320
  if (!clientRef.current) {
176
321
  clientRef.current = new AuthonMobileClient(config);
177
322
  }
@@ -180,7 +325,13 @@ function AuthonProvider({ children, storage, ...config }) {
180
325
  if (storage) {
181
326
  client.setStorage(storage);
182
327
  }
183
- client.initialize().then(async (tokens) => {
328
+ const init = async () => {
329
+ const tokens = await client.initialize();
330
+ await client.ensureInitialized();
331
+ const p = await client.getProviders();
332
+ const b = await client.getBranding();
333
+ setProviders(p);
334
+ setBranding(b);
184
335
  if (tokens) {
185
336
  const u = await client.getUser();
186
337
  setUser(u);
@@ -194,11 +345,33 @@ function AuthonProvider({ children, storage, ...config }) {
194
345
  } else {
195
346
  setAuthState((prev) => ({ ...prev, isLoaded: true }));
196
347
  }
197
- });
348
+ };
349
+ init();
350
+ const unsubs = [
351
+ client.on("signedOut", () => {
352
+ setUser(null);
353
+ setAuthState({
354
+ isLoaded: true,
355
+ isSignedIn: false,
356
+ userId: null,
357
+ sessionId: null,
358
+ accessToken: null
359
+ });
360
+ }),
361
+ client.on("tokenRefreshed", () => {
362
+ const token = client.getAccessToken();
363
+ if (token) {
364
+ setAuthState((prev) => ({ ...prev, accessToken: token }));
365
+ }
366
+ })
367
+ ];
368
+ return () => {
369
+ unsubs.forEach((fn) => fn());
370
+ client.destroy();
371
+ };
198
372
  }, []);
199
373
  const signIn = (0, import_react.useCallback)(async (params) => {
200
- const tokens = await client.signIn(params);
201
- const u = await client.getUser();
374
+ const { tokens, user: u } = await client.signIn(params);
202
375
  setUser(u);
203
376
  setAuthState({
204
377
  isLoaded: true,
@@ -209,8 +382,7 @@ function AuthonProvider({ children, storage, ...config }) {
209
382
  });
210
383
  }, [client]);
211
384
  const signUp = (0, import_react.useCallback)(async (params) => {
212
- const tokens = await client.signUp(params);
213
- const u = await client.getUser();
385
+ const { tokens, user: u } = await client.signUp(params);
214
386
  setUser(u);
215
387
  setAuthState({
216
388
  isLoaded: true,
@@ -222,18 +394,37 @@ function AuthonProvider({ children, storage, ...config }) {
222
394
  }, [client]);
223
395
  const signOut = (0, import_react.useCallback)(async () => {
224
396
  await client.signOut();
225
- setUser(null);
226
- setAuthState({
227
- isLoaded: true,
228
- isSignedIn: false,
229
- userId: null,
230
- sessionId: null,
231
- accessToken: null
232
- });
233
397
  }, [client]);
234
398
  const getToken = (0, import_react.useCallback)(() => {
235
399
  return client.getAccessToken();
236
400
  }, [client]);
401
+ const startOAuth = (0, import_react.useCallback)(
402
+ async (provider, redirectUri) => {
403
+ const uri = redirectUri || `${client.getApiUrl()}/v1/auth/oauth/redirect`;
404
+ return client.getOAuthUrl(provider, uri);
405
+ },
406
+ [client]
407
+ );
408
+ const completeOAuthCb = (0, import_react.useCallback)(
409
+ async (state) => {
410
+ const { tokens, user: u } = await client.completeOAuth(state);
411
+ setUser(u);
412
+ setAuthState({
413
+ isLoaded: true,
414
+ isSignedIn: true,
415
+ userId: u?.id || null,
416
+ sessionId: null,
417
+ accessToken: tokens.accessToken
418
+ });
419
+ },
420
+ [client]
421
+ );
422
+ const on = (0, import_react.useCallback)(
423
+ (event, listener) => {
424
+ return client.on(event, listener);
425
+ },
426
+ [client]
427
+ );
237
428
  const value = (0, import_react.useMemo)(
238
429
  () => ({
239
430
  ...authState,
@@ -241,9 +432,15 @@ function AuthonProvider({ children, storage, ...config }) {
241
432
  signIn,
242
433
  signUp,
243
434
  signOut,
244
- getToken
435
+ getToken,
436
+ providers,
437
+ branding,
438
+ startOAuth,
439
+ completeOAuth: completeOAuthCb,
440
+ on,
441
+ client
245
442
  }),
246
- [authState, user, signIn, signUp, signOut, getToken]
443
+ [authState, user, signIn, signUp, signOut, getToken, providers, branding, startOAuth, completeOAuthCb, on, client]
247
444
  );
248
445
  return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(AuthonContext.Provider, { value, children });
249
446
  }
@@ -263,11 +460,195 @@ function useUser() {
263
460
  const { isLoaded, isSignedIn, user } = useAuthon();
264
461
  return { isLoaded, isSignedIn, user };
265
462
  }
463
+
464
+ // src/icons.tsx
465
+ var import_react3 = require("react");
466
+ var import_react_native_svg = __toESM(require("react-native-svg"), 1);
467
+ var import_jsx_runtime2 = require("react/jsx-runtime");
468
+ function GoogleIcon({ size = 20 }) {
469
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_react_native_svg.default, { viewBox: "0 0 24 24", width: size, height: size, children: [
470
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native_svg.Path, { fill: "#4285F4", d: "M22.56 12.25c0-.78-.07-1.53-.2-2.25H12v4.26h5.92a5.06 5.06 0 01-2.2 3.32v2.77h3.57c2.08-1.92 3.28-4.74 3.28-8.1z" }),
471
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native_svg.Path, { fill: "#34A853", d: "M12 23c2.97 0 5.46-.98 7.28-2.66l-3.57-2.77c-.98.66-2.23 1.06-3.71 1.06-2.86 0-5.29-1.93-6.16-4.53H2.18v2.84C3.99 20.53 7.7 23 12 23z" }),
472
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native_svg.Path, { fill: "#FBBC05", d: "M5.84 14.09c-.22-.66-.35-1.36-.35-2.09s.13-1.43.35-2.09V7.07H2.18C1.43 8.55 1 10.22 1 12s.43 3.45 1.18 4.93l2.85-2.22.81-.62z" }),
473
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native_svg.Path, { fill: "#EA4335", d: "M12 5.38c1.62 0 3.06.56 4.21 1.64l3.15-3.15C17.45 2.09 14.97 1 12 1 7.7 1 3.99 3.47 2.18 7.07l3.66 2.84c.87-2.6 3.3-4.53 6.16-4.53z" })
474
+ ] });
475
+ }
476
+ function AppleIcon({ size = 20, color = "#fff" }) {
477
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native_svg.default, { viewBox: "0 0 24 24", width: size, height: size, fill: color, children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native_svg.Path, { d: "M17.05 20.28c-.98.95-2.05.88-3.08.4-1.09-.5-2.08-.48-3.24 0-1.44.62-2.2.44-3.06-.4C2.79 15.25 3.51 7.59 9.05 7.31c1.35.07 2.29.74 3.08.8 1.18-.24 2.31-.93 3.57-.84 1.51.12 2.65.72 3.4 1.8-3.12 1.87-2.38 5.98.48 7.13-.57 1.5-1.31 2.99-2.54 4.09zM12.03 7.25c-.15-2.23 1.66-4.07 3.74-4.25.29 2.58-2.34 4.5-3.74 4.25z" }) });
478
+ }
479
+ function KakaoIcon({ size = 20 }) {
480
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native_svg.default, { viewBox: "0 0 24 24", width: size, height: size, children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native_svg.Path, { fill: "#191919", d: "M12 3C6.48 3 2 6.36 2 10.43c0 2.62 1.75 4.93 4.37 6.23l-1.12 4.14c-.1.36.31.65.62.44l4.93-3.26c.39.04.79.06 1.2.06 5.52 0 10-3.36 10-7.61C22 6.36 17.52 3 12 3z" }) });
481
+ }
482
+ function NaverIcon({ size = 20, color = "#fff" }) {
483
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native_svg.default, { viewBox: "0 0 24 24", width: size, height: size, children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native_svg.Path, { fill: color, d: "M16.273 12.845 7.376 0H0v24h7.726V11.156L16.624 24H24V0h-7.727v12.845Z" }) });
484
+ }
485
+ function FacebookIcon({ size = 20, color = "#fff" }) {
486
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native_svg.default, { viewBox: "0 0 24 24", width: size, height: size, children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native_svg.Path, { fill: color, d: "M24 12.07C24 5.41 18.63 0 12 0S0 5.4 0 12.07C0 18.1 4.39 23.1 10.13 24v-8.44H7.08v-3.49h3.04V9.41c0-3.02 1.8-4.7 4.54-4.7 1.31 0 2.68.24 2.68.24v2.97h-1.5c-1.5 0-1.96.93-1.96 1.89v2.26h3.33l-.53 3.49h-2.8V24C19.62 23.1 24 18.1 24 12.07z" }) });
487
+ }
488
+ function GithubIcon({ size = 20, color = "#fff" }) {
489
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native_svg.default, { viewBox: "0 0 24 24", width: size, height: size, fill: color, children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native_svg.Path, { d: "M12 0C5.37 0 0 5.37 0 12c0 5.31 3.435 9.795 8.205 11.385.6.105.825-.255.825-.57 0-.285-.015-1.23-.015-2.235-3.015.555-3.795-.735-4.035-1.41-.135-.345-.72-1.41-1.23-1.695-.42-.225-1.02-.78-.015-.795.945-.015 1.62.87 1.845 1.23 1.08 1.815 2.805 1.305 3.495.99.105-.78.42-1.305.765-1.605-2.67-.3-5.46-1.335-5.46-5.925 0-1.305.465-2.385 1.23-3.225-.12-.3-.54-1.53.12-3.18 0 0 1.005-.315 3.3 1.23.96-.27 1.98-.405 3-.405s2.04.135 3 .405c2.295-1.56 3.3-1.23 3.3-1.23.66 1.65.24 2.88.12 3.18.765.84 1.23 1.905 1.23 3.225 0 4.605-2.805 5.625-5.475 5.925.435.375.81 1.095.81 2.22 0 1.605-.015 2.895-.015 3.3 0 .315.225.69.825.57A12.02 12.02 0 0024 12c0-6.63-5.37-12-12-12z" }) });
490
+ }
491
+ function DiscordIcon({ size = 20, color = "#fff" }) {
492
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native_svg.default, { viewBox: "0 0 24 24", width: size, height: size, fill: color, children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native_svg.Path, { d: "M20.32 4.37a19.8 19.8 0 00-4.89-1.52.07.07 0 00-.08.04c-.21.38-.44.87-.61 1.26a18.27 18.27 0 00-5.49 0 12.64 12.64 0 00-.62-1.26.07.07 0 00-.08-.04 19.74 19.74 0 00-4.89 1.52.07.07 0 00-.03.03C1.11 8.39.34 12.28.73 16.12a.08.08 0 00.03.06 19.9 19.9 0 005.99 3.03.08.08 0 00.08-.03c.46-.63.87-1.3 1.22-2a.08.08 0 00-.04-.11 13.1 13.1 0 01-1.87-.9.08.08 0 01-.01-.13c.13-.09.25-.19.37-.29a.07.07 0 01.08-.01c3.93 1.8 8.18 1.8 12.07 0a.07.07 0 01.08 0c.12.1.25.2.37.3a.08.08 0 01-.01.12c-.6.35-1.22.65-1.87.9a.08.08 0 00-.04.1c.36.7.77 1.37 1.22 2a.08.08 0 00.08.03 19.83 19.83 0 006-3.03.08.08 0 00.03-.05c.47-4.87-.78-9.09-3.3-12.84a.06.06 0 00-.03-.03zM8.02 13.62c-1.11 0-2.03-1.02-2.03-2.28 0-1.26.9-2.28 2.03-2.28 1.14 0 2.04 1.03 2.03 2.28 0 1.26-.9 2.28-2.03 2.28zm7.5 0c-1.11 0-2.03-1.02-2.03-2.28 0-1.26.9-2.28 2.03-2.28 1.14 0 2.04 1.03 2.03 2.28 0 1.26-.89 2.28-2.03 2.28z" }) });
493
+ }
494
+ function XIcon({ size = 20, color = "#fff" }) {
495
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native_svg.default, { viewBox: "0 0 24 24", width: size, height: size, fill: color, children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native_svg.Path, { d: "M18.244 2.25h3.308l-7.227 8.26 8.502 11.24H16.17l-5.214-6.817L4.99 21.75H1.68l7.73-8.835L1.254 2.25H8.08l4.713 6.231zm-1.161 17.52h1.833L7.084 4.126H5.117z" }) });
496
+ }
497
+ function LineIcon({ size = 20, color = "#fff" }) {
498
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native_svg.default, { viewBox: "0 0 24 24", width: size, height: size, fill: color, children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native_svg.Path, { d: "M19.365 9.863c.349 0 .63.285.63.631 0 .345-.281.63-.63.63H17.61v1.125h1.755c.349 0 .63.283.63.63 0 .344-.281.629-.63.629h-2.386c-.345 0-.627-.285-.627-.629V8.108c0-.345.282-.63.63-.63h2.386c.346 0 .627.285.627.63 0 .349-.281.63-.63.63H17.61v1.125h1.755zm-3.855 3.016c0 .27-.174.51-.432.596-.064.021-.133.031-.199.031-.211 0-.391-.09-.51-.25l-2.443-3.317v2.94c0 .344-.279.629-.631.629-.346 0-.626-.285-.626-.629V8.108c0-.27.173-.51.43-.595.06-.023.136-.033.194-.033.195 0 .375.104.495.254l2.462 3.33V8.108c0-.345.282-.63.63-.63.345 0 .63.285.63.63v4.771zm-5.741 0c0 .344-.282.629-.631.629-.345 0-.627-.285-.627-.629V8.108c0-.345.282-.63.63-.63.346 0 .628.285.628.63v4.771zm-2.466.629H4.917c-.345 0-.63-.285-.63-.629V8.108c0-.345.285-.63.63-.63.348 0 .63.285.63.63v4.141h1.756c.348 0 .629.283.629.63 0 .344-.282.629-.629.629M24 10.314C24 4.943 18.615.572 12 .572S0 4.943 0 10.314c0 4.811 4.27 8.842 10.035 9.608.391.082.923.258 1.058.59.12.301.079.766.038 1.08l-.164 1.02c-.045.301-.24 1.186 1.049.645 1.291-.539 6.916-4.078 9.436-6.975C23.176 14.393 24 12.458 24 10.314" }) });
499
+ }
500
+ function MicrosoftIcon({ size = 20 }) {
501
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_react_native_svg.default, { viewBox: "0 0 24 24", width: size, height: size, children: [
502
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native_svg.Rect, { fill: "#F25022", x: 1, y: 1, width: 10, height: 10 }),
503
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native_svg.Rect, { fill: "#7FBA00", x: 13, y: 1, width: 10, height: 10 }),
504
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native_svg.Rect, { fill: "#00A4EF", x: 1, y: 13, width: 10, height: 10 }),
505
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native_svg.Rect, { fill: "#FFB900", x: 13, y: 13, width: 10, height: 10 })
506
+ ] });
507
+ }
508
+ var ICON_MAP = {
509
+ google: GoogleIcon,
510
+ apple: AppleIcon,
511
+ kakao: KakaoIcon,
512
+ naver: NaverIcon,
513
+ facebook: FacebookIcon,
514
+ github: GithubIcon,
515
+ discord: DiscordIcon,
516
+ x: XIcon,
517
+ line: LineIcon,
518
+ microsoft: MicrosoftIcon
519
+ };
520
+ function ProviderIcon({ provider, size = 20, color }) {
521
+ const Icon = ICON_MAP[provider];
522
+ if (!Icon) return null;
523
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Icon, { size, color });
524
+ }
525
+
526
+ // src/SocialButton.tsx
527
+ var import_react4 = require("react");
528
+ var import_react_native = require("react-native");
529
+ var import_shared = require("@authon/shared");
530
+ var import_jsx_runtime3 = require("react/jsx-runtime");
531
+ function SocialButton({
532
+ provider,
533
+ onPress,
534
+ loading = false,
535
+ disabled = false,
536
+ label,
537
+ style,
538
+ labelStyle,
539
+ iconSize = 20,
540
+ borderRadius = 10,
541
+ height = 48
542
+ }) {
543
+ const colors = import_shared.PROVIDER_COLORS[provider] || { bg: "#333", text: "#fff" };
544
+ const displayName = import_shared.PROVIDER_DISPLAY_NAMES[provider] || provider;
545
+ const buttonLabel = label ?? `Continue with ${displayName}`;
546
+ const needsBorder = colors.bg.toLowerCase() === "#ffffff";
547
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
548
+ import_react_native.TouchableOpacity,
549
+ {
550
+ style: [
551
+ styles.button,
552
+ {
553
+ backgroundColor: colors.bg,
554
+ borderRadius,
555
+ height
556
+ },
557
+ needsBorder && styles.bordered,
558
+ style
559
+ ],
560
+ onPress: () => onPress(provider),
561
+ disabled: disabled || loading,
562
+ activeOpacity: 0.8,
563
+ children: loading ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react_native.ActivityIndicator, { color: colors.text, size: "small" }) : /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_jsx_runtime3.Fragment, { children: [
564
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(ProviderIcon, { provider, size: iconSize, color: colors.text }),
565
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
566
+ import_react_native.Text,
567
+ {
568
+ style: [
569
+ styles.label,
570
+ { color: colors.text },
571
+ labelStyle
572
+ ],
573
+ numberOfLines: 1,
574
+ children: buttonLabel
575
+ }
576
+ )
577
+ ] })
578
+ }
579
+ );
580
+ }
581
+ var styles = import_react_native.StyleSheet.create({
582
+ button: {
583
+ flexDirection: "row",
584
+ alignItems: "center",
585
+ justifyContent: "center",
586
+ gap: 10,
587
+ paddingHorizontal: 16
588
+ },
589
+ bordered: {
590
+ borderWidth: 1,
591
+ borderColor: "#dadce0"
592
+ },
593
+ label: {
594
+ fontSize: 15,
595
+ fontWeight: "600"
596
+ }
597
+ });
598
+
599
+ // src/SocialButtons.tsx
600
+ var import_react5 = require("react");
601
+ var import_react_native2 = require("react-native");
602
+ var import_jsx_runtime4 = require("react/jsx-runtime");
603
+ function SocialButtons({
604
+ onSuccess,
605
+ onError,
606
+ style,
607
+ gap = 10,
608
+ buttonProps
609
+ }) {
610
+ const { providers, startOAuth, completeOAuth } = useAuthon();
611
+ const [loadingProvider, setLoadingProvider] = (0, import_react5.useState)(null);
612
+ if (providers.length === 0) return null;
613
+ const handlePress = async (provider) => {
614
+ setLoadingProvider(provider);
615
+ try {
616
+ const { url, state } = await startOAuth(provider);
617
+ await import_react_native2.Linking.openURL(url);
618
+ await completeOAuth(state);
619
+ onSuccess?.();
620
+ } catch (e) {
621
+ const error = e instanceof Error ? e : new Error(String(e));
622
+ if (error.message !== "OAuth timeout") {
623
+ onError?.(error);
624
+ }
625
+ } finally {
626
+ setLoadingProvider(null);
627
+ }
628
+ };
629
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_react_native2.View, { style: [styles2.container, { gap }, style], children: providers.map((provider) => /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
630
+ SocialButton,
631
+ {
632
+ provider,
633
+ onPress: handlePress,
634
+ loading: loadingProvider === provider,
635
+ disabled: !!loadingProvider,
636
+ ...buttonProps
637
+ },
638
+ provider
639
+ )) });
640
+ }
641
+ var styles2 = import_react_native2.StyleSheet.create({
642
+ container: {}
643
+ });
266
644
  // Annotate the CommonJS export names for ESM import in node:
267
645
  0 && (module.exports = {
268
646
  AuthonContext,
269
647
  AuthonMobileClient,
270
648
  AuthonProvider,
649
+ ProviderIcon,
650
+ SocialButton,
651
+ SocialButtons,
271
652
  useAuthon,
272
653
  useUser
273
654
  });