@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 +407 -26
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +137 -44
- package/dist/index.d.ts +137 -44
- package/dist/index.js +399 -26
- package/dist/index.js.map +1 -1
- package/package.json +5 -3
package/dist/index.js
CHANGED
|
@@ -8,7 +8,14 @@ var AuthonMobileClient = class {
|
|
|
8
8
|
apiUrl;
|
|
9
9
|
publishableKey;
|
|
10
10
|
tokens = null;
|
|
11
|
+
user = null;
|
|
11
12
|
storage = null;
|
|
13
|
+
refreshTimer = null;
|
|
14
|
+
listeners = /* @__PURE__ */ new Map();
|
|
15
|
+
// Cached provider/branding data
|
|
16
|
+
_providers = [];
|
|
17
|
+
_branding = null;
|
|
18
|
+
_initialized = false;
|
|
12
19
|
constructor(config) {
|
|
13
20
|
this.publishableKey = config.publishableKey;
|
|
14
21
|
this.apiUrl = (config.apiUrl || DEFAULT_API_URL).replace(/\/$/, "");
|
|
@@ -16,6 +23,7 @@ var AuthonMobileClient = class {
|
|
|
16
23
|
setStorage(storage) {
|
|
17
24
|
this.storage = storage;
|
|
18
25
|
}
|
|
26
|
+
// ── Initialization ──
|
|
19
27
|
async initialize() {
|
|
20
28
|
if (!this.storage) return null;
|
|
21
29
|
const stored = await this.storage.getItem(STORAGE_KEY);
|
|
@@ -24,6 +32,7 @@ var AuthonMobileClient = class {
|
|
|
24
32
|
const tokens = JSON.parse(stored);
|
|
25
33
|
if (tokens.expiresAt > Date.now()) {
|
|
26
34
|
this.tokens = tokens;
|
|
35
|
+
this.scheduleRefresh(tokens.expiresAt);
|
|
27
36
|
return tokens;
|
|
28
37
|
}
|
|
29
38
|
return await this.refreshToken(tokens.refreshToken);
|
|
@@ -32,17 +41,39 @@ var AuthonMobileClient = class {
|
|
|
32
41
|
return null;
|
|
33
42
|
}
|
|
34
43
|
}
|
|
44
|
+
/** Fetch providers + branding from API (lazy, cached) */
|
|
45
|
+
async ensureInitialized() {
|
|
46
|
+
if (this._initialized) return;
|
|
47
|
+
try {
|
|
48
|
+
const [branding, providersRes] = await Promise.all([
|
|
49
|
+
this.request("GET", "/v1/auth/branding"),
|
|
50
|
+
this.request("GET", "/v1/auth/providers")
|
|
51
|
+
]);
|
|
52
|
+
this._branding = branding;
|
|
53
|
+
this._providers = providersRes.providers;
|
|
54
|
+
this._initialized = true;
|
|
55
|
+
} catch (err) {
|
|
56
|
+
this.emit("error", err instanceof Error ? err : new Error(String(err)));
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
// ── Auth ──
|
|
35
60
|
async signIn(params) {
|
|
36
61
|
const res = await this.request("POST", "/v1/auth/signin", params);
|
|
37
62
|
this.tokens = this.toTokenPair(res);
|
|
63
|
+
this.user = res.user;
|
|
38
64
|
await this.persistTokens();
|
|
39
|
-
|
|
65
|
+
this.scheduleRefresh(this.tokens.expiresAt);
|
|
66
|
+
this.emit("signedIn", res.user);
|
|
67
|
+
return { tokens: this.tokens, user: res.user };
|
|
40
68
|
}
|
|
41
69
|
async signUp(params) {
|
|
42
70
|
const res = await this.request("POST", "/v1/auth/signup", params);
|
|
43
71
|
this.tokens = this.toTokenPair(res);
|
|
72
|
+
this.user = res.user;
|
|
44
73
|
await this.persistTokens();
|
|
45
|
-
|
|
74
|
+
this.scheduleRefresh(this.tokens.expiresAt);
|
|
75
|
+
this.emit("signedIn", res.user);
|
|
76
|
+
return { tokens: this.tokens, user: res.user };
|
|
46
77
|
}
|
|
47
78
|
async signOut() {
|
|
48
79
|
if (this.tokens) {
|
|
@@ -51,19 +82,23 @@ var AuthonMobileClient = class {
|
|
|
51
82
|
} catch {
|
|
52
83
|
}
|
|
53
84
|
}
|
|
54
|
-
this.
|
|
55
|
-
|
|
56
|
-
await this.storage.removeItem(STORAGE_KEY);
|
|
57
|
-
}
|
|
85
|
+
this.clearSession();
|
|
86
|
+
this.emit("signedOut");
|
|
58
87
|
}
|
|
59
88
|
async getUser() {
|
|
60
89
|
if (!this.tokens) return null;
|
|
61
90
|
try {
|
|
62
|
-
|
|
91
|
+
const user = await this.request("GET", "/v1/auth/me");
|
|
92
|
+
this.user = user;
|
|
93
|
+
return user;
|
|
63
94
|
} catch {
|
|
64
95
|
return null;
|
|
65
96
|
}
|
|
66
97
|
}
|
|
98
|
+
getCachedUser() {
|
|
99
|
+
return this.user;
|
|
100
|
+
}
|
|
101
|
+
// ── Token management ──
|
|
67
102
|
async refreshToken(refreshToken) {
|
|
68
103
|
const token = refreshToken || this.tokens?.refreshToken;
|
|
69
104
|
if (!token) return null;
|
|
@@ -77,13 +112,15 @@ var AuthonMobileClient = class {
|
|
|
77
112
|
body: JSON.stringify({ refreshToken: token })
|
|
78
113
|
});
|
|
79
114
|
if (!res.ok) {
|
|
80
|
-
this.
|
|
81
|
-
if (this.storage) await this.storage.removeItem(STORAGE_KEY);
|
|
115
|
+
this.clearSession();
|
|
82
116
|
return null;
|
|
83
117
|
}
|
|
84
118
|
const data = await res.json();
|
|
85
119
|
this.tokens = this.toTokenPair(data);
|
|
120
|
+
this.user = data.user;
|
|
86
121
|
await this.persistTokens();
|
|
122
|
+
this.scheduleRefresh(this.tokens.expiresAt);
|
|
123
|
+
this.emit("tokenRefreshed");
|
|
87
124
|
return this.tokens;
|
|
88
125
|
} catch {
|
|
89
126
|
return null;
|
|
@@ -95,6 +132,98 @@ var AuthonMobileClient = class {
|
|
|
95
132
|
isAuthenticated() {
|
|
96
133
|
return this.tokens !== null && this.tokens.expiresAt > Date.now();
|
|
97
134
|
}
|
|
135
|
+
// ── OAuth ──
|
|
136
|
+
async getProviders() {
|
|
137
|
+
await this.ensureInitialized();
|
|
138
|
+
return this._providers;
|
|
139
|
+
}
|
|
140
|
+
async getBranding() {
|
|
141
|
+
await this.ensureInitialized();
|
|
142
|
+
return this._branding;
|
|
143
|
+
}
|
|
144
|
+
async getOAuthUrl(provider, redirectUri) {
|
|
145
|
+
const params = new URLSearchParams({ redirectUri, flow: "redirect" });
|
|
146
|
+
return await this.request(
|
|
147
|
+
"GET",
|
|
148
|
+
`/v1/auth/oauth/${provider}/url?${params.toString()}`
|
|
149
|
+
);
|
|
150
|
+
}
|
|
151
|
+
async pollOAuth(state) {
|
|
152
|
+
try {
|
|
153
|
+
const res = await fetch(
|
|
154
|
+
`${this.apiUrl}/v1/auth/oauth/poll?state=${encodeURIComponent(state)}`,
|
|
155
|
+
{ headers: { "x-api-key": this.publishableKey } }
|
|
156
|
+
);
|
|
157
|
+
if (!res.ok) return null;
|
|
158
|
+
const data = await res.json();
|
|
159
|
+
if (data.status === "completed" && data.accessToken) {
|
|
160
|
+
return data;
|
|
161
|
+
}
|
|
162
|
+
return null;
|
|
163
|
+
} catch {
|
|
164
|
+
return null;
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
/** Poll for OAuth completion (3 minute timeout, matching JS SDK) */
|
|
168
|
+
async completeOAuth(state) {
|
|
169
|
+
const maxAttempts = 360;
|
|
170
|
+
for (let i = 0; i < maxAttempts; i++) {
|
|
171
|
+
const result = await this.pollOAuth(state);
|
|
172
|
+
if (result) {
|
|
173
|
+
this.tokens = this.toTokenPair(result);
|
|
174
|
+
this.user = result.user;
|
|
175
|
+
await this.persistTokens();
|
|
176
|
+
this.scheduleRefresh(this.tokens.expiresAt);
|
|
177
|
+
this.emit("signedIn", result.user);
|
|
178
|
+
return { tokens: this.tokens, user: result.user };
|
|
179
|
+
}
|
|
180
|
+
await new Promise((r) => setTimeout(r, 500));
|
|
181
|
+
}
|
|
182
|
+
throw new Error("OAuth timeout");
|
|
183
|
+
}
|
|
184
|
+
getApiUrl() {
|
|
185
|
+
return this.apiUrl;
|
|
186
|
+
}
|
|
187
|
+
// ── Event system ──
|
|
188
|
+
on(event, listener) {
|
|
189
|
+
if (!this.listeners.has(event)) this.listeners.set(event, /* @__PURE__ */ new Set());
|
|
190
|
+
const set = this.listeners.get(event);
|
|
191
|
+
set.add(listener);
|
|
192
|
+
return () => set.delete(listener);
|
|
193
|
+
}
|
|
194
|
+
emit(event, ...args) {
|
|
195
|
+
this.listeners.get(event)?.forEach((fn) => fn(...args));
|
|
196
|
+
}
|
|
197
|
+
// ── Cleanup ──
|
|
198
|
+
destroy() {
|
|
199
|
+
this.clearRefreshTimer();
|
|
200
|
+
this.listeners.clear();
|
|
201
|
+
}
|
|
202
|
+
// ── Private ──
|
|
203
|
+
clearSession() {
|
|
204
|
+
this.tokens = null;
|
|
205
|
+
this.user = null;
|
|
206
|
+
this.clearRefreshTimer();
|
|
207
|
+
if (this.storage) {
|
|
208
|
+
this.storage.removeItem(STORAGE_KEY).catch(() => {
|
|
209
|
+
});
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
clearRefreshTimer() {
|
|
213
|
+
if (this.refreshTimer) {
|
|
214
|
+
clearTimeout(this.refreshTimer);
|
|
215
|
+
this.refreshTimer = null;
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
/** Schedule auto-refresh 60 seconds before token expiry (like JS SDK) */
|
|
219
|
+
scheduleRefresh(expiresAt) {
|
|
220
|
+
this.clearRefreshTimer();
|
|
221
|
+
const refreshIn = Math.max(expiresAt - Date.now() - 6e4, 3e4);
|
|
222
|
+
this.refreshTimer = setTimeout(() => {
|
|
223
|
+
this.refreshToken().catch(() => {
|
|
224
|
+
});
|
|
225
|
+
}, refreshIn);
|
|
226
|
+
}
|
|
98
227
|
async persistTokens() {
|
|
99
228
|
if (this.storage && this.tokens) {
|
|
100
229
|
await this.storage.setItem(STORAGE_KEY, JSON.stringify(this.tokens));
|
|
@@ -122,7 +251,8 @@ var AuthonMobileClient = class {
|
|
|
122
251
|
});
|
|
123
252
|
if (!res.ok) {
|
|
124
253
|
const error = await res.json().catch(() => ({ message: res.statusText }));
|
|
125
|
-
|
|
254
|
+
const msg = Array.isArray(error.message) ? error.message[0] : error.message || `Request failed with status ${res.status}`;
|
|
255
|
+
throw new Error(msg);
|
|
126
256
|
}
|
|
127
257
|
const text = await res.text();
|
|
128
258
|
return text ? JSON.parse(text) : void 0;
|
|
@@ -142,6 +272,8 @@ function AuthonProvider({ children, storage, ...config }) {
|
|
|
142
272
|
accessToken: null
|
|
143
273
|
});
|
|
144
274
|
const [user, setUser] = useState(null);
|
|
275
|
+
const [providers, setProviders] = useState([]);
|
|
276
|
+
const [branding, setBranding] = useState(null);
|
|
145
277
|
if (!clientRef.current) {
|
|
146
278
|
clientRef.current = new AuthonMobileClient(config);
|
|
147
279
|
}
|
|
@@ -150,7 +282,13 @@ function AuthonProvider({ children, storage, ...config }) {
|
|
|
150
282
|
if (storage) {
|
|
151
283
|
client.setStorage(storage);
|
|
152
284
|
}
|
|
153
|
-
|
|
285
|
+
const init = async () => {
|
|
286
|
+
const tokens = await client.initialize();
|
|
287
|
+
await client.ensureInitialized();
|
|
288
|
+
const p = await client.getProviders();
|
|
289
|
+
const b = await client.getBranding();
|
|
290
|
+
setProviders(p);
|
|
291
|
+
setBranding(b);
|
|
154
292
|
if (tokens) {
|
|
155
293
|
const u = await client.getUser();
|
|
156
294
|
setUser(u);
|
|
@@ -164,11 +302,33 @@ function AuthonProvider({ children, storage, ...config }) {
|
|
|
164
302
|
} else {
|
|
165
303
|
setAuthState((prev) => ({ ...prev, isLoaded: true }));
|
|
166
304
|
}
|
|
167
|
-
}
|
|
305
|
+
};
|
|
306
|
+
init();
|
|
307
|
+
const unsubs = [
|
|
308
|
+
client.on("signedOut", () => {
|
|
309
|
+
setUser(null);
|
|
310
|
+
setAuthState({
|
|
311
|
+
isLoaded: true,
|
|
312
|
+
isSignedIn: false,
|
|
313
|
+
userId: null,
|
|
314
|
+
sessionId: null,
|
|
315
|
+
accessToken: null
|
|
316
|
+
});
|
|
317
|
+
}),
|
|
318
|
+
client.on("tokenRefreshed", () => {
|
|
319
|
+
const token = client.getAccessToken();
|
|
320
|
+
if (token) {
|
|
321
|
+
setAuthState((prev) => ({ ...prev, accessToken: token }));
|
|
322
|
+
}
|
|
323
|
+
})
|
|
324
|
+
];
|
|
325
|
+
return () => {
|
|
326
|
+
unsubs.forEach((fn) => fn());
|
|
327
|
+
client.destroy();
|
|
328
|
+
};
|
|
168
329
|
}, []);
|
|
169
330
|
const signIn = useCallback(async (params) => {
|
|
170
|
-
const tokens = await client.signIn(params);
|
|
171
|
-
const u = await client.getUser();
|
|
331
|
+
const { tokens, user: u } = await client.signIn(params);
|
|
172
332
|
setUser(u);
|
|
173
333
|
setAuthState({
|
|
174
334
|
isLoaded: true,
|
|
@@ -179,8 +339,7 @@ function AuthonProvider({ children, storage, ...config }) {
|
|
|
179
339
|
});
|
|
180
340
|
}, [client]);
|
|
181
341
|
const signUp = useCallback(async (params) => {
|
|
182
|
-
const tokens = await client.signUp(params);
|
|
183
|
-
const u = await client.getUser();
|
|
342
|
+
const { tokens, user: u } = await client.signUp(params);
|
|
184
343
|
setUser(u);
|
|
185
344
|
setAuthState({
|
|
186
345
|
isLoaded: true,
|
|
@@ -192,18 +351,37 @@ function AuthonProvider({ children, storage, ...config }) {
|
|
|
192
351
|
}, [client]);
|
|
193
352
|
const signOut = useCallback(async () => {
|
|
194
353
|
await client.signOut();
|
|
195
|
-
setUser(null);
|
|
196
|
-
setAuthState({
|
|
197
|
-
isLoaded: true,
|
|
198
|
-
isSignedIn: false,
|
|
199
|
-
userId: null,
|
|
200
|
-
sessionId: null,
|
|
201
|
-
accessToken: null
|
|
202
|
-
});
|
|
203
354
|
}, [client]);
|
|
204
355
|
const getToken = useCallback(() => {
|
|
205
356
|
return client.getAccessToken();
|
|
206
357
|
}, [client]);
|
|
358
|
+
const startOAuth = useCallback(
|
|
359
|
+
async (provider, redirectUri) => {
|
|
360
|
+
const uri = redirectUri || `${client.getApiUrl()}/v1/auth/oauth/redirect`;
|
|
361
|
+
return client.getOAuthUrl(provider, uri);
|
|
362
|
+
},
|
|
363
|
+
[client]
|
|
364
|
+
);
|
|
365
|
+
const completeOAuthCb = useCallback(
|
|
366
|
+
async (state) => {
|
|
367
|
+
const { tokens, user: u } = await client.completeOAuth(state);
|
|
368
|
+
setUser(u);
|
|
369
|
+
setAuthState({
|
|
370
|
+
isLoaded: true,
|
|
371
|
+
isSignedIn: true,
|
|
372
|
+
userId: u?.id || null,
|
|
373
|
+
sessionId: null,
|
|
374
|
+
accessToken: tokens.accessToken
|
|
375
|
+
});
|
|
376
|
+
},
|
|
377
|
+
[client]
|
|
378
|
+
);
|
|
379
|
+
const on = useCallback(
|
|
380
|
+
(event, listener) => {
|
|
381
|
+
return client.on(event, listener);
|
|
382
|
+
},
|
|
383
|
+
[client]
|
|
384
|
+
);
|
|
207
385
|
const value = useMemo(
|
|
208
386
|
() => ({
|
|
209
387
|
...authState,
|
|
@@ -211,9 +389,15 @@ function AuthonProvider({ children, storage, ...config }) {
|
|
|
211
389
|
signIn,
|
|
212
390
|
signUp,
|
|
213
391
|
signOut,
|
|
214
|
-
getToken
|
|
392
|
+
getToken,
|
|
393
|
+
providers,
|
|
394
|
+
branding,
|
|
395
|
+
startOAuth,
|
|
396
|
+
completeOAuth: completeOAuthCb,
|
|
397
|
+
on,
|
|
398
|
+
client
|
|
215
399
|
}),
|
|
216
|
-
[authState, user, signIn, signUp, signOut, getToken]
|
|
400
|
+
[authState, user, signIn, signUp, signOut, getToken, providers, branding, startOAuth, completeOAuthCb, on, client]
|
|
217
401
|
);
|
|
218
402
|
return /* @__PURE__ */ jsx(AuthonContext.Provider, { value, children });
|
|
219
403
|
}
|
|
@@ -233,10 +417,199 @@ function useUser() {
|
|
|
233
417
|
const { isLoaded, isSignedIn, user } = useAuthon();
|
|
234
418
|
return { isLoaded, isSignedIn, user };
|
|
235
419
|
}
|
|
420
|
+
|
|
421
|
+
// src/icons.tsx
|
|
422
|
+
import "react";
|
|
423
|
+
import Svg, { Path, Rect } from "react-native-svg";
|
|
424
|
+
import { jsx as jsx2, jsxs } from "react/jsx-runtime";
|
|
425
|
+
function GoogleIcon({ size = 20 }) {
|
|
426
|
+
return /* @__PURE__ */ jsxs(Svg, { viewBox: "0 0 24 24", width: size, height: size, children: [
|
|
427
|
+
/* @__PURE__ */ jsx2(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" }),
|
|
428
|
+
/* @__PURE__ */ jsx2(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" }),
|
|
429
|
+
/* @__PURE__ */ jsx2(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" }),
|
|
430
|
+
/* @__PURE__ */ jsx2(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" })
|
|
431
|
+
] });
|
|
432
|
+
}
|
|
433
|
+
function AppleIcon({ size = 20, color = "#fff" }) {
|
|
434
|
+
return /* @__PURE__ */ jsx2(Svg, { viewBox: "0 0 24 24", width: size, height: size, fill: color, children: /* @__PURE__ */ jsx2(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" }) });
|
|
435
|
+
}
|
|
436
|
+
function KakaoIcon({ size = 20 }) {
|
|
437
|
+
return /* @__PURE__ */ jsx2(Svg, { viewBox: "0 0 24 24", width: size, height: size, children: /* @__PURE__ */ jsx2(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" }) });
|
|
438
|
+
}
|
|
439
|
+
function NaverIcon({ size = 20, color = "#fff" }) {
|
|
440
|
+
return /* @__PURE__ */ jsx2(Svg, { viewBox: "0 0 24 24", width: size, height: size, children: /* @__PURE__ */ jsx2(Path, { fill: color, d: "M16.273 12.845 7.376 0H0v24h7.726V11.156L16.624 24H24V0h-7.727v12.845Z" }) });
|
|
441
|
+
}
|
|
442
|
+
function FacebookIcon({ size = 20, color = "#fff" }) {
|
|
443
|
+
return /* @__PURE__ */ jsx2(Svg, { viewBox: "0 0 24 24", width: size, height: size, children: /* @__PURE__ */ jsx2(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" }) });
|
|
444
|
+
}
|
|
445
|
+
function GithubIcon({ size = 20, color = "#fff" }) {
|
|
446
|
+
return /* @__PURE__ */ jsx2(Svg, { viewBox: "0 0 24 24", width: size, height: size, fill: color, children: /* @__PURE__ */ jsx2(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" }) });
|
|
447
|
+
}
|
|
448
|
+
function DiscordIcon({ size = 20, color = "#fff" }) {
|
|
449
|
+
return /* @__PURE__ */ jsx2(Svg, { viewBox: "0 0 24 24", width: size, height: size, fill: color, children: /* @__PURE__ */ jsx2(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" }) });
|
|
450
|
+
}
|
|
451
|
+
function XIcon({ size = 20, color = "#fff" }) {
|
|
452
|
+
return /* @__PURE__ */ jsx2(Svg, { viewBox: "0 0 24 24", width: size, height: size, fill: color, children: /* @__PURE__ */ jsx2(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" }) });
|
|
453
|
+
}
|
|
454
|
+
function LineIcon({ size = 20, color = "#fff" }) {
|
|
455
|
+
return /* @__PURE__ */ jsx2(Svg, { viewBox: "0 0 24 24", width: size, height: size, fill: color, children: /* @__PURE__ */ jsx2(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" }) });
|
|
456
|
+
}
|
|
457
|
+
function MicrosoftIcon({ size = 20 }) {
|
|
458
|
+
return /* @__PURE__ */ jsxs(Svg, { viewBox: "0 0 24 24", width: size, height: size, children: [
|
|
459
|
+
/* @__PURE__ */ jsx2(Rect, { fill: "#F25022", x: 1, y: 1, width: 10, height: 10 }),
|
|
460
|
+
/* @__PURE__ */ jsx2(Rect, { fill: "#7FBA00", x: 13, y: 1, width: 10, height: 10 }),
|
|
461
|
+
/* @__PURE__ */ jsx2(Rect, { fill: "#00A4EF", x: 1, y: 13, width: 10, height: 10 }),
|
|
462
|
+
/* @__PURE__ */ jsx2(Rect, { fill: "#FFB900", x: 13, y: 13, width: 10, height: 10 })
|
|
463
|
+
] });
|
|
464
|
+
}
|
|
465
|
+
var ICON_MAP = {
|
|
466
|
+
google: GoogleIcon,
|
|
467
|
+
apple: AppleIcon,
|
|
468
|
+
kakao: KakaoIcon,
|
|
469
|
+
naver: NaverIcon,
|
|
470
|
+
facebook: FacebookIcon,
|
|
471
|
+
github: GithubIcon,
|
|
472
|
+
discord: DiscordIcon,
|
|
473
|
+
x: XIcon,
|
|
474
|
+
line: LineIcon,
|
|
475
|
+
microsoft: MicrosoftIcon
|
|
476
|
+
};
|
|
477
|
+
function ProviderIcon({ provider, size = 20, color }) {
|
|
478
|
+
const Icon = ICON_MAP[provider];
|
|
479
|
+
if (!Icon) return null;
|
|
480
|
+
return /* @__PURE__ */ jsx2(Icon, { size, color });
|
|
481
|
+
}
|
|
482
|
+
|
|
483
|
+
// src/SocialButton.tsx
|
|
484
|
+
import "react";
|
|
485
|
+
import {
|
|
486
|
+
TouchableOpacity,
|
|
487
|
+
Text,
|
|
488
|
+
ActivityIndicator,
|
|
489
|
+
StyleSheet
|
|
490
|
+
} from "react-native";
|
|
491
|
+
import { PROVIDER_COLORS, PROVIDER_DISPLAY_NAMES } from "@authon/shared";
|
|
492
|
+
import { Fragment, jsx as jsx3, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
493
|
+
function SocialButton({
|
|
494
|
+
provider,
|
|
495
|
+
onPress,
|
|
496
|
+
loading = false,
|
|
497
|
+
disabled = false,
|
|
498
|
+
label,
|
|
499
|
+
style,
|
|
500
|
+
labelStyle,
|
|
501
|
+
iconSize = 20,
|
|
502
|
+
borderRadius = 10,
|
|
503
|
+
height = 48
|
|
504
|
+
}) {
|
|
505
|
+
const colors = PROVIDER_COLORS[provider] || { bg: "#333", text: "#fff" };
|
|
506
|
+
const displayName = PROVIDER_DISPLAY_NAMES[provider] || provider;
|
|
507
|
+
const buttonLabel = label ?? `Continue with ${displayName}`;
|
|
508
|
+
const needsBorder = colors.bg.toLowerCase() === "#ffffff";
|
|
509
|
+
return /* @__PURE__ */ jsx3(
|
|
510
|
+
TouchableOpacity,
|
|
511
|
+
{
|
|
512
|
+
style: [
|
|
513
|
+
styles.button,
|
|
514
|
+
{
|
|
515
|
+
backgroundColor: colors.bg,
|
|
516
|
+
borderRadius,
|
|
517
|
+
height
|
|
518
|
+
},
|
|
519
|
+
needsBorder && styles.bordered,
|
|
520
|
+
style
|
|
521
|
+
],
|
|
522
|
+
onPress: () => onPress(provider),
|
|
523
|
+
disabled: disabled || loading,
|
|
524
|
+
activeOpacity: 0.8,
|
|
525
|
+
children: loading ? /* @__PURE__ */ jsx3(ActivityIndicator, { color: colors.text, size: "small" }) : /* @__PURE__ */ jsxs2(Fragment, { children: [
|
|
526
|
+
/* @__PURE__ */ jsx3(ProviderIcon, { provider, size: iconSize, color: colors.text }),
|
|
527
|
+
/* @__PURE__ */ jsx3(
|
|
528
|
+
Text,
|
|
529
|
+
{
|
|
530
|
+
style: [
|
|
531
|
+
styles.label,
|
|
532
|
+
{ color: colors.text },
|
|
533
|
+
labelStyle
|
|
534
|
+
],
|
|
535
|
+
numberOfLines: 1,
|
|
536
|
+
children: buttonLabel
|
|
537
|
+
}
|
|
538
|
+
)
|
|
539
|
+
] })
|
|
540
|
+
}
|
|
541
|
+
);
|
|
542
|
+
}
|
|
543
|
+
var styles = StyleSheet.create({
|
|
544
|
+
button: {
|
|
545
|
+
flexDirection: "row",
|
|
546
|
+
alignItems: "center",
|
|
547
|
+
justifyContent: "center",
|
|
548
|
+
gap: 10,
|
|
549
|
+
paddingHorizontal: 16
|
|
550
|
+
},
|
|
551
|
+
bordered: {
|
|
552
|
+
borderWidth: 1,
|
|
553
|
+
borderColor: "#dadce0"
|
|
554
|
+
},
|
|
555
|
+
label: {
|
|
556
|
+
fontSize: 15,
|
|
557
|
+
fontWeight: "600"
|
|
558
|
+
}
|
|
559
|
+
});
|
|
560
|
+
|
|
561
|
+
// src/SocialButtons.tsx
|
|
562
|
+
import { useState as useState2 } from "react";
|
|
563
|
+
import { View, StyleSheet as StyleSheet2, Linking } from "react-native";
|
|
564
|
+
import { jsx as jsx4 } from "react/jsx-runtime";
|
|
565
|
+
function SocialButtons({
|
|
566
|
+
onSuccess,
|
|
567
|
+
onError,
|
|
568
|
+
style,
|
|
569
|
+
gap = 10,
|
|
570
|
+
buttonProps
|
|
571
|
+
}) {
|
|
572
|
+
const { providers, startOAuth, completeOAuth } = useAuthon();
|
|
573
|
+
const [loadingProvider, setLoadingProvider] = useState2(null);
|
|
574
|
+
if (providers.length === 0) return null;
|
|
575
|
+
const handlePress = async (provider) => {
|
|
576
|
+
setLoadingProvider(provider);
|
|
577
|
+
try {
|
|
578
|
+
const { url, state } = await startOAuth(provider);
|
|
579
|
+
await Linking.openURL(url);
|
|
580
|
+
await completeOAuth(state);
|
|
581
|
+
onSuccess?.();
|
|
582
|
+
} catch (e) {
|
|
583
|
+
const error = e instanceof Error ? e : new Error(String(e));
|
|
584
|
+
if (error.message !== "OAuth timeout") {
|
|
585
|
+
onError?.(error);
|
|
586
|
+
}
|
|
587
|
+
} finally {
|
|
588
|
+
setLoadingProvider(null);
|
|
589
|
+
}
|
|
590
|
+
};
|
|
591
|
+
return /* @__PURE__ */ jsx4(View, { style: [styles2.container, { gap }, style], children: providers.map((provider) => /* @__PURE__ */ jsx4(
|
|
592
|
+
SocialButton,
|
|
593
|
+
{
|
|
594
|
+
provider,
|
|
595
|
+
onPress: handlePress,
|
|
596
|
+
loading: loadingProvider === provider,
|
|
597
|
+
disabled: !!loadingProvider,
|
|
598
|
+
...buttonProps
|
|
599
|
+
},
|
|
600
|
+
provider
|
|
601
|
+
)) });
|
|
602
|
+
}
|
|
603
|
+
var styles2 = StyleSheet2.create({
|
|
604
|
+
container: {}
|
|
605
|
+
});
|
|
236
606
|
export {
|
|
237
607
|
AuthonContext,
|
|
238
608
|
AuthonMobileClient,
|
|
239
609
|
AuthonProvider,
|
|
610
|
+
ProviderIcon,
|
|
611
|
+
SocialButton,
|
|
612
|
+
SocialButtons,
|
|
240
613
|
useAuthon,
|
|
241
614
|
useUser
|
|
242
615
|
};
|