@authon/react-native 0.1.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/README.md ADDED
@@ -0,0 +1,112 @@
1
+ # @authon/react-native
2
+
3
+ React Native SDK for [Authon](https://authon.dev) — native OAuth, secure token storage, and React hooks.
4
+
5
+ ## Install
6
+
7
+ ```bash
8
+ npm install @authon/react-native
9
+ # or
10
+ pnpm add @authon/react-native
11
+ ```
12
+
13
+ Requires `react-native >= 0.72`, `expo-auth-session`, and `expo-secure-store` (or bare RN equivalents).
14
+
15
+ ## Quick Start
16
+
17
+ ### 1. Provider
18
+
19
+ ```tsx
20
+ // App.tsx
21
+ import { AuthonProvider } from '@authon/react-native';
22
+
23
+ export default function App() {
24
+ return (
25
+ <AuthonProvider publishableKey="pk_live_...">
26
+ <Navigation />
27
+ </AuthonProvider>
28
+ );
29
+ }
30
+ ```
31
+
32
+ ### 2. Use Hooks
33
+
34
+ ```tsx
35
+ import { useAuthon, useUser } from '@authon/react-native';
36
+ import { View, Text, Button } from 'react-native';
37
+
38
+ function ProfileScreen() {
39
+ const { isSignedIn, signOut } = useAuthon();
40
+ const { user } = useUser();
41
+
42
+ if (!isSignedIn) {
43
+ return <SignInScreen />;
44
+ }
45
+
46
+ return (
47
+ <View>
48
+ <Text>Welcome, {user?.displayName}</Text>
49
+ <Button title="Sign Out" onPress={signOut} />
50
+ </View>
51
+ );
52
+ }
53
+
54
+ function SignInScreen() {
55
+ const { signInWithOAuth, signInWithEmail } = useAuthon();
56
+
57
+ return (
58
+ <View>
59
+ <Button title="Sign in with Google" onPress={() => signInWithOAuth('google')} />
60
+ <Button title="Sign in with Apple" onPress={() => signInWithOAuth('apple')} />
61
+ </View>
62
+ );
63
+ }
64
+ ```
65
+
66
+ ## API Reference
67
+
68
+ ### `<AuthonProvider>`
69
+
70
+ ```tsx
71
+ <AuthonProvider
72
+ publishableKey="pk_live_..."
73
+ config={{
74
+ apiUrl: 'https://api.authon.dev',
75
+ scheme: 'myapp', // Custom URL scheme for OAuth redirect
76
+ }}
77
+ >
78
+ ```
79
+
80
+ ### Hooks
81
+
82
+ #### `useAuthon()`
83
+
84
+ ```ts
85
+ const {
86
+ isSignedIn, // boolean
87
+ isLoading, // boolean
88
+ user, // AuthonUser | null
89
+ signInWithOAuth, // (provider: string) => Promise<void>
90
+ signInWithEmail, // (email: string, password: string) => Promise<AuthonUser>
91
+ signOut, // () => Promise<void>
92
+ getToken, // () => Promise<string | null>
93
+ } = useAuthon();
94
+ ```
95
+
96
+ #### `useUser()`
97
+
98
+ ```ts
99
+ const { user, isLoading } = useUser();
100
+ ```
101
+
102
+ ### Token Storage
103
+
104
+ Tokens are stored using `expo-secure-store` (Expo) or the platform keychain (bare RN), keeping credentials encrypted at rest.
105
+
106
+ ## Documentation
107
+
108
+ [authon.dev/docs](https://authon.dev/docs)
109
+
110
+ ## License
111
+
112
+ [MIT](../../LICENSE)
package/dist/index.cjs ADDED
@@ -0,0 +1,266 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/index.ts
21
+ var index_exports = {};
22
+ __export(index_exports, {
23
+ AuthonContext: () => AuthonContext,
24
+ AuthonMobileClient: () => AuthonMobileClient,
25
+ AuthonProvider: () => AuthonProvider,
26
+ useAuthon: () => useAuthon,
27
+ useUser: () => useUser
28
+ });
29
+ module.exports = __toCommonJS(index_exports);
30
+
31
+ // src/AuthonProvider.tsx
32
+ var import_react = require("react");
33
+
34
+ // src/client.ts
35
+ var DEFAULT_API_URL = "https://api.authon.dev";
36
+ var STORAGE_KEY = "@authon/tokens";
37
+ var AuthonMobileClient = class {
38
+ apiUrl;
39
+ publishableKey;
40
+ tokens = null;
41
+ storage = null;
42
+ constructor(config) {
43
+ this.publishableKey = config.publishableKey;
44
+ this.apiUrl = (config.apiUrl || DEFAULT_API_URL).replace(/\/$/, "");
45
+ }
46
+ setStorage(storage) {
47
+ this.storage = storage;
48
+ }
49
+ async initialize() {
50
+ if (!this.storage) return null;
51
+ const stored = await this.storage.getItem(STORAGE_KEY);
52
+ if (!stored) return null;
53
+ try {
54
+ const tokens = JSON.parse(stored);
55
+ if (tokens.expiresAt > Date.now()) {
56
+ this.tokens = tokens;
57
+ return tokens;
58
+ }
59
+ return await this.refreshToken(tokens.refreshToken);
60
+ } catch {
61
+ await this.storage.removeItem(STORAGE_KEY);
62
+ return null;
63
+ }
64
+ }
65
+ async signIn(params) {
66
+ const res = await this.request("POST", "/v1/auth/sign-in", params);
67
+ this.tokens = res;
68
+ await this.persistTokens();
69
+ return this.tokens;
70
+ }
71
+ async signUp(params) {
72
+ const res = await this.request("POST", "/v1/auth/sign-up", params);
73
+ this.tokens = res;
74
+ await this.persistTokens();
75
+ return this.tokens;
76
+ }
77
+ async signOut() {
78
+ if (this.tokens) {
79
+ try {
80
+ await this.request("POST", "/v1/auth/sign-out", void 0);
81
+ } catch {
82
+ }
83
+ }
84
+ this.tokens = null;
85
+ if (this.storage) {
86
+ await this.storage.removeItem(STORAGE_KEY);
87
+ }
88
+ }
89
+ async getUser() {
90
+ if (!this.tokens) return null;
91
+ try {
92
+ return await this.request("GET", "/v1/auth/me");
93
+ } catch {
94
+ return null;
95
+ }
96
+ }
97
+ async refreshToken(refreshToken) {
98
+ const token = refreshToken || this.tokens?.refreshToken;
99
+ if (!token) return null;
100
+ try {
101
+ const res = await fetch(`${this.apiUrl}/v1/auth/refresh`, {
102
+ method: "POST",
103
+ headers: {
104
+ "Content-Type": "application/json",
105
+ "X-Publishable-Key": this.publishableKey
106
+ },
107
+ body: JSON.stringify({ refreshToken: token })
108
+ });
109
+ if (!res.ok) {
110
+ this.tokens = null;
111
+ if (this.storage) await this.storage.removeItem(STORAGE_KEY);
112
+ return null;
113
+ }
114
+ this.tokens = await res.json();
115
+ await this.persistTokens();
116
+ return this.tokens;
117
+ } catch {
118
+ return null;
119
+ }
120
+ }
121
+ getAccessToken() {
122
+ return this.tokens?.accessToken || null;
123
+ }
124
+ isAuthenticated() {
125
+ return this.tokens !== null && this.tokens.expiresAt > Date.now();
126
+ }
127
+ async persistTokens() {
128
+ if (this.storage && this.tokens) {
129
+ await this.storage.setItem(STORAGE_KEY, JSON.stringify(this.tokens));
130
+ }
131
+ }
132
+ async request(method, path, body) {
133
+ const headers = {
134
+ "Content-Type": "application/json",
135
+ "X-Publishable-Key": this.publishableKey
136
+ };
137
+ if (this.tokens?.accessToken) {
138
+ headers["Authorization"] = `Bearer ${this.tokens.accessToken}`;
139
+ }
140
+ const res = await fetch(`${this.apiUrl}${path}`, {
141
+ method,
142
+ headers,
143
+ body: body ? JSON.stringify(body) : void 0
144
+ });
145
+ if (!res.ok) {
146
+ const error = await res.json().catch(() => ({ message: res.statusText }));
147
+ throw new Error(error.message || `Request failed with status ${res.status}`);
148
+ }
149
+ const text = await res.text();
150
+ return text ? JSON.parse(text) : void 0;
151
+ }
152
+ };
153
+
154
+ // src/AuthonProvider.tsx
155
+ var import_jsx_runtime = require("react/jsx-runtime");
156
+ var AuthonContext = (0, import_react.createContext)(null);
157
+ function AuthonProvider({ children, storage, ...config }) {
158
+ const clientRef = (0, import_react.useRef)(null);
159
+ const [authState, setAuthState] = (0, import_react.useState)({
160
+ isLoaded: false,
161
+ isSignedIn: false,
162
+ userId: null,
163
+ sessionId: null,
164
+ accessToken: null
165
+ });
166
+ const [user, setUser] = (0, import_react.useState)(null);
167
+ if (!clientRef.current) {
168
+ clientRef.current = new AuthonMobileClient(config);
169
+ }
170
+ const client = clientRef.current;
171
+ (0, import_react.useEffect)(() => {
172
+ if (storage) {
173
+ client.setStorage(storage);
174
+ }
175
+ client.initialize().then(async (tokens) => {
176
+ if (tokens) {
177
+ const u = await client.getUser();
178
+ setUser(u);
179
+ setAuthState({
180
+ isLoaded: true,
181
+ isSignedIn: true,
182
+ userId: u?.id || null,
183
+ sessionId: null,
184
+ accessToken: tokens.accessToken
185
+ });
186
+ } else {
187
+ setAuthState((prev) => ({ ...prev, isLoaded: true }));
188
+ }
189
+ });
190
+ }, []);
191
+ const signIn = (0, import_react.useCallback)(async (params) => {
192
+ const tokens = await client.signIn(params);
193
+ const u = await client.getUser();
194
+ setUser(u);
195
+ setAuthState({
196
+ isLoaded: true,
197
+ isSignedIn: true,
198
+ userId: u?.id || null,
199
+ sessionId: null,
200
+ accessToken: tokens.accessToken
201
+ });
202
+ }, [client]);
203
+ const signUp = (0, import_react.useCallback)(async (params) => {
204
+ const tokens = await client.signUp(params);
205
+ const u = await client.getUser();
206
+ setUser(u);
207
+ setAuthState({
208
+ isLoaded: true,
209
+ isSignedIn: true,
210
+ userId: u?.id || null,
211
+ sessionId: null,
212
+ accessToken: tokens.accessToken
213
+ });
214
+ }, [client]);
215
+ const signOut = (0, import_react.useCallback)(async () => {
216
+ await client.signOut();
217
+ setUser(null);
218
+ setAuthState({
219
+ isLoaded: true,
220
+ isSignedIn: false,
221
+ userId: null,
222
+ sessionId: null,
223
+ accessToken: null
224
+ });
225
+ }, [client]);
226
+ const getToken = (0, import_react.useCallback)(() => {
227
+ return client.getAccessToken();
228
+ }, [client]);
229
+ const value = (0, import_react.useMemo)(
230
+ () => ({
231
+ ...authState,
232
+ user,
233
+ signIn,
234
+ signUp,
235
+ signOut,
236
+ getToken
237
+ }),
238
+ [authState, user, signIn, signUp, signOut, getToken]
239
+ );
240
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(AuthonContext.Provider, { value, children });
241
+ }
242
+
243
+ // src/useAuthon.ts
244
+ var import_react2 = require("react");
245
+ function useAuthon() {
246
+ const context = (0, import_react2.useContext)(AuthonContext);
247
+ if (!context) {
248
+ throw new Error("useAuthon must be used within an <AuthonProvider>");
249
+ }
250
+ return context;
251
+ }
252
+
253
+ // src/useUser.ts
254
+ function useUser() {
255
+ const { isLoaded, isSignedIn, user } = useAuthon();
256
+ return { isLoaded, isSignedIn, user };
257
+ }
258
+ // Annotate the CommonJS export names for ESM import in node:
259
+ 0 && (module.exports = {
260
+ AuthonContext,
261
+ AuthonMobileClient,
262
+ AuthonProvider,
263
+ useAuthon,
264
+ useUser
265
+ });
266
+ //# sourceMappingURL=index.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/index.ts","../src/AuthonProvider.tsx","../src/client.ts","../src/useAuthon.ts","../src/useUser.ts"],"sourcesContent":["export { AuthonProvider, AuthonContext } from './AuthonProvider';\nexport type { AuthonContextValue } from './AuthonProvider';\nexport { useAuthon } from './useAuthon';\nexport { useUser } from './useUser';\nexport { AuthonMobileClient } from './client';\nexport type {\n AuthonReactNativeConfig,\n AuthState,\n AuthonUser,\n SignInParams,\n SignUpParams,\n} from './types';\n","import React, { createContext, useCallback, useEffect, useMemo, useRef, useState } from 'react';\nimport { AuthonMobileClient } from './client';\nimport type { AuthState, AuthonReactNativeConfig, AuthonUser, SignInParams, SignUpParams } from './types';\n\nexport interface AuthonContextValue extends AuthState {\n user: AuthonUser | null;\n signIn: (params: SignInParams) => Promise<void>;\n signUp: (params: SignUpParams) => Promise<void>;\n signOut: () => Promise<void>;\n getToken: () => string | null;\n}\n\nexport const AuthonContext = createContext<AuthonContextValue | null>(null);\n\ninterface AuthonProviderProps extends AuthonReactNativeConfig {\n children: React.ReactNode;\n storage?: {\n getItem(key: string): Promise<string | null>;\n setItem(key: string, value: string): Promise<void>;\n removeItem(key: string): Promise<void>;\n };\n}\n\nexport function AuthonProvider({ children, storage, ...config }: AuthonProviderProps) {\n const clientRef = useRef<AuthonMobileClient | null>(null);\n const [authState, setAuthState] = useState<AuthState>({\n isLoaded: false,\n isSignedIn: false,\n userId: null,\n sessionId: null,\n accessToken: null,\n });\n const [user, setUser] = useState<AuthonUser | null>(null);\n\n if (!clientRef.current) {\n clientRef.current = new AuthonMobileClient(config);\n }\n\n const client = clientRef.current;\n\n useEffect(() => {\n if (storage) {\n client.setStorage(storage);\n }\n\n client.initialize().then(async (tokens) => {\n if (tokens) {\n const u = await client.getUser();\n setUser(u);\n setAuthState({\n isLoaded: true,\n isSignedIn: true,\n userId: u?.id || null,\n sessionId: null,\n accessToken: tokens.accessToken,\n });\n } else {\n setAuthState((prev) => ({ ...prev, isLoaded: true }));\n }\n });\n }, []);\n\n const signIn = useCallback(async (params: SignInParams) => {\n const tokens = await client.signIn(params);\n const u = await client.getUser();\n setUser(u);\n setAuthState({\n isLoaded: true,\n isSignedIn: true,\n userId: u?.id || null,\n sessionId: null,\n accessToken: tokens.accessToken,\n });\n }, [client]);\n\n const signUp = useCallback(async (params: SignUpParams) => {\n const tokens = await client.signUp(params);\n const u = await client.getUser();\n setUser(u);\n setAuthState({\n isLoaded: true,\n isSignedIn: true,\n userId: u?.id || null,\n sessionId: null,\n accessToken: tokens.accessToken,\n });\n }, [client]);\n\n const signOut = useCallback(async () => {\n await client.signOut();\n setUser(null);\n setAuthState({\n isLoaded: true,\n isSignedIn: false,\n userId: null,\n sessionId: null,\n accessToken: null,\n });\n }, [client]);\n\n const getToken = useCallback(() => {\n return client.getAccessToken();\n }, [client]);\n\n const value = useMemo<AuthonContextValue>(\n () => ({\n ...authState,\n user,\n signIn,\n signUp,\n signOut,\n getToken,\n }),\n [authState, user, signIn, signUp, signOut, getToken],\n );\n\n return <AuthonContext.Provider value={value}>{children}</AuthonContext.Provider>;\n}\n","import type { AuthonReactNativeConfig, AuthonUser, SignInParams, SignUpParams } from './types';\n\nconst DEFAULT_API_URL = 'https://api.authon.dev';\n\ninterface TokenPair {\n accessToken: string;\n refreshToken: string;\n expiresAt: number;\n}\n\ntype TokenStorage = {\n getItem(key: string): Promise<string | null>;\n setItem(key: string, value: string): Promise<void>;\n removeItem(key: string): Promise<void>;\n};\n\nconst STORAGE_KEY = '@authon/tokens';\n\nexport class AuthonMobileClient {\n private apiUrl: string;\n private publishableKey: string;\n private tokens: TokenPair | null = null;\n private storage: TokenStorage | null = null;\n\n constructor(config: AuthonReactNativeConfig) {\n this.publishableKey = config.publishableKey;\n this.apiUrl = (config.apiUrl || DEFAULT_API_URL).replace(/\\/$/, '');\n }\n\n setStorage(storage: TokenStorage) {\n this.storage = storage;\n }\n\n async initialize(): Promise<TokenPair | null> {\n if (!this.storage) return null;\n\n const stored = await this.storage.getItem(STORAGE_KEY);\n if (!stored) return null;\n\n try {\n const tokens: TokenPair = JSON.parse(stored);\n if (tokens.expiresAt > Date.now()) {\n this.tokens = tokens;\n return tokens;\n }\n // Try refreshing\n return await this.refreshToken(tokens.refreshToken);\n } catch {\n await this.storage.removeItem(STORAGE_KEY);\n return null;\n }\n }\n\n async signIn(params: SignInParams): Promise<TokenPair> {\n const res = await this.request('POST', '/v1/auth/sign-in', params);\n this.tokens = res as TokenPair;\n await this.persistTokens();\n return this.tokens;\n }\n\n async signUp(params: SignUpParams): Promise<TokenPair> {\n const res = await this.request('POST', '/v1/auth/sign-up', params);\n this.tokens = res as TokenPair;\n await this.persistTokens();\n return this.tokens;\n }\n\n async signOut(): Promise<void> {\n if (this.tokens) {\n try {\n await this.request('POST', '/v1/auth/sign-out', undefined);\n } catch {\n // Ignore sign-out errors\n }\n }\n this.tokens = null;\n if (this.storage) {\n await this.storage.removeItem(STORAGE_KEY);\n }\n }\n\n async getUser(): Promise<AuthonUser | null> {\n if (!this.tokens) return null;\n try {\n return (await this.request('GET', '/v1/auth/me')) as AuthonUser;\n } catch {\n return null;\n }\n }\n\n async refreshToken(refreshToken?: string): Promise<TokenPair | null> {\n const token = refreshToken || this.tokens?.refreshToken;\n if (!token) return null;\n\n try {\n const res = await fetch(`${this.apiUrl}/v1/auth/refresh`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n 'X-Publishable-Key': this.publishableKey,\n },\n body: JSON.stringify({ refreshToken: token }),\n });\n\n if (!res.ok) {\n this.tokens = null;\n if (this.storage) await this.storage.removeItem(STORAGE_KEY);\n return null;\n }\n\n this.tokens = (await res.json()) as TokenPair;\n await this.persistTokens();\n return this.tokens;\n } catch {\n return null;\n }\n }\n\n getAccessToken(): string | null {\n return this.tokens?.accessToken || null;\n }\n\n isAuthenticated(): boolean {\n return this.tokens !== null && this.tokens.expiresAt > Date.now();\n }\n\n private async persistTokens(): Promise<void> {\n if (this.storage && this.tokens) {\n await this.storage.setItem(STORAGE_KEY, JSON.stringify(this.tokens));\n }\n }\n\n private async request(method: string, path: string, body?: unknown): Promise<unknown> {\n const headers: Record<string, string> = {\n 'Content-Type': 'application/json',\n 'X-Publishable-Key': this.publishableKey,\n };\n\n if (this.tokens?.accessToken) {\n headers['Authorization'] = `Bearer ${this.tokens.accessToken}`;\n }\n\n const res = await fetch(`${this.apiUrl}${path}`, {\n method,\n headers,\n body: body ? JSON.stringify(body) : undefined,\n });\n\n if (!res.ok) {\n const error = await res.json().catch(() => ({ message: res.statusText }));\n throw new Error(error.message || `Request failed with status ${res.status}`);\n }\n\n const text = await res.text();\n return text ? JSON.parse(text) : undefined;\n }\n}\n","import { useContext } from 'react';\nimport { AuthonContext, type AuthonContextValue } from './AuthonProvider';\n\nexport function useAuthon(): AuthonContextValue {\n const context = useContext(AuthonContext);\n if (!context) {\n throw new Error('useAuthon must be used within an <AuthonProvider>');\n }\n return context;\n}\n","import { useAuthon } from './useAuthon';\nimport type { AuthonUser } from './types';\n\nexport function useUser(): {\n isLoaded: boolean;\n isSignedIn: boolean;\n user: AuthonUser | null;\n} {\n const { isLoaded, isSignedIn, user } = useAuthon();\n return { isLoaded, isSignedIn, user };\n}\n"],"mappings":"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","names":["import_react"]}
@@ -0,0 +1,105 @@
1
+ import * as react_jsx_runtime from 'react/jsx-runtime';
2
+ import React from 'react';
3
+
4
+ interface AuthonReactNativeConfig {
5
+ publishableKey: string;
6
+ apiUrl?: string;
7
+ }
8
+ interface AuthState {
9
+ isLoaded: boolean;
10
+ isSignedIn: boolean;
11
+ userId: string | null;
12
+ sessionId: string | null;
13
+ accessToken: string | null;
14
+ }
15
+ interface AuthonUser {
16
+ id: string;
17
+ email?: string;
18
+ emailVerified: boolean;
19
+ phone?: string;
20
+ phoneVerified: boolean;
21
+ username?: string;
22
+ firstName?: string;
23
+ lastName?: string;
24
+ displayName?: string;
25
+ avatarUrl?: string;
26
+ banned: boolean;
27
+ metadata?: Record<string, unknown>;
28
+ externalAccounts?: Array<{
29
+ provider: string;
30
+ providerId: string;
31
+ email?: string;
32
+ }>;
33
+ createdAt: string;
34
+ updatedAt: string;
35
+ }
36
+ interface SignInParams {
37
+ strategy: 'email_password' | 'oauth';
38
+ email?: string;
39
+ password?: string;
40
+ provider?: string;
41
+ }
42
+ interface SignUpParams {
43
+ email: string;
44
+ password: string;
45
+ firstName?: string;
46
+ lastName?: string;
47
+ username?: string;
48
+ }
49
+
50
+ interface AuthonContextValue extends AuthState {
51
+ user: AuthonUser | null;
52
+ signIn: (params: SignInParams) => Promise<void>;
53
+ signUp: (params: SignUpParams) => Promise<void>;
54
+ signOut: () => Promise<void>;
55
+ getToken: () => string | null;
56
+ }
57
+ declare const AuthonContext: React.Context<AuthonContextValue | null>;
58
+ interface AuthonProviderProps extends AuthonReactNativeConfig {
59
+ children: React.ReactNode;
60
+ storage?: {
61
+ getItem(key: string): Promise<string | null>;
62
+ setItem(key: string, value: string): Promise<void>;
63
+ removeItem(key: string): Promise<void>;
64
+ };
65
+ }
66
+ declare function AuthonProvider({ children, storage, ...config }: AuthonProviderProps): react_jsx_runtime.JSX.Element;
67
+
68
+ declare function useAuthon(): AuthonContextValue;
69
+
70
+ declare function useUser(): {
71
+ isLoaded: boolean;
72
+ isSignedIn: boolean;
73
+ user: AuthonUser | null;
74
+ };
75
+
76
+ interface TokenPair {
77
+ accessToken: string;
78
+ refreshToken: string;
79
+ expiresAt: number;
80
+ }
81
+ type TokenStorage = {
82
+ getItem(key: string): Promise<string | null>;
83
+ setItem(key: string, value: string): Promise<void>;
84
+ removeItem(key: string): Promise<void>;
85
+ };
86
+ declare class AuthonMobileClient {
87
+ private apiUrl;
88
+ private publishableKey;
89
+ private tokens;
90
+ private storage;
91
+ constructor(config: AuthonReactNativeConfig);
92
+ setStorage(storage: TokenStorage): void;
93
+ initialize(): Promise<TokenPair | null>;
94
+ signIn(params: SignInParams): Promise<TokenPair>;
95
+ signUp(params: SignUpParams): Promise<TokenPair>;
96
+ signOut(): Promise<void>;
97
+ getUser(): Promise<AuthonUser | null>;
98
+ refreshToken(refreshToken?: string): Promise<TokenPair | null>;
99
+ getAccessToken(): string | null;
100
+ isAuthenticated(): boolean;
101
+ private persistTokens;
102
+ private request;
103
+ }
104
+
105
+ export { type AuthState, AuthonContext, type AuthonContextValue, AuthonMobileClient, AuthonProvider, type AuthonReactNativeConfig, type AuthonUser, type SignInParams, type SignUpParams, useAuthon, useUser };
@@ -0,0 +1,105 @@
1
+ import * as react_jsx_runtime from 'react/jsx-runtime';
2
+ import React from 'react';
3
+
4
+ interface AuthonReactNativeConfig {
5
+ publishableKey: string;
6
+ apiUrl?: string;
7
+ }
8
+ interface AuthState {
9
+ isLoaded: boolean;
10
+ isSignedIn: boolean;
11
+ userId: string | null;
12
+ sessionId: string | null;
13
+ accessToken: string | null;
14
+ }
15
+ interface AuthonUser {
16
+ id: string;
17
+ email?: string;
18
+ emailVerified: boolean;
19
+ phone?: string;
20
+ phoneVerified: boolean;
21
+ username?: string;
22
+ firstName?: string;
23
+ lastName?: string;
24
+ displayName?: string;
25
+ avatarUrl?: string;
26
+ banned: boolean;
27
+ metadata?: Record<string, unknown>;
28
+ externalAccounts?: Array<{
29
+ provider: string;
30
+ providerId: string;
31
+ email?: string;
32
+ }>;
33
+ createdAt: string;
34
+ updatedAt: string;
35
+ }
36
+ interface SignInParams {
37
+ strategy: 'email_password' | 'oauth';
38
+ email?: string;
39
+ password?: string;
40
+ provider?: string;
41
+ }
42
+ interface SignUpParams {
43
+ email: string;
44
+ password: string;
45
+ firstName?: string;
46
+ lastName?: string;
47
+ username?: string;
48
+ }
49
+
50
+ interface AuthonContextValue extends AuthState {
51
+ user: AuthonUser | null;
52
+ signIn: (params: SignInParams) => Promise<void>;
53
+ signUp: (params: SignUpParams) => Promise<void>;
54
+ signOut: () => Promise<void>;
55
+ getToken: () => string | null;
56
+ }
57
+ declare const AuthonContext: React.Context<AuthonContextValue | null>;
58
+ interface AuthonProviderProps extends AuthonReactNativeConfig {
59
+ children: React.ReactNode;
60
+ storage?: {
61
+ getItem(key: string): Promise<string | null>;
62
+ setItem(key: string, value: string): Promise<void>;
63
+ removeItem(key: string): Promise<void>;
64
+ };
65
+ }
66
+ declare function AuthonProvider({ children, storage, ...config }: AuthonProviderProps): react_jsx_runtime.JSX.Element;
67
+
68
+ declare function useAuthon(): AuthonContextValue;
69
+
70
+ declare function useUser(): {
71
+ isLoaded: boolean;
72
+ isSignedIn: boolean;
73
+ user: AuthonUser | null;
74
+ };
75
+
76
+ interface TokenPair {
77
+ accessToken: string;
78
+ refreshToken: string;
79
+ expiresAt: number;
80
+ }
81
+ type TokenStorage = {
82
+ getItem(key: string): Promise<string | null>;
83
+ setItem(key: string, value: string): Promise<void>;
84
+ removeItem(key: string): Promise<void>;
85
+ };
86
+ declare class AuthonMobileClient {
87
+ private apiUrl;
88
+ private publishableKey;
89
+ private tokens;
90
+ private storage;
91
+ constructor(config: AuthonReactNativeConfig);
92
+ setStorage(storage: TokenStorage): void;
93
+ initialize(): Promise<TokenPair | null>;
94
+ signIn(params: SignInParams): Promise<TokenPair>;
95
+ signUp(params: SignUpParams): Promise<TokenPair>;
96
+ signOut(): Promise<void>;
97
+ getUser(): Promise<AuthonUser | null>;
98
+ refreshToken(refreshToken?: string): Promise<TokenPair | null>;
99
+ getAccessToken(): string | null;
100
+ isAuthenticated(): boolean;
101
+ private persistTokens;
102
+ private request;
103
+ }
104
+
105
+ export { type AuthState, AuthonContext, type AuthonContextValue, AuthonMobileClient, AuthonProvider, type AuthonReactNativeConfig, type AuthonUser, type SignInParams, type SignUpParams, useAuthon, useUser };
package/dist/index.js ADDED
@@ -0,0 +1,235 @@
1
+ // src/AuthonProvider.tsx
2
+ import { createContext, useCallback, useEffect, useMemo, useRef, useState } from "react";
3
+
4
+ // src/client.ts
5
+ var DEFAULT_API_URL = "https://api.authon.dev";
6
+ var STORAGE_KEY = "@authon/tokens";
7
+ var AuthonMobileClient = class {
8
+ apiUrl;
9
+ publishableKey;
10
+ tokens = null;
11
+ storage = null;
12
+ constructor(config) {
13
+ this.publishableKey = config.publishableKey;
14
+ this.apiUrl = (config.apiUrl || DEFAULT_API_URL).replace(/\/$/, "");
15
+ }
16
+ setStorage(storage) {
17
+ this.storage = storage;
18
+ }
19
+ async initialize() {
20
+ if (!this.storage) return null;
21
+ const stored = await this.storage.getItem(STORAGE_KEY);
22
+ if (!stored) return null;
23
+ try {
24
+ const tokens = JSON.parse(stored);
25
+ if (tokens.expiresAt > Date.now()) {
26
+ this.tokens = tokens;
27
+ return tokens;
28
+ }
29
+ return await this.refreshToken(tokens.refreshToken);
30
+ } catch {
31
+ await this.storage.removeItem(STORAGE_KEY);
32
+ return null;
33
+ }
34
+ }
35
+ async signIn(params) {
36
+ const res = await this.request("POST", "/v1/auth/sign-in", params);
37
+ this.tokens = res;
38
+ await this.persistTokens();
39
+ return this.tokens;
40
+ }
41
+ async signUp(params) {
42
+ const res = await this.request("POST", "/v1/auth/sign-up", params);
43
+ this.tokens = res;
44
+ await this.persistTokens();
45
+ return this.tokens;
46
+ }
47
+ async signOut() {
48
+ if (this.tokens) {
49
+ try {
50
+ await this.request("POST", "/v1/auth/sign-out", void 0);
51
+ } catch {
52
+ }
53
+ }
54
+ this.tokens = null;
55
+ if (this.storage) {
56
+ await this.storage.removeItem(STORAGE_KEY);
57
+ }
58
+ }
59
+ async getUser() {
60
+ if (!this.tokens) return null;
61
+ try {
62
+ return await this.request("GET", "/v1/auth/me");
63
+ } catch {
64
+ return null;
65
+ }
66
+ }
67
+ async refreshToken(refreshToken) {
68
+ const token = refreshToken || this.tokens?.refreshToken;
69
+ if (!token) return null;
70
+ try {
71
+ const res = await fetch(`${this.apiUrl}/v1/auth/refresh`, {
72
+ method: "POST",
73
+ headers: {
74
+ "Content-Type": "application/json",
75
+ "X-Publishable-Key": this.publishableKey
76
+ },
77
+ body: JSON.stringify({ refreshToken: token })
78
+ });
79
+ if (!res.ok) {
80
+ this.tokens = null;
81
+ if (this.storage) await this.storage.removeItem(STORAGE_KEY);
82
+ return null;
83
+ }
84
+ this.tokens = await res.json();
85
+ await this.persistTokens();
86
+ return this.tokens;
87
+ } catch {
88
+ return null;
89
+ }
90
+ }
91
+ getAccessToken() {
92
+ return this.tokens?.accessToken || null;
93
+ }
94
+ isAuthenticated() {
95
+ return this.tokens !== null && this.tokens.expiresAt > Date.now();
96
+ }
97
+ async persistTokens() {
98
+ if (this.storage && this.tokens) {
99
+ await this.storage.setItem(STORAGE_KEY, JSON.stringify(this.tokens));
100
+ }
101
+ }
102
+ async request(method, path, body) {
103
+ const headers = {
104
+ "Content-Type": "application/json",
105
+ "X-Publishable-Key": this.publishableKey
106
+ };
107
+ if (this.tokens?.accessToken) {
108
+ headers["Authorization"] = `Bearer ${this.tokens.accessToken}`;
109
+ }
110
+ const res = await fetch(`${this.apiUrl}${path}`, {
111
+ method,
112
+ headers,
113
+ body: body ? JSON.stringify(body) : void 0
114
+ });
115
+ if (!res.ok) {
116
+ const error = await res.json().catch(() => ({ message: res.statusText }));
117
+ throw new Error(error.message || `Request failed with status ${res.status}`);
118
+ }
119
+ const text = await res.text();
120
+ return text ? JSON.parse(text) : void 0;
121
+ }
122
+ };
123
+
124
+ // src/AuthonProvider.tsx
125
+ import { jsx } from "react/jsx-runtime";
126
+ var AuthonContext = createContext(null);
127
+ function AuthonProvider({ children, storage, ...config }) {
128
+ const clientRef = useRef(null);
129
+ const [authState, setAuthState] = useState({
130
+ isLoaded: false,
131
+ isSignedIn: false,
132
+ userId: null,
133
+ sessionId: null,
134
+ accessToken: null
135
+ });
136
+ const [user, setUser] = useState(null);
137
+ if (!clientRef.current) {
138
+ clientRef.current = new AuthonMobileClient(config);
139
+ }
140
+ const client = clientRef.current;
141
+ useEffect(() => {
142
+ if (storage) {
143
+ client.setStorage(storage);
144
+ }
145
+ client.initialize().then(async (tokens) => {
146
+ if (tokens) {
147
+ const u = await client.getUser();
148
+ setUser(u);
149
+ setAuthState({
150
+ isLoaded: true,
151
+ isSignedIn: true,
152
+ userId: u?.id || null,
153
+ sessionId: null,
154
+ accessToken: tokens.accessToken
155
+ });
156
+ } else {
157
+ setAuthState((prev) => ({ ...prev, isLoaded: true }));
158
+ }
159
+ });
160
+ }, []);
161
+ const signIn = useCallback(async (params) => {
162
+ const tokens = await client.signIn(params);
163
+ const u = await client.getUser();
164
+ setUser(u);
165
+ setAuthState({
166
+ isLoaded: true,
167
+ isSignedIn: true,
168
+ userId: u?.id || null,
169
+ sessionId: null,
170
+ accessToken: tokens.accessToken
171
+ });
172
+ }, [client]);
173
+ const signUp = useCallback(async (params) => {
174
+ const tokens = await client.signUp(params);
175
+ const u = await client.getUser();
176
+ setUser(u);
177
+ setAuthState({
178
+ isLoaded: true,
179
+ isSignedIn: true,
180
+ userId: u?.id || null,
181
+ sessionId: null,
182
+ accessToken: tokens.accessToken
183
+ });
184
+ }, [client]);
185
+ const signOut = useCallback(async () => {
186
+ await client.signOut();
187
+ setUser(null);
188
+ setAuthState({
189
+ isLoaded: true,
190
+ isSignedIn: false,
191
+ userId: null,
192
+ sessionId: null,
193
+ accessToken: null
194
+ });
195
+ }, [client]);
196
+ const getToken = useCallback(() => {
197
+ return client.getAccessToken();
198
+ }, [client]);
199
+ const value = useMemo(
200
+ () => ({
201
+ ...authState,
202
+ user,
203
+ signIn,
204
+ signUp,
205
+ signOut,
206
+ getToken
207
+ }),
208
+ [authState, user, signIn, signUp, signOut, getToken]
209
+ );
210
+ return /* @__PURE__ */ jsx(AuthonContext.Provider, { value, children });
211
+ }
212
+
213
+ // src/useAuthon.ts
214
+ import { useContext } from "react";
215
+ function useAuthon() {
216
+ const context = useContext(AuthonContext);
217
+ if (!context) {
218
+ throw new Error("useAuthon must be used within an <AuthonProvider>");
219
+ }
220
+ return context;
221
+ }
222
+
223
+ // src/useUser.ts
224
+ function useUser() {
225
+ const { isLoaded, isSignedIn, user } = useAuthon();
226
+ return { isLoaded, isSignedIn, user };
227
+ }
228
+ export {
229
+ AuthonContext,
230
+ AuthonMobileClient,
231
+ AuthonProvider,
232
+ useAuthon,
233
+ useUser
234
+ };
235
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/AuthonProvider.tsx","../src/client.ts","../src/useAuthon.ts","../src/useUser.ts"],"sourcesContent":["import React, { createContext, useCallback, useEffect, useMemo, useRef, useState } from 'react';\nimport { AuthonMobileClient } from './client';\nimport type { AuthState, AuthonReactNativeConfig, AuthonUser, SignInParams, SignUpParams } from './types';\n\nexport interface AuthonContextValue extends AuthState {\n user: AuthonUser | null;\n signIn: (params: SignInParams) => Promise<void>;\n signUp: (params: SignUpParams) => Promise<void>;\n signOut: () => Promise<void>;\n getToken: () => string | null;\n}\n\nexport const AuthonContext = createContext<AuthonContextValue | null>(null);\n\ninterface AuthonProviderProps extends AuthonReactNativeConfig {\n children: React.ReactNode;\n storage?: {\n getItem(key: string): Promise<string | null>;\n setItem(key: string, value: string): Promise<void>;\n removeItem(key: string): Promise<void>;\n };\n}\n\nexport function AuthonProvider({ children, storage, ...config }: AuthonProviderProps) {\n const clientRef = useRef<AuthonMobileClient | null>(null);\n const [authState, setAuthState] = useState<AuthState>({\n isLoaded: false,\n isSignedIn: false,\n userId: null,\n sessionId: null,\n accessToken: null,\n });\n const [user, setUser] = useState<AuthonUser | null>(null);\n\n if (!clientRef.current) {\n clientRef.current = new AuthonMobileClient(config);\n }\n\n const client = clientRef.current;\n\n useEffect(() => {\n if (storage) {\n client.setStorage(storage);\n }\n\n client.initialize().then(async (tokens) => {\n if (tokens) {\n const u = await client.getUser();\n setUser(u);\n setAuthState({\n isLoaded: true,\n isSignedIn: true,\n userId: u?.id || null,\n sessionId: null,\n accessToken: tokens.accessToken,\n });\n } else {\n setAuthState((prev) => ({ ...prev, isLoaded: true }));\n }\n });\n }, []);\n\n const signIn = useCallback(async (params: SignInParams) => {\n const tokens = await client.signIn(params);\n const u = await client.getUser();\n setUser(u);\n setAuthState({\n isLoaded: true,\n isSignedIn: true,\n userId: u?.id || null,\n sessionId: null,\n accessToken: tokens.accessToken,\n });\n }, [client]);\n\n const signUp = useCallback(async (params: SignUpParams) => {\n const tokens = await client.signUp(params);\n const u = await client.getUser();\n setUser(u);\n setAuthState({\n isLoaded: true,\n isSignedIn: true,\n userId: u?.id || null,\n sessionId: null,\n accessToken: tokens.accessToken,\n });\n }, [client]);\n\n const signOut = useCallback(async () => {\n await client.signOut();\n setUser(null);\n setAuthState({\n isLoaded: true,\n isSignedIn: false,\n userId: null,\n sessionId: null,\n accessToken: null,\n });\n }, [client]);\n\n const getToken = useCallback(() => {\n return client.getAccessToken();\n }, [client]);\n\n const value = useMemo<AuthonContextValue>(\n () => ({\n ...authState,\n user,\n signIn,\n signUp,\n signOut,\n getToken,\n }),\n [authState, user, signIn, signUp, signOut, getToken],\n );\n\n return <AuthonContext.Provider value={value}>{children}</AuthonContext.Provider>;\n}\n","import type { AuthonReactNativeConfig, AuthonUser, SignInParams, SignUpParams } from './types';\n\nconst DEFAULT_API_URL = 'https://api.authon.dev';\n\ninterface TokenPair {\n accessToken: string;\n refreshToken: string;\n expiresAt: number;\n}\n\ntype TokenStorage = {\n getItem(key: string): Promise<string | null>;\n setItem(key: string, value: string): Promise<void>;\n removeItem(key: string): Promise<void>;\n};\n\nconst STORAGE_KEY = '@authon/tokens';\n\nexport class AuthonMobileClient {\n private apiUrl: string;\n private publishableKey: string;\n private tokens: TokenPair | null = null;\n private storage: TokenStorage | null = null;\n\n constructor(config: AuthonReactNativeConfig) {\n this.publishableKey = config.publishableKey;\n this.apiUrl = (config.apiUrl || DEFAULT_API_URL).replace(/\\/$/, '');\n }\n\n setStorage(storage: TokenStorage) {\n this.storage = storage;\n }\n\n async initialize(): Promise<TokenPair | null> {\n if (!this.storage) return null;\n\n const stored = await this.storage.getItem(STORAGE_KEY);\n if (!stored) return null;\n\n try {\n const tokens: TokenPair = JSON.parse(stored);\n if (tokens.expiresAt > Date.now()) {\n this.tokens = tokens;\n return tokens;\n }\n // Try refreshing\n return await this.refreshToken(tokens.refreshToken);\n } catch {\n await this.storage.removeItem(STORAGE_KEY);\n return null;\n }\n }\n\n async signIn(params: SignInParams): Promise<TokenPair> {\n const res = await this.request('POST', '/v1/auth/sign-in', params);\n this.tokens = res as TokenPair;\n await this.persistTokens();\n return this.tokens;\n }\n\n async signUp(params: SignUpParams): Promise<TokenPair> {\n const res = await this.request('POST', '/v1/auth/sign-up', params);\n this.tokens = res as TokenPair;\n await this.persistTokens();\n return this.tokens;\n }\n\n async signOut(): Promise<void> {\n if (this.tokens) {\n try {\n await this.request('POST', '/v1/auth/sign-out', undefined);\n } catch {\n // Ignore sign-out errors\n }\n }\n this.tokens = null;\n if (this.storage) {\n await this.storage.removeItem(STORAGE_KEY);\n }\n }\n\n async getUser(): Promise<AuthonUser | null> {\n if (!this.tokens) return null;\n try {\n return (await this.request('GET', '/v1/auth/me')) as AuthonUser;\n } catch {\n return null;\n }\n }\n\n async refreshToken(refreshToken?: string): Promise<TokenPair | null> {\n const token = refreshToken || this.tokens?.refreshToken;\n if (!token) return null;\n\n try {\n const res = await fetch(`${this.apiUrl}/v1/auth/refresh`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n 'X-Publishable-Key': this.publishableKey,\n },\n body: JSON.stringify({ refreshToken: token }),\n });\n\n if (!res.ok) {\n this.tokens = null;\n if (this.storage) await this.storage.removeItem(STORAGE_KEY);\n return null;\n }\n\n this.tokens = (await res.json()) as TokenPair;\n await this.persistTokens();\n return this.tokens;\n } catch {\n return null;\n }\n }\n\n getAccessToken(): string | null {\n return this.tokens?.accessToken || null;\n }\n\n isAuthenticated(): boolean {\n return this.tokens !== null && this.tokens.expiresAt > Date.now();\n }\n\n private async persistTokens(): Promise<void> {\n if (this.storage && this.tokens) {\n await this.storage.setItem(STORAGE_KEY, JSON.stringify(this.tokens));\n }\n }\n\n private async request(method: string, path: string, body?: unknown): Promise<unknown> {\n const headers: Record<string, string> = {\n 'Content-Type': 'application/json',\n 'X-Publishable-Key': this.publishableKey,\n };\n\n if (this.tokens?.accessToken) {\n headers['Authorization'] = `Bearer ${this.tokens.accessToken}`;\n }\n\n const res = await fetch(`${this.apiUrl}${path}`, {\n method,\n headers,\n body: body ? JSON.stringify(body) : undefined,\n });\n\n if (!res.ok) {\n const error = await res.json().catch(() => ({ message: res.statusText }));\n throw new Error(error.message || `Request failed with status ${res.status}`);\n }\n\n const text = await res.text();\n return text ? JSON.parse(text) : undefined;\n }\n}\n","import { useContext } from 'react';\nimport { AuthonContext, type AuthonContextValue } from './AuthonProvider';\n\nexport function useAuthon(): AuthonContextValue {\n const context = useContext(AuthonContext);\n if (!context) {\n throw new Error('useAuthon must be used within an <AuthonProvider>');\n }\n return context;\n}\n","import { useAuthon } from './useAuthon';\nimport type { AuthonUser } from './types';\n\nexport function useUser(): {\n isLoaded: boolean;\n isSignedIn: boolean;\n user: AuthonUser | null;\n} {\n const { isLoaded, isSignedIn, user } = useAuthon();\n return { isLoaded, isSignedIn, user };\n}\n"],"mappings":"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","names":[]}
package/package.json ADDED
@@ -0,0 +1,44 @@
1
+ {
2
+ "name": "@authon/react-native",
3
+ "version": "0.1.0",
4
+ "description": "Authon React Native SDK — mobile authentication",
5
+ "type": "module",
6
+ "main": "./dist/index.cjs",
7
+ "module": "./dist/index.js",
8
+ "types": "./dist/index.d.ts",
9
+ "exports": {
10
+ ".": {
11
+ "types": "./dist/index.d.ts",
12
+ "import": "./dist/index.js",
13
+ "require": "./dist/index.cjs"
14
+ }
15
+ },
16
+ "files": ["dist"],
17
+ "scripts": {
18
+ "build": "tsup",
19
+ "dev": "tsup --watch"
20
+ },
21
+ "license": "MIT",
22
+ "repository": {
23
+ "type": "git",
24
+ "url": "https://github.com/mikusnuz/authon-sdk.git",
25
+ "directory": "packages/react-native"
26
+ },
27
+ "publishConfig": {
28
+ "access": "public"
29
+ },
30
+ "keywords": ["authon", "react-native", "mobile", "auth"],
31
+ "dependencies": {
32
+ "@authon/shared": "workspace:*"
33
+ },
34
+ "peerDependencies": {
35
+ "react": "^18.0.0 || ^19.0.0",
36
+ "react-native": ">=0.70.0"
37
+ },
38
+ "devDependencies": {
39
+ "@types/react": "^19.0.0",
40
+ "react": "^19.0.0",
41
+ "tsup": "^8.0.0",
42
+ "typescript": "^5.9.3"
43
+ }
44
+ }