@edcalderon/auth 1.1.1 โ†’ 1.1.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/README.md +139 -397
  3. package/package.json +1 -1
package/CHANGELOG.md CHANGED
@@ -1,5 +1,17 @@
1
1
  # Changelog
2
2
 
3
+ ## [1.1.3] - 2026-03-02
4
+
5
+ ### Docs
6
+
7
+ - ๐Ÿ“ Fully rewrote README to document the new `v1.1.0` Universal Compatibility (Web + Next.js + React Native/Expo) APIs and export paths.
8
+
9
+ ## [1.1.2] - 2026-03-02
10
+
11
+ ### Changed
12
+
13
+ - ๐Ÿงช Test release to verify readme-maintainer guard via pre-push hook
14
+
3
15
  ## [1.1.1] - 2026-03-02
4
16
 
5
17
  ### Fixed
package/README.md CHANGED
@@ -4,502 +4,244 @@
4
4
  [![npm downloads](https://img.shields.io/npm/dm/@edcalderon/auth?style=flat-square&color=10b981)](https://www.npmjs.com/package/@edcalderon/auth)
5
5
  [![GitHub](https://img.shields.io/badge/GitHub-Repository-181717?style=flat-square&logo=github)](https://github.com/edcalderon/my-second-brain/tree/main/packages/auth)
6
6
 
7
- A universal, **provider-agnostic** authentication orchestration package for React applications. Swap between Supabase, Firebase, Directus, Google OAuth, or any custom provider without changing a single line of component code.
7
+ A universal, **provider-agnostic** authentication orchestration package designed for absolute runtime portability. One abstraction that works flawlessly across React Web `(18.x/19.x)`, Next.js `(14/15)`, and React Native/Expo `(SDK 50+)`.
8
+
9
+ Swap between Supabase, Firebase, Hybrid, or any custom provider without changing a single line of your UX component code.
8
10
 
9
11
  ---
10
12
 
11
- ## ๐Ÿ“‹ Latest Changes (v1.0.3)
13
+ ## ๐Ÿ“‹ Latest Changes (v1.1.3)
12
14
 
13
- ### Fixed
15
+ ### Docs
14
16
 
15
- - ๐Ÿ› Updated import from `@ed/auth` (old internal alias) to `@edcalderon/auth` in dashboard consumer
16
- - ๐Ÿ“ Added `update-readme` script โ€” uses `versioning update-readme` to keep README in sync with CHANGELOG
17
- - ๐Ÿ”„ Versioning package used as dev dependency for README maintenance
17
+ - ๐Ÿ“ Fully rewrote README to document the new `v1.1.0` Universal Compatibility (Web + Next.js + React Native/Expo) APIs and export paths.
18
18
 
19
19
  For full version history, see [CHANGELOG.md](./CHANGELOG.md) and [GitHub releases](https://github.com/edcalderon/my-second-brain/releases)
20
20
 
21
21
  ---
22
22
 
23
- ## ๐Ÿ—๏ธ Architecture
24
-
25
- The package follows a **Single Source of Truth** model with a **Federated OAuth Strategy**:
26
-
27
- - **Principal Database (Source of Truth)**: Supabase anchors user identities, metadata, roles, and RLS policies in PostgreSQL (`auth.users`, `auth.identities`).
28
- - **OAuth / Identity Providers**: External services (Firebase, Directus, native Google OAuth, Auth0, etc.) handle frontend login bridges or federated SSO flows.
29
- - **The Orchestrator (`@edcalderon/auth`)**: A thin bridge layer that exposes generic interfaces (`User`, `AuthClient`). Applications consume a unified context without coupling to any specific vendor.
23
+ ## ๐Ÿš€ Runtime Support Matrix
30
24
 
31
- **Architecture Flow:**
25
+ | Target Runtime | Engine / Framework | Notes | Supported Flow Semantics |
26
+ |----------------|--------------------|-------|-----------------|
27
+ | **Web** | React, Vite, SPA | Standard web APIs available (`window`) | `popup`, `redirect` |
28
+ | **Server** | Next.js Client | Compatible with App Router Contexts | `redirect`, `popup` |
29
+ | **Native** | Expo/React Native | Clean native bundles, strictly no web assumptions | `native` |
32
30
 
33
- 1. **Frontend Applications** `=>` consume **`@edcalderon/auth`** via `useAuth()`
34
- 2. **`@edcalderon/auth`** orchestrates the adapters:
35
- - `=>` **Supabase Adapter** (Direct Session)
36
- - `=>` **Hybrid Bridge** (Firebase OAuth + Supabase Session)
37
- - `=>` **Custom Adapters** (e.g. Directus SSO, Auth0)
38
- 3. **Identity Providers** (Firebase/Directus) `=>` Sync Session to **Supabase**
39
- 4. **Supabase** `=>` Manages Roles & Scopes in the **PostgreSQL** Database
40
31
  ---
41
32
 
42
- ## Features
33
+ ## ๐Ÿ—๏ธ Architecture
34
+
35
+ The package follows a **Single Source of Truth** model with a **Federated OAuth Strategy**:
36
+ - **Principal Database (Source of Truth)**: Supabase anchors user identities, metadata, roles, and RLS policies in PostgreSQL.
37
+ - **The Orchestrator (`@edcalderon/auth`)**: A thin bridge layer exposing a generic interface (`User`, `AuthClient`).
43
38
 
44
- - ๐ŸŽฏ **Provider-Agnostic** โ€” one interface, any backend
45
- - โš›๏ธ **React-First** โ€” `AuthProvider` + `useAuth` hook with full TypeScript types
46
- - ๐Ÿ”Œ **Extensible Adapter System** โ€” implement `AuthClient` to add any provider
47
- - ๐Ÿ”€ **Hybrid Flows** โ€” Firebase popup โ†’ Supabase session bridging out of the box
48
- - ๐Ÿ›ก๏ธ **Unified User Model** โ€” `User` type normalizes identities across providers
49
- - ๐Ÿ”‘ **Session Token Access** โ€” `getSessionToken()` for API calls regardless of provider
50
- - ๐Ÿ“ฆ **Tree-Shakeable** โ€” import only the adapters you need
51
- - ๐Ÿ—๏ธ **Zero Lock-In** โ€” swap providers by changing one line of dependency injection
39
+ The UI consumes a **unified context** disconnected entirely from provider implementations.
52
40
 
53
41
  ---
54
42
 
55
43
  ## Installation
56
44
 
57
- ### From NPM (public)
58
-
59
45
  ```bash
60
46
  npm install @edcalderon/auth
61
47
  # or
62
48
  pnpm add @edcalderon/auth
63
- # or
64
- yarn add @edcalderon/auth
65
- ```
66
-
67
- ### From Monorepo (internal workspace)
68
-
69
- ```bash
70
- pnpm --filter <your-app> add @edcalderon/auth@workspace:*
71
49
  ```
72
50
 
73
51
  ### Peer Dependencies
74
52
 
75
- Install the peer dependencies for your chosen provider(s):
53
+ Install peers depending on what adapters you use. (The NPM module avoids forcing packages you won't ship to Native vs Web via strict subpath exports).
76
54
 
77
55
  ```bash
78
- # For Supabase
56
+ # Core requirements
57
+ pnpm add react react-dom
58
+
59
+ # Supabase (Adapter peers)
79
60
  pnpm add @supabase/supabase-js
80
61
 
81
- # For Firebase
62
+ # Firebase (Hybrid/Pure peers)
82
63
  pnpm add firebase
83
64
 
84
- # For Hybrid (Firebase + Supabase)
85
- pnpm add @supabase/supabase-js firebase
65
+ # Expo/Native Only
66
+ pnpm add react-native
86
67
  ```
87
68
 
88
- > **Note:** `react` and `react-dom` (v18+ or v19+) are required peer dependencies.
89
-
90
69
  ---
91
70
 
92
- ## Quick Start
93
-
94
- ### 1. Choose Your Provider
95
-
96
- | Provider | Class | Peer Dependency | Use Case |
97
- |----------|-------|-----------------|----------|
98
- | Supabase | `SupabaseClient` | `@supabase/supabase-js` | Direct Supabase Auth |
99
- | Firebase | `FirebaseClient` | `firebase` | Firebase-only applications |
100
- | Hybrid | `HybridClient` | Both | Firebase popup โ†’ Supabase session |
101
- | Custom | Implement `AuthClient` | Your choice | Directus, Auth0, Keycloak, etc. |
71
+ ## Subpath Exports (Crucial for RN/Next.js compatibility)
102
72
 
103
- ### 2. Create the Provider Wrapper
73
+ The package avoids bleeding `window` or `document` objects into Expo bundles or bleeding heavy native dependencies into web implementations via strict environment exports:
104
74
 
105
- #### Supabase (Direct)
106
-
107
- ```tsx
108
- // components/auth/AuthProvider.tsx
109
- "use client";
75
+ - `@edcalderon/auth` (Shared Core interfaces + Contexts)
76
+ - `@edcalderon/auth/supabase`
77
+ - `@edcalderon/auth/firebase-web`
78
+ - `@edcalderon/auth/firebase-native`
79
+ - `@edcalderon/auth/hybrid-web`
80
+ - `@edcalderon/auth/hybrid-native`
110
81
 
111
- import { AuthProvider as UniversalAuthProvider, SupabaseClient, useAuth as useUniversalAuth } from "@edcalderon/auth";
112
- import { supabase } from "@/lib/supabase";
113
- import { useMemo, type ReactNode } from "react";
82
+ ---
114
83
 
115
- export function AuthProvider({ children }: { children: ReactNode }) {
116
- const client = useMemo(() => new SupabaseClient(supabase), []);
117
- return <UniversalAuthProvider client={client}>{children}</UniversalAuthProvider>;
118
- }
84
+ ## Quick Start (Web & Next.js)
119
85
 
120
- export const useAuth = useUniversalAuth;
121
- ```
86
+ ### 1. Unified React Component UI (Usage)
122
87
 
123
- #### Hybrid (Firebase โ†’ Supabase)
88
+ Your component code is 100% blind to what provider or environment you are using. The `signIn` orchestration handles translating standard intent into provider actions seamlessly.
124
89
 
125
90
  ```tsx
126
91
  "use client";
127
-
128
- import { AuthProvider as UniversalAuthProvider, HybridClient, useAuth as useUniversalAuth } from "@edcalderon/auth";
129
- import { supabase } from "@/lib/supabase";
130
- import { auth, googleProvider, signInWithPopup, signOut, GoogleAuthProvider } from "@/lib/firebase";
131
- import { useMemo, type ReactNode } from "react";
132
-
133
- export function AuthProvider({ children }: { children: ReactNode }) {
134
- const client = useMemo(() => new HybridClient({
135
- supabase,
136
- firebaseAuth: auth,
137
- firebaseMethods: {
138
- signInWithPopup,
139
- signOut,
140
- credentialFromResult: GoogleAuthProvider.credentialFromResult,
141
- },
142
- googleProvider,
143
- }), []);
144
-
145
- return <UniversalAuthProvider client={client}>{children}</UniversalAuthProvider>;
146
- }
147
-
148
- export const useAuth = useUniversalAuth;
149
- ```
150
-
151
- ### 3. Use in Components
152
-
153
- Every component consumes **identical signatures** regardless of which provider is active:
154
-
155
- ```tsx
156
- import { useAuth } from "@/components/auth/AuthProvider";
92
+ import { useAuth } from "@edcalderon/auth";
157
93
 
158
94
  export default function Dashboard() {
159
- const { user, loading, error, signInWithGoogle, signOutUser } = useAuth();
95
+ const { user, loading, error, signIn, signOutUser } = useAuth();
160
96
 
161
97
  if (loading) return <Spinner />;
162
98
  if (error) return <p>Error: {error}</p>;
163
- if (!user) return <button onClick={() => signInWithGoogle()}>Sign In with Google</button>;
99
+
100
+ if (!user) {
101
+ return (
102
+ <button onClick={() => signIn({ provider: "google", flow: "popup" })}>
103
+ Sign In with Google
104
+ </button>
105
+ );
106
+ }
164
107
 
165
108
  return (
166
109
  <div>
167
- <p>Welcome, {user.email} (via {user.provider})</p>
110
+ <p>Welcome, {user.email}</p>
168
111
  <button onClick={signOutUser}>Sign Out</button>
169
112
  </div>
170
113
  );
171
114
  }
172
115
  ```
173
116
 
174
- ---
175
-
176
- ## ๐Ÿ”Œ Extensibility โ€” Custom Adapters
177
-
178
- The core strength of `@edcalderon/auth` is that **any authentication provider** can be integrated by implementing the `AuthClient` interface. No changes to your React components are required.
117
+ ### 2. Provider Top-Level App Injectors
179
118
 
180
- ### The `AuthClient` Interface
119
+ Wire the environment appropriate class up at your app root.
181
120
 
182
- ```typescript
183
- export interface AuthClient {
184
- getUser(): Promise<User | null>;
185
- signInWithEmail(email: string, password: string): Promise<User>;
186
- signInWithGoogle(redirectTo?: string): Promise<void>;
187
- signOut(): Promise<void>;
188
- onAuthStateChange(callback: (user: User | null) => void): () => void;
189
- getSessionToken(): Promise<string | null>;
190
- }
191
- ```
121
+ #### Supabase (Web/Native Universal)
192
122
 
193
- ### The `User` Type
123
+ ```tsx
124
+ "use client";
125
+ import { AuthProvider } from "@edcalderon/auth";
126
+ import { SupabaseClient } from "@edcalderon/auth/supabase";
127
+ import { supabase } from "@/lib/supabase";
194
128
 
195
- ```typescript
196
- export interface User {
197
- id: string;
198
- email?: string;
199
- avatarUrl?: string;
200
- provider?: string;
201
- metadata?: Record<string, any>;
129
+ export function AppProviders({ children }) {
130
+ // Works perfectly in both web and Next.js out of the box
131
+ const client = new SupabaseClient({ supabase });
132
+ return <AuthProvider client={client}>{children}</AuthProvider>;
202
133
  }
203
134
  ```
204
135
 
205
- ### Example: Directus Adapter
206
-
207
- A custom Directus adapter that uses Directus SSO (e.g., Google OAuth through Directus) and optionally syncs sessions back to Supabase:
208
-
209
- ```typescript
210
- import type { AuthClient, User } from "@edcalderon/auth";
211
-
212
- interface DirectusClientOptions {
213
- directusUrl: string;
214
- supabase?: any; // Optional: sync to Supabase as source of truth
215
- }
216
-
217
- export class DirectusClient implements AuthClient {
218
- private directusUrl: string;
219
- private supabase: any;
220
- private currentUser: User | null = null;
221
- private listeners: Set<(user: User | null) => void> = new Set();
222
-
223
- constructor(options: DirectusClientOptions) {
224
- this.directusUrl = options.directusUrl;
225
- this.supabase = options.supabase;
226
- }
227
-
228
- private mapUser(directusUser: any): User | null {
229
- if (!directusUser) return null;
230
- return {
231
- id: directusUser.id,
232
- email: directusUser.email,
233
- avatarUrl: directusUser.avatar
234
- ? `${this.directusUrl}/assets/${directusUser.avatar}`
235
- : undefined,
236
- provider: "directus",
237
- metadata: {
238
- firstName: directusUser.first_name,
239
- lastName: directusUser.last_name,
240
- role: directusUser.role,
241
- },
242
- };
243
- }
244
-
245
- async getUser(): Promise<User | null> {
246
- try {
247
- const res = await fetch(`${this.directusUrl}/users/me`, {
248
- credentials: "include",
249
- });
250
- if (!res.ok) return null;
251
- const { data } = await res.json();
252
- this.currentUser = this.mapUser(data);
253
- return this.currentUser;
254
- } catch {
255
- return null;
256
- }
257
- }
136
+ #### Hybrid (Firebase UI โ†’ Supabase Database Session Bridging for Web)
258
137
 
259
- async signInWithEmail(email: string, password: string): Promise<User> {
260
- const res = await fetch(`${this.directusUrl}/auth/login`, {
261
- method: "POST",
262
- headers: { "Content-Type": "application/json" },
263
- credentials: "include",
264
- body: JSON.stringify({ email, password }),
265
- });
266
- if (!res.ok) throw new Error("Directus login failed");
267
- const user = await this.getUser();
268
- if (!user) throw new Error("No user after login");
269
- this.notifyListeners(user);
270
-
271
- // Optional: sync to Supabase
272
- if (this.supabase) {
273
- await this.syncToSupabase(user);
274
- }
275
- return user;
276
- }
277
-
278
- async signInWithGoogle(redirectTo?: string): Promise<void> {
279
- // Directus SSO โ€” redirect to Directus Google OAuth endpoint
280
- const callback = redirectTo || window.location.origin + "/auth/callback";
281
- window.location.href =
282
- `${this.directusUrl}/auth/login/google?redirect=${encodeURIComponent(callback)}`;
283
- }
138
+ Perfect if you want Firebase to handle the Google popup, but want to automatically consume the ID Token into Supabase to maintain your DB as the source of truth!
284
139
 
285
- async signOut(): Promise<void> {
286
- await fetch(`${this.directusUrl}/auth/logout`, {
287
- method: "POST",
288
- credentials: "include",
289
- });
290
- this.currentUser = null;
291
- this.notifyListeners(null);
292
- }
293
-
294
- onAuthStateChange(callback: (user: User | null) => void): () => void {
295
- this.listeners.add(callback);
296
- return () => { this.listeners.delete(callback); };
297
- }
298
-
299
- async getSessionToken(): Promise<string | null> {
300
- try {
301
- const res = await fetch(`${this.directusUrl}/auth/refresh`, {
302
- method: "POST",
303
- credentials: "include",
304
- });
305
- if (!res.ok) return null;
306
- const { data } = await res.json();
307
- return data?.access_token ?? null;
308
- } catch {
309
- return null;
310
- }
311
- }
140
+ ```tsx
141
+ "use client";
142
+ import { AuthProvider } from "@edcalderon/auth";
143
+ import { HybridWebClient } from "@edcalderon/auth/hybrid-web";
144
+ import { supabase } from "@/lib/supabase";
145
+ import { auth, signInWithPopup, signOut, GoogleAuthProvider } from "@/lib/firebase";
312
146
 
313
- private notifyListeners(user: User | null) {
314
- this.listeners.forEach((cb) => cb(user));
315
- }
147
+ export function AppProviders({ children }) {
148
+ const client = new HybridWebClient({
149
+ supabase,
150
+ firebaseAuth: auth,
151
+ firebaseMethods: { signInWithPopup, signOut, credentialFromResult: GoogleAuthProvider.credentialFromResult },
152
+ googleProvider: new GoogleAuthProvider(),
153
+ });
316
154
 
317
- private async syncToSupabase(user: User) {
318
- // Sync user identity to Supabase as source of truth
319
- // Implementation depends on your Supabase setup
320
- }
155
+ return <AuthProvider client={client}>{children}</AuthProvider>;
321
156
  }
322
157
  ```
323
158
 
324
- **Usage:**
325
-
326
- ```tsx
327
- import { AuthProvider as UniversalAuthProvider } from "@edcalderon/auth";
328
- import { DirectusClient } from "./adapters/DirectusClient";
159
+ ---
329
160
 
330
- const client = new DirectusClient({
331
- directusUrl: "https://directus.example.com",
332
- supabase: supabaseInstance, // optional sync
333
- });
161
+ ## Quick Start (Expo & React Native)
334
162
 
335
- <UniversalAuthProvider client={client}>
336
- <App />
337
- </UniversalAuthProvider>
338
- ```
163
+ React Native apps cannot safely utilize Web's window or popup assumptions. Because of the unified typings, your components never have to change, you just wire up the specific native adapters.
339
164
 
340
- ### Example: Auth0 Adapter (Skeleton)
165
+ ### Hybrid Strategy Native (`expo-auth-session`)
341
166
 
342
- ```typescript
343
- import type { AuthClient, User } from "@edcalderon/auth";
167
+ Instead of trying to pop up Firebase Web via polyfills, explicitly hand over native execution capabilities down to the adapter utilizing React Native Expo equivalents.
344
168
 
345
- export class Auth0Client implements AuthClient {
346
- constructor(private auth0: any) {}
169
+ ```tsx
170
+ import { AuthProvider } from "@edcalderon/auth";
171
+ import { HybridNativeClient } from "@edcalderon/auth/hybrid-native";
172
+ import { supabase } from "@/lib/supabase";
173
+ import { auth, signInWithCredential } from "firebase/auth";
174
+ import * as Google from 'expo-auth-session/providers/google'; // Or react-native-google-signin
175
+
176
+ export function ExpoProviders({ children }) {
177
+ // 1. You provide strictly native capability functions out of your Expo ecosystem
178
+ const nativeGoogleHandler = async (options) => {
179
+ // e.g promptAsync()
180
+ // Exchange credential response for Firebase Native Credentials
181
+ // Return { credential, idToken }
182
+ };
183
+
184
+ const client = new HybridNativeClient({
185
+ supabase,
186
+ firebaseAuth: auth,
187
+ firebaseMethods: { signInWithCredential, signOut },
188
+ oauthHandlers: {
189
+ "google": nativeGoogleHandler
190
+ }
191
+ });
347
192
 
348
- async getUser(): Promise<User | null> { /* ... */ }
349
- async signInWithEmail(email: string, password: string): Promise<User> { /* ... */ }
350
- async signInWithGoogle(redirectTo?: string): Promise<void> { /* ... */ }
351
- async signOut(): Promise<void> { /* ... */ }
352
- onAuthStateChange(callback: (user: User | null) => void): () => void { /* ... */ }
353
- async getSessionToken(): Promise<string | null> { /* ... */ }
193
+ return <AuthProvider client={client}>{children}</AuthProvider>;
354
194
  }
355
195
  ```
356
196
 
357
- By implementing the `AuthClient` interface, any provider fits into the same `<AuthProvider>` and `useAuth()` workflow โ€” **zero changes** to your component tree.
197
+ Now, clicking `signIn({ provider: "google", flow: "native" })` from anywhere inside your Expo app safely triggers `nativeGoogleHandler` and orchestrates Firebase translation down to Supabase seamlessly behind the scenes!
358
198
 
359
199
  ---
360
200
 
361
- ## Built-in Adapters
362
-
363
- ### `SupabaseClient`
364
-
365
- Direct Supabase Auth adapter. Uses `@supabase/supabase-js` for session management, OAuth, and email/password.
366
-
367
- ```typescript
368
- import { SupabaseClient } from "@edcalderon/auth";
369
- import { createClient } from "@supabase/supabase-js";
370
-
371
- const supabase = createClient(SUPABASE_URL, SUPABASE_ANON_KEY);
372
- const client = new SupabaseClient(supabase);
373
- ```
374
-
375
- **Features:**
376
- - Email/password sign-in (`signInWithPassword`)
377
- - Google OAuth (`signInWithOAuth`)
378
- - Session token via `getSession().access_token`
379
- - Real-time auth state changes via `onAuthStateChange`
201
+ ## ๐Ÿ”Œ API Reference - Extensibility
380
202
 
381
- ### `FirebaseClient`
382
-
383
- Firebase-only adapter. Uses Firebase Auth methods via dependency injection (tree-shaking friendly).
384
-
385
- ```typescript
386
- import { FirebaseClient } from "@edcalderon/auth";
387
- import { getAuth, GoogleAuthProvider, signInWithEmailAndPassword, signInWithPopup, signOut, onAuthStateChanged } from "firebase/auth";
388
-
389
- const auth = getAuth(app);
390
- const client = new FirebaseClient(auth, {
391
- signInWithEmailAndPassword,
392
- signInWithPopup,
393
- signOut,
394
- onAuthStateChanged,
395
- }, new GoogleAuthProvider());
396
- ```
397
-
398
- **Features:**
399
- - Email/password sign-in
400
- - Google popup sign-in
401
- - Firebase ID token via `getIdToken()`
402
- - Real-time auth state changes
403
-
404
- ### `HybridClient`
203
+ ### The `AuthClient` Interface
405
204
 
406
- Bridges Firebase Google popup โ†’ Supabase `signInWithIdToken`. Perfect for apps that need Firebase's popup UX but Supabase as the data backend.
205
+ The core strength of `@edcalderon/auth` is that **any authentication service** can be mapped directly onto the `AuthClient` type, exposing typed portability out-of-the-box.
407
206
 
408
207
  ```typescript
409
- import { HybridClient } from "@edcalderon/auth";
410
-
411
- const client = new HybridClient({
412
- supabase,
413
- firebaseAuth: auth,
414
- firebaseMethods: { signInWithPopup, signOut, credentialFromResult: GoogleAuthProvider.credentialFromResult },
415
- googleProvider: new GoogleAuthProvider(),
416
- });
417
- ```
208
+ type AuthRuntime = "web" | "native" | "server";
209
+ type OAuthFlow = "popup" | "redirect" | "native";
418
210
 
419
- **Features:**
420
- - Firebase popup โ†’ extracts Google OIDC ID token โ†’ passes to Supabase `signInWithIdToken`
421
- - Graceful fallback to Supabase native OAuth when Firebase is not configured
422
- - Dual sign-out (Firebase + Supabase)
423
- - Auth state tracked via Supabase session
424
-
425
- ---
426
-
427
- ## API Reference
428
-
429
- ### `<AuthProvider>`
430
-
431
- React context provider that wraps your app with authentication state.
211
+ export interface SignInOptions {
212
+ provider?: "google" | "apple" | "github" | string;
213
+ flow?: OAuthFlow;
214
+ redirectUri?: string;
215
+ }
432
216
 
433
- ```tsx
434
- <AuthProvider client={authClient}>
435
- {children}
436
- </AuthProvider>
217
+ export interface AuthClient {
218
+ runtime: AuthRuntime;
219
+ capabilities(): { runtime: AuthRuntime; supportedFlows: OAuthFlow[] };
220
+
221
+ getUser(): Promise<User | null>;
222
+ signInWithEmail(email: string, password: string): Promise<User>;
223
+ signIn(options: SignInOptions): Promise<void>;
224
+ signOut(): Promise<void>;
225
+
226
+ onAuthStateChange(callback: (user: User | null) => void): () => void;
227
+ getSessionToken(): Promise<string | null>;
228
+ }
437
229
  ```
438
230
 
439
- | Prop | Type | Description |
440
- |------|------|-------------|
441
- | `client` | `AuthClient` | The authentication adapter instance |
442
- | `children` | `ReactNode` | Child components |
443
-
444
- ### `useAuth()`
445
-
446
- React hook that returns the current authentication state and actions.
231
+ ### The `User` Type
447
232
 
448
233
  ```typescript
449
- const {
450
- user, // User | null
451
- loading, // boolean
452
- error, // string | null
453
- client, // AuthClient (direct access)
454
- signInWithEmail, // (email: string, password: string) => Promise<User>
455
- signInWithGoogle, // (redirectTo?: string) => Promise<void>
456
- signOutUser, // () => Promise<void>
457
- } = useAuth();
234
+ export interface User {
235
+ id: string;
236
+ email?: string;
237
+ avatarUrl?: string;
238
+ provider?: string;
239
+ providerUserId?: string;
240
+ roles?: string[];
241
+ metadata?: Record<string, any>;
242
+ }
458
243
  ```
459
244
 
460
- > **Note:** `useAuth()` must be called within an `<AuthProvider>`. It will throw if used outside the provider tree.
461
-
462
- ---
463
-
464
- ## Publishing & Releases
465
-
466
- ### Automated NPM Publishing
467
-
468
- This package uses GitHub Actions for automated publishing to NPM when version tags are created.
469
-
470
- #### Release Process
471
-
472
- 1. **Update Version**: Bump the version in `package.json`
473
- ```bash
474
- cd packages/auth
475
- npm version patch # or minor, major
476
- ```
477
-
478
- 2. **Create Git Tag**: Create and push an `auth-v*` tag
479
- ```bash
480
- git add packages/auth/package.json
481
- git commit -m "chore(auth): bump version to X.Y.Z"
482
- git tag auth-vX.Y.Z
483
- git push && git push --tags
484
- ```
485
-
486
- 3. **Automated Publishing**: GitHub Actions will automatically build and publish to NPM
487
-
488
- #### NPM Token Setup
489
-
490
- To enable automated publishing:
491
-
492
- 1. Go to [NPM](https://www.npmjs.com/) โ†’ Access Tokens โ†’ Generate New Token
493
- 2. Create a token with **Automation** scope
494
- 3. Add to GitHub repository secrets as `NPM_TOKEN`
495
-
496
- ---
497
-
498
- ## Documentation
499
-
500
- - **[CHANGELOG](CHANGELOG.md)** โ€” Version history and changes
501
- - **[GitHub Releases](https://github.com/edcalderon/my-second-brain/releases)** โ€” Tagged releases
502
-
503
245
  ---
504
246
 
505
247
  ## License
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@edcalderon/auth",
3
- "version": "1.1.1",
3
+ "version": "1.1.3",
4
4
  "description": "A universal, provider-agnostic authentication package (Web + Next.js + Expo/React Native)",
5
5
  "exports": {
6
6
  ".": {