@recursiv/sdk 0.5.8 → 0.6.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 CHANGED
@@ -81,6 +81,7 @@ for await (const chunk of r.agents.chatStream(agent.id, { message: 'Hello!' }))
81
81
  | Resource | Key methods |
82
82
  |----------|------------|
83
83
  | `r.auth` | `signUp`, `signIn`, `signOut`, `createApiKey` |
84
+ | `@recursiv/sdk/next` | `createRecursivAuth` — cookie-session server auth for Next.js App Router (see below) |
84
85
  | `r.users` | `me`, `get` |
85
86
  | `r.organizations` | `create`, `members`, `addMember`, `invite` |
86
87
  | `r.profiles` | `me`, `get`, `search`, `follow`, `unfollow` |
@@ -240,6 +241,42 @@ function ChatRoom({ conversationId }) {
240
241
  }
241
242
  ```
242
243
 
244
+ ## Next.js server auth (`@recursiv/sdk/next`)
245
+
246
+ Cookie-session helpers for the App Router (Next 14 and 15). Each user signs in once, gets a **project-scoped per-user API key** in an httpOnly cookie, and every request acts as that user — no platform key on the server.
247
+
248
+ ```typescript
249
+ // src/lib/recursiv.ts (server-only module)
250
+ import 'server-only';
251
+ import { createRecursivAuth } from '@recursiv/sdk/next';
252
+
253
+ export const auth = createRecursivAuth(); // RECURSIV_PROJECT_ID from env
254
+
255
+ // src/actions/auth.ts ('use server')
256
+ export async function signIn(input: { email: string; password: string }) {
257
+ const { user } = await auth.signIn(input); // mints key + sets session cookie
258
+ return user;
259
+ }
260
+
261
+ // any server component or route handler
262
+ const sdk = await auth.getSdk(); // Recursiv acting as the signed-in user
263
+ const { data: me } = await sdk.users.me();
264
+ ```
265
+
266
+ Route handlers building their own response pass a cookie writer, and the cookie contract (name, lifetime, attributes) is fully configurable:
267
+
268
+ ```typescript
269
+ const auth = createRecursivAuth({ cookie: { name: 'myapp_session', maxAge: 60 * 60 * 24 * 90 } });
270
+
271
+ export async function POST(req: NextRequest) {
272
+ const res = NextResponse.json({ ok: true });
273
+ await auth.verifyOtp(await req.json(), { response: res.cookies });
274
+ return res;
275
+ }
276
+ ```
277
+
278
+ Server-side only — the `server-only` guard fails the build if it's ever imported into a client component. Keep it out of `middleware.ts` as well (edge bundle size); gate routes with a plain cookie-presence check on a shared constant.
279
+
243
280
  ## Error handling
244
281
 
245
282
  ```typescript
@@ -287,7 +324,7 @@ if (page1.meta.has_more) {
287
324
  | Environment | Status | Notes |
288
325
  |-------------|--------|-------|
289
326
  | Node.js >= 18 | Full support | ESM only. Uses native fetch. |
290
- | Next.js | Full support | Works in both server components and API routes |
327
+ | Next.js | Full support | Server components, server actions, and route handlers. Use `@recursiv/sdk/next` for cookie-session auth (Next 14 and 15). |
291
328
  | React (Vite, CRA) | Full support | Bundle-friendly, zero dependencies |
292
329
  | React Native / Expo | Supported with caveats | `chatStream()` requires manual SSE handling. See [React Native guide](./docs/guide-react-native.md). |
293
330
  | Deno | Full support | ESM native, fetch native |
@@ -0,0 +1,11 @@
1
+ /**
2
+ * @recursiv/sdk/next — Next.js App Router server-auth helpers.
3
+ *
4
+ * Server-side only: `server-only` makes any import from a Client Component
5
+ * fail at build time. Requires Next 14+ (App Router).
6
+ */
7
+ import 'server-only';
8
+ export { createRecursivAuth, RecursivNextAuth } from './server-auth.js';
9
+ export { DEFAULT_USER_KEY_SCOPES } from './scopes.js';
10
+ export type { RecursivNextAuthConfig, SessionUser, AuthResult, WriteOptions, SessionCookieOptions, SessionCookieDescriptor, CookieWriter, RequestCookiesLike, } from './server-auth.js';
11
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/next/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,OAAO,aAAa,CAAC;AAErB,OAAO,EAAE,kBAAkB,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AACxE,OAAO,EAAE,uBAAuB,EAAE,MAAM,aAAa,CAAC;AACtD,YAAY,EACV,sBAAsB,EACtB,WAAW,EACX,UAAU,EACV,YAAY,EACZ,oBAAoB,EACpB,uBAAuB,EACvB,YAAY,EACZ,kBAAkB,GACnB,MAAM,kBAAkB,CAAC"}
@@ -0,0 +1,10 @@
1
+ /**
2
+ * @recursiv/sdk/next — Next.js App Router server-auth helpers.
3
+ *
4
+ * Server-side only: `server-only` makes any import from a Client Component
5
+ * fail at build time. Requires Next 14+ (App Router).
6
+ */
7
+ import 'server-only';
8
+ export { createRecursivAuth, RecursivNextAuth } from './server-auth.js';
9
+ export { DEFAULT_USER_KEY_SCOPES } from './scopes.js';
10
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/next/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,OAAO,aAAa,CAAC;AAErB,OAAO,EAAE,kBAAkB,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AACxE,OAAO,EAAE,uBAAuB,EAAE,MAAM,aAAa,CAAC"}
@@ -0,0 +1,35 @@
1
+ /**
2
+ * Default scopes for per-user API keys minted at sign-up / sign-in.
3
+ *
4
+ * AUTH MODEL (post-Project-Membership rollout):
5
+ * Each user gets a project-scoped api-key (api_key.project_id is set, NOT
6
+ * api_key.organization_id). They become a `project_member` of the project,
7
+ * not an `organization_member` of the project's owning org. This keeps app
8
+ * customers separate from the team workspace — the org's `/settings/team`
9
+ * shows teammates only, not customers.
10
+ *
11
+ * See packages/server/src/db/CLAUDE.md in the Recursiv platform repo for
12
+ * the data model.
13
+ *
14
+ * SECURITY NOTE on `databases:*` and `storage:*`:
15
+ * These are project-level scopes. Granted on a per-user key, they let any
16
+ * signed-in user run raw SQL against the project DB or list any object in
17
+ * the project bucket directly via the API — bypassing any per-user guards
18
+ * your server code enforces (e.g. a `WHERE user_id` predicate).
19
+ *
20
+ * For a SHARED-DATA app (Twitter-style social) this is fine — members are
21
+ * expected to see each other's content. For a PRIVATE-DATA app (CRM, internal
22
+ * tool) you must tighten this before shipping. Two paths:
23
+ * - Move DB and storage operations into server actions that hold a
24
+ * project-scoped admin key (read it from a non-client env var) and pass
25
+ * a narrower `scopes` list to `createRecursivAuth`.
26
+ * - Or, if the app does need direct per-user DB access, enforce row-level
27
+ * scoping via a request-level signed predicate the platform validates.
28
+ *
29
+ * Apps with their own scope needs should pass an explicit `scopes` array to
30
+ * `createRecursivAuth` instead of relying on this default — and note that
31
+ * existing users keep the scopes minted at their last sign-in until they
32
+ * re-authenticate.
33
+ */
34
+ export declare const DEFAULT_USER_KEY_SCOPES: string[];
35
+ //# sourceMappingURL=scopes.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scopes.d.ts","sourceRoot":"","sources":["../../src/next/scopes.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AACH,eAAO,MAAM,uBAAuB,UAanC,CAAC"}
@@ -0,0 +1,48 @@
1
+ /**
2
+ * Default scopes for per-user API keys minted at sign-up / sign-in.
3
+ *
4
+ * AUTH MODEL (post-Project-Membership rollout):
5
+ * Each user gets a project-scoped api-key (api_key.project_id is set, NOT
6
+ * api_key.organization_id). They become a `project_member` of the project,
7
+ * not an `organization_member` of the project's owning org. This keeps app
8
+ * customers separate from the team workspace — the org's `/settings/team`
9
+ * shows teammates only, not customers.
10
+ *
11
+ * See packages/server/src/db/CLAUDE.md in the Recursiv platform repo for
12
+ * the data model.
13
+ *
14
+ * SECURITY NOTE on `databases:*` and `storage:*`:
15
+ * These are project-level scopes. Granted on a per-user key, they let any
16
+ * signed-in user run raw SQL against the project DB or list any object in
17
+ * the project bucket directly via the API — bypassing any per-user guards
18
+ * your server code enforces (e.g. a `WHERE user_id` predicate).
19
+ *
20
+ * For a SHARED-DATA app (Twitter-style social) this is fine — members are
21
+ * expected to see each other's content. For a PRIVATE-DATA app (CRM, internal
22
+ * tool) you must tighten this before shipping. Two paths:
23
+ * - Move DB and storage operations into server actions that hold a
24
+ * project-scoped admin key (read it from a non-client env var) and pass
25
+ * a narrower `scopes` list to `createRecursivAuth`.
26
+ * - Or, if the app does need direct per-user DB access, enforce row-level
27
+ * scoping via a request-level signed predicate the platform validates.
28
+ *
29
+ * Apps with their own scope needs should pass an explicit `scopes` array to
30
+ * `createRecursivAuth` instead of relying on this default — and note that
31
+ * existing users keep the scopes minted at their last sign-in until they
32
+ * re-authenticate.
33
+ */
34
+ export const DEFAULT_USER_KEY_SCOPES = [
35
+ 'users:read',
36
+ 'posts:read', 'posts:write',
37
+ 'communities:read', 'communities:write',
38
+ 'chat:read', 'chat:write',
39
+ 'agents:read', 'agents:write',
40
+ 'tags:read', 'tags:write',
41
+ 'commands:read', 'commands:write',
42
+ 'organizations:read',
43
+ 'memory:read', 'memory:write',
44
+ // ⚠️ Tighten when the app holds private per-user data — see note above.
45
+ 'databases:read', 'databases:write',
46
+ 'storage:read', 'storage:write',
47
+ ];
48
+ //# sourceMappingURL=scopes.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scopes.js","sourceRoot":"","sources":["../../src/next/scopes.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AACH,MAAM,CAAC,MAAM,uBAAuB,GAAG;IACrC,YAAY;IACZ,YAAY,EAAE,aAAa;IAC3B,kBAAkB,EAAE,mBAAmB;IACvC,WAAW,EAAE,YAAY;IACzB,aAAa,EAAE,cAAc;IAC7B,WAAW,EAAE,YAAY;IACzB,eAAe,EAAE,gBAAgB;IACjC,oBAAoB;IACpB,aAAa,EAAE,cAAc;IAC7B,yEAAyE;IACzE,gBAAgB,EAAE,iBAAiB;IACnC,cAAc,EAAE,eAAe;CAChC,CAAC"}
@@ -0,0 +1,187 @@
1
+ import { Recursiv } from '../index.js';
2
+ import type { AuthSession, SignUpInput, SignInInput, SendOtpInput, VerifyOtpInput } from '../resources/auth.js';
3
+ export interface SessionUser {
4
+ id: string;
5
+ name: string;
6
+ email: string;
7
+ image: string | null;
8
+ }
9
+ export interface SessionCookieOptions {
10
+ /** Cookie name. Default: `'recursiv_session'`. */
11
+ name?: string;
12
+ /** Lifetime in seconds. Default: 30 days. */
13
+ maxAge?: number;
14
+ /** Default: `'/'`. */
15
+ path?: string;
16
+ /** Default: `'lax'`. */
17
+ sameSite?: 'lax' | 'strict' | 'none';
18
+ /** Default: `process.env.NODE_ENV === 'production'`. */
19
+ secure?: boolean;
20
+ domain?: string;
21
+ /** Default: `true`. Only disable if you fully understand the XSS exposure. */
22
+ httpOnly?: boolean;
23
+ }
24
+ export interface RecursivNextAuthConfig {
25
+ /**
26
+ * Project the per-user keys are scoped to. Default:
27
+ * `process.env.RECURSIV_PROJECT_ID`. The project must have
28
+ * `project_settings.allow_public_signup=true` (provision_app sets this
29
+ * automatically) so new users are auto-added as project_members.
30
+ * Mutually exclusive with `organizationId`.
31
+ */
32
+ projectId?: string;
33
+ /**
34
+ * Org-scoped keys instead (teammates managing the workspace, not app
35
+ * customers). Mutually exclusive with `projectId`.
36
+ */
37
+ organizationId?: string;
38
+ /** Default: `process.env.RECURSIV_API_BASE_URL` or the SDK default. */
39
+ baseUrl?: string;
40
+ /**
41
+ * Optional project API key used ONLY to brand auth emails (sign-in OTP,
42
+ * password reset) for your org — the per-user pattern needs no server key
43
+ * otherwise. Default: `process.env.RECURSIV_API_KEY` when set (the SDK
44
+ * constructor picks it up); keyless requests get platform branding.
45
+ */
46
+ apiKey?: string;
47
+ /** Scopes minted onto per-user keys. Default: `DEFAULT_USER_KEY_SCOPES`. */
48
+ scopes?: string[];
49
+ /** Name given to minted keys. Default: `` () => `app-session-${Date.now()}` ``. */
50
+ keyName?: () => string;
51
+ cookie?: SessionCookieOptions;
52
+ /** Passed through to every `Recursiv` instance. */
53
+ timeout?: number;
54
+ /**
55
+ * Passed through to every `Recursiv` instance. NOTE the SDK default (2)
56
+ * retries 429/5xx on ALL methods including POST — set 0 if duplicate
57
+ * side effects (OTP emails, checkout sessions) are worse than a retry.
58
+ */
59
+ maxRetries?: number;
60
+ }
61
+ /** A fully-resolved Set-Cookie payload, for callers that write cookies themselves. */
62
+ export interface SessionCookieDescriptor {
63
+ name: string;
64
+ value: string;
65
+ options: {
66
+ httpOnly: boolean;
67
+ sameSite: 'lax' | 'strict' | 'none';
68
+ secure: boolean;
69
+ path: string;
70
+ maxAge: number;
71
+ domain?: string;
72
+ };
73
+ }
74
+ /** Structurally matches both `(await cookies())` and `NextResponse.cookies`. */
75
+ export interface CookieWriter {
76
+ set(name: string, value: string, options?: Record<string, unknown>): unknown;
77
+ }
78
+ /** Structurally matches `NextRequest` (and anything else exposing request cookies). */
79
+ export interface RequestCookiesLike {
80
+ cookies: {
81
+ get(name: string): {
82
+ value: string;
83
+ } | undefined;
84
+ };
85
+ }
86
+ export interface WriteOptions {
87
+ /**
88
+ * Write the session cookie onto this instead of `cookies()` — pass
89
+ * `response.cookies` from a route handler building a `NextResponse`.
90
+ */
91
+ response?: CookieWriter;
92
+ /** Set to `false` to skip cookie writing entirely (descriptor is still returned). */
93
+ setCookie?: boolean;
94
+ }
95
+ export interface AuthResult {
96
+ user: SessionUser;
97
+ /** The per-user API key. Also written to the session cookie unless opted out. */
98
+ apiKey: string;
99
+ /** Public key prefix, for display / account-linking records. */
100
+ keyPrefix: string | null;
101
+ session: AuthSession;
102
+ /** The exact cookie that was (or would be) written. */
103
+ cookie: SessionCookieDescriptor;
104
+ }
105
+ export declare class RecursivNextAuth {
106
+ readonly cookieName: string;
107
+ private readonly cookieOptions;
108
+ private readonly config;
109
+ constructor(config?: RecursivNextAuthConfig);
110
+ /** Keyless SDK for pre-auth calls. Picks up `RECURSIV_API_KEY` from env when set (email branding). */
111
+ anonSdk(): Recursiv;
112
+ /** SDK bound to an explicit per-user key. */
113
+ sdkFor(apiKey: string): Recursiv;
114
+ private sdkOptions;
115
+ /** The signed-in user's API key from the session cookie, or null. */
116
+ getSessionKey(): Promise<string | null>;
117
+ /** SDK acting as the signed-in user. Throws `AuthenticationError` when signed out. */
118
+ getSdk(): Promise<Recursiv>;
119
+ /** Like `getSdk()` but resolves null instead of throwing when signed out. */
120
+ trySdk(): Promise<Recursiv | null>;
121
+ /** The signed-in user's profile, or null when signed out / the key no longer validates. */
122
+ getUser(): Promise<SessionUser | null>;
123
+ /** Email+password sign-up → per-user key → session cookie. */
124
+ signUp(input: SignUpInput, opts?: WriteOptions): Promise<AuthResult>;
125
+ /** Email+password sign-in → per-user key → session cookie. */
126
+ signIn(input: SignInInput, opts?: WriteOptions): Promise<AuthResult>;
127
+ /**
128
+ * Send a sign-in OTP. Branding follows the API key on the request
129
+ * (`config.apiKey` / env `RECURSIV_API_KEY`); keyless → platform branding.
130
+ */
131
+ sendOtp(input: SendOtpInput): Promise<{
132
+ success: boolean;
133
+ }>;
134
+ /** Verify a sign-in OTP (auto-creates the user) → per-user key → session cookie. */
135
+ verifyOtp(input: VerifyOtpInput, opts?: WriteOptions): Promise<AuthResult>;
136
+ /**
137
+ * Clear the session cookie. NOTE: the per-user API key itself is NOT
138
+ * revoked (we hold no session token to revoke it with) — it simply ages
139
+ * out. Matches the template/app behavior this replaces.
140
+ */
141
+ signOut(opts?: {
142
+ response?: CookieWriter;
143
+ }): Promise<void>;
144
+ /** Session key from a request-shaped object (`NextRequest`), no `next/headers` needed. */
145
+ sessionKeyFromRequest(req: RequestCookiesLike): string | null;
146
+ /** SDK for the request's session, or null when it has none. */
147
+ sdkFromRequest(req: RequestCookiesLike): Recursiv | null;
148
+ /** The Set-Cookie payload for a given key, for callers that write cookies themselves. */
149
+ sessionCookie(apiKey: string): SessionCookieDescriptor;
150
+ /** An expired Set-Cookie payload that clears the session. */
151
+ clearSessionCookie(): SessionCookieDescriptor;
152
+ private requireScope;
153
+ private mintKeyAndSetCookie;
154
+ private writeCookie;
155
+ }
156
+ /**
157
+ * Create the app's auth singleton. Configure once (usually in a
158
+ * `server-only` lib module) and import everywhere server-side:
159
+ *
160
+ * ```ts
161
+ * // src/lib/recursiv.ts
162
+ * import 'server-only';
163
+ * import { createRecursivAuth } from '@recursiv/sdk/next';
164
+ * export const auth = createRecursivAuth(); // RECURSIV_PROJECT_ID from env
165
+ *
166
+ * // a server component
167
+ * const sdk = await auth.trySdk();
168
+ * const feed = sdk ? await sdk.posts.list() : null;
169
+ *
170
+ * // a server action
171
+ * 'use server';
172
+ * export async function signIn(input: { email: string; password: string }) {
173
+ * const { user } = await auth.signIn(input);
174
+ * return user;
175
+ * }
176
+ *
177
+ * // a route handler with a custom cookie contract
178
+ * const auth = createRecursivAuth({ cookie: { name: 'myapp_key', maxAge: 60 * 60 * 24 * 90 } });
179
+ * export async function POST(req: NextRequest) {
180
+ * const res = NextResponse.json({ ok: true });
181
+ * await auth.verifyOtp(await req.json(), { response: res.cookies });
182
+ * return res;
183
+ * }
184
+ * ```
185
+ */
186
+ export declare function createRecursivAuth(config?: RecursivNextAuthConfig): RecursivNextAuth;
187
+ //# sourceMappingURL=server-auth.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server-auth.d.ts","sourceRoot":"","sources":["../../src/next/server-auth.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,249 @@
1
+ /**
2
+ * Next.js App Router server-auth helpers for the per-user API key pattern.
3
+ *
4
+ * The model (same as the nextjs template, Kempt, Alua, Minds):
5
+ * - sign-up / sign-in / OTP verify mints a PROJECT-SCOPED per-user API key
6
+ * (the user becomes a `project_member`, never an `organization_member`),
7
+ * - that key lives in an httpOnly cookie,
8
+ * - every request rebuilds a `Recursiv` bound to the caller's own key.
9
+ * There is deliberately no storage abstraction beyond the cookie and no
10
+ * god/platform key required at runtime.
11
+ *
12
+ * Works on both Next 14 and Next 15 App Router: `cookies()` is sync in 14
13
+ * and a Promise in 15 — every access goes through `await cookies()`, which
14
+ * is a no-op await on 14. Public signatures use local structural types so
15
+ * the emitted .d.ts never references Next's own types.
16
+ *
17
+ * This module must only run on the server. The public entry (`./index.ts`)
18
+ * enforces that with `import 'server-only'`; the implementation lives here
19
+ * so unit tests can import it directly (the `server-only` package throws
20
+ * under Node's default export condition, i.e. in vitest).
21
+ */
22
+ import { cookies } from 'next/headers';
23
+ import { Recursiv } from '../index.js';
24
+ import { AuthenticationError } from '../errors.js';
25
+ import { DEFAULT_USER_KEY_SCOPES } from './scopes.js';
26
+ const DEFAULT_COOKIE_NAME = 'recursiv_session';
27
+ const DEFAULT_MAX_AGE = 60 * 60 * 24 * 30; // 30 days
28
+ export class RecursivNextAuth {
29
+ cookieName;
30
+ cookieOptions;
31
+ config;
32
+ constructor(config = {}) {
33
+ if (config.projectId && config.organizationId) {
34
+ throw new Error('createRecursivAuth: pass projectId (app customers) OR organizationId (team keys), not both.');
35
+ }
36
+ this.config = config;
37
+ this.cookieName = config.cookie?.name ?? DEFAULT_COOKIE_NAME;
38
+ this.cookieOptions = {
39
+ httpOnly: config.cookie?.httpOnly ?? true,
40
+ sameSite: config.cookie?.sameSite ?? 'lax',
41
+ secure: config.cookie?.secure ??
42
+ (typeof process !== 'undefined' && process.env?.NODE_ENV === 'production'),
43
+ path: config.cookie?.path ?? '/',
44
+ maxAge: config.cookie?.maxAge ?? DEFAULT_MAX_AGE,
45
+ ...(config.cookie?.domain ? { domain: config.cookie.domain } : {}),
46
+ };
47
+ }
48
+ // ---------------------------------------------------------------- SDK factories
49
+ /** Keyless SDK for pre-auth calls. Picks up `RECURSIV_API_KEY` from env when set (email branding). */
50
+ anonSdk() {
51
+ return new Recursiv({
52
+ allowNoKey: true,
53
+ ...(this.config.apiKey ? { apiKey: this.config.apiKey } : {}),
54
+ ...this.sdkOptions(),
55
+ });
56
+ }
57
+ /** SDK bound to an explicit per-user key. */
58
+ sdkFor(apiKey) {
59
+ return new Recursiv({ apiKey, ...this.sdkOptions() });
60
+ }
61
+ sdkOptions() {
62
+ const { baseUrl, timeout, maxRetries } = this.config;
63
+ return {
64
+ ...(baseUrl ? { baseUrl } : {}),
65
+ ...(timeout !== undefined ? { timeout } : {}),
66
+ ...(maxRetries !== undefined ? { maxRetries } : {}),
67
+ };
68
+ }
69
+ // ------------------------------------------------- cookie-store-bound (next/headers)
70
+ /** The signed-in user's API key from the session cookie, or null. */
71
+ async getSessionKey() {
72
+ const store = await cookies();
73
+ return store.get(this.cookieName)?.value ?? null;
74
+ }
75
+ /** SDK acting as the signed-in user. Throws `AuthenticationError` when signed out. */
76
+ async getSdk() {
77
+ const key = await this.getSessionKey();
78
+ if (!key) {
79
+ throw new AuthenticationError({
80
+ type: 'auth_error',
81
+ message: `Not signed in: no '${this.cookieName}' session cookie. Redirect the user to your sign-in page, or use trySdk() for optional-auth paths.`,
82
+ code: 'session_required',
83
+ });
84
+ }
85
+ return this.sdkFor(key);
86
+ }
87
+ /** Like `getSdk()` but resolves null instead of throwing when signed out. */
88
+ async trySdk() {
89
+ const key = await this.getSessionKey();
90
+ return key ? this.sdkFor(key) : null;
91
+ }
92
+ /** The signed-in user's profile, or null when signed out / the key no longer validates. */
93
+ async getUser() {
94
+ try {
95
+ const sdk = await this.trySdk();
96
+ if (!sdk)
97
+ return null;
98
+ const { data } = await sdk.users.me();
99
+ if (!data)
100
+ return null;
101
+ return {
102
+ id: data.id,
103
+ name: data.name,
104
+ email: data.email ?? '',
105
+ image: data.image ?? null,
106
+ };
107
+ }
108
+ catch {
109
+ return null;
110
+ }
111
+ }
112
+ // ------------------------------------------------------------------- auth flows
113
+ /** Email+password sign-up → per-user key → session cookie. */
114
+ async signUp(input, opts) {
115
+ const scope = this.requireScope();
116
+ const sdk = this.anonSdk();
117
+ const session = await sdk.auth.signUp(input, scope);
118
+ return this.mintKeyAndSetCookie(sdk, session, opts);
119
+ }
120
+ /** Email+password sign-in → per-user key → session cookie. */
121
+ async signIn(input, opts) {
122
+ this.requireScope();
123
+ const sdk = this.anonSdk();
124
+ const session = await sdk.auth.signIn(input);
125
+ return this.mintKeyAndSetCookie(sdk, session, opts);
126
+ }
127
+ /**
128
+ * Send a sign-in OTP. Branding follows the API key on the request
129
+ * (`config.apiKey` / env `RECURSIV_API_KEY`); keyless → platform branding.
130
+ */
131
+ async sendOtp(input) {
132
+ return this.anonSdk().auth.sendOtp(input);
133
+ }
134
+ /** Verify a sign-in OTP (auto-creates the user) → per-user key → session cookie. */
135
+ async verifyOtp(input, opts) {
136
+ const scope = this.requireScope();
137
+ const sdk = this.anonSdk();
138
+ const session = await sdk.auth.verifyOtp(input, scope);
139
+ return this.mintKeyAndSetCookie(sdk, session, opts);
140
+ }
141
+ /**
142
+ * Clear the session cookie. NOTE: the per-user API key itself is NOT
143
+ * revoked (we hold no session token to revoke it with) — it simply ages
144
+ * out. Matches the template/app behavior this replaces.
145
+ */
146
+ async signOut(opts) {
147
+ await this.writeCookie(this.clearSessionCookie(), opts);
148
+ }
149
+ // ------------------------------------------- request-bound (NextRequest / middleware)
150
+ /** Session key from a request-shaped object (`NextRequest`), no `next/headers` needed. */
151
+ sessionKeyFromRequest(req) {
152
+ return req.cookies.get(this.cookieName)?.value ?? null;
153
+ }
154
+ /** SDK for the request's session, or null when it has none. */
155
+ sdkFromRequest(req) {
156
+ const key = this.sessionKeyFromRequest(req);
157
+ return key ? this.sdkFor(key) : null;
158
+ }
159
+ // --------------------------------------------------------------- manual plumbing
160
+ /** The Set-Cookie payload for a given key, for callers that write cookies themselves. */
161
+ sessionCookie(apiKey) {
162
+ return { name: this.cookieName, value: apiKey, options: { ...this.cookieOptions } };
163
+ }
164
+ /** An expired Set-Cookie payload that clears the session. */
165
+ clearSessionCookie() {
166
+ return {
167
+ name: this.cookieName,
168
+ value: '',
169
+ options: { ...this.cookieOptions, maxAge: 0 },
170
+ };
171
+ }
172
+ // ------------------------------------------------------------------------ internals
173
+ requireScope() {
174
+ const projectId = this.config.projectId ??
175
+ (typeof process !== 'undefined' ? process.env?.RECURSIV_PROJECT_ID : undefined);
176
+ if (this.config.organizationId)
177
+ return { organizationId: this.config.organizationId };
178
+ if (projectId)
179
+ return { projectId };
180
+ throw new Error('createRecursivAuth: no key scope configured. Pass projectId (or set RECURSIV_PROJECT_ID) so per-user keys bind users as project_members — or organizationId for team-scoped keys.');
181
+ }
182
+ async mintKeyAndSetCookie(sdk, session, opts) {
183
+ const scope = this.requireScope();
184
+ // Two-step (not *AndCreateKey) so the key prefix survives — apps use it
185
+ // for account-linking records and display.
186
+ const key = await sdk.auth.createApiKey({
187
+ name: this.config.keyName?.() ?? `app-session-${Date.now()}`,
188
+ scopes: this.config.scopes ?? DEFAULT_USER_KEY_SCOPES,
189
+ ...scope,
190
+ }, session.token);
191
+ const cookie = this.sessionCookie(key.key);
192
+ await this.writeCookie(cookie, opts);
193
+ return {
194
+ user: session.user,
195
+ apiKey: key.key,
196
+ keyPrefix: key.prefix ?? null,
197
+ session,
198
+ cookie,
199
+ };
200
+ }
201
+ async writeCookie(descriptor, opts) {
202
+ if (opts?.setCookie === false)
203
+ return;
204
+ if (opts?.response) {
205
+ opts.response.set(descriptor.name, descriptor.value, descriptor.options);
206
+ return;
207
+ }
208
+ // Next 15 returns a Promise; Next 14 returns the store directly — await
209
+ // covers both. Writing requires a Server Action or Route Handler context
210
+ // (Next enforces this); pass `opts.response` from route handlers that
211
+ // build their own NextResponse.
212
+ const store = (await cookies());
213
+ store.set(descriptor.name, descriptor.value, descriptor.options);
214
+ }
215
+ }
216
+ /**
217
+ * Create the app's auth singleton. Configure once (usually in a
218
+ * `server-only` lib module) and import everywhere server-side:
219
+ *
220
+ * ```ts
221
+ * // src/lib/recursiv.ts
222
+ * import 'server-only';
223
+ * import { createRecursivAuth } from '@recursiv/sdk/next';
224
+ * export const auth = createRecursivAuth(); // RECURSIV_PROJECT_ID from env
225
+ *
226
+ * // a server component
227
+ * const sdk = await auth.trySdk();
228
+ * const feed = sdk ? await sdk.posts.list() : null;
229
+ *
230
+ * // a server action
231
+ * 'use server';
232
+ * export async function signIn(input: { email: string; password: string }) {
233
+ * const { user } = await auth.signIn(input);
234
+ * return user;
235
+ * }
236
+ *
237
+ * // a route handler with a custom cookie contract
238
+ * const auth = createRecursivAuth({ cookie: { name: 'myapp_key', maxAge: 60 * 60 * 24 * 90 } });
239
+ * export async function POST(req: NextRequest) {
240
+ * const res = NextResponse.json({ ok: true });
241
+ * await auth.verifyOtp(await req.json(), { response: res.cookies });
242
+ * return res;
243
+ * }
244
+ * ```
245
+ */
246
+ export function createRecursivAuth(config = {}) {
247
+ return new RecursivNextAuth(config);
248
+ }
249
+ //# sourceMappingURL=server-auth.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server-auth.js","sourceRoot":"","sources":["../../src/next/server-auth.ts"],"names":[],"mappings":"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"}
@@ -3,6 +3,12 @@ export interface AppSubscriptionCheckoutResult {
3
3
  /** Stripe Checkout URL to redirect the user to. */
4
4
  url: string;
5
5
  }
6
+ export interface AppSubscriptionStatusResult {
7
+ tier: string;
8
+ status: 'active' | 'past_due' | 'canceled' | 'none';
9
+ active: boolean;
10
+ currentPeriodEnd: string | null;
11
+ }
6
12
  /**
7
13
  * Per-app-user consumer subscriptions (e.g. Plus/Pro) billed through the app's
8
14
  * own Stripe account + products. Drives the tier the video primitive gates on.
@@ -17,5 +23,9 @@ export declare class AppSubscriptionsResource {
17
23
  }): Promise<{
18
24
  data: AppSubscriptionCheckoutResult;
19
25
  }>;
26
+ /** Read the current user's app-subscription status for this project-scoped key. */
27
+ status(): Promise<{
28
+ data: AppSubscriptionStatusResult;
29
+ }>;
20
30
  }
