@recursiv/sdk 0.5.8 → 0.6.1
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 +38 -1
- package/dist/next/index.d.ts +11 -0
- package/dist/next/index.d.ts.map +1 -0
- package/dist/next/index.js +10 -0
- package/dist/next/index.js.map +1 -0
- package/dist/next/scopes.d.ts +35 -0
- package/dist/next/scopes.d.ts.map +1 -0
- package/dist/next/scopes.js +48 -0
- package/dist/next/scopes.js.map +1 -0
- package/dist/next/server-auth.d.ts +187 -0
- package/dist/next/server-auth.d.ts.map +1 -0
- package/dist/next/server-auth.js +249 -0
- package/dist/next/server-auth.js.map +1 -0
- package/dist/resources/agents.d.ts +1 -1
- package/dist/resources/agents.d.ts.map +1 -1
- package/dist/resources/agents.js +2 -2
- package/dist/resources/agents.js.map +1 -1
- package/dist/resources/app-subscriptions.d.ts +10 -0
- package/dist/resources/app-subscriptions.d.ts.map +1 -1
- package/dist/resources/app-subscriptions.js +4 -0
- package/dist/resources/app-subscriptions.js.map +1 -1
- package/dist/resources/auth.d.ts +16 -1
- package/dist/resources/auth.d.ts.map +1 -1
- package/dist/resources/auth.js +88 -10
- package/dist/resources/auth.js.map +1 -1
- package/dist/resources/dispatcher.d.ts +31 -8
- package/dist/resources/dispatcher.d.ts.map +1 -1
- package/dist/resources/dispatcher.js +33 -21
- package/dist/resources/dispatcher.js.map +1 -1
- package/dist/resources/organization-settings.d.ts +13 -0
- package/dist/resources/organization-settings.d.ts.map +1 -1
- package/dist/resources/organization-settings.js +4 -0
- package/dist/resources/organization-settings.js.map +1 -1
- package/llm.md +31 -0
- package/package.json +23 -8
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 |
|
|
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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"}
|
|
@@ -62,7 +62,7 @@ export interface SalesLead {
|
|
|
62
62
|
* Validation happens server-side too; this list lets apps validate or
|
|
63
63
|
* surface choices client-side without round-tripping the API.
|
|
64
64
|
*/
|
|
65
|
-
export declare const SUPPORTED_MODELS: readonly ["google/gemini-3.1-pro-preview", "google/gemini-3-flash-preview", "anthropic/claude-opus-4.6", "anthropic/claude-sonnet-4.6", "openai/gpt-5.4", "openai/gpt-4o-mini", "moonshotai/kimi-
|
|
65
|
+
export declare const SUPPORTED_MODELS: readonly ["google/gemini-3.1-pro-preview", "google/gemini-3-flash-preview", "anthropic/claude-opus-4.6", "anthropic/claude-sonnet-4.6", "openai/gpt-5.4", "openai/gpt-4o-mini", "moonshotai/kimi-k3", "x-ai/grok-4.3", "deepseek/deepseek-v3.2", "minimax/minimax-m2.5"];
|
|
66
66
|
export type SupportedModel = (typeof SUPPORTED_MODELS)[number];
|
|
67
67
|
export interface EnsurePersonalAgentOverrides {
|
|
68
68
|
/** Override the agent's display name. Defaults to 'Agent'. */
|