@recursiv/sdk 0.7.50 → 0.7.52

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (44) hide show
  1. package/README.md +69 -12
  2. package/dist/client.js +3 -1
  3. package/dist/index.d.ts +13 -6
  4. package/dist/index.js +5 -1
  5. package/dist/realtime.d.ts +79 -9
  6. package/dist/realtime.js +339 -76
  7. package/dist/resources/admin.d.ts +13 -0
  8. package/dist/resources/agents.d.ts +41 -4
  9. package/dist/resources/agents.js +45 -24
  10. package/dist/resources/app-subscriptions.d.ts +102 -4
  11. package/dist/resources/app-subscriptions.js +43 -3
  12. package/dist/resources/auth.d.ts +198 -2
  13. package/dist/resources/auth.js +397 -3
  14. package/dist/resources/boosts.d.ts +170 -0
  15. package/dist/resources/boosts.js +75 -0
  16. package/dist/resources/chat.d.ts +33 -3
  17. package/dist/resources/chat.js +38 -2
  18. package/dist/resources/communities.d.ts +23 -11
  19. package/dist/resources/communities.js +20 -6
  20. package/dist/resources/curator.d.ts +24 -6
  21. package/dist/resources/curator.js +2 -1
  22. package/dist/resources/deployments.d.ts +8 -3
  23. package/dist/resources/discovery.d.ts +15 -1
  24. package/dist/resources/discovery.js +29 -1
  25. package/dist/resources/invite-codes-admin.d.ts +13 -0
  26. package/dist/resources/invite-codes.d.ts +10 -0
  27. package/dist/resources/invite-codes.js +6 -6
  28. package/dist/resources/notifications.d.ts +74 -5
  29. package/dist/resources/notifications.js +38 -8
  30. package/dist/resources/posts.d.ts +28 -5
  31. package/dist/resources/posts.js +13 -4
  32. package/dist/resources/profiles.d.ts +45 -9
  33. package/dist/resources/profiles.js +54 -3
  34. package/dist/resources/protocols.d.ts +195 -14
  35. package/dist/resources/protocols.js +77 -12
  36. package/dist/resources/settings.d.ts +25 -3
  37. package/dist/resources/settings.js +28 -2
  38. package/dist/resources/video.d.ts +19 -0
  39. package/dist/resources/video.js +8 -0
  40. package/dist/resources/wallet.d.ts +41 -1
  41. package/dist/resources/wallet.js +8 -0
  42. package/dist/types.d.ts +217 -6
  43. package/llm.md +68 -20
  44. package/package.json +2 -2
