@base44-preview/sdk 0.8.55-pr.345.357a9ca → 0.8.56-pr.346.ce5b5be

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/dist/client.js CHANGED
@@ -3,6 +3,7 @@ import { createEntitiesModule } from "./modules/entities.js";
3
3
  import { createIntegrationsModule } from "./modules/integrations.js";
4
4
  import { createAuthModule } from "./modules/auth.js";
5
5
  import { createSsoModule } from "./modules/sso.js";
6
+ import { createBrowserModule } from "./modules/browser.js";
6
7
  import { createConnectorsModule, createUserConnectorsModule, } from "./modules/connectors.js";
7
8
  import { getAccessToken } from "./utils/auth-utils.js";
8
9
  import { createFetchWithAuth } from "./utils/fetch-with-auth.js";
@@ -228,6 +229,7 @@ export function createClient(config) {
228
229
  }),
229
230
  integrations: createIntegrationsModule(serviceRoleAxiosClient, appId),
230
231
  sso: createSsoModule(serviceRoleAxiosClient, appId),
232
+ browser: createBrowserModule(serviceRoleAxiosClient),
231
233
  connectors: createConnectorsModule(serviceRoleAxiosClient, appId),
232
234
  functions: createFunctionsModule(serviceRoleFunctionsAxiosClient, appId, {
233
235
  getAuthHeaders: () => {
@@ -2,6 +2,7 @@ import type { EntitiesModule } from "./modules/entities.types.js";
2
2
  import type { IntegrationsModule } from "./modules/integrations.types.js";
3
3
  import type { AuthModule } from "./modules/auth.types.js";
4
4
  import type { SsoModule } from "./modules/sso.types.js";
5
+ import type { BrowserModule } from "./modules/browser.types.js";
5
6
  import type { PaymentsModule, ServiceRolePaymentsModule } from "./modules/payments.types.js";
6
7
  import type { ConnectorsModule, UserConnectorsModule } from "./modules/connectors.types.js";
7
8
  import type { FunctionsModule } from "./modules/functions.types.js";
@@ -228,6 +229,8 @@ export interface Base44Client {
228
229
  aiGateway: AiGatewayModule;
229
230
  /** {@link AppLogsModule | App logs module} with elevated permissions. */
230
231
  appLogs: AppLogsModule;
232
+ /** {@link BrowserModule | Browser module} for remote browser sessions. */
233
+ browser: BrowserModule;
231
234
  /** {@link ConnectorsModule | Connectors module} for OAuth token retrieval. */
232
235
  connectors: ConnectorsModule;
233
236
  /** {@link EntitiesModule | Entities module} with elevated permissions. */
package/dist/index.d.ts CHANGED
@@ -15,6 +15,7 @@ export type { AppModule, AppPublicSettings, AppPublicSettingsResponse, } from ".
15
15
  export type { ActorsModule, ActorClient, ActorRef, Connection, ActorSubscription, ActorConnectOptions, ActorNameRegistry, ActorRegistry, } from "./modules/actors.types.js";
16
16
  export type { SsoModule, SsoAccessTokenResponse } from "./modules/sso.types.js";
17
17
  export type { PaymentsModule, ServiceRolePaymentsModule, PaymentsErrorCode, PaymentsRecurringFrequency, CheckoutBuyer, CheckoutFreeTrial, CheckoutItem, CheckoutItemRecurring, CheckoutPresentation, CheckoutElement, CheckoutMount, MountableCheckout, CreateCheckoutParams, CreateCheckoutResult, CompleteCheckoutResult, EmbeddedCheckout, PayPalEmbeddedCheckout, StripeEmbeddedCheckout, MountCheckoutOptions, ListPurchasesParams, ServiceRoleListPurchasesParams, ListPurchasesResult, Purchase, PurchaseItem, PurchaseStatus, RefundParams, RefundResult, CancelSubscriptionOptions, SubscriptionResult, } from "./modules/payments.types.js";
18
+ export type { BrowserModule, BrowserSession, BrowserSessionOptions, } from "./modules/browser.types.js";
18
19
  export { Actor, type Conn } from "./actor.js";
19
20
  export type { ConnectorsModule, UserConnectorsModule, ConnectorApiRequest, ConnectorApiResponse, ConnectorApiResponsePhase, } from "./modules/connectors.types.js";
20
21
  export type { CustomIntegrationsModule, CustomIntegrationCallParams, CustomIntegrationCallResponse, } from "./modules/custom-integrations.types.js";
@@ -0,0 +1,10 @@
1
+ import { AxiosInstance } from "axios";
2
+ import { BrowserModule } from "./browser.types.js";
3
+ /**
4
+ * Creates the Browser module for the Base44 SDK.
5
+ *
6
+ * @param axios - Axios instance (should be service role client)
7
+ * @returns Browser module with methods to create and end remote browser sessions
8
+ * @internal
9
+ */
10
+ export declare function createBrowserModule(axios: AxiosInstance): BrowserModule;
@@ -0,0 +1,42 @@
1
+ /**
2
+ * Creates the Browser module for the Base44 SDK.
3
+ *
4
+ * @param axios - Axios instance (should be service role client)
5
+ * @returns Browser module with methods to create and end remote browser sessions
6
+ * @internal
7
+ */
8
+ export function createBrowserModule(axios) {
9
+ const endSession = async (sessionId) => {
10
+ if (!sessionId || typeof sessionId !== "string") {
11
+ throw new Error("Session ID is required and must be a string");
12
+ }
13
+ await axios.delete(`/v1/browser-sessions/${encodeURIComponent(sessionId)}`);
14
+ };
15
+ return {
16
+ async getSession(options = {}) {
17
+ var _a;
18
+ // The app is derived from the service token, so the route isn't app-scoped.
19
+ const response = await axios.post("/v1/browser-sessions", {
20
+ capture_debug_artifacts: (_a = options.captureDebugArtifacts) !== null && _a !== void 0 ? _a : true,
21
+ // Omit when unset so the backend applies its configured default.
22
+ ...(options.sessionTimeoutSeconds !== undefined && {
23
+ session_timeout_seconds: options.sessionTimeoutSeconds,
24
+ }),
25
+ });
26
+ const data = response;
27
+ return {
28
+ sessionId: data.session_id,
29
+ connectionUrl: data.connection_url,
30
+ connectionScope: data.connection_scope,
31
+ ...(data.connection_expires_at && {
32
+ connectionExpiresAt: data.connection_expires_at,
33
+ }),
34
+ ...(data.session_expires_at && {
35
+ sessionExpiresAt: data.session_expires_at,
36
+ }),
37
+ end: () => endSession(data.session_id),
38
+ };
39
+ },
40
+ endSession,
41
+ };
42
+ }
@@ -0,0 +1,130 @@
1
+ /**
2
+ * Options for {@linkcode BrowserModule.getSession | getSession()}.
3
+ */
4
+ export interface BrowserSessionOptions {
5
+ /**
6
+ * Whether to capture browser recordings and diagnostic logs for the session.
7
+ *
8
+ * Captured artifacts stay with the remote browser provider and can't be retrieved through the SDK. Defaults to `true`.
9
+ */
10
+ captureDebugArtifacts?: boolean;
11
+ /**
12
+ * Maximum lifetime of the session, in whole seconds.
13
+ *
14
+ * The session ends when the timeout expires, even if it's still in use. Base44 sets minimum and maximum allowed values and clamps the timeout to that range. When omitted, Base44 applies a default timeout.
15
+ */
16
+ sessionTimeoutSeconds?: number;
17
+ }
18
+ /**
19
+ * A remote browser session returned by {@linkcode BrowserModule.getSession | getSession()}.
20
+ */
21
+ export interface BrowserSession {
22
+ /**
23
+ * Opaque session identifier issued to your app.
24
+ *
25
+ * Pass it unchanged to {@linkcode BrowserModule.endSession | endSession()} to end the session from a different request.
26
+ */
27
+ sessionId: string;
28
+ /**
29
+ * Signed WebSocket URL for connecting to the browser over the Chrome DevTools Protocol (CDP).
30
+ *
31
+ * Treat the complete URL as a credential. Don't log it or send it to the frontend.
32
+ */
33
+ connectionUrl: string;
34
+ /**
35
+ * Scope of the CDP connection.
36
+ *
37
+ * - `'browser'`: The socket controls the whole browser.
38
+ * - `'page'`: The socket controls a single page.
39
+ */
40
+ connectionScope: "browser" | "page";
41
+ /** ISO 8601 timestamp when the connection URL expires. Omitted when the provider doesn't expose it. */
42
+ connectionExpiresAt?: string;
43
+ /** ISO 8601 timestamp when the browser session expires. Omitted when the provider doesn't expose it. */
44
+ sessionExpiresAt?: string;
45
+ /**
46
+ * Ends the session. Equivalent to calling {@linkcode BrowserModule.endSession | endSession()} with this session's ID.
47
+ */
48
+ end: () => Promise<void>;
49
+ }
50
+ /**
51
+ * Browser module for running browser automation from your backend.
52
+ *
53
+ * This module creates remote browser sessions that you can control with a CDP client library such as Playwright or Puppeteer. Base44 doesn't store browser state, so each session is independent. End each session when you're done with it. Otherwise it keeps running until its timeout expires. To change the timeout, pass the `sessionTimeoutSeconds` option to {@linkcode BrowserModule.getSession | getSession()}.
54
+ *
55
+ * This module is only available to use with a client in service role authentication mode, which means it can only be used in backend environments.
56
+ */
57
+ export interface BrowserModule {
58
+ /**
59
+ * Creates a new remote browser session and returns its connection details.
60
+ *
61
+ * Each call creates a fresh session. Calls aren't retried automatically, and repeating a failed call doesn't resume a previous session. Session creation is rate limited per app.
62
+ *
63
+ * @param options - Optional session settings.
64
+ * @returns Promise resolving to the new browser session.
65
+ *
66
+ * @example
67
+ * ```typescript
68
+ * // Open a page in a remote browser with Playwright
69
+ * import { createClientFromRequest } from 'npm:@base44/sdk';
70
+ * import { chromium } from 'npm:playwright-core';
71
+ *
72
+ * Deno.serve(async (req) => {
73
+ * const base44 = createClientFromRequest(req);
74
+ * const session = await base44.asServiceRole.browser.getSession();
75
+ *
76
+ * try {
77
+ * const browser = await chromium.connectOverCDP(session.connectionUrl);
78
+ * const page = browser.contexts()[0]?.pages()[0] ?? (await browser.newPage());
79
+ * await page.goto('https://example.com');
80
+ * const title = await page.title();
81
+ * await browser.close();
82
+ *
83
+ * return Response.json({ title });
84
+ * } finally {
85
+ * await session.end();
86
+ * }
87
+ * });
88
+ * ```
89
+ *
90
+ * @example
91
+ * ```typescript
92
+ * // Turn off recordings and diagnostic logs
93
+ * const session = await base44.asServiceRole.browser.getSession({
94
+ * captureDebugArtifacts: false,
95
+ * });
96
+ * ```
97
+ *
98
+ * @example
99
+ * ```typescript
100
+ * // Request a custom session timeout
101
+ * const session = await base44.asServiceRole.browser.getSession({
102
+ * sessionTimeoutSeconds: 600,
103
+ * });
104
+ * ```
105
+ */
106
+ getSession(options?: BrowserSessionOptions): Promise<BrowserSession>;
107
+ /**
108
+ * Ends a browser session created by your app.
109
+ *
110
+ * Use this when the session was created in a different request. Otherwise call `end()` on the session returned by {@linkcode getSession | getSession()}. Ending a session that has already ended succeeds, so it's safe to call more than once. The call fails with the `browser_session_not_found` error code if the ID wasn't issued to your app.
111
+ *
112
+ * @param sessionId - The `sessionId` returned by {@linkcode getSession | getSession()}, unchanged.
113
+ * @returns Promise that resolves when the session has ended.
114
+ *
115
+ * @example
116
+ * ```typescript
117
+ * // End a session whose ID was saved by an earlier request
118
+ * import { createClientFromRequest } from 'npm:@base44/sdk';
119
+ *
120
+ * Deno.serve(async (req) => {
121
+ * const base44 = createClientFromRequest(req);
122
+ * const { sessionId } = await req.json();
123
+ * await base44.asServiceRole.browser.endSession(sessionId);
124
+ *
125
+ * return new Response(null, { status: 204 });
126
+ * });
127
+ * ```
128
+ */
129
+ endSession(sessionId: string): Promise<void>;
130
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -81,7 +81,7 @@ export interface ConnectorApiRequest {
81
81
  export interface ConnectorApiResponse<T = unknown> {
82
82
  /** `true` only when the upstream API returned a 2xx status. Proxy and upstream errors are `false`. */
83
83
  success: boolean;
84
- /** How far the call progressed. Only `not_sent` proves the provider did not execute it. */
84
+ /** How far the call progressed. */
85
85
  phase: ConnectorApiResponsePhase;
86
86
  /** The upstream HTTP status code, or `null` when no response was received. */
87
87
  status: number | null;
@@ -702,6 +702,10 @@ export interface EntityHandler<T = any> {
702
702
  *
703
703
  * Permanently removes all records that match the provided query.
704
704
  *
705
+ * This isn't a transaction. Each record is deleted on its own, so if the call
706
+ * fails partway, the records already deleted stay deleted. Learn more about
707
+ * [concurrent updates](/developers/backend/resources/entities/entity-schemas#concurrent-updates).
708
+ *
705
709
  * @param query - Query matching {@linkcode EntityFilterQuery}. Every matching record is deleted.
706
710
  * @returns Promise resolving to the deletion result.
707
711
  *
@@ -722,6 +726,10 @@ export interface EntityHandler<T = any> {
722
726
  * Efficiently creates multiple records at once. This is faster
723
727
  * than creating them individually.
724
728
  *
729
+ * This isn't a transaction. Each record is written on its own, so if the call
730
+ * fails partway, the records already written stay written. Learn more about
731
+ * [concurrent updates](/developers/backend/resources/entities/entity-schemas#concurrent-updates).
732
+ *
725
733
  * @param data - Array of record data objects.
726
734
  * @returns Promise resolving to an array of created records.
727
735
  *
@@ -749,6 +757,15 @@ export interface EntityHandler<T = any> {
749
757
  * so you don't re-process the same entities on each iteration. For
750
758
  * example, filter by `status: 'pending'` when setting status to `'processed'`.
751
759
  *
760
+ * Each matching record is updated on its own, and the call isn't a transaction.
761
+ * To claim one record safely, so that only one of 2 users acting at the same
762
+ * time succeeds, pass that record's `id` as a plain value plus the conditions
763
+ * that must still be true, then check `updated` in the response. The conditions
764
+ * are only checked again at write time when the query names a single `id`. Any
765
+ * other query, including several IDs in `$in` or `$or`, finds the matching
766
+ * records first and then updates them. Learn more about
767
+ * [concurrent updates](/developers/backend/resources/entities/entity-schemas#concurrent-updates).
768
+ *
752
769
  * To update a single record by ID, use {@linkcode update | update()} instead. To update
753
770
  * multiple specific records with different data each, use {@linkcode bulkUpdate | bulkUpdate()}.
754
771
  *
@@ -808,6 +825,21 @@ export interface EntityHandler<T = any> {
808
825
  * hasMore = result.has_more;
809
826
  * }
810
827
  * ```
828
+ *
829
+ * @example
830
+ * ```typescript
831
+ * // Claim a record
832
+ * // Only one user can claim the task, even if several try at the same time
833
+ * const result = await base44.entities.Task.updateMany(
834
+ * { id: taskId, status: 'open' },
835
+ * { $set: { status: 'claimed', claimed_by: user.email } }
836
+ * );
837
+ * if (result.updated === 1) {
838
+ * // This user claimed the task
839
+ * } else {
840
+ * // Someone else claimed it first, or it was no longer open
841
+ * }
842
+ * ```
811
843
  */
812
844
  updateMany(query: Partial<T>, data: Record<string, Record<string, any>>): Promise<UpdateManyResult>;
813
845
  /**
@@ -919,6 +951,11 @@ export interface EntityHandler<T = any> {
919
951
  * key, the last one wins. Updates merge the given fields into the existing record, like
920
952
  * {@linkcode update | update()}.
921
953
  *
954
+ * This isn't a transaction. Each record is written on its own, so if the call
955
+ * fails partway, the records already written stay written. Concurrent calls with
956
+ * the same key can also create duplicate records. Learn more about
957
+ * [concurrent updates](/developers/backend/resources/entities/entity-schemas#concurrent-updates).
958
+ *
922
959
  * @param records - Array of record data objects. Each must carry a value, not an object or
923
960
  * array, for every field named in `options.key`, to find or create by. Other fields are
924
961
  * optional, and only the ones you include are merged into a matched record, like `update()`.
@@ -955,6 +992,10 @@ export interface EntityHandler<T = any> {
955
992
  *
956
993
  * You can update up to 500 records per request.
957
994
  *
995
+ * This isn't a transaction. Each record is written on its own, so if the call
996
+ * fails partway, the records already written stay written. Learn more about
997
+ * [concurrent updates](/developers/backend/resources/entities/entity-schemas#concurrent-updates).
998
+ *
958
999
  * To apply the same update to all records matching a query, use
959
1000
  * {@linkcode updateMany | updateMany()}. To update a single record by ID, use
960
1001
  * {@linkcode update | update()}.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@base44-preview/sdk",
3
- "version": "0.8.55-pr.345.357a9ca",
3
+ "version": "0.8.56-pr.346.ce5b5be",
4
4
  "description": "JavaScript SDK for Base44 API",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",