@base44-preview/sdk 0.8.52-pr.298.d08e0ba → 0.8.52-pr.299.9f7108e

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
@@ -151,5 +151,3 @@ npm run create-docs
151
151
  cd docs
152
152
  mintlify dev
153
153
  ```
154
-
155
- See [experimental app-user MFA](MFA.md) for challenge handling and managed continuation.
package/dist/client.js CHANGED
@@ -11,6 +11,7 @@ import { createAgentsModule } from "./modules/agents.js";
11
11
  import { createAiGatewayModule } from "./modules/ai-gateway.js";
12
12
  import { createAppLogsModule } from "./modules/app-logs.js";
13
13
  import { createAppModule } from "./modules/app.js";
14
+ import { createMcpModule } from "./modules/mcp.js";
14
15
  import { createUsersModule } from "./modules/users.js";
15
16
  import { RoomsSocket } from "./utils/socket-utils.js";
16
17
  import { createAnalyticsModule } from "./modules/analytics.js";
@@ -201,6 +202,7 @@ export function createClient(config) {
201
202
  }),
202
203
  appLogs: createAppLogsModule(axiosClient, appId),
203
204
  app: createAppModule(axiosClient, appId),
205
+ mcp: createMcpModule(axiosClient, appId),
204
206
  users: createUsersModule(axiosClient, appId),
205
207
  analytics: createAnalyticsModule({
206
208
  axiosClient,
@@ -8,6 +8,7 @@ import type { AgentsModule } from "./modules/agents.types.js";
8
8
  import type { AiGatewayModule } from "./modules/ai-gateway.types.js";
9
9
  import type { AppLogsModule } from "./modules/app-logs.types.js";
10
10
  import type { AppModule } from "./modules/app.types.js";
11
+ import type { McpModule } from "./modules/mcp.types.js";
11
12
  import type { AnalyticsModule } from "./modules/analytics.types.js";
12
13
  import type { ActorsModule } from "./modules/actors.types.js";
13
14
  import type { FetchWithAuthInit } from "./utils/fetch-with-auth.js";
@@ -138,6 +139,8 @@ export interface Base44Client {
138
139
  functions: FunctionsModule;
139
140
  /** {@link IntegrationsModule | Integrations module} for calling pre-built integration endpoints. */
140
141
  integrations: IntegrationsModule;
142
+ /** {@link McpModule | MCP module} for the app's MCP consent page. */
143
+ mcp: McpModule;
141
144
  /** Cleanup function to disconnect WebSocket connections. Call when you're done with the client. */
142
145
  cleanup: () => void;
143
146
  /**
package/dist/index.d.ts CHANGED
@@ -12,10 +12,10 @@ export type { AgentsModule, AgentName, AgentNameRegistry, AgentConversation, Age
12
12
  export type { AiGatewayModule, AiGatewayConnection, AiGatewayConnectionOptions, } from "./modules/ai-gateway.types.js";
13
13
  export type { AppLogsModule } from "./modules/app-logs.types.js";
14
14
  export type { AppModule, AppPublicSettings, AppPublicSettingsResponse, } from "./modules/app.types.js";
15
+ export type { McpModule, McpConsentInfo, McpConsentTool, McpConsentAction, McpAuthorizeGrantResponse, } from "./modules/mcp.types.js";
15
16
  export type { ActorsModule, ActorClient, ActorRef, Connection, ActorSubscription, ActorConnectOptions, ActorNameRegistry, ActorRegistry, } from "./modules/actors.types.js";
16
17
  export type { SsoModule, SsoAccessTokenResponse } from "./modules/sso.types.js";
17
18
  export { Actor, type Conn } from "./actor.js";
18
19
  export type { ConnectorsModule, UserConnectorsModule, ConnectorApiRequest, ConnectorApiResponse, ConnectorApiResponsePhase, } from "./modules/connectors.types.js";
19
20
  export type { CustomIntegrationsModule, CustomIntegrationCallParams, CustomIntegrationCallResponse, } from "./modules/custom-integrations.types.js";
20
21
  export type { GetAccessTokenOptions, SaveAccessTokenOptions, RemoveAccessTokenOptions, GetLoginUrlOptions, } from "./utils/auth-utils.types.js";
21
- export type { MfaChallenge, MfaModule, MfaProof, LoginResult, MfaEnrollmentResult } from "./modules/mfa.js";
@@ -1,4 +1,3 @@
1
- import { createMfaModule, prepareMfaPkce } from "./mfa.js";
2
1
  import { resetAnalyticsSessionContext } from "./analytics.js";
3
2
  function isInsideIframe() {
4
3
  if (typeof window === "undefined")
@@ -20,9 +19,9 @@ function loginViaPopup(url, redirectUrl, expectedOrigin) {
20
19
  const height = 600;
21
20
  const left = Math.round(window.screenX + (window.outerWidth - width) / 2);
22
21
  const top = Math.round(window.screenY + (window.outerHeight - height) / 2);
23
- const popup = window.open("about:blank", "base44_auth", `width=${width},height=${height},left=${left},top=${top},resizable=yes,scrollbars=yes`);
22
+ const popup = window.open(url, "base44_auth", `width=${width},height=${height},left=${left},top=${top},resizable=yes,scrollbars=yes`);
24
23
  if (!popup) {
25
- return Promise.resolve();
24
+ return;
26
25
  }
27
26
  const cleanup = () => {
28
27
  window.removeEventListener("message", onMessage);
@@ -53,7 +52,6 @@ function loginViaPopup(url, redirectUrl, expectedOrigin) {
53
52
  cleanup();
54
53
  }, 500);
55
54
  window.addEventListener("message", onMessage);
56
- return url.then(value => { popup.location.href = value; }, error => { cleanup(); throw error; });
57
55
  }
58
56
  /**
59
57
  * Creates the auth module for the Base44 SDK.
@@ -84,8 +82,7 @@ export function createAuthModule(axios, functionsAxiosClient, appId, options) {
84
82
  // to the identity transitions below (`setToken`, `logout`) instead of to the
85
83
  // header a caller may have set on the instance directly.
86
84
  let hasAccessToken = Boolean(options.token);
87
- const module = {
88
- mfa: createMfaModule(axios, appId, token => module.setToken(token)),
85
+ return {
89
86
  hasToken() {
90
87
  return hasAccessToken;
91
88
  },
@@ -122,10 +119,9 @@ export function createAuthModule(axios, functionsAxiosClient, appId, options) {
122
119
  window.location.href = loginUrl;
123
120
  },
124
121
  // Redirects the user to a provider's login page
125
- async loginWithProvider(provider, fromUrl = "/") {
122
+ loginWithProvider(provider, fromUrl = "/") {
126
123
  // Build the full redirect URL
127
124
  const redirectUrl = new URL(fromUrl, window.location.origin).toString();
128
- const mfaPkce = provider === "sso" ? Promise.resolve("") : prepareMfaPkce(appId).then(value => `&app_mfa_code_challenge=${value}`);
129
125
  const queryParams = `app_id=${appId}&from_url=${encodeURIComponent(redirectUrl)}`;
130
126
  // SSO uses a different URL structure with appId in the path
131
127
  let authPath;
@@ -141,11 +137,11 @@ export function createAuthModule(axios, functionsAxiosClient, appId, options) {
141
137
  // When running inside an iframe, use a popup to avoid OAuth providers
142
138
  // blocking iframe navigation.
143
139
  if (isInsideIframe()) {
144
- const popupLoginUrl = mfaPkce.then(pkce => `${loginUrl}${pkce}&popup_origin=${encodeURIComponent(window.location.origin)}`);
140
+ const popupLoginUrl = `${loginUrl}&popup_origin=${encodeURIComponent(window.location.origin)}`;
145
141
  return loginViaPopup(popupLoginUrl, redirectUrl, window.location.origin);
146
142
  }
147
143
  // Default: full-page redirect
148
- window.location.href = loginUrl + await mfaPkce;
144
+ window.location.href = loginUrl;
149
145
  },
150
146
  // Logout the current user
151
147
  logout(redirectUrl) {
@@ -211,8 +207,6 @@ export function createAuthModule(axios, functionsAxiosClient, appId, options) {
211
207
  password,
212
208
  ...(turnstileToken && { turnstile_token: turnstileToken }),
213
209
  });
214
- if (response.mfa_required)
215
- return response;
216
210
  const { access_token, user } = response;
217
211
  if (access_token) {
218
212
  this.setToken(access_token);
@@ -284,5 +278,4 @@ export function createAuthModule(axios, functionsAxiosClient, appId, options) {
284
278
  });
285
279
  },
286
280
  };
287
- return module;
288
281
  }
@@ -1,4 +1,3 @@
1
- import type { LoginResult, MfaModule } from "./mfa.js";
2
1
  /**
3
2
  * An authenticated user.
4
3
  */
@@ -38,7 +37,6 @@ export interface User {
38
37
  * Response from login endpoints containing user information and access token.
39
38
  */
40
39
  export interface LoginResponse {
41
- mfa_required?: false;
42
40
  /** JWT access token for authentication. */
43
41
  access_token: string;
44
42
  /** User information. */
@@ -119,8 +117,6 @@ export interface AuthModuleOptions {
119
117
  * The auth module is only available in user authentication mode (`base44.auth`).
120
118
  */
121
119
  export interface AuthModule {
122
- /** Multi-factor enrollment and login for this app. */
123
- mfa: MfaModule;
124
120
  /**
125
121
  * Gets the current authenticated user's information.
126
122
  *
@@ -223,7 +219,7 @@ export interface AuthModule {
223
219
  * ```