@@ -12,8 +12,11 @@ import { parseSSE } from '../lib/sse.js';
12
12
  export const SUPPORTED_MODELS = [
13
13
  // <<< GENERATED: openrouter-sync — do not edit by hand (npm run models:sync)
14
14
  'anthropic/claude-fable-5',
15
+ 'anthropic/claude-fable-5.1',
15
16
  'anthropic/claude-opus-4.6',
16
17
  'anthropic/claude-opus-4.8',
18
+ 'anthropic/claude-opus-5',
19
+ 'anthropic/claude-opus-5.5',
17
20
  'anthropic/claude-sonnet-4.6',
18
21
  'anthropic/claude-sonnet-5',
19
22
  'deepseek/deepseek-v3.2',
@@ -21,6 +24,7 @@ export const SUPPORTED_MODELS = [
21
24
  'google/gemini-3-flash-preview',
22
25
  'google/gemini-3.1-pro-preview',
23
26
  'google/gemini-3.5-flash',
27
+ 'google/gemini-3.8-flash',
24
28
  'minimax/minimax-m2.5',
25
29
  'minimax/minimax-m3',
26
30
  'moonshotai/kimi-k3',
@@ -28,6 +32,8 @@ export const SUPPORTED_MODELS = [
28
32
  'openai/gpt-5.5',
29
33
  'openai/gpt-5.6-sol',
30
34
  'openai/gpt-5.6-terra',
35
+ 'openai/gpt-6-astra',
36
+ 'openai/gpt-6-sol',
31
37
  'x-ai/grok-4.3',
32
38
  // >>> GENERATED
33
39
  ];
@@ -51,7 +57,7 @@ export class AgentsResource {
51
57
  get(id) {
52
58
  return this.client.get(`/agents/${id}`);
53
59
  }
54
- /** Create a new AI agent */
60
+ /** Create a new AI agent. Omit username for a server-generated collision-resistant handle. */
55
61
  create(input) {
56
62
  return this.client.post('/agents', input);
57
63
  }
@@ -92,7 +98,14 @@ export class AgentsResource {
92
98
  conversationMessages(id, conversationId, params) {
93
99
  return this.client.get(`/agents/${id}/conversations/${conversationId}/messages`, params);
94
100
  }
95
- /** List discoverable agents (public + same-org) */
101
+ /**
102
+ * List the agents a member may discover: an app key gets the agents of its
103
+ * project and owning org, a personal key gets global and same-org agents.
104
+ * Only member-facing agents are returned. Agents that run a tenant (a
105
+ * project's Lead, swarm workers, dispatcher role agents, MCP client agents,
106
+ * the workspace AI, anyone's personal AI) never appear here; list your own
107
+ * with `list()`.
108
+ */
96
109
  listDiscoverable(params) {
97
110
  return this.client.get('/agents/discoverable', params);
98
111
  }
@@ -181,26 +194,19 @@ export class AgentsResource {
181
194
  * For React Native, use `chatStreamText()` instead.
182
195
  */
183
196
  async *chatStream(id, input) {
184
- const response = await this.client.fetchRaw(`/agents/${id}/chat/stream`, {
185
- method: 'POST',
186
- headers: { 'Content-Type': 'application/json' },
187
- body: JSON.stringify(input),
188
- });
189
- if (!response.ok) {
190
- let errorBody;
191
- try {
192
- errorBody = await response.json();
193
- }
194
- catch {
195
- throw new RecursivError(response.status, {
196
- type: 'api_error',
197
- message: `HTTP ${response.status}: ${response.statusText}`,
198
- code: 'stream_error',
199
- });
200
- }
201
- throw new RecursivError(response.status, errorBody.error);
202
- }
203
- yield* parseSSE(response.body);
197
+ yield* this.streamChunks(id, input);
198
+ }
199
+ /**
200
+ * Retry a turn: stream a fresh reply to one of your existing messages
201
+ * without sending it again. Use it for "Try again" after a reply failed.
202
+ * The agent's earlier reply to that message, if any, is removed first.
203
+ *
204
+ * The message must be yours and the latest one in the conversation
205
+ * (409 `retry_not_latest` otherwise), and a reply still being written must
206
+ * finish or be stopped first (409 `run_in_progress`).
207
+ */
208
+ async *retryChatStream(id, input) {
209
+ yield* this.streamChunks(id, input);
204
210
  }
205
211
  /**
206
212
  * Chat with an agent and get the full response text.
@@ -220,12 +226,19 @@ export class AgentsResource {
220
226
  * });
221
227
  * ```
222
228
  */
223
- async chatStreamText(id, input) {
229
+ chatStreamText(id, input) {
230
+ return this.streamText(id, input);
231
+ }
232
+ /** `retryChatStream()` for platforms without `ReadableStream` (React Native). */
233
+ retryChatStreamText(id, input) {
234
+ return this.streamText(id, input);
235
+ }
236
+ async openStream(id, input, accept) {
224
237
  const response = await this.client.fetchRaw(`/agents/${id}/chat/stream`, {
225
238
  method: 'POST',
226
239
  headers: {
227
240
  'Content-Type': 'application/json',
228
- Accept: 'text/event-stream',
241
+ ...(accept ? { Accept: accept } : {}),
229
242
  },
230
243
  body: JSON.stringify(input),
231
244
  });
@@ -243,6 +256,14 @@ export class AgentsResource {
243
256
  }
244
257
  throw new RecursivError(response.status, errorBody.error);
245
258
  }
259
+ return response;
260
+ }
261
+ async *streamChunks(id, input) {
262
+ const response = await this.openStream(id, input);
263
+ yield* parseSSE(response.body);
264
+ }
265
+ async streamText(id, input) {
266
+ const response = await this.openStream(id, input, 'text/event-stream');
246
267
  const text = await response.text();
247
268
  const lines = text.split('\n');
248
269
  let fullText = '';
@@ -6,12 +6,64 @@ export interface AppSubscriptionCheckoutResult {
6
6
  export interface AppSubscriptionPortalResult {
7
7
  /** Stripe Billing Portal URL for the current app user. */
8
8
  url: string;
9
+ /**
10
+ * The page the portal opens on: `cancel` for the plan's cancel confirmation, null for the
11
+ * portal home. A plan already set to end opens the home, where the member can renew it.
12
+ * Absent from older servers.
13
+ */
14
+ flow?: 'cancel' | null;
15
+ }
16
+ /** The boost credit a paid plan on this app adds to the member's boost balance. */
17
+ export interface AppSubscriptionBoostCredit {
18
+ /** Micro-USD (1 USD = 1,000,000) each paid billing period of a plan adds, by tier key (e.g. `plus`, `pro`). */
19
+ perPeriodMicros: Record<string, number>;
20
+ /** What the member's current plan adds each paid period; 0 without a paid plan here. */
21
+ currentMicros: number;
22
+ /**
23
+ * When the next paid period starts and adds `currentMicros`. Null without a plan that adds
24
+ * credit, or while a payment is overdue. A plan set to end at the period's end still shows it.
25
+ */
26
+ nextGrantAt: string | null;
27
+ /**
28
+ * Plan credit the member owes: taken back after their plan dropped or ended inside a period, but
29
+ * already spent. The next plan credit repays it before adding anything. 0 when nothing is owed
30
+ * (absent from older servers).
31
+ */
32
+ owedMicros?: number;
9
33
  }
10
34
  export interface AppSubscriptionStatusResult {
11
35
  tier: string;
12
- status: 'active' | 'past_due' | 'canceled' | 'none';
36
+ /** 'legacy' is a membership carried over from a previous platform, with no subscription here. */
37
+ status: 'active' | 'past_due' | 'canceled' | 'none' | 'legacy';
13
38
  active: boolean;
14
39
  currentPeriodEnd: string | null;
40
+ /** Where the entitlement comes from: a Stripe subscription here, or the legacy import. */
41
+ source?: 'stripe' | 'legacy';
42
+ /**
43
+ * The boost credit each paid period of a plan adds (once per period, from the payment that
44
+ * starts it). Null when this app's plans include none; absent from older servers.
45
+ */
46
+ boostCredit?: AppSubscriptionBoostCredit | null;
47
+ }
48
+ export interface AppSubscriptionTierChangePreview {
49
+ /** The plan the preview prices. */
50
+ tier: string;
51
+ /** The plan the member pays for now. */
52
+ currentTier: string;
53
+ /** Prorated charge (positive) or credit (negative) for the rest of this period, in minor units. */
54
+ prorationAmount: number;
55
+ /** What the next invoice totals with the change applied, in minor units. */
56
+ amountDue: number;
57
+ currency: string;
58
+ /** Pass to `changeTier` so the charge matches this preview exactly. */
59
+ prorationDate: number;
60
+ nextPaymentAt: string | null;
61
+ }
62
+ export interface AppSubscriptionTierChangeResult {
63
+ tier: string;
64
+ previousTier: string;
65
+ status: 'active' | 'past_due' | 'canceled';
66
+ currentPeriodEnd: string | null;
15
67
  }
16
68
  /**
17
69
  * Per-app-user consumer subscriptions (e.g. Plus/Pro) billed through the app's
@@ -20,20 +72,66 @@ export interface AppSubscriptionStatusResult {
20
72
  export declare class AppSubscriptionsResource {
21
73
  private client;
22
74
  constructor(client: HttpClient);
23
- /** Start a Stripe Checkout for the current user to subscribe to a plan tier ('plus' | 'pro'). */
75
+ /**
76
+ * Start a Stripe Checkout for the current user to subscribe to a plan tier ('plus' | 'pro').
77
+ * Answers 409 `subscription_exists` when the member already has a subscription:
78
+ * use `changeTier` for them instead, so they are never billed twice.
79
+ *
80
+ * Only one checkout can be paid at a time. Repeating the same request (same tier and
81
+ * `return_url`) returns the checkout already open; any other request expires the
82
+ * member's earlier open checkouts for this app. Answers 503 `checkout_busy` when
83
+ * Stripe is too slow to finish safely: retry. `return_url` keeps its own query and fragment;
84
+ * `sub=success&tier=<tier>` or `sub=cancelled` is added to its query (to the
85
+ * fragment's query for a hash route such as `#/billing`).
86
+ */
24
87
  checkout(input: {
25
88
  tier: string;
26
89
  return_url: string;
27
90
  }): Promise<{
28
91
  data: AppSubscriptionCheckoutResult;
29
92
  }>;
30
- /** Open the current app user's Stripe Billing Portal for this project. */
93
+ /**
94
+ * Price a switch of the current member's plan to `tier`, prorated, without changing anything.
95
+ * Errors (409) name why a switch cannot run: `no_subscription`, `already_on_tier`,
96
+ * `subscription_not_active`, `subscription_canceling`, `legacy_membership`.
97
+ */
98
+ previewTierChange(input: {
99
+ tier: string;
100
+ }): Promise<{
101
+ data: AppSubscriptionTierChangePreview;
102
+ }>;
103
+ /**
104
+ * Switch the current member's existing subscription to `tier`, prorated, in place.
105
+ * Never opens a second subscription. Pass `proration_date` from `previewTierChange`
106
+ * to charge exactly what the preview showed. A switch to a lower plan takes effect
107
+ * now: the unused time on the higher plan is credited, and that plan ends at once.
108
+ * Not retried automatically: on an
109
+ * unclear failure, read `status()` before trying again (a repeat answers 409
110
+ * `already_on_tier` rather than charging twice).
111
+ */
112
+ changeTier(input: {
113
+ tier: string;
114
+ proration_date?: number;
115
+ }): Promise<{
116
+ data: AppSubscriptionTierChangeResult;
117
+ }>;
118
+ /**
119
+ * Open the current app user's Stripe Billing Portal for this project.
120
+ *
121
+ * `flow: 'cancel'` opens it straight on the cancel confirmation for the member's plan, and
122
+ * returns to `return_url` once they confirm. Answers 409 `no_subscription` when there is no
123
+ * plan to cancel, and 409 `legacy_membership` for a carried-over member with nothing to manage.
124
+ */
31
125
  createPortalSession(input: {
32
126
  return_url: string;
127
+ flow?: 'cancel';
33
128
  }): Promise<{
34
129
  data: AppSubscriptionPortalResult;
35
130
  }>;
36
- /** Read the current user's app-subscription status for this project-scoped key. */
131
+ /**
132
+ * Read the current user's app-subscription status for this project-scoped key, with the
133
+ * boost credit the app's plans include (`boostCredit`).
134
+ */
37
135
  status(): Promise<{
38
136
  data: AppSubscriptionStatusResult;
39
137
  }>;
@@ -7,15 +7,55 @@ export class AppSubscriptionsResource {
7
7
  constructor(client) {
8
8
  this.client = client;
9
9
  }
10
- /** Start a Stripe Checkout for the current user to subscribe to a plan tier ('plus' | 'pro'). */
10
+ /**
11
+ * Start a Stripe Checkout for the current user to subscribe to a plan tier ('plus' | 'pro').
12
+ * Answers 409 `subscription_exists` when the member already has a subscription:
13
+ * use `changeTier` for them instead, so they are never billed twice.
14
+ *
15
+ * Only one checkout can be paid at a time. Repeating the same request (same tier and
16
+ * `return_url`) returns the checkout already open; any other request expires the
17
+ * member's earlier open checkouts for this app. Answers 503 `checkout_busy` when
18
+ * Stripe is too slow to finish safely: retry. `return_url` keeps its own query and fragment;
19
+ * `sub=success&tier=<tier>` or `sub=cancelled` is added to its query (to the
20
+ * fragment's query for a hash route such as `#/billing`).
21
+ */
11
22
  checkout(input) {
12
23
  return this.client.post('/app-subscriptions/checkout', input);
13
24
  }
14
- /** Open the current app user's Stripe Billing Portal for this project. */
25
+ /**
26
+ * Price a switch of the current member's plan to `tier`, prorated, without changing anything.
27
+ * Errors (409) name why a switch cannot run: `no_subscription`, `already_on_tier`,
28
+ * `subscription_not_active`, `subscription_canceling`, `legacy_membership`.
29
+ */
30
+ previewTierChange(input) {
31
+ return this.client.get('/app-subscriptions/change-tier/preview', { tier: input.tier });
32
+ }
33
+ /**
34
+ * Switch the current member's existing subscription to `tier`, prorated, in place.
35
+ * Never opens a second subscription. Pass `proration_date` from `previewTierChange`
36
+ * to charge exactly what the preview showed. A switch to a lower plan takes effect
37
+ * now: the unused time on the higher plan is credited, and that plan ends at once.
38
+ * Not retried automatically: on an
39
+ * unclear failure, read `status()` before trying again (a repeat answers 409
40
+ * `already_on_tier` rather than charging twice).
41
+ */
42
+ changeTier(input) {
43
+ return this.client.post('/app-subscriptions/change-tier', input, { retry: false });
44
+ }
45
+ /**
46
+ * Open the current app user's Stripe Billing Portal for this project.
47
+ *
48
+ * `flow: 'cancel'` opens it straight on the cancel confirmation for the member's plan, and
49
+ * returns to `return_url` once they confirm. Answers 409 `no_subscription` when there is no
50
+ * plan to cancel, and 409 `legacy_membership` for a carried-over member with nothing to manage.
51
+ */
15
52
  createPortalSession(input) {
16
53
  return this.client.post('/app-subscriptions/portal', input);
17
54
  }
18
- /** Read the current user's app-subscription status for this project-scoped key. */
55
+ /**
56
+ * Read the current user's app-subscription status for this project-scoped key, with the
57
+ * boost credit the app's plans include (`boostCredit`).
58
+ */
19
59
  status() {
20
60
  return this.client.get('/app-subscriptions/status');
21
61
  }
@@ -17,6 +17,73 @@ export interface SignInInput {
17
17
  email: string;
18
18
  password: string;
19
19
  }
20
+ export interface UsernameSignInInput {
21
+ /** The member's handle, without the leading @. Matching is case-insensitive. */
22
+ username: string;
23
+ password: string;
24
+ }
25
+ /** The customer app a keyless auth call is made for (see `signIn`). */
26
+ export interface AppContext {
27
+ projectId?: string;
28
+ organizationId?: string;
29
+ }
30
+ export interface ResetPasswordInput {
31
+ /** The new password. Must meet the server's password policy. */
32
+ newPassword: string;
33
+ /** The reset token from the link in the reset email. */
34
+ token: string;
35
+ }
36
+ /**
37
+ * How a two-factor change is confirmed. An account with a password sends
38
+ * `password`. An account with no password (OTP-only) sends `emailCode`, the
39
+ * six digits from `requestTwoFactorEmailCode` (or `settings.requestConfirmationCode('two_factor')`).
40
+ */
41
+ export interface TwoFactorConfirmation {
42
+ password?: string;
43
+ emailCode?: string;
44
+ }
45
+ /** Public facts about a registered OAuth (MCP) client, for a consent screen. */
46
+ export interface OAuthClientInfo {
47
+ client_id: string;
48
+ /** Chosen by whoever registered the client. Show it as a claim, next to the redirect host. */
49
+ name: string | null;
50
+ icon: string | null;
51
+ type: 'public' | 'web';
52
+ disabled: boolean;
53
+ /** Hosts the client may send the member back to. This is the fact to show. */
54
+ redirect_hosts: string[];
55
+ /** Present when `redirectUri` was passed: whether the client registered it. */
56
+ redirect_uri_registered?: boolean;
57
+ scopes_supported: string[];
58
+ /** Present when `scope` was passed: the requested scopes this server grants, and the rest. */
59
+ requested_scopes?: string[];
60
+ unsupported_scopes?: string[];
61
+ }
62
+ /**
63
+ * The `details` of the `two_factor_required` error a password sign-in throws
64
+ * for a two-factor account. The challenge is single-use, lives ten minutes
65
+ * and allows five codes.
66
+ */
67
+ export interface TwoFactorChallenge {
68
+ /** Pass to `completeTwoFactorSignIn`. Null only from a server older than this field. */
69
+ twoFactorToken: string | null;
70
+ /** Second factors the server offers for this account, e.g. `['totp']`. Backup codes always work. */
71
+ methods: string[];
72
+ }
73
+ export interface CompleteTwoFactorSignInInput {
74
+ /** From the `two_factor_required` error's `details.twoFactorToken`. */
75
+ twoFactorToken: string;
76
+ /** The six digits from the authenticator app, or one backup code. */
77
+ code: string;
78
+ /** `backup_code` for a backup code. Defaults to `totp`. */
79
+ method?: 'totp' | 'backup_code';
80
+ }
81
+ export interface TwoFactorEnrollment {
82
+ /** otpauth:// URI for an authenticator app (render it as a QR code). */
83
+ totpURI: string;
84
+ /** One-time backup codes. Shown once; ask the member to save them. */
85
+ backupCodes: string[];
86
+ }
20
87
  export interface SendOtpInput {
21
88
  email: string;
22
89
  }
@@ -143,6 +210,16 @@ export declare class AuthResource {
143
210
  projectId?: string;
144
211
  organizationId?: string;
145
212
  }): Promise<AuthSession>;
213
+ /**
214
+ * Sign in with a username (handle) and password.
215
+ *
216
+ * Handles are unique per network, not globally, so pass the customer app's
217
+ * `appContext` when the API is reached through a shared hostname: the server
218
+ * resolves the handle on that app's network and never on another. Returns a
219
+ * session token, like `signIn`. A two-factor account throws
220
+ * `two_factor_required`; finish with `completeTwoFactorSignIn`.
221
+ */
222
+ signInWithUsername(input: UsernameSignInInput, appContext?: AppContext): Promise<AuthSession>;
146
223
  /**
147
224
  * Send a one-time password to an email address.
148
225
  * Works for both new and existing users — no password required.
@@ -180,12 +257,21 @@ export declare class AuthResource {
180
257
  * whether the email exists, to avoid leaking account existence.
181
258
  *
182
259
  * Sends the client's API key (when configured) so the server can brand the
183
- * reset email for YOUR org — same surface-scoped rule as `sendOtp`.
260
+ * reset email for YOUR org — same surface-scoped rule as `sendOtp`. Keyless
261
+ * apps pass `appContext` (same shape as `sendOtp`) for the same effect.
184
262
  */
185
263
  forgetPassword(input: {
186
264
  email: string;
187
265
  redirectTo?: string;
188
- }): Promise<{
266
+ }, appContext?: AppContext): Promise<{
267
+ success: true;
268
+ }>;
269
+ /**
270
+ * Set a new password with the token from a password reset email (the
271
+ * `token` your reset screen receives). Every existing session and API key
272
+ * for the account is revoked by the server, so sign in again afterwards.
273
+ */
274
+ resetPassword(input: ResetPasswordInput, appContext?: AppContext): Promise<{
189
275
  success: true;
190
276
  }>;
191
277
  /**
@@ -231,6 +317,17 @@ export declare class AuthResource {
231
317
  user: AuthSession['user'];
232
318
  session: AuthSession;
233
319
  }>;
320
+ /**
321
+ * `signInWithUsername`, then the app API key, exactly like `signInAndCreateKey`.
322
+ * The key's project/organization is forwarded as the sign-in's app context,
323
+ * so the handle is resolved on the app's network.
324
+ */
325
+ signInWithUsernameAndCreateKey(credentials: UsernameSignInInput, keyInput: CreateApiKeyInput): Promise<{
326
+ apiKey: string;
327
+ apiKeyId: string;
328
+ user: AuthSession['user'];
329
+ session: AuthSession;
330
+ }>;
234
331
  /**
235
332
  * Complete mobile auth flow: sign up → create API key → return key.
236
333
  *
@@ -246,6 +343,10 @@ export declare class AuthResource {
246
343
  * Exchange a legacy Minds session (the OAuth access token or minds_sess JWT
247
344
  * the legacy mobile app stored) for a session on this stack. Only answers
248
345
  * during the cutover window; every failure means "show the OTP screen".
346
+ *
347
+ * A legacy token is single-use: after one successful exchange the server
348
+ * answers `legacy_token_used`, so erase the stored legacy token as soon as
349
+ * this resolves and never retry it.
249
350
  */
250
351
  legacyHandoff(legacyToken: string, appContext?: {
251
352
  projectId?: string;
@@ -275,6 +376,101 @@ export declare class AuthResource {
275
376
  user: AuthSession['user'];
276
377
  session: AuthSession;
277
378
  }>;
379
+ /**
380
+ * Set the API-origin session cookie from a session token this client
381
+ * already holds, so a browser can continue an OAuth authorize request
382
+ * (`/api/auth/mcp/authorize`) without signing in again: the one-tap
383
+ * "Continue as @handle". Browser only in effect: the cookie is stored by the
384
+ * browser because the request is sent with `credentials: 'include'`.
385
+ * Returns the account the cookie now signs in.
386
+ */
387
+ exchangeSessionForCookie(sessionToken: string): Promise<{
388
+ user: {
389
+ id: string;
390
+ name: string | null;
391
+ username: string | null;
392
+ image: string | null;
393
+ };
394
+ }>;
395
+ /**
396
+ * Public facts about the OAuth client behind an authorize request: its name,
397
+ * icon, redirect hosts, whether `redirectUri` is one it registered, and which
398
+ * requested scopes are granted. No authentication needed.
399
+ */
400
+ getOAuthClientInfo(input: {
401
+ clientId: string;
402
+ redirectUri?: string;
403
+ scope?: string;
404
+ }): Promise<OAuthClientInfo>;
405
+ /**
406
+ * Finish a password sign-in on a two-factor account. `signIn`,
407
+ * `signInWithUsername` and their `*AndCreateKey` forms throw
408
+ * `AuthenticationError` with code `two_factor_required`; its `details` is a
409
+ * `TwoFactorChallenge`. Send its `twoFactorToken` with the code the member
410
+ * types. Returns the session, like `signIn`.
411
+ *
412
+ * Errors keep the server's code: `INVALID_CODE` / `INVALID_BACKUP_CODE` (a
413
+ * wrong code: ask again), `INVALID_TWO_FACTOR_COOKIE` (the challenge expired
414
+ * or was used: sign in again), `TOO_MANY_ATTEMPTS_REQUEST_NEW_CODE` (five
415
+ * wrong codes on this challenge: sign in again), and
416
+ * `ACCOUNT_TEMPORARILY_LOCKED` (too many wrong codes on the account: wait
417
+ * `retryAfter` seconds).
418
+ */
419
+ completeTwoFactorSignIn(input: CompleteTwoFactorSignInInput): Promise<AuthSession>;
420
+ /**
421
+ * `completeTwoFactorSignIn`, then the app API key, exactly like
422
+ * `signInAndCreateKey`: the second half of a `*AndCreateKey` sign-in that
423
+ * threw `two_factor_required`.
424
+ */
425
+ completeTwoFactorSignInAndCreateKey(input: CompleteTwoFactorSignInInput, keyInput: CreateApiKeyInput): Promise<{
426
+ apiKey: string;
427
+ apiKeyId: string;
428
+ user: AuthSession['user'];
429
+ session: AuthSession;
430
+ }>;
431
+ private sessionRequest;
432
+ private static confirmationBody;
433
+ /**
434
+ * Email a two-factor confirmation code to an account that has no password.
435
+ * An account with a password answers `PASSWORD_REQUIRED`: it confirms with
436
+ * the password instead. Pass the app's `appContext` (as for `sendOtp`) when
437
+ * the API is reached through a shared hostname, so the email carries the
438
+ * app's brand rather than the platform's.
439
+ */
440
+ requestTwoFactorEmailCode(sessionToken: string, appContext?: AppContext): Promise<{
441
+ expiresAt: string;
442
+ }>;
443
+ /**
444
+ * Start two-factor enrollment. Returns the authenticator URI and backup
445
+ * codes; two-factor is not on until `verifyTwoFactor` accepts a code from
446
+ * the authenticator.
447
+ *
448
+ * An account with no password answers `PASSWORD_REQUIRED_FOR_TWO_FACTOR`
449
+ * unless the server enables code-only enrollment: its sign-ins (email
450
+ * code, passkey, social) do not ask for the second factor yet.
451
+ */
452
+ enableTwoFactor(input: TwoFactorConfirmation & {
453
+ issuer?: string;
454
+ }, sessionToken: string): Promise<TwoFactorEnrollment & {
455
+ sessionToken: string;
456
+ }>;
457
+ /**
458
+ * Confirm enrollment with a code from the authenticator app. This is the
459
+ * call that turns two-factor on.
460
+ */
461
+ verifyTwoFactor(input: {
462
+ code: string;
463
+ }, sessionToken: string): Promise<{
464
+ sessionToken: string;
465
+ }>;
466
+ /** Turn two-factor off. Confirmed with the password, or an email code for accounts without one. */
467
+ disableTwoFactor(input: TwoFactorConfirmation, sessionToken: string): Promise<{
468
+ sessionToken: string;
469
+ }>;
470
+ /** Replace the backup codes. The old ones stop working. */
471
+ regenerateTwoFactorBackupCodes(input: TwoFactorConfirmation, sessionToken: string): Promise<{
472
+ backupCodes: string[];
473
+ }>;
278
474
  /**
279
475
  * The key-mint leg of the `*AndCreateKey` flows. When the mint fails, the
280
476
  * caller receives only the thrown error — the session created one step