better-near-auth 1.4.1 → 1.4.2
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/package.json +1 -1
- package/skills/tanstack/SKILL.md +51 -19
package/package.json
CHANGED
package/skills/tanstack/SKILL.md
CHANGED
|
@@ -60,13 +60,19 @@ import { useRouter } from "@tanstack/react-router";
|
|
|
60
60
|
import { useQuery } from "@tanstack/react-query";
|
|
61
61
|
import type { Auth } from "./auth-types.gen";
|
|
62
62
|
import { getAccount, getHostUrl, getNetworkId } from "@/app";
|
|
63
|
+
import type { ClientRuntimeConfig } from "./app";
|
|
63
64
|
|
|
64
|
-
|
|
65
|
+
interface AuthClientOpts {
|
|
66
|
+
runtimeConfig?: Partial<ClientRuntimeConfig>;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
export function createAuthClient(opts?: AuthClientOpts) {
|
|
70
|
+
const config = opts?.runtimeConfig;
|
|
65
71
|
return createBetterAuthClient({
|
|
66
|
-
baseURL: getHostUrl(),
|
|
72
|
+
baseURL: getHostUrl(config),
|
|
67
73
|
fetchOptions: { credentials: "include" },
|
|
68
74
|
plugins: [
|
|
69
|
-
siwnClient({ recipient: getAccount(), networkId: getNetworkId() }),
|
|
75
|
+
siwnClient({ recipient: getAccount(config), networkId: getNetworkId(config) }),
|
|
70
76
|
],
|
|
71
77
|
});
|
|
72
78
|
}
|
|
@@ -82,7 +88,7 @@ export function useAuthClient(): AuthClient {
|
|
|
82
88
|
The auth client is created once in the router setup (not per component call) and accessed via context:
|
|
83
89
|
|
|
84
90
|
```typescript
|
|
85
|
-
// hydrate.tsx
|
|
91
|
+
// hydrate.tsx — browser, no runtimeConfig needed (reads window.__RUNTIME_CONFIG__)
|
|
86
92
|
import { createAuthClient } from "./auth";
|
|
87
93
|
|
|
88
94
|
const { router } = createRouter({
|
|
@@ -91,23 +97,19 @@ const { router } = createRouter({
|
|
|
91
97
|
},
|
|
92
98
|
});
|
|
93
99
|
|
|
94
|
-
// router.server.tsx —
|
|
100
|
+
// router.server.tsx — server, MUST pass runtimeConfig
|
|
95
101
|
context: {
|
|
96
|
-
authClient: createAuthClient(),
|
|
102
|
+
authClient: createAuthClient({ runtimeConfig: renderOptions.runtimeConfig }),
|
|
97
103
|
}
|
|
98
104
|
```
|
|
99
105
|
|
|
100
106
|
## Type Inference from AuthClient
|
|
101
107
|
|
|
102
|
-
Don't manually define `Organization`, `Passkey`, or other entity types. Infer them from the client's
|
|
108
|
+
Don't manually define `Organization`, `Passkey`, or other entity types. Use `$Infer` to get them directly from the auth client's type system:
|
|
103
109
|
|
|
104
110
|
```typescript
|
|
105
|
-
type
|
|
106
|
-
|
|
107
|
-
}> ? U : never;
|
|
108
|
-
|
|
109
|
-
export type Organization = UnwrapListResponse<AuthClient["organization"]["list"]>;
|
|
110
|
-
export type Passkey = UnwrapListResponse<AuthClient["passkey"]["listUserPasskeys"]>;
|
|
111
|
+
export type Organization = AuthClient["$Infer"]["Organization"];
|
|
112
|
+
export type Passkey = AuthClient["$Infer"]["Passkey"];
|
|
111
113
|
```
|
|
112
114
|
|
|
113
115
|
This automatically includes any additional fields the server configured. Single source of truth: the `AuthClient` type, which is itself derived from the plugin list.
|
|
@@ -217,7 +219,15 @@ This means UI can display the user's NEAR account even when the wallet is discon
|
|
|
217
219
|
|
|
218
220
|
## SSR Safety
|
|
219
221
|
|
|
220
|
-
`siwnClient()` is SSR-safe — wallet resources are lazily initialized on first client-side access. On the server they sit dormant.
|
|
222
|
+
`siwnClient()` is SSR-safe — wallet resources are lazily initialized on first client-side access. On the server they sit dormant. However, `createAuthClient()` calls `getHostUrl()`, `getAccount()`, and `getNetworkId()`, which read `window.__RUNTIME_CONFIG__` by default. On the server, you **must** pass `{ runtimeConfig }` so these helpers read from the provided config instead of the browser-only `window` object:
|
|
223
|
+
|
|
224
|
+
```typescript
|
|
225
|
+
// Server (router.server.tsx) — MUST pass runtimeConfig
|
|
226
|
+
createAuthClient({ runtimeConfig: renderOptions.runtimeConfig })
|
|
227
|
+
|
|
228
|
+
// Client (hydrate.tsx) — no config needed, reads window.__RUNTIME_CONFIG__
|
|
229
|
+
createAuthClient()
|
|
230
|
+
```
|
|
221
231
|
|
|
222
232
|
Methods that work on server (via `$fetch` only): `nonce`, `verify`, `view`, `relayTransaction`, `getRelayStatus`, `getRelayerInfo`, `relayHistory`, `getProfile`, `listAccounts`.
|
|
223
233
|
|
|
@@ -261,9 +271,10 @@ export const authClient = createAuthClient({
|
|
|
261
271
|
});
|
|
262
272
|
|
|
263
273
|
// OR: Router context singleton (SSR)
|
|
264
|
-
export function createAuthClient() {
|
|
274
|
+
export function createAuthClient(opts?: AuthClientOpts) {
|
|
275
|
+
const config = opts?.runtimeConfig;
|
|
265
276
|
return createBetterAuthClient({
|
|
266
|
-
plugins: [siwnClient({ recipient: getAccount() })],
|
|
277
|
+
plugins: [siwnClient({ recipient: getAccount(config) })],
|
|
267
278
|
});
|
|
268
279
|
}
|
|
269
280
|
// Create once in router setup, access via useAuthClient()
|
|
@@ -346,14 +357,35 @@ Correct (SSR):
|
|
|
346
357
|
|
|
347
358
|
```typescript
|
|
348
359
|
// Factory — one instance per router/request
|
|
349
|
-
export function createAuthClient() {
|
|
360
|
+
export function createAuthClient(opts?: AuthClientOpts) {
|
|
361
|
+
const config = opts?.runtimeConfig;
|
|
350
362
|
return createBetterAuthClient({
|
|
351
|
-
plugins: [siwnClient({ recipient: getAccount() })],
|
|
363
|
+
plugins: [siwnClient({ recipient: getAccount(config) })],
|
|
352
364
|
});
|
|
353
365
|
}
|
|
354
|
-
// Created in createRouter() context
|
|
366
|
+
// Created in createRouter() context with runtimeConfig
|
|
355
367
|
```
|
|
356
368
|
|
|
357
369
|
On the server, a module-level singleton's `$fetch` and session state would be shared across concurrent requests. Router context isolates one client per request on server, one per app on client.
|
|
358
370
|
|
|
359
371
|
Source: router.server.tsx:60-71
|
|
372
|
+
|
|
373
|
+
### MEDIUM Calling createAuthClient() without runtimeConfig on the server
|
|
374
|
+
|
|
375
|
+
Wrong:
|
|
376
|
+
|
|
377
|
+
```typescript
|
|
378
|
+
// router.server.tsx — throws "Runtime config is only available in the browser"
|
|
379
|
+
authClient: createAuthClient(),
|
|
380
|
+
```
|
|
381
|
+
|
|
382
|
+
Correct:
|
|
383
|
+
|
|
384
|
+
```typescript
|
|
385
|
+
// router.server.tsx — pass runtimeConfig from renderOptions
|
|
386
|
+
authClient: createAuthClient({ runtimeConfig: renderOptions.runtimeConfig }),
|
|
387
|
+
```
|
|
388
|
+
|
|
389
|
+
`getHostUrl()`, `getAccount()`, and `getNetworkId()` read `window.__RUNTIME_CONFIG__` by default. On the server, `window` is undefined, so they throw. Always pass `{ runtimeConfig }` when calling `createAuthClient()` in `router.server.tsx` or `getRouteHead()`.
|
|
390
|
+
|
|
391
|
+
Source: auth.ts:18-27
|