21
31
  //# sourceMappingURL=app-subscriptions.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"app-subscriptions.d.ts","sourceRoot":"","sources":["../../src/resources/app-subscriptions.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAE/C,MAAM,WAAW,6BAA6B;IAC5C,mDAAmD;IACnD,GAAG,EAAE,MAAM,CAAC;CACb;AAED;;;GAGG;AACH,qBAAa,wBAAwB;IACvB,OAAO,CAAC,MAAM;gBAAN,MAAM,EAAE,UAAU;IAEtC,iGAAiG;IACjG,QAAQ,CAAC,KAAK,EAAE;QACd,IAAI,EAAE,MAAM,CAAC;QACb,UAAU,EAAE,MAAM,CAAC;KACpB,GAAG,OAAO,CAAC;QAAE,IAAI,EAAE,6BAA6B,CAAA;KAAE,CAAC;CAGrD"}
1
+ {"version":3,"file":"app-subscriptions.d.ts","sourceRoot":"","sources":["../../src/resources/app-subscriptions.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAE/C,MAAM,WAAW,6BAA6B;IAC5C,mDAAmD;IACnD,GAAG,EAAE,MAAM,CAAC;CACb;AAED,MAAM,WAAW,2BAA2B;IAC1C,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,QAAQ,GAAG,UAAU,GAAG,UAAU,GAAG,MAAM,CAAC;IACpD,MAAM,EAAE,OAAO,CAAC;IAChB,gBAAgB,EAAE,MAAM,GAAG,IAAI,CAAC;CACjC;AAED;;;GAGG;AACH,qBAAa,wBAAwB;IACvB,OAAO,CAAC,MAAM;gBAAN,MAAM,EAAE,UAAU;IAEtC,iGAAiG;IACjG,QAAQ,CAAC,KAAK,EAAE;QACd,IAAI,EAAE,MAAM,CAAC;QACb,UAAU,EAAE,MAAM,CAAC;KACpB,GAAG,OAAO,CAAC;QAAE,IAAI,EAAE,6BAA6B,CAAA;KAAE,CAAC;IAIpD,mFAAmF;IACnF,MAAM,IAAI,OAAO,CAAC;QAAE,IAAI,EAAE,2BAA2B,CAAA;KAAE,CAAC;CAGzD"}
@@ -11,5 +11,9 @@ export class AppSubscriptionsResource {
11
11
  checkout(input) {
12
12
  return this.client.post('/app-subscriptions/checkout', input);
13
13
  }
14
+ /** Read the current user's app-subscription status for this project-scoped key. */
15
+ status() {
16
+ return this.client.get('/app-subscriptions/status');
17
+ }
14
18
  }
15
19
  //# sourceMappingURL=app-subscriptions.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"app-subscriptions.js","sourceRoot":"","sources":["../../src/resources/app-subscriptions.ts"],"names":[],"mappings":"AAOA;;;GAGG;AACH,MAAM,OAAO,wBAAwB;IACf;IAApB,YAAoB,MAAkB;QAAlB,WAAM,GAAN,MAAM,CAAY;IAAG,CAAC;IAE1C,iGAAiG;IACjG,QAAQ,CAAC,KAGR;QACC,OAAO,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,6BAA6B,EAAE,KAAK,CAAC,CAAC;IAChE,CAAC;CACF"}
1
+ {"version":3,"file":"app-subscriptions.js","sourceRoot":"","sources":["../../src/resources/app-subscriptions.ts"],"names":[],"mappings":"AAcA;;;GAGG;AACH,MAAM,OAAO,wBAAwB;IACf;IAApB,YAAoB,MAAkB;QAAlB,WAAM,GAAN,MAAM,CAAY;IAAG,CAAC;IAE1C,iGAAiG;IACjG,QAAQ,CAAC,KAGR;QACC,OAAO,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,6BAA6B,EAAE,KAAK,CAAC,CAAC;IAChE,CAAC;IAED,mFAAmF;IACnF,MAAM;QACJ,OAAO,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,2BAA2B,CAAC,CAAC;IACtD,CAAC;CACF"}
@@ -9,6 +9,8 @@ export interface OrganizationSettingsData {
9
9
  /** When true, POST /api-keys auto-adds new signups as org members. */
10
10
  allow_public_signup: boolean;
11
11
  preferred_contact_email: string | null;
12
+ /** Brand name used for project/org-scoped auth OTP emails. */
13
+ auth_email_brand_name: string | null;
12
14
  github_connected: boolean;
13
15
  github_owner: string | null;
14
16
  github_connected_at: string | null;
@@ -52,6 +54,15 @@ export interface PreferredContactEmailResult {
52
54
  preferred_contact_email: string | null;
53
55
  updated_at: string;
54
56
  }
57
+ export interface SetAuthEmailBrandInput {
58
+ auth_email_brand_name: string | null;
59
+ }
60
+ export interface AuthEmailBrandResult {
61
+ id: string;
62
+ organization_id: string;
63
+ auth_email_brand_name: string | null;
64
+ updated_at: string;
65
+ }
55
66
  export interface ValidateTemplateInput {
56
67
  url: string;
57
68
  }
@@ -90,6 +101,8 @@ export declare class OrganizationSettingsResource {
90
101
  setAllowPublicSignup(organizationId: string, input: SetAllowPublicSignupInput): Promise<SingleResponse<AllowPublicSignupResult>>;
91
102
  /** Set preferred contact email for agent outreach and operational alerts */
92
103
  setPreferredContactEmail(organizationId: string, input: SetPreferredContactEmailInput): Promise<SingleResponse<PreferredContactEmailResult>>;
104
+ /** Set the brand name used by project/org-scoped auth OTP emails */
105
+ setAuthEmailBrandName(organizationId: string, input: SetAuthEmailBrandInput): Promise<SingleResponse<AuthEmailBrandResult>>;
93
106
  /** Validate a template URL */
94
107
  validateTemplateUrl(organizationId: string, input: ValidateTemplateInput): Promise<SingleResponse<ValidateTemplateResult>>;
95
108
  /** Connect a GitHub account to the organization */
@@ -1 +1 @@
1
- {"version":3,"file":"organization-settings.d.ts","sourceRoot":"","sources":["../../src/resources/organization-settings.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"organization-settings.d.ts","sourceRoot":"","sources":["../../src/resources/organization-settings.ts"],"names":[],"mappings":"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"}
@@ -32,6 +32,10 @@ export class OrganizationSettingsResource {
32
32
  setPreferredContactEmail(organizationId, input) {
33
33
  return this.client.put(`/organization-settings/${organizationId}/settings/preferred-contact`, input);
34
34
  }
35
+ /** Set the brand name used by project/org-scoped auth OTP emails */
36
+ setAuthEmailBrandName(organizationId, input) {
37
+ return this.client.put(`/organization-settings/${organizationId}/settings/auth-email-brand`, input);
38
+ }
35
39
  /** Validate a template URL */
36
40
  validateTemplateUrl(organizationId, input) {
37
41
  return this.client.post(`/organization-settings/${organizationId}/settings/validate-template`, input);
@@ -1 +1 @@
1
- {"version":3,"file":"organization-settings.js","sourceRoot":"","sources":["../../src/resources/organization-settings.ts"],"names":[],"mappings":"AAsFA,MAAM,OAAO,4BAA4B;IACnB;IAApB,YAAoB,MAAkB;QAAlB,WAAM,GAAN,MAAM,CAAY;IAAG,CAAC;IAE1C,gCAAgC;IAChC,GAAG,CACD,cAAsB;QAEtB,OAAO,IAAI,CAAC,MAAM,CAAC,GAAG,CACpB,0BAA0B,cAAc,WAAW,CACpD,CAAC;IACJ,CAAC;IAED,gDAAgD;IAChD,kBAAkB,CAChB,cAAsB,EACtB,KAA8B;QAE9B,OAAO,IAAI,CAAC,MAAM,CAAC,GAAG,CACpB,0BAA0B,cAAc,4BAA4B,EACpE,KAAK,CACN,CAAC;IACJ,CAAC;IAED,qDAAqD;IACrD,sBAAsB,CACpB,cAAsB,EACtB,KAA4B;QAE5B,OAAO,IAAI,CAAC,MAAM,CAAC,GAAG,CACpB,0BAA0B,cAAc,0BAA0B,EAClE,KAAK,CACN,CAAC;IACJ,CAAC;IAED;;;;;;;;;OASG;IACH,oBAAoB,CAClB,cAAsB,EACtB,KAAgC;QAEhC,OAAO,IAAI,CAAC,MAAM,CAAC,GAAG,CACpB,0BAA0B,cAAc,+BAA+B,EACvE,KAAK,CACN,CAAC;IACJ,CAAC;IAED,4EAA4E;IAC5E,wBAAwB,CACtB,cAAsB,EACtB,KAAoC;QAEpC,OAAO,IAAI,CAAC,MAAM,CAAC,GAAG,CACpB,0BAA0B,cAAc,6BAA6B,EACrE,KAAK,CACN,CAAC;IACJ,CAAC;IAED,8BAA8B;IAC9B,mBAAmB,CACjB,cAAsB,EACtB,KAA4B;QAE5B,OAAO,IAAI,CAAC,MAAM,CAAC,IAAI,CACrB,0BAA0B,cAAc,6BAA6B,EACrE,KAAK,CACN,CAAC;IACJ,CAAC;IAED,mDAAmD;IACnD,aAAa,CACX,cAAsB,EACtB,KAAyB;QAEzB,OAAO,IAAI,CAAC,MAAM,CAAC,IAAI,CACrB,0BAA0B,cAAc,0BAA0B,EAClE,KAAK,CACN,CAAC;IACJ,CAAC;IAED,0DAA0D;IAC1D,gBAAgB,CACd,cAAsB;QAEtB,OAAO,IAAI,CAAC,MAAM,CAAC,IAAI,CACrB,0BAA0B,cAAc,6BAA6B,CACtE,CAAC;IACJ,CAAC;CACF"}
1
+ {"version":3,"file":"organization-settings.js","sourceRoot":"","sources":["../../src/resources/organization-settings.ts"],"names":[],"mappings":"AAmGA,MAAM,OAAO,4BAA4B;IACnB;IAApB,YAAoB,MAAkB;QAAlB,WAAM,GAAN,MAAM,CAAY;IAAG,CAAC;IAE1C,gCAAgC;IAChC,GAAG,CACD,cAAsB;QAEtB,OAAO,IAAI,CAAC,MAAM,CAAC,GAAG,CACpB,0BAA0B,cAAc,WAAW,CACpD,CAAC;IACJ,CAAC;IAED,gDAAgD;IAChD,kBAAkB,CAChB,cAAsB,EACtB,KAA8B;QAE9B,OAAO,IAAI,CAAC,MAAM,CAAC,GAAG,CACpB,0BAA0B,cAAc,4BAA4B,EACpE,KAAK,CACN,CAAC;IACJ,CAAC;IAED,qDAAqD;IACrD,sBAAsB,CACpB,cAAsB,EACtB,KAA4B;QAE5B,OAAO,IAAI,CAAC,MAAM,CAAC,GAAG,CACpB,0BAA0B,cAAc,0BAA0B,EAClE,KAAK,CACN,CAAC;IACJ,CAAC;IAED;;;;;;;;;OASG;IACH,oBAAoB,CAClB,cAAsB,EACtB,KAAgC;QAEhC,OAAO,IAAI,CAAC,MAAM,CAAC,GAAG,CACpB,0BAA0B,cAAc,+BAA+B,EACvE,KAAK,CACN,CAAC;IACJ,CAAC;IAED,4EAA4E;IAC5E,wBAAwB,CACtB,cAAsB,EACtB,KAAoC;QAEpC,OAAO,IAAI,CAAC,MAAM,CAAC,GAAG,CACpB,0BAA0B,cAAc,6BAA6B,EACrE,KAAK,CACN,CAAC;IACJ,CAAC;IAED,oEAAoE;IACpE,qBAAqB,CACnB,cAAsB,EACtB,KAA6B;QAE7B,OAAO,IAAI,CAAC,MAAM,CAAC,GAAG,CACpB,0BAA0B,cAAc,4BAA4B,EACpE,KAAK,CACN,CAAC;IACJ,CAAC;IAED,8BAA8B;IAC9B,mBAAmB,CACjB,cAAsB,EACtB,KAA4B;QAE5B,OAAO,IAAI,CAAC,MAAM,CAAC,IAAI,CACrB,0BAA0B,cAAc,6BAA6B,EACrE,KAAK,CACN,CAAC;IACJ,CAAC;IAED,mDAAmD;IACnD,aAAa,CACX,cAAsB,EACtB,KAAyB;QAEzB,OAAO,IAAI,CAAC,MAAM,CAAC,IAAI,CACrB,0BAA0B,cAAc,0BAA0B,EAClE,KAAK,CACN,CAAC;IACJ,CAAC;IAED,0DAA0D;IAC1D,gBAAgB,CACd,cAAsB;QAEtB,OAAO,IAAI,CAAC,MAAM,CAAC,IAAI,CACrB,0BAA0B,cAAc,6BAA6B,CACtE,CAAC;IACJ,CAAC;CACF"}
package/llm.md CHANGED
@@ -326,6 +326,37 @@ Available scopes: `posts:read`, `posts:write`, `users:read`, `users:write`, `com
326
326
 
327
327
  **Scope enforcement:** Every API call checks scopes. A 403 `AuthorizationError` means your key is missing the required scope. Grant only the scopes your app needs (least privilege). The `admin` scope can only be created by platform administrators — attempting to self-grant it returns 403.
328
328
 
329
+ ### @recursiv/sdk/next — Next.js App Router server auth
330
+
331
+ Server-only sub-path (Next 14+, both 14 and 15). Per-user-key pattern: auth flows mint a project-scoped key and store it in an httpOnly cookie; every request rebuilds an SDK bound to the caller's own key. No platform key needed at runtime.
332
+
333
+ ```typescript
334
+ // src/lib/recursiv.ts
335
+ import 'server-only';
336
+ import { createRecursivAuth } from '@recursiv/sdk/next';
337
+ export const auth = createRecursivAuth(); // RECURSIV_PROJECT_ID + RECURSIV_API_BASE_URL from env
338
+
339
+ // server action ('use server')
340
+ const { user } = await auth.signIn({ email, password }); // mints key + sets cookie
341
+ await auth.signOut();
342
+
343
+ // server component / route handler
344
+ const sdk = await auth.getSdk(); // throws AuthenticationError when signed out
345
+ const maybe = await auth.trySdk(); // null when signed out
346
+ const me = await auth.getUser(); // SessionUser | null
347
+
348
+ // route handler writing its own response (custom cookie contract)
349
+ const auth = createRecursivAuth({ cookie: { name: 'myapp_key', maxAge: 60 * 60 * 24 * 90 } });
350
+ const res = NextResponse.json({ ok: true });
351
+ await auth.verifyOtp({ email, otp }, { response: res.cookies });
352
+
353
+ // request-bound, e.g. a route handler that already holds a NextRequest
354
+ const key = auth.sessionKeyFromRequest(req);
355
+ const sdk2 = auth.sdkFromRequest(req); // Recursiv | null
356
+ ```
357
+
358
+ Config: `projectId` (default env `RECURSIV_PROJECT_ID`) XOR `organizationId`; `scopes` (default `DEFAULT_USER_KEY_SCOPES` — pass your own for least privilege); `cookie: { name, maxAge, sameSite, secure, domain, httpOnly, path }`; `apiKey` (only for branded auth emails); `baseUrl`, `timeout`, `maxRetries` (set `maxRetries: 0` if duplicate OTP/checkout POSTs are worse than a retry). Auth results include `keyPrefix` for account-linking records. Never import this sub-path in client components (`server-only` enforces it). Keep it out of `middleware.ts` too (it drags the whole SDK into the edge bundle) — middleware should do a plain presence check on a shared cookie-name constant and redirect.
359
+
329
360
  ### r.users
330
361
 
331
362
  ```typescript
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@recursiv/sdk",
3
- "version": "0.5.8",
3
+ "version": "0.6.0",
4
4
  "description": "TypeScript SDK for the Recursiv API",
5
5
  "license": "FSL-1.1-ALv2",
6
6
  "type": "module",
@@ -17,6 +17,11 @@
17
17
  "types": "./dist/react/index.d.ts",
18
18
  "import": "./dist/react/index.js",
19
19
  "default": "./dist/react/index.js"
20
+ },
21
+ "./next": {
22
+ "types": "./dist/next/index.d.ts",
23
+ "import": "./dist/next/index.js",
24
+ "default": "./dist/next/index.js"
20
25
  }
21
26
  },
22
27
  "files": [
@@ -42,21 +47,31 @@
42
47
  "registry": "https://registry.npmjs.org/",
43
48
  "access": "public"
44
49
  },
45
- "scripts": {
46
- "build": "tsc",
47
- "prepublishOnly": "tsc",
48
- "typecheck": "tsc --noEmit",
49
- "test": "vitest run"
50
- },
51
50
  "devDependencies": {
52
51
  "@types/react": "^19.2.14",
52
+ "next": "^15.5.20",
53
53
  "typescript": "~5.9.2",
54
54
  "vitest": "^4.1.0"
55
55
  },
56
56
  "dependencies": {
57
+ "server-only": "^0.0.1",
57
58
  "socket.io-client": "^4.8.3"
58
59
  },
59
60
  "peerDependencies": {
61
+ "next": ">=14.0.0 <16",
60
62
  "react": "^18.3.1 || ^19.0.0"
63
+ },
64
+ "peerDependenciesMeta": {
65
+ "next": {
66
+ "optional": true
67
+ },
68
+ "react": {
69
+ "optional": true
70
+ }
71
+ },
72
+ "scripts": {
73
+ "build": "tsc",
74
+ "typecheck": "tsc --noEmit",
75
+ "test": "vitest run"
61
76
  }
62
- }
77
+ }