@uninspired/auth-client 1.0.13 → 1.0.15
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 +281 -5
- package/dist/AuthClient.d.ts +1 -1
- package/dist/AuthClient.js +1 -1
- package/dist/AuthClient.js.map +1 -1
- package/dist/react/AuthContext.d.ts +2 -2
- package/dist/react/AuthProvider.d.ts +2 -2
- package/dist/react/AuthProvider.js +1 -1
- package/dist/react/AuthProvider.js.map +1 -1
- package/dist/types/src/checkout.d.ts +1 -0
- package/dist/types/src/intent.d.ts +1 -0
- package/dist/types/src/promo.d.ts +1 -0
- package/dist/types/src/purchases.d.ts +4 -1
- package/dist/types/src/session.d.ts +3 -1
- package/package.json +7 -3
package/README.md
CHANGED
|
@@ -1,15 +1,291 @@
|
|
|
1
1
|
# @uninspired/auth-client
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Client SDK for integrating Uninspired Studio authentication, purchases, and checkout into product apps (e.g. Momentum, Unpinned).
|
|
4
|
+
|
|
5
|
+
Works in any JavaScript environment. Includes a React provider and hook for apps that use React.
|
|
6
|
+
|
|
7
|
+
## Installation
|
|
4
8
|
|
|
5
9
|
```bash
|
|
6
|
-
bun
|
|
10
|
+
bun add @uninspired/auth-client
|
|
11
|
+
# or
|
|
12
|
+
npm install @uninspired/auth-client
|
|
7
13
|
```
|
|
8
14
|
|
|
9
|
-
|
|
15
|
+
### Peer dependencies
|
|
16
|
+
|
|
17
|
+
For React apps, also install:
|
|
10
18
|
|
|
11
19
|
```bash
|
|
12
|
-
bun
|
|
20
|
+
bun add react react-dom
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
`@posthog/react` is an optional peer dependency — the `AuthProvider` automatically identifies users when a PostHog instance is available in the React tree.
|
|
24
|
+
|
|
25
|
+
## What it provides
|
|
26
|
+
|
|
27
|
+
| Feature | Description |
|
|
28
|
+
|---|---|
|
|
29
|
+
| **Session management** | Fetch the current user session (including anonymous sessions) |
|
|
30
|
+
| **Anonymous sign-in** | Automatically sign in visitors as anonymous users |
|
|
31
|
+
| **Sign out** | End the current session |
|
|
32
|
+
| **Purchase data** | Fetch Paddle transactions and Stripe/Paddle subscriptions |
|
|
33
|
+
| **Access checks** | `isPurchased()` and `isSubscribed()` helpers for gating features |
|
|
34
|
+
| **Login URL builder** | Generate a link to the accounts page with a post-login redirect back to your app |
|
|
35
|
+
| **Checkout URL builder** | Generate a link to the hosted checkout flow |
|
|
36
|
+
| **Newsletter** | Subscribe/unsubscribe from mailing lists |
|
|
37
|
+
| **PostHog integration** | Auto-identify users in PostHog when authenticated |
|
|
38
|
+
|
|
39
|
+
Authentication methods (magic link, email OTP, passkey) are handled on the accounts page — this client manages sessions and purchase data, not the login UI itself.
|
|
40
|
+
|
|
41
|
+
## Quick start (React)
|
|
42
|
+
|
|
43
|
+
```tsx
|
|
44
|
+
import { AuthProvider, useAuth } from "@uninspired/auth-client";
|
|
45
|
+
|
|
46
|
+
function App() {
|
|
47
|
+
return (
|
|
48
|
+
<AuthProvider
|
|
49
|
+
baseUrl="https://auth.uninspired.app"
|
|
50
|
+
frontendUrl="https://uninspired.app"
|
|
51
|
+
mailingListPublicKey="your-public-key"
|
|
52
|
+
>
|
|
53
|
+
<MyApp />
|
|
54
|
+
</AuthProvider>
|
|
55
|
+
);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
function MyApp() {
|
|
59
|
+
const { isLoggedIn, session, isPurchased, getLoginUrl, signOut } = useAuth();
|
|
60
|
+
|
|
61
|
+
if (!isLoggedIn) {
|
|
62
|
+
return (
|
|
63
|
+
<a href={getLoginUrl({ redirectUrl: window.location.href, appName: "My App" })}>
|
|
64
|
+
Log in
|
|
65
|
+
</a>
|
|
66
|
+
);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
const hasPro = isPurchased(["pri_01234567890"]);
|
|
70
|
+
|
|
71
|
+
return (
|
|
72
|
+
<div>
|
|
73
|
+
<p>Hello, {session?.user.email ?? "guest"}</p>
|
|
74
|
+
{hasPro ? <ProFeature /> : <UpgradePrompt />}
|
|
75
|
+
<button onClick={() => signOut()}>Sign out</button>
|
|
76
|
+
</div>
|
|
77
|
+
);
|
|
78
|
+
}
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
## `AuthClient` (vanilla / SSR)
|
|
82
|
+
|
|
83
|
+
Use `AuthClient` directly when you are not in a React tree, or in server-side rendering.
|
|
84
|
+
|
|
85
|
+
```ts
|
|
86
|
+
import { AuthClient } from "@uninspired/auth-client";
|
|
87
|
+
|
|
88
|
+
const client = new AuthClient(
|
|
89
|
+
"https://auth.uninspired.app", // API URL
|
|
90
|
+
"https://uninspired.app", // Accounts frontend URL
|
|
91
|
+
request.headers.get("cookie"), // optional: forward cookies for SSR
|
|
92
|
+
"your-mailing-list-public-key", // optional
|
|
93
|
+
);
|
|
94
|
+
|
|
95
|
+
const session = await client.getSession();
|
|
96
|
+
const purchases = await client.getPurchases();
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
### Constructor
|
|
100
|
+
|
|
101
|
+
```ts
|
|
102
|
+
new AuthClient(apiUrl, frontendUrl, cookie?, mailingListPublicKey?)
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
| Parameter | Description |
|
|
106
|
+
|---|---|
|
|
107
|
+
| `apiUrl` | Auth API base URL (e.g. `https://auth.uninspired.app`) |
|
|
108
|
+
| `frontendUrl` | Accounts frontend URL (e.g. `https://uninspired.app`) |
|
|
109
|
+
| `cookie` | Optional cookie header string for server-side session lookup |
|
|
110
|
+
| `mailingListPublicKey` | Optional public key for mailing list endpoints |
|
|
111
|
+
|
|
112
|
+
All API requests use `credentials: "include"` in the browser, so session cookies are sent automatically on the same root domain.
|
|
113
|
+
|
|
114
|
+
### Methods
|
|
115
|
+
|
|
116
|
+
#### Session
|
|
117
|
+
|
|
118
|
+
```ts
|
|
119
|
+
const session = await client.getSession();
|
|
120
|
+
// Returns Session | null
|
|
121
|
+
|
|
122
|
+
await client.signInAnonymously();
|
|
123
|
+
// Creates an anonymous session (done automatically by AuthProvider)
|
|
124
|
+
|
|
125
|
+
await client.signOut(onSuccess?);
|
|
126
|
+
// Signs out the current user
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
#### Purchases
|
|
130
|
+
|
|
131
|
+
```ts
|
|
132
|
+
const purchases = await client.getPurchases();
|
|
133
|
+
// Returns UserPurchases | null
|
|
13
134
|
```
|
|
14
135
|
|
|
15
|
-
|
|
136
|
+
`UserPurchases` contains:
|
|
137
|
+
|
|
138
|
+
```ts
|
|
139
|
+
{
|
|
140
|
+
paddle: {
|
|
141
|
+
customerId?: string;
|
|
142
|
+
subscriptions: Array<{ id, status, items: [{ priceId, productId }] }>;
|
|
143
|
+
transactions: Array<{ id, items: string[], adjustments: [...] }>;
|
|
144
|
+
};
|
|
145
|
+
stripe: Array<{ id, status, items: string[] }>;
|
|
146
|
+
mailingList: { subscribed: boolean };
|
|
147
|
+
}
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
#### URL builders
|
|
151
|
+
|
|
152
|
+
```ts
|
|
153
|
+
// Link to the accounts login page, redirect back after auth
|
|
154
|
+
const loginUrl = client.getLoginUrl({
|
|
155
|
+
redirectUrl: "https://myapp.uninspired.app/dashboard",
|
|
156
|
+
appName: "My App", // optional, shown on the login page
|
|
157
|
+
});
|
|
158
|
+
|
|
159
|
+
// Link to the hosted checkout flow
|
|
160
|
+
const checkoutUrl = client.getCheckoutUrl({
|
|
161
|
+
priceId: "pri_01234567890",
|
|
162
|
+
productId: "pro_01234567890",
|
|
163
|
+
discountCode: "SAVE20", // optional
|
|
164
|
+
successUrl: "https://myapp.uninspired.app/welcome", // optional
|
|
165
|
+
quantity: 1, // optional, defaults to 1
|
|
166
|
+
});
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
#### Newsletter
|
|
170
|
+
|
|
171
|
+
```ts
|
|
172
|
+
await client.newsletterSubscribe("user@example.com", "my-app-group", "https://callback.url");
|
|
173
|
+
await client.newsletterUnsubscribe("user@example.com");
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
## `AuthProvider` and `useAuth` (React)
|
|
177
|
+
|
|
178
|
+
### `AuthProvider` props
|
|
179
|
+
|
|
180
|
+
| Prop | Type | Description |
|
|
181
|
+
|---|---|---|
|
|
182
|
+
| `baseUrl` | `string` | Auth API URL |
|
|
183
|
+
| `frontendUrl` | `string` | Accounts frontend URL |
|
|
184
|
+
| `mailingListPublicKey` | `string?` | Public key for mailing list API |
|
|
185
|
+
| `initialSession` | `Session \| null?` | Pre-fetched session for SSR |
|
|
186
|
+
| `initialPurchases` | `UserPurchases \| null?` | Pre-fetched purchases for SSR |
|
|
187
|
+
| `authClient` | `AuthClient?` | Custom client instance |
|
|
188
|
+
| `queryClient` | `QueryClient?` | Custom TanStack Query client |
|
|
189
|
+
|
|
190
|
+
The provider automatically:
|
|
191
|
+
|
|
192
|
+
1. Fetches the session on mount (with 1-minute stale time)
|
|
193
|
+
2. Signs in anonymously if no session exists
|
|
194
|
+
3. Fetches purchases when a session is available
|
|
195
|
+
4. Identifies the user in PostHog when authenticated
|
|
196
|
+
|
|
197
|
+
### `useAuth()` return value
|
|
198
|
+
|
|
199
|
+
| Property | Type | Description |
|
|
200
|
+
|---|---|---|
|
|
201
|
+
| `session` | `Session \| null` | Current session |
|
|
202
|
+
| `isLoggedIn` | `boolean` | `true` if user is authenticated (not anonymous) |
|
|
203
|
+
| `isSessionFetching` | `boolean` | Session query loading state |
|
|
204
|
+
| `refetchSession` | `() => Promise<void>` | Re-fetch session |
|
|
205
|
+
| `purchases` | `UserPurchases \| null` | User's purchase data |
|
|
206
|
+
| `isPurchasesFetching` | `boolean` | Purchases query loading state |
|
|
207
|
+
| `refetchPurchases` | `() => Promise<void>` | Re-fetch purchases |
|
|
208
|
+
| `signOut` | `(onSuccess?) => Promise<void>` | Sign out (resets PostHog) |
|
|
209
|
+
| `getLoginUrl` | `AuthClient["getLoginUrl"]` | Build login URL |
|
|
210
|
+
| `getCheckoutUrl` | `AuthClient["getCheckoutUrl"]` | Build checkout URL |
|
|
211
|
+
| `isPurchased` | `(priceIds: string[]) => boolean` | Check one-time purchase |
|
|
212
|
+
| `isSubscribed` | `(priceIds: string[], productId: string) => boolean` | Check active subscription |
|
|
213
|
+
| `newsletterSubscribe` | `AuthClient["newsletterSubscribe"]` | Subscribe to newsletter |
|
|
214
|
+
| `newsletterUnsubscribe` | `AuthClient["newsletterUnsubscribe"]` | Unsubscribe from newsletter |
|
|
215
|
+
|
|
216
|
+
### Access checks
|
|
217
|
+
|
|
218
|
+
```tsx
|
|
219
|
+
const { isPurchased, isSubscribed } = useAuth();
|
|
220
|
+
|
|
221
|
+
// One-time purchase: true if user bought any of these price IDs (and hasn't been refunded)
|
|
222
|
+
isPurchased(["pri_lifetime", "pri_bundle"]);
|
|
223
|
+
|
|
224
|
+
// Subscription: true if user has an active Paddle or Stripe subscription
|
|
225
|
+
isSubscribed(["pri_monthly", "pri_yearly"], "pro_product_id");
|
|
226
|
+
```
|
|
227
|
+
|
|
228
|
+
## Server-side rendering
|
|
229
|
+
|
|
230
|
+
For SSR frameworks, fetch session and purchases on the server and pass them as initial data:
|
|
231
|
+
|
|
232
|
+
```tsx
|
|
233
|
+
// server
|
|
234
|
+
import { AuthClient } from "@uninspired/auth-client";
|
|
235
|
+
|
|
236
|
+
const client = new AuthClient(
|
|
237
|
+
process.env.AUTH_API_URL,
|
|
238
|
+
process.env.ACCOUNTS_FRONTEND_URL,
|
|
239
|
+
request.headers.get("cookie"),
|
|
240
|
+
);
|
|
241
|
+
|
|
242
|
+
const [session, purchases] = await Promise.all([
|
|
243
|
+
client.getSession(),
|
|
244
|
+
client.getPurchases(),
|
|
245
|
+
]);
|
|
246
|
+
|
|
247
|
+
// render
|
|
248
|
+
<AuthProvider
|
|
249
|
+
baseUrl={process.env.AUTH_API_URL}
|
|
250
|
+
frontendUrl={process.env.ACCOUNTS_FRONTEND_URL}
|
|
251
|
+
initialSession={session}
|
|
252
|
+
initialPurchases={purchases}
|
|
253
|
+
>
|
|
254
|
+
{children}
|
|
255
|
+
</AuthProvider>
|
|
256
|
+
```
|
|
257
|
+
|
|
258
|
+
Forward the request's `Cookie` header to the constructor so the API can resolve the session server-side.
|
|
259
|
+
|
|
260
|
+
## Cross-subdomain cookies
|
|
261
|
+
|
|
262
|
+
Sessions use cross-subdomain cookies scoped to the Uninspired Studio root domain (e.g. `.uninspired.app`). Your product app must be hosted on a subdomain of the same root domain for cookies to be shared automatically.
|
|
263
|
+
|
|
264
|
+
Make sure your app's origin is listed in the auth API's `FRONTEND_URLS` configuration.
|
|
265
|
+
|
|
266
|
+
## Types
|
|
267
|
+
|
|
268
|
+
The package re-exports shared types:
|
|
269
|
+
|
|
270
|
+
```ts
|
|
271
|
+
import type { Session, UserPurchases } from "@uninspired/auth-client";
|
|
272
|
+
```
|
|
273
|
+
|
|
274
|
+
## Building from source
|
|
275
|
+
|
|
276
|
+
This package is part of the US Auth monorepo. To build locally:
|
|
277
|
+
|
|
278
|
+
```bash
|
|
279
|
+
cd packages/auth-client
|
|
280
|
+
bun run build
|
|
281
|
+
```
|
|
282
|
+
|
|
283
|
+
Output goes to `dist/`.
|
|
284
|
+
|
|
285
|
+
## Environment URLs
|
|
286
|
+
|
|
287
|
+
| Environment | API | Accounts frontend |
|
|
288
|
+
|---|---|---|
|
|
289
|
+
| Production | `https://auth.uninspired.app` | `https://uninspired.app` |
|
|
290
|
+
| Development | `https://auth.dev.uninspired.app` | `https://dev.uninspired.app` |
|
|
291
|
+
| Local | `http://localhost:3000` | `http://localhost:5173` |
|
package/dist/AuthClient.d.ts
CHANGED
|
@@ -5,7 +5,7 @@ declare class AuthClient {
|
|
|
5
5
|
#private;
|
|
6
6
|
constructor(apiUrl: string, frontendUrl: string, cookie?: string, mailingListPublicKey?: string);
|
|
7
7
|
getSession: () => Promise<Session | null>;
|
|
8
|
-
signInAnonymously: () => Promise<
|
|
8
|
+
signInAnonymously: () => Promise<Session | null>;
|
|
9
9
|
signOut: (onSuccess?: () => void) => Promise<void>;
|
|
10
10
|
getPurchases: () => Promise<UserPurchases | null>;
|
|
11
11
|
newsletterSubscribe: (email: string, userGroup?: string, callbackUrl?: string) => Promise<void>;
|
package/dist/AuthClient.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{anonymousClient as e,emailOTPClient as t,magicLinkClient as n}from"better-auth/client/plugins";import{passkeyClient as r}from"@better-auth/passkey/client";import{createAuthClient as i}from"better-auth/client";import{hc as a}from"hono/client";var o=class{#e;#t;#n;#r;#i;constructor(o,s,c,l){this.#i=c,this.#e=s,this.#t=i({baseURL:o,plugins:[e(),n(),t(),r()]}),this.#n=a(new URL(`/api/app`,o).toString(),{fetch:(e,t)=>fetch(e,{...t,credentials:`include`})}),this.#r=a(new URL(`/api/mailing-list`,o).toString(),{fetch:(e,t)=>fetch(e,{...t,headers:{"Content-Type":`application/json`,"X-Public-Key":l,...t.headers}})})}getSession=async()=>{let{data:e,error:t}=await this.#t.getSession({},{headers:this.#i?{Cookie:this.#i}:void 0});if(t)throw t;return e};signInAnonymously=async()=>{let{error:e}=await this.#t.signIn.anonymous();if(e)throw e};signOut=async e=>{let{error:t}=await this.#t.signOut({fetchOptions:{onSuccess:e}},{headers:this.#i?{Cookie:this.#i}:void 0});if(t)throw t};getPurchases=async()=>{let e=await this.#n.purchases.$get(void 0,{headers:this.#i?{Cookie:this.#i}:void 0});if(!e.ok)throw Error(`Failed to get purchases`,{cause:await e.text()});return await e.json()};#a=(e,t)=>JSON.stringify({type:`redirect`,redirectUrl:e,appName:t});newsletterSubscribe=async(e,t,n)=>{let r=await this.#r.subscribe.$post({json:{email:e,userGroup:t??`us-auth`,callbackUrl:n??``}});if(!r.ok)throw Error(await r.text())};newsletterUnsubscribe=async e=>{let t=await this.#r.unsubscribe.$post({query:{email:e}});if(!t.ok)throw Error(await t.text())};getLoginUrl=e=>{let t=new URL(`/login`,this.#e);return e?.redirectUrl&&t.searchParams.set(`intent`,this.#a(e.redirectUrl,e.appName)),t.toString()};getCheckoutUrl=e=>{let t=new URL(`/auth/checkout`,this.#e);return t.searchParams.set(`priceId`,e.priceId),t.searchParams.set(`productId`,e.productId),e.discountCode&&t.searchParams.set(`discountCode`,e.discountCode),e.successUrl&&t.searchParams.set(`successUrl`,e.successUrl),t.searchParams.set(`quantity`,e.quantity?.toString()??`1`),t.toString()}};export{o as AuthClient};
|
|
1
|
+
import{anonymousClient as e,emailOTPClient as t,magicLinkClient as n}from"better-auth/client/plugins";import{passkeyClient as r}from"@better-auth/passkey/client";import{createAuthClient as i}from"better-auth/client";import{hc as a}from"hono/client";var o=class{#e;#t;#n;#r;#i;constructor(o,s,c,l){this.#i=c,this.#e=s,this.#t=i({baseURL:o,plugins:[e(),n(),t(),r()]}),this.#n=a(new URL(`/api/app`,o).toString(),{fetch:(e,t)=>fetch(e,{...t,credentials:`include`})}),this.#r=a(new URL(`/api/mailing-list`,o).toString(),{fetch:(e,t)=>fetch(e,{...t,headers:{"Content-Type":`application/json`,"X-Public-Key":l,...t.headers}})})}getSession=async()=>{let{data:e,error:t}=await this.#t.getSession({},{headers:this.#i?{Cookie:this.#i}:void 0});if(t)throw t;return e};signInAnonymously=async()=>{let{error:e}=await this.#t.signIn.anonymous();if(e)throw e;return this.getSession()};signOut=async e=>{let{error:t}=await this.#t.signOut({fetchOptions:{onSuccess:e}},{headers:this.#i?{Cookie:this.#i}:void 0});if(t)throw t};getPurchases=async()=>{let e=await this.#n.purchases.$get(void 0,{headers:this.#i?{Cookie:this.#i}:void 0});if(!e.ok)throw Error(`Failed to get purchases`,{cause:await e.text()});return await e.json()};#a=(e,t)=>JSON.stringify({type:`redirect`,redirectUrl:e,appName:t});newsletterSubscribe=async(e,t,n)=>{let r=await this.#r.subscribe.$post({json:{email:e,userGroup:t??`us-auth`,callbackUrl:n??``}});if(!r.ok)throw Error(await r.text())};newsletterUnsubscribe=async e=>{let t=await this.#r.unsubscribe.$post({query:{email:e}});if(!t.ok)throw Error(await t.text())};getLoginUrl=e=>{let t=new URL(`/login`,this.#e);return e?.redirectUrl&&t.searchParams.set(`intent`,this.#a(e.redirectUrl,e.appName)),t.toString()};getCheckoutUrl=e=>{let t=new URL(`/auth/checkout`,this.#e);return t.searchParams.set(`priceId`,e.priceId),t.searchParams.set(`productId`,e.productId),e.discountCode&&t.searchParams.set(`discountCode`,e.discountCode),e.successUrl&&t.searchParams.set(`successUrl`,e.successUrl),t.searchParams.set(`quantity`,e.quantity?.toString()??`1`),t.toString()}};export{o as AuthClient};
|
|
2
2
|
//# sourceMappingURL=AuthClient.js.map
|
package/dist/AuthClient.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AuthClient.js","names":["#cookie","#frontendUrl","#authClient","#appClient","#mailingListClient","#getRedirectIntent"],"sources":["../src/AuthClient.ts"],"sourcesContent":["import {\n magicLinkClient,\n emailOTPClient,\n anonymousClient,\n} from \"better-auth/client/plugins\";\nimport { passkeyClient } from \"@better-auth/passkey/client\";\nimport { createAuthClient } from \"better-auth/client\";\nimport { hc } from \"hono/client\";\nimport type { AppRouter, MailingListRouter } from \"@us-auth/api\";\nimport type { UserPurchases, Session, RedirectIntent } from \"@us-auth/types\";\n\nexport class AuthClient {\n #frontendUrl: string;\n #authClient;\n #appClient: ReturnType<typeof hc<AppRouter>>;\n #mailingListClient: ReturnType<typeof hc<MailingListRouter>>;\n #cookie: string | undefined;\n\n constructor(\n apiUrl: string,\n frontendUrl: string,\n cookie?: string,\n mailingListPublicKey?: string,\n ) {\n this.#cookie = cookie;\n this.#frontendUrl = frontendUrl;\n this.#authClient = createAuthClient({\n baseURL: apiUrl,\n plugins: [\n anonymousClient(),\n magicLinkClient(),\n emailOTPClient(),\n passkeyClient(),\n ],\n });\n this.#appClient = hc<AppRouter>(new URL(\"/api/app\", apiUrl).toString(), {\n fetch: (url: any, init: any) =>\n fetch(url, {\n ...init,\n credentials: \"include\",\n }),\n });\n this.#mailingListClient = hc<MailingListRouter>(\n new URL(\"/api/mailing-list\", apiUrl).toString(),\n {\n fetch: (url: any, init: any) =>\n fetch(url, {\n ...init,\n headers: {\n \"Content-Type\": \"application/json\",\n \"X-Public-Key\": mailingListPublicKey,\n ...init.headers,\n },\n }),\n },\n );\n }\n\n // Authentication\n getSession = async (): Promise<Session | null> => {\n const { data, error } = await this.#authClient.getSession(\n {},\n {\n headers: this.#cookie\n ? {\n Cookie: this.#cookie,\n }\n : undefined,\n },\n );\n if (error) throw error;\n return data;\n };\n\n signInAnonymously = async (): Promise<
|
|
1
|
+
{"version":3,"file":"AuthClient.js","names":["#cookie","#frontendUrl","#authClient","#appClient","#mailingListClient","#getRedirectIntent"],"sources":["../src/AuthClient.ts"],"sourcesContent":["import {\n magicLinkClient,\n emailOTPClient,\n anonymousClient,\n} from \"better-auth/client/plugins\";\nimport { passkeyClient } from \"@better-auth/passkey/client\";\nimport { createAuthClient } from \"better-auth/client\";\nimport { hc } from \"hono/client\";\nimport type { AppRouter, MailingListRouter } from \"@us-auth/api\";\nimport type { UserPurchases, Session, RedirectIntent } from \"@us-auth/types\";\n\nexport class AuthClient {\n #frontendUrl: string;\n #authClient;\n #appClient: ReturnType<typeof hc<AppRouter>>;\n #mailingListClient: ReturnType<typeof hc<MailingListRouter>>;\n #cookie: string | undefined;\n\n constructor(\n apiUrl: string,\n frontendUrl: string,\n cookie?: string,\n mailingListPublicKey?: string,\n ) {\n this.#cookie = cookie;\n this.#frontendUrl = frontendUrl;\n this.#authClient = createAuthClient({\n baseURL: apiUrl,\n plugins: [\n anonymousClient(),\n magicLinkClient(),\n emailOTPClient(),\n passkeyClient(),\n ],\n });\n this.#appClient = hc<AppRouter>(new URL(\"/api/app\", apiUrl).toString(), {\n fetch: (url: any, init: any) =>\n fetch(url, {\n ...init,\n credentials: \"include\",\n }),\n });\n this.#mailingListClient = hc<MailingListRouter>(\n new URL(\"/api/mailing-list\", apiUrl).toString(),\n {\n fetch: (url: any, init: any) =>\n fetch(url, {\n ...init,\n headers: {\n \"Content-Type\": \"application/json\",\n \"X-Public-Key\": mailingListPublicKey,\n ...init.headers,\n },\n }),\n },\n );\n }\n\n // Authentication\n getSession = async (): Promise<Session | null> => {\n const { data, error } = await this.#authClient.getSession(\n {},\n {\n headers: this.#cookie\n ? {\n Cookie: this.#cookie,\n }\n : undefined,\n },\n );\n if (error) throw error;\n return data;\n };\n\n signInAnonymously = async (): Promise<Session | null> => {\n const { error } = await this.#authClient.signIn.anonymous();\n if (error) throw error;\n return this.getSession();\n };\n\n signOut = async (onSuccess?: () => void): Promise<void> => {\n const { error } = await this.#authClient.signOut(\n {\n fetchOptions: { onSuccess },\n },\n {\n headers: this.#cookie ? { Cookie: this.#cookie } : undefined,\n },\n );\n if (error) throw error;\n return;\n };\n\n // Purchases\n getPurchases = async (): Promise<UserPurchases | null> => {\n const res = await this.#appClient.purchases.$get(undefined, {\n headers: this.#cookie ? { Cookie: this.#cookie } : undefined,\n });\n if (!res.ok) {\n throw new Error(\"Failed to get purchases\", {\n cause: await res.text(),\n });\n }\n const data = await res.json();\n return data as UserPurchases | null;\n };\n\n #getRedirectIntent = (redirectUrl: string, appName?: string) => {\n return JSON.stringify({\n type: \"redirect\",\n redirectUrl,\n appName,\n } satisfies RedirectIntent);\n };\n\n // Mailing List\n newsletterSubscribe = async (\n email: string,\n userGroup?: string,\n callbackUrl?: string,\n ): Promise<void> => {\n const res = await this.#mailingListClient.subscribe.$post({\n json: {\n email,\n userGroup: userGroup ?? \"us-auth\",\n callbackUrl: callbackUrl ?? \"\",\n },\n });\n if (!res.ok) {\n throw new Error(await res.text());\n }\n return;\n };\n\n newsletterUnsubscribe = async (email: string): Promise<void> => {\n const res = await this.#mailingListClient.unsubscribe.$post({\n query: {\n email,\n },\n });\n if (!res.ok) {\n throw new Error(await res.text());\n }\n return;\n };\n\n // Utils\n getLoginUrl = (options?: { redirectUrl?: string; appName?: string }) => {\n const url = new URL(\"/login\", this.#frontendUrl);\n if (options?.redirectUrl) {\n url.searchParams.set(\n \"intent\",\n this.#getRedirectIntent(options.redirectUrl, options.appName),\n );\n }\n return url.toString();\n };\n\n getCheckoutUrl = (options: {\n priceId: string;\n productId: string;\n discountCode?: string;\n successUrl?: string;\n quantity?: number;\n }) => {\n const url = new URL(\"/auth/checkout\", this.#frontendUrl);\n url.searchParams.set(\"priceId\", options.priceId);\n url.searchParams.set(\"productId\", options.productId);\n if (options.discountCode) {\n url.searchParams.set(\"discountCode\", options.discountCode);\n }\n if (options.successUrl) {\n url.searchParams.set(\"successUrl\", options.successUrl);\n }\n url.searchParams.set(\"quantity\", options.quantity?.toString() ?? \"1\");\n return url.toString();\n };\n}\n"],"mappings":"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"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { UserPurchases } from "../types/src/purchases.js";
|
|
2
2
|
import { Session } from "../types/src/session.js";
|
|
3
3
|
import { AuthClient } from "../AuthClient.js";
|
|
4
|
-
import * as react from "react";
|
|
4
|
+
import * as _$react from "react";
|
|
5
5
|
|
|
6
6
|
//#region src/react/AuthContext.d.ts
|
|
7
7
|
type AuthContextType = {
|
|
@@ -20,7 +20,7 @@ type AuthContextType = {
|
|
|
20
20
|
isSubscribed: (priceIds: string[], productId: string) => boolean;
|
|
21
21
|
isLoggedIn: boolean;
|
|
22
22
|
} | null;
|
|
23
|
-
declare const AuthContext: react.Context<AuthContextType>;
|
|
23
|
+
declare const AuthContext: _$react.Context<AuthContextType>;
|
|
24
24
|
//#endregion
|
|
25
25
|
export { AuthContext, AuthContextType };
|
|
26
26
|
//# sourceMappingURL=AuthContext.d.ts.map
|
|
@@ -3,7 +3,7 @@ import { Session } from "../types/src/session.js";
|
|
|
3
3
|
import { AuthClient } from "../AuthClient.js";
|
|
4
4
|
import { PropsWithChildren } from "react";
|
|
5
5
|
import { QueryClient } from "@tanstack/react-query";
|
|
6
|
-
import * as react_jsx_runtime0 from "react/jsx-runtime";
|
|
6
|
+
import * as _$react_jsx_runtime0 from "react/jsx-runtime";
|
|
7
7
|
|
|
8
8
|
//#region src/react/AuthProvider.d.ts
|
|
9
9
|
interface AuthProviderProps extends PropsWithChildren {
|
|
@@ -24,7 +24,7 @@ declare const AuthProvider: ({
|
|
|
24
24
|
authClient: providedAuthClient,
|
|
25
25
|
queryClient: providedQueryClient,
|
|
26
26
|
mailingListPublicKey
|
|
27
|
-
}: AuthProviderProps) => react_jsx_runtime0.JSX.Element;
|
|
27
|
+
}: AuthProviderProps) => _$react_jsx_runtime0.JSX.Element;
|
|
28
28
|
//#endregion
|
|
29
29
|
export { AuthProvider, AuthProviderProps };
|
|
30
30
|
//# sourceMappingURL=AuthProvider.d.ts.map
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{AuthClient as e}from"../AuthClient.js";import{AuthContext as t}from"./AuthContext.js";import{useCallback as n,useEffect as r,useMemo as i}from"react";import{QueryClient as
|
|
1
|
+
import{AuthClient as e}from"../AuthClient.js";import{AuthContext as t}from"./AuthContext.js";import{useCallback as n,useEffect as r,useMemo as i,useRef as a}from"react";import{QueryClient as o,useQuery as s}from"@tanstack/react-query";import{usePostHog as c}from"@posthog/react";import{jsx as l}from"react/jsx-runtime";const u=({children:u,baseUrl:d,frontendUrl:f,initialSession:p,initialPurchases:m,authClient:h,queryClient:g,mailingListPublicKey:_})=>{let v=c(),y=i(()=>h??new e(d,f,void 0,_),[d,h,_]),b=i(()=>g??new o,[g]),{data:x,isFetching:S,refetch:C}=s({queryKey:[`us-auth-session`],staleTime:1e3*60,initialData:p,queryFn:y.getSession},b),w=i(()=>!(!x||x.user.isAnonymous),[x]),T=a(!1);r(()=>{S||x===null&&(T.current||(T.current=!0,y.signInAnonymously().then(e=>{b.setQueryData([`us-auth-session`],e)}).catch(e=>console.error(e))))},[y,S,b,x]),r(()=>{x?.user&&v&&v.get_distinct_id()!==x.user.id&&v.identify(x.user.id,{email:x.user.email})},[x,v]);let{data:E,isFetching:D,refetch:O}=s({queryKey:[`us-auth-purchases`],staleTime:1e3*60,initialData:m,queryFn:y.getPurchases},b),k=i(()=>y.getLoginUrl,[y]),A=i(()=>y.getCheckoutUrl,[y]),j=i(e=>()=>y.signOut(()=>{v?.reset(),e?.()}),[y,v]),M=i(()=>y.newsletterSubscribe,[y]),N=i(()=>y.newsletterUnsubscribe,[y]),P=n(e=>E?E.paddle.transactions.some(t=>t.items.some(t=>e.includes(t))&&!t.adjustments.some(e=>e.status===`approved`&&e.action===`refund`)):!1,[E]),F=n((e,t)=>{if(!E)return!1;let n=E.paddle.subscriptions.some(n=>n.items.some(n=>e.includes(n.priceId)||t===n.productId)&&n.status===`active`),r=E.stripe.some(t=>t.status===`active`&&t.items.some(t=>e.includes(t)));return n||r},[E]);return l(t.Provider,{value:{session:x??null,isSessionFetching:S,refetchSession:async()=>{await C()},purchases:E??null,isPurchasesFetching:D,refetchPurchases:async()=>{await O()},signOut:j,newsletterSubscribe:M,newsletterUnsubscribe:N,getLoginUrl:k,getCheckoutUrl:A,isSubscribed:F,isPurchased:P,isLoggedIn:w},children:u})};export{u as AuthProvider};
|
|
2
2
|
//# sourceMappingURL=AuthProvider.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AuthProvider.js","names":[],"sources":["../../src/react/AuthProvider.tsx"],"sourcesContent":["import {
|
|
1
|
+
{"version":3,"file":"AuthProvider.js","names":[],"sources":["../../src/react/AuthProvider.tsx"],"sourcesContent":["import {\n useCallback,\n useEffect,\n useMemo,\n useRef,\n type PropsWithChildren,\n} from \"react\";\nimport { AuthContext } from \"./AuthContext\";\nimport { AuthClient } from \"../AuthClient\";\nimport type { Session, UserPurchases } from \"@us-auth/types\";\nimport { QueryClient, useQuery } from \"@tanstack/react-query\";\nimport { usePostHog } from \"@posthog/react\";\n\nexport interface AuthProviderProps extends PropsWithChildren {\n authClient?: AuthClient;\n queryClient?: QueryClient;\n baseUrl: string;\n frontendUrl: string;\n initialSession?: Session | null;\n initialPurchases?: UserPurchases | null;\n mailingListPublicKey?: string;\n}\n\nexport const AuthProvider = ({\n children,\n baseUrl,\n frontendUrl,\n initialSession,\n initialPurchases,\n authClient: providedAuthClient,\n queryClient: providedQueryClient,\n mailingListPublicKey,\n}: AuthProviderProps) => {\n const ph = usePostHog();\n\n const authClient = useMemo(\n () =>\n providedAuthClient ??\n new AuthClient(baseUrl, frontendUrl, undefined, mailingListPublicKey),\n [baseUrl, providedAuthClient, mailingListPublicKey],\n );\n const queryClient = useMemo(\n () => providedQueryClient ?? new QueryClient(),\n [providedQueryClient],\n );\n\n const {\n data: session,\n isFetching: isSessionFetching,\n refetch: refetchSession,\n } = useQuery(\n {\n queryKey: [\"us-auth-session\"],\n staleTime: 1000 * 60,\n initialData: initialSession,\n queryFn: authClient.getSession,\n },\n queryClient,\n );\n\n const isLoggedIn = useMemo(() => {\n if (!session || session.user.isAnonymous) return false;\n return true;\n }, [session]);\n\n const anonymousSignInAttempted = useRef(false);\n\n // Log unauthenticated users in anonymously automatically\n useEffect(() => {\n if (isSessionFetching) return;\n // Wait for the session query to settle to an explicit null, not undefined.\n if (session !== null) return;\n if (anonymousSignInAttempted.current) return;\n\n anonymousSignInAttempted.current = true;\n authClient\n .signInAnonymously()\n .then((newSession) => {\n queryClient.setQueryData([\"us-auth-session\"], newSession);\n })\n .catch((e) => console.error(e));\n }, [authClient, isSessionFetching, queryClient, session]);\n\n useEffect(() => {\n if (session?.user && ph) {\n const distinctId = ph.get_distinct_id();\n if (distinctId !== session.user.id) {\n ph.identify(session.user.id, {\n email: session.user.email,\n });\n }\n }\n }, [session, ph]);\n\n const {\n data: purchases,\n isFetching: isPurchasesFetching,\n refetch: refetchPurchases,\n } = useQuery(\n {\n queryKey: [\"us-auth-purchases\"],\n staleTime: 1000 * 60,\n initialData: initialPurchases,\n queryFn: authClient.getPurchases,\n },\n queryClient,\n );\n\n const getLoginUrl = useMemo(() => authClient.getLoginUrl, [authClient]);\n const getCheckoutUrl = useMemo(() => authClient.getCheckoutUrl, [authClient]);\n const signOut = useMemo(\n (onSuccess?: () => void) => () =>\n authClient.signOut(() => {\n ph?.reset();\n onSuccess?.();\n }),\n [authClient, ph],\n );\n const newsletterSubscribe = useMemo(\n () => authClient.newsletterSubscribe,\n [authClient],\n );\n const newsletterUnsubscribe = useMemo(\n () => authClient.newsletterUnsubscribe,\n [authClient],\n );\n\n const isPurchased = useCallback(\n (priceIds: string[]): boolean => {\n if (!purchases) return false;\n return purchases.paddle.transactions.some(\n (tra) =>\n tra.items.some((item) => priceIds.includes(item)) &&\n !tra.adjustments.some(\n (adj) => adj.status === \"approved\" && adj.action === \"refund\",\n ),\n );\n },\n [purchases],\n );\n\n const isSubscribed = useCallback(\n (priceIds: string[], productId: string): boolean => {\n if (!purchases) return false;\n\n const paddleSubscriptions = purchases.paddle.subscriptions.some(\n (sub) =>\n sub.items.some(\n (item) =>\n priceIds.includes(item.priceId) || productId === item.productId,\n ) && sub.status === \"active\",\n );\n\n const stripeSubscriptions = purchases.stripe.some(\n (sub) =>\n sub.status === \"active\" &&\n sub.items.some((item) => priceIds.includes(item)),\n );\n\n return paddleSubscriptions || stripeSubscriptions;\n },\n [purchases],\n );\n\n return (\n <AuthContext.Provider\n value={{\n session: session ?? null,\n isSessionFetching,\n refetchSession: async () => {\n await refetchSession();\n },\n purchases: purchases ?? null,\n isPurchasesFetching,\n refetchPurchases: async () => {\n await refetchPurchases();\n },\n signOut,\n newsletterSubscribe,\n newsletterUnsubscribe,\n getLoginUrl,\n getCheckoutUrl,\n isSubscribed,\n isPurchased,\n isLoggedIn,\n }}\n >\n {children}\n </AuthContext.Provider>\n );\n};\n"],"mappings":"+TAuBA,MAAa,GAAgB,CAC3B,WACA,UACA,cACA,iBACA,mBACA,WAAY,EACZ,YAAa,EACb,0BACuB,CACvB,IAAM,EAAK,GAAY,CAEjB,EAAa,MAEf,GACA,IAAI,EAAW,EAAS,EAAa,IAAA,GAAW,EAAqB,CACvE,CAAC,EAAS,EAAoB,EAAqB,CACpD,CACK,EAAc,MACZ,GAAuB,IAAI,EACjC,CAAC,EAAoB,CACtB,CAEK,CACJ,KAAM,EACN,WAAY,EACZ,QAAS,GACP,EACF,CACE,SAAU,CAAC,kBAAkB,CAC7B,UAAW,IAAO,GAClB,YAAa,EACb,QAAS,EAAW,WACrB,CACD,EACD,CAEK,EAAa,MACjB,EAAI,CAAC,GAAW,EAAQ,KAAK,aAE5B,CAAC,EAAQ,CAAC,CAEP,EAA2B,EAAO,GAAM,CAG9C,MAAgB,CACV,GAEA,IAAY,OACZ,EAAyB,UAE7B,EAAyB,QAAU,GACnC,EACG,mBAAmB,CACnB,KAAM,GAAe,CACpB,EAAY,aAAa,CAAC,kBAAkB,CAAE,EAAW,EACzD,CACD,MAAO,GAAM,QAAQ,MAAM,EAAE,CAAC,IAChC,CAAC,EAAY,EAAmB,EAAa,EAAQ,CAAC,CAEzD,MAAgB,CACV,GAAS,MAAQ,GACA,EAAG,iBACR,GAAK,EAAQ,KAAK,IAC9B,EAAG,SAAS,EAAQ,KAAK,GAAI,CAC3B,MAAO,EAAQ,KAAK,MACrB,CAAC,EAGL,CAAC,EAAS,EAAG,CAAC,CAEjB,GAAM,CACJ,KAAM,EACN,WAAY,EACZ,QAAS,GACP,EACF,CACE,SAAU,CAAC,oBAAoB,CAC/B,UAAW,IAAO,GAClB,YAAa,EACb,QAAS,EAAW,aACrB,CACD,EACD,CAEK,EAAc,MAAc,EAAW,YAAa,CAAC,EAAW,CAAC,CACjE,EAAiB,MAAc,EAAW,eAAgB,CAAC,EAAW,CAAC,CACvE,EAAU,EACb,OACC,EAAW,YAAc,CACvB,GAAI,OAAO,CACX,KAAa,EACb,CACJ,CAAC,EAAY,EAAG,CACjB,CACK,EAAsB,MACpB,EAAW,oBACjB,CAAC,EAAW,CACb,CACK,EAAwB,MACtB,EAAW,sBACjB,CAAC,EAAW,CACb,CAEK,EAAc,EACjB,GACM,EACE,EAAU,OAAO,aAAa,KAClC,GACC,EAAI,MAAM,KAAM,GAAS,EAAS,SAAS,EAAK,CAAC,EACjD,CAAC,EAAI,YAAY,KACd,GAAQ,EAAI,SAAW,YAAc,EAAI,SAAW,SACtD,CACJ,CAPsB,GASzB,CAAC,EAAU,CACZ,CAEK,EAAe,GAClB,EAAoB,IAA+B,CAClD,GAAI,CAAC,EAAW,MAAO,GAEvB,IAAM,EAAsB,EAAU,OAAO,cAAc,KACxD,GACC,EAAI,MAAM,KACP,GACC,EAAS,SAAS,EAAK,QAAQ,EAAI,IAAc,EAAK,UACzD,EAAI,EAAI,SAAW,SACvB,CAEK,EAAsB,EAAU,OAAO,KAC1C,GACC,EAAI,SAAW,UACf,EAAI,MAAM,KAAM,GAAS,EAAS,SAAS,EAAK,CAAC,CACpD,CAED,OAAO,GAAuB,GAEhC,CAAC,EAAU,CACZ,CAED,OACE,EAAC,EAAY,SAAb,CACE,MAAO,CACL,QAAS,GAAW,KACpB,oBACA,eAAgB,SAAY,CAC1B,MAAM,GAAgB,EAExB,UAAW,GAAa,KACxB,sBACA,iBAAkB,SAAY,CAC5B,MAAM,GAAkB,EAE1B,UACA,sBACA,wBACA,cACA,iBACA,eACA,cACA,aACD,CAEA,WACoB,CAAA"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
@@ -24,7 +24,10 @@ declare const userPurchasesSchema: z.ZodObject<{
|
|
|
24
24
|
id: z.ZodString;
|
|
25
25
|
createdAt: z.ZodCoercedDate<unknown>;
|
|
26
26
|
status: z.ZodString;
|
|
27
|
-
items: z.ZodArray<z.
|
|
27
|
+
items: z.ZodArray<z.ZodObject<{
|
|
28
|
+
priceId: z.ZodString;
|
|
29
|
+
productId: z.ZodString;
|
|
30
|
+
}, z.core.$strip>>;
|
|
28
31
|
}, z.core.$strip>>;
|
|
29
32
|
transactions: z.ZodArray<z.ZodObject<{
|
|
30
33
|
id: z.ZodString;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@uninspired/auth-client",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.15",
|
|
4
4
|
"description": "Auth client for Uninspired Studio Products",
|
|
5
5
|
"author": "Chris Kolb <chris@uninspired.studio>",
|
|
6
6
|
"license": "MIT",
|
|
@@ -13,7 +13,9 @@
|
|
|
13
13
|
"dist"
|
|
14
14
|
],
|
|
15
15
|
"scripts": {
|
|
16
|
-
"build": "tsdown --config tsdown.config.ts"
|
|
16
|
+
"build": "tsdown --config tsdown.config.ts",
|
|
17
|
+
"check": "tsc -b",
|
|
18
|
+
"lint": "eslint ."
|
|
17
19
|
},
|
|
18
20
|
"devDependencies": {
|
|
19
21
|
"@us-auth/types": "workspace:*",
|
|
@@ -21,7 +23,9 @@
|
|
|
21
23
|
"@types/react": "^19",
|
|
22
24
|
"@types/react-dom": "^19",
|
|
23
25
|
"@us-auth/api": "workspace:*",
|
|
24
|
-
"
|
|
26
|
+
"@us-auth/eslint-config": "workspace:*",
|
|
27
|
+
"tsdown": "^0.21.3",
|
|
28
|
+
"typescript": "^5.8.3"
|
|
25
29
|
},
|
|
26
30
|
"peerDependencies": {
|
|
27
31
|
"typescript": "^5",
|