224
220
  *
225
221
  */
226
- loginWithProvider(provider: string, fromUrl?: string): Promise<void>;
222
+ loginWithProvider(provider: string, fromUrl?: string): void;
227
223
  /**
228
224
  * Logs out the current user.
229
225
  *
@@ -306,7 +302,7 @@ export interface AuthModule {
306
302
  * );
307
303
  * ```
308
304
  */
309
- loginViaEmailPassword(email: string, password: string, turnstileToken?: string): Promise<LoginResult>;
305
+ loginViaEmailPassword(email: string, password: string, turnstileToken?: string): Promise<LoginResponse>;
310
306
  /**
311
307
  * Checks if the current user is authenticated.
312
308
  *
@@ -431,7 +427,7 @@ export interface AuthModule {
431
427
  * );
432
428
  * ```
433
429
  */
434
- verifyOtp(params: VerifyOtpParams): Promise<LoginResult>;
430
+ verifyOtp(params: VerifyOtpParams): Promise<any>;
435
431
  /**
436
432
  * Resends an OTP code to the user's email address.
437
433
  *
@@ -0,0 +1,11 @@
1
+ import { AxiosInstance } from "axios";
2
+ import { McpModule } from "./mcp.types";
3
+ /**
4
+ * Creates the MCP module for the Base44 SDK.
5
+ *
6
+ * @param axios - Axios instance
7
+ * @param appId - Application ID
8
+ * @returns MCP module for the app's MCP consent page
9
+ * @internal
10
+ */
11
+ export declare function createMcpModule(axios: AxiosInstance, appId: string): McpModule;
@@ -0,0 +1,20 @@
1
+ /**
2
+ * Creates the MCP module for the Base44 SDK.
3
+ *
4
+ * @param axios - Axios instance
5
+ * @param appId - Application ID
6
+ * @returns MCP module for the app's MCP consent page
7
+ * @internal
8
+ */
9
+ export function createMcpModule(axios, appId) {
10
+ return {
11
+ async getConsentInfo(ctx) {
12
+ return axios.get(`/apps/${appId}/mcp/consent-info`, {
13
+ params: { handle: ctx },
14
+ });
15
+ },
16
+ async authorizeGrant(ctx, action) {
17
+ return axios.post(`/apps/${appId}/mcp/authorize-grant`, { ctx, action });
18
+ },
19
+ };
20
+ }
@@ -0,0 +1,101 @@
1
+ /**
2
+ * One tool shown on the MCP consent page.
3
+ */
4
+ export interface McpConsentTool {
5
+ /** The tool's MCP name. */
6
+ name: string;
7
+ /** Human-readable title, when the tool has one. */
8
+ title?: string | null;
9
+ /** What the tool does. */
10
+ description?: string | null;
11
+ /** Whether the tool only reads data. */
12
+ read_only_hint?: boolean | null;
13
+ }
14
+ /**
15
+ * Display details for a pending MCP authorization request, as returned by
16
+ * {@link McpModule.getConsentInfo}.
17
+ */
18
+ export interface McpConsentInfo {
19
+ /** The app's display name. */
20
+ app_name: string;
21
+ /** The name of the AI client asking for access. */
22
+ client_name: string;
23
+ /**
24
+ * Whether the request came from a signed-in user of this app. When `false`,
25
+ * send the user to `login_path` before showing approve and deny.
26
+ */
27
+ authenticated: boolean;
28
+ /** The tools the client will be able to use. Empty unless `authenticated` is `true`. */
29
+ tools: McpConsentTool[];
30
+ /** The app's login route for a signed-out user, such as `/login`. */
31
+ login_path: string;
32
+ }
33
+ /**
34
+ * The user's decision on an MCP authorization request.
35
+ */
36
+ export type McpConsentAction = "approve" | "deny";
37
+ /**
38
+ * Result of {@link McpModule.authorizeGrant}.
39
+ */
40
+ export interface McpAuthorizeGrantResponse {
41
+ /**
42
+ * Where to send the browser next: the AI client's redirect URI, carrying the
43
+ * authorization code on approve or an `access_denied` error on deny. It may
44
+ * use a custom scheme such as `cursor://`.
45
+ */
46
+ redirect_url: string;
47
+ }
48
+ /**
49
+ * MCP module for the app's MCP consent page.
50
+ *
51
+ * When an AI client connects to the app's MCP server, Base44 sends the user to
52
+ * the app's consent page with an opaque `ctx` query parameter. The page reads
53
+ * the request's details with {@link McpModule.getConsentInfo | getConsentInfo()}
54
+ * and records the user's decision with {@link McpModule.authorizeGrant | authorizeGrant()}.
55
+ *
56
+ * ## Authentication Modes
57
+ *
58
+ * This module is available to use with a client in user authentication mode. The
59
+ * signed-in user's token is sent when the client has one; otherwise the app's
60
+ * session cookie identifies the user.
61
+ */
62
+ export interface McpModule {
63
+ /**
64
+ * Gets the display details for a pending MCP authorization request.
65
+ *
66
+ * Rejects with a {@linkcode Base44Error} with `status` `404` when the `ctx`
67
+ * handle is unknown or expired.
68
+ *
69
+ * @param ctx - The `ctx` query parameter the consent page was opened with.
70
+ * @returns Promise resolving to the request's display details.
71
+ *
72
+ * @example
73
+ * ```typescript
74
+ * const ctx = new URLSearchParams(window.location.search).get('ctx');
75
+ * const info = await base44.mcp.getConsentInfo(ctx);
76
+ * if (!info.authenticated) {
77
+ * window.location.href = info.login_path;
78
+ * }
79
+ * ```
80
+ */
81
+ getConsentInfo(ctx: string): Promise<McpConsentInfo>;
82
+ /**
83
+ * Records the signed-in user's decision on an MCP authorization request.
84
+ *
85
+ * The `ctx` handle is single-use. Rejects with a {@linkcode Base44Error}:
86
+ * `status` `401` when the user must sign in again (the handle is still valid),
87
+ * and `400`, `403`, `404` or `409` when the request can no longer be
88
+ * completed and the user must reconnect from the AI client.
89
+ *
90
+ * @param ctx - The `ctx` query parameter the consent page was opened with.
91
+ * @param action - `"approve"` to grant access, `"deny"` to refuse it.
92
+ * @returns Promise resolving to the URL to send the browser to.
93
+ *
94
+ * @example
95
+ * ```typescript
96
+ * const { redirect_url } = await base44.mcp.authorizeGrant(ctx, 'approve');
97
+ * window.location.href = redirect_url;
98
+ * ```
99
+ */
100
+ authorizeGrant(ctx: string, action: McpConsentAction): Promise<McpAuthorizeGrantResponse>;
101
+ }
@@ -0,0 +1 @@
1
+ export {};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@base44-preview/sdk",
3
- "version": "0.8.52-pr.298.d08e0ba",
3
+ "version": "0.8.52-pr.299.9f7108e",
4
4
  "description": "JavaScript SDK for Base44 API",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -1,52 +0,0 @@
1
- import type { AxiosInstance } from 'axios';
2
- import type { LoginResponse } from './auth.types.js';
3
- /** A restricted, short-lived login outcome. It is never an access token. */
4
- export interface MfaChallenge {
5
- mfa_required: true;
6
- next_step: 'enroll' | 'verify';
7
- mfa_methods: ('totp' | 'sms')[];
8
- mfa_session_token: string;
9
- expires_in_seconds: number;
10
- phone_hint?: string;
11
- access_token?: never;
12
- user?: never;
13
- }
14
- export type LoginResult = LoginResponse | MfaChallenge;
15
- export interface MfaEnrollmentResult extends LoginResponse {
16
- backup_codes?: string[];
17
- }
18
- export interface MfaProof {
19
- code: string;
20
- method: 'totp' | 'sms';
21
- remember_device?: boolean;
22
- }
23
- /** App-scoped MFA. Pass the challenge credential explicitly; do not set it as the SDK token. */
24
- export interface MfaModule {
25
- getStatus(): Promise<{
26
- mfa_enabled: boolean;
27
- methods: ('totp' | 'sms')[];
28
- backup_codes_remaining: number;
29
- policy: 'off' | 'required';
30
- }>;
31
- /** Requires an app admin session; resets a user in this app only. */
32
- resetForUser(appUserId: string): Promise<{
33
- success: true;
34
- }>;
35
- /** Open managed settings with fresh primary authentication and factor verification. */
36
- openSecurity(returnTo?: string): void;
37
- setupTotp(challenge: MfaChallenge): Promise<{
38
- secret: string;
39
- secret_formatted: string;
40
- qr_code: string;
41
- }>;
42
- sendSms(challenge: MfaChallenge, phoneNumber: string): Promise<unknown>;
43
- enrollTotp(challenge: MfaChallenge, code: string, rememberDevice?: boolean): Promise<MfaEnrollmentResult>;
44
- enrollSms(challenge: MfaChallenge, code: string, rememberDevice?: boolean): Promise<MfaEnrollmentResult>;
45
- verify(challenge: MfaChallenge, proof: MfaProof): Promise<LoginResponse>;
46
- verifyRecoveryCode(challenge: MfaChallenge, code: string, rememberDevice?: boolean): Promise<LoginResponse>;
47
- resendSms(challenge: MfaChallenge): Promise<unknown>;
48
- /** Open Base44's managed MFA flow on this app's origin. */
49
- continueLogin(challenge: MfaChallenge, returnTo?: string): Promise<void>;
50
- }
51
- export declare function prepareMfaPkce(appId: string): Promise<string>;
52
- export declare function createMfaModule(axios: AxiosInstance, appId: string, setToken: (token: string) => void): MfaModule;
@@ -1,43 +0,0 @@
1
- export async function prepareMfaPkce(appId) {
2
- const encode = (value) => btoa(String.fromCharCode(...value)).replace(/\+/g, '-').replace(/\//g, '_').replace(/=+$/, '');
3
- const verifier = encode(crypto.getRandomValues(new Uint8Array(32)));
4
- sessionStorage.setItem(`app-mfa-pkce:${appId}`, verifier);
5
- return encode(new Uint8Array(await crypto.subtle.digest('SHA-256', new TextEncoder().encode(verifier))));
6
- }
7
- export function createMfaModule(axios, appId, setToken) {
8
- const post = async (challenge, path, payload = {}) => {
9
- const response = await axios.post(`/apps/${appId}/auth/mfa${path}`, payload, {
10
- headers: { Authorization: `Bearer ${challenge.mfa_session_token}` }, withCredentials: true,
11
- });
12
- const token = response.access_token;
13
- if (token)
14
- setToken(token);
15
- return response;
16
- };
17
- return {
18
- getStatus: () => axios.get(`/apps/${appId}/auth/mfa/status`),
19
- resetForUser: appUserId => axios.post(`/apps/${appId}/auth/mfa/reset`, { app_user_id: appUserId }),
20
- openSecurity(returnTo = '/') {
21
- const target = new URL(returnTo, window.location.origin);
22
- if (target.origin !== window.location.origin)
23
- throw new Error('MFA must return to this app.');
24
- window.location.href = `/auth/mfa?${new URLSearchParams({ security: '1', from_url: target.pathname + target.search + target.hash })}`;
25
- },
26
- setupTotp: challenge => post(challenge, '/totp/setup'),
27
- sendSms: (challenge, phoneNumber) => post(challenge, '/sms/send-code', { phone_number: phoneNumber }),
28
- enrollTotp: (challenge, code, rememberDevice = false) => post(challenge, '/totp/verify', { code, remember_device: rememberDevice }),
29
- enrollSms: (challenge, code, rememberDevice = false) => post(challenge, '/sms/verify', { code, remember_device: rememberDevice }),
30
- verify: (challenge, proof) => post(challenge, '/verify', proof),
31
- verifyRecoveryCode: (challenge, code, rememberDevice = false) => post(challenge, '/verify-backup', { backup_code: code, remember_device: rememberDevice }),
32
- resendSms: challenge => post(challenge, '/resend'),
33
- async continueLogin(challenge, returnTo = '/') {
34
- const target = new URL(returnTo, window.location.origin);
35
- if (target.origin !== window.location.origin)
36
- throw new Error('MFA must return to this app.');
37
- const codeChallenge = await prepareMfaPkce(appId);
38
- const handoff = await post(challenge, '/handoff', { code_challenge: codeChallenge });
39
- const query = new URLSearchParams({ app_id: appId, mfa_code: handoff.code, from_url: target.pathname + target.search + target.hash });
40
- window.location.href = `/auth/mfa?${query}`;
41
- },
42
- };
43
- }