@recursiv/sdk 0.7.49 → 0.7.51

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.
@@ -9,9 +9,32 @@ export interface AppSubscriptionPortalResult {
9
9
  }
10
10
  export interface AppSubscriptionStatusResult {
11
11
  tier: string;
12
- status: 'active' | 'past_due' | 'canceled' | 'none';
12
+ /** 'legacy' is a membership carried over from a previous platform, with no subscription here. */
13
+ status: 'active' | 'past_due' | 'canceled' | 'none' | 'legacy';
13
14
  active: boolean;
14
15
  currentPeriodEnd: string | null;
16
+ /** Where the entitlement comes from: a Stripe subscription here, or the legacy import. */
17
+ source?: 'stripe' | 'legacy';
18
+ }
19
+ export interface AppSubscriptionTierChangePreview {
20
+ /** The plan the preview prices. */
21
+ tier: string;
22
+ /** The plan the member pays for now. */
23
+ currentTier: string;
24
+ /** Prorated charge (positive) or credit (negative) for the rest of this period, in minor units. */
25
+ prorationAmount: number;
26
+ /** What the next invoice totals with the change applied, in minor units. */
27
+ amountDue: number;
28
+ currency: string;
29
+ /** Pass to `changeTier` so the charge matches this preview exactly. */
30
+ prorationDate: number;
31
+ nextPaymentAt: string | null;
32
+ }
33
+ export interface AppSubscriptionTierChangeResult {
34
+ tier: string;
35
+ previousTier: string;
36
+ status: 'active' | 'past_due' | 'canceled';
37
+ currentPeriodEnd: string | null;
15
38
  }
16
39
  /**
17
40
  * Per-app-user consumer subscriptions (e.g. Plus/Pro) billed through the app's
@@ -20,13 +43,42 @@ export interface AppSubscriptionStatusResult {
20
43
  export declare class AppSubscriptionsResource {
21
44
  private client;
22
45
  constructor(client: HttpClient);
23
- /** Start a Stripe Checkout for the current user to subscribe to a plan tier ('plus' | 'pro'). */
46
+ /**
47
+ * Start a Stripe Checkout for the current user to subscribe to a plan tier ('plus' | 'pro').
48
+ * Answers 409 `subscription_exists` when the member already has a subscription:
49
+ * use `changeTier` for them instead, so they are never billed twice.
50
+ */
24
51
  checkout(input: {
25
52
  tier: string;
26
53
  return_url: string;
27
54
  }): Promise<{
28
55
  data: AppSubscriptionCheckoutResult;
29
56
  }>;
57
+ /**
58
+ * Price a switch of the current member's plan to `tier`, prorated, without changing anything.
59
+ * Errors (409) name why a switch cannot run: `no_subscription`, `already_on_tier`,
60
+ * `subscription_not_active`, `subscription_canceling`, `legacy_membership`.
61
+ */
62
+ previewTierChange(input: {
63
+ tier: string;
64
+ }): Promise<{
65
+ data: AppSubscriptionTierChangePreview;
66
+ }>;
67
+ /**
68
+ * Switch the current member's existing subscription to `tier`, prorated, in place.
69
+ * Never opens a second subscription. Pass `proration_date` from `previewTierChange`
70
+ * to charge exactly what the preview showed. A switch to a lower plan takes effect
71
+ * now: the unused time on the higher plan is credited, and that plan ends at once.
72
+ * Not retried automatically: on an
73
+ * unclear failure, read `status()` before trying again (a repeat answers 409
74
+ * `already_on_tier` rather than charging twice).
75
+ */
76
+ changeTier(input: {
77
+ tier: string;
78
+ proration_date?: number;
79
+ }): Promise<{
80
+ data: AppSubscriptionTierChangeResult;
81
+ }>;
30
82
  /** Open the current app user's Stripe Billing Portal for this project. */
31
83
  createPortalSession(input: {
32
84
  return_url: string;
@@ -7,10 +7,34 @@ 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
+ */
11
15
  checkout(input) {
12
16
  return this.client.post('/app-subscriptions/checkout', input);
13
17
  }
18
+ /**
19
+ * Price a switch of the current member's plan to `tier`, prorated, without changing anything.
20
+ * Errors (409) name why a switch cannot run: `no_subscription`, `already_on_tier`,
21
+ * `subscription_not_active`, `subscription_canceling`, `legacy_membership`.
22
+ */
23
+ previewTierChange(input) {
24
+ return this.client.get('/app-subscriptions/change-tier/preview', { tier: input.tier });
25
+ }
26
+ /**
27
+ * Switch the current member's existing subscription to `tier`, prorated, in place.
28
+ * Never opens a second subscription. Pass `proration_date` from `previewTierChange`
29
+ * to charge exactly what the preview showed. A switch to a lower plan takes effect
30
+ * now: the unused time on the higher plan is credited, and that plan ends at once.
31
+ * Not retried automatically: on an
32
+ * unclear failure, read `status()` before trying again (a repeat answers 409
33
+ * `already_on_tier` rather than charging twice).
34
+ */
35
+ changeTier(input) {
36
+ return this.client.post('/app-subscriptions/change-tier', input, { retry: false });
37
+ }
14
38
  /** Open the current app user's Stripe Billing Portal for this project. */
15
39
  createPortalSession(input) {
16
40
  return this.client.post('/app-subscriptions/portal', input);
@@ -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