@base44-preview/sdk 0.8.48-pr.287.fd215cb → 0.8.48-pr.289.b9ea964

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/actor.d.ts CHANGED
@@ -25,8 +25,8 @@ export interface Storage {
25
25
  get<T>(key: string): Promise<T | undefined>;
26
26
  put(key: string, value: unknown): Promise<void>;
27
27
  delete(key: string): Promise<boolean>;
28
- /** Wipe the room's entire persisted storage (match-end cleanup). Safe: a
29
- * later rejoin re-bootstraps exactly like a brand-new room. */
28
+ /** Wipe the session's entire persisted storage. A later connection starts
29
+ * with the same empty storage as a new session. */
30
30
  deleteAll(): Promise<void>;
31
31
  }
32
32
  /**
package/dist/index.d.ts CHANGED
@@ -4,7 +4,7 @@ import { getAccessToken, saveAccessToken, removeAccessToken, getLoginUrl } from
4
4
  export { createClient, createClientFromRequest, Base44Error, getAccessToken, saveAccessToken, removeAccessToken, getLoginUrl, };
5
5
  export type { Base44Client, CreateClientAnalyticsConfig, CreateClientConfig, CreateClientOptions, Base44ErrorJSON, };
6
6
  export * from "./types.js";
7
- export type { DeleteManyResult, DeleteResult, EntitiesModule, EntityAggregateResult, EntityAggregateSpec, EntityDateBucketUnit, EntityDistinctOptions, EntityFilterOperators, EntityFilterQuery, EntityFilterValue, EntityHandler, EntityListOptions, EntityPage, EntityRecord, EntityTypeRegistry, EntityUpsertOptions, EntityUpsertResult, ImportResult, RealtimeEventType, RealtimeEvent, RealtimeCallback, SortField, UpdateManyResult, } from "./modules/entities.types.js";
7
+ export type { DeleteManyResult, DeleteResult, EntitiesModule, EntityFilterOperators, EntityFilterQuery, EntityFilterValue, EntityHandler, EntityRecord, EntityTypeRegistry, ImportResult, RealtimeEventType, RealtimeEvent, RealtimeCallback, SortField, UpdateManyResult, } from "./modules/entities.types.js";
8
8
  export type { AuthModule, LoginResponse, RegisterParams, VerifyOtpParams, ChangePasswordParams, ResetPasswordParams, User, } from "./modules/auth.types.js";
9
9
  export type { IntegrationsModule, IntegrationEndpointFunction, CoreIntegrations, InvokeLLMParams, GenerateImageParams, GenerateImageResult, UploadFileParams, UploadFileResult, SendEmailParams, SendEmailResult, ExtractDataFromUploadedFileParams, ExtractDataFromUploadedFileResult, UploadPrivateFileParams, UploadPrivateFileResult, CreateFileSignedUrlParams, CreateFileSignedUrlResult, } from "./modules/integrations.types.js";
10
10
  export type { FunctionsModule, FunctionName, FunctionNameRegistry, } from "./modules/functions.types.js";
@@ -1,9 +1,10 @@
1
1
  /**
2
- * Extend this interface to add typed `subscribe` callbacks and `send` payloads
3
- * for your deployed Actors.
2
+ * Maps actor names to their incoming and outgoing message types.
4
3
  *
5
- * This is separate from {@link ActorNameRegistry} (which is auto-generated
6
- * by `base44 types generate`), so there are no conflicts.
4
+ * Extend this interface through module augmentation when you want typed actor
5
+ * messages without generating types with the CLI. For each actor, `toServer`
6
+ * defines incoming messages that a client sends to the actor. `toClient` defines
7
+ * outgoing messages that the actor sends to connected clients.
7
8
  *
8
9
  * @example
9
10
  * ```typescript
@@ -20,8 +21,10 @@
20
21
  export interface ActorRegistry {
21
22
  }
22
23
  /**
23
- * Auto-populated by `base44 types generate` with the names of your deployed actors.
24
- * Do not edit this interface manually — use {@link ActorRegistry} for message types.
24
+ * Lists actor names when your project includes types generated by the CLI.
25
+ *
26
+ * The generated names provide autocomplete for deployed actors. To define
27
+ * incoming and outgoing message types manually, augment {@link ActorRegistry}.
25
28
  */
26
29
  export interface ActorNameRegistry {
27
30
  }
@@ -32,71 +35,163 @@ type ToClientFor<N extends string> = N extends keyof ActorRegistry ? ActorRegist
32
35
  type ToServerFor<N extends string> = N extends keyof ActorRegistry ? ActorRegistry[N] extends {
33
36
  toServer: infer O;
34
37
  } ? O : unknown : unknown;
35
- /** Options for {@link ActorRef.connect}. */
38
+ /**
39
+ * Options for {@link ActorRef.connect}.
40
+ */
36
41
  export interface ActorConnectOptions {
37
42
  /**
38
- * The connection id — becomes the actor's `conn.id`. Supply a stable value
39
- * (e.g. persisted per tab) so a reconnect reuses the same server-side
40
- * identity; omit for an auto-generated per-connection id.
43
+ * Connection ID that the actor receives as `conn.id`.
44
+ *
45
+ * Specify a stable value, such as a value persisted per client, so
46
+ * reconnections from that client reuse the same connection ID. Omit this property
47
+ * to generate an ID.
41
48
  */
42
49
  id?: string;
43
50
  }
44
- /** Handle for one listener registered via {@link Connection.subscribe}. */
51
+ /**
52
+ * Represents an outgoing-message listener registered with
53
+ * {@link Connection.subscribe}.
54
+ */
45
55
  export interface ActorSubscription {
46
- /** Remove this listener; other listeners and the socket stay live. */
56
+ /**
57
+ * Removes this listener. Other listeners and the socket stay open.
58
+ *
59
+ * @example
60
+ * ```typescript
61
+ * const sub = conn.subscribe((msg) => console.log(msg));
62
+ * sub.unsubscribe();
63
+ * ```
64
+ */
47
65
  unsubscribe(): void;
48
66
  }
49
67
  /**
50
- * A live connection to an actor instance, returned by {@link ActorRef.connect}.
51
- * `subscribe`/`send` are always valid — you only get a `Connection` once the
52
- * socket has been opened, so there's no pre-connect state to guard against.
68
+ * Represents a client's WebSocket connection to an actor session.
69
+ *
70
+ * {@link ActorRef.connect} returns this object while the socket connects.
71
+ * The socket buffers messages sent during connection setup until it opens.
53
72
  */
54
73
  export interface Connection<N extends string = string> {
55
- /** The connection id (the value the actor sees as `conn.id`). */
74
+ /** Connection ID that the actor receives as `conn.id`. */
56
75
  readonly id: string;
57
- /** Register a message listener. Multiple are allowed; returns a per-listener unsubscribe. */
76
+ /**
77
+ * Registers a listener for outgoing messages from the actor.
78
+ *
79
+ * You can register multiple listeners on the same connection.
80
+ *
81
+ * @param callback - Called with each outgoing message sent to this connection.
82
+ * @returns A handle you can use to remove this listener without closing the socket.
83
+ *
84
+ * @example
85
+ * ```typescript
86
+ * const conn = base44.actors.Chat("session-1").connect();
87
+ * const sub = conn.subscribe((msg) => {
88
+ * if (msg.type === "message") console.log(msg.text);
89
+ * });
90
+ * ```
91
+ */
58
92
  subscribe(callback: (data: ToClientFor<N>) => void): ActorSubscription;
59
- /** Send a message. Buffered by the socket until it's open; dropped after
60
- * {@link close}. */
93
+ /**
94
+ * Sends an incoming message to the actor.
95
+ *
96
+ * The socket buffers messages until it opens. After {@link close}, the socket
97
+ * drops further sends.
98
+ *
99
+ * @param data - Incoming message to send. Typed through {@link ActorRegistry} when configured.
100
+ *
101
+ * @example
102
+ * ```typescript
103
+ * conn.send({ type: "message", text: "Hello" });
104
+ * ```
105
+ */
61
106
  send(data: ToServerFor<N>): void;
62
107
  /**
63
- * Tear down the socket, heartbeat, and all listeners. Safe to call more
64
- * than once. A connection also closes itself when it fails permanently —
65
- * see {@link ActorRef.connect}.
108
+ * Closes the connection and removes all listeners.
109
+ *
110
+ * Safe to call more than once. A connection also closes itself when it fails
111
+ * permanently. See {@link ActorRef.connect} for how to open a fresh connection.
112
+ *
113
+ * @example
114
+ * ```typescript
115
+ * conn.close();
116
+ * ```
66
117
  */
67
118
  close(): void;
68
119
  }
69
120
  /**
70
- * A handle to one actor instance — `base44.actors.MyActor(id)`. Call
71
- * {@link connect} to open the socket and get a {@link Connection}.
121
+ * Represents an actor session selected by actor name and session ID.
122
+ *
123
+ * Call {@link connect} to open the WebSocket and get a {@link Connection}.
72
124
  */
73
125
  export interface ActorRef<N extends string = string> {
74
126
  /**
75
- * Open the WebSocket and return the {@link Connection}. Idempotent while the
76
- * connection is open.
127
+ * Creates or returns the {@link Connection} for this session.
128
+ *
129
+ * Repeated calls return the same connection until it closes. After a permanent
130
+ * failure, such as a missing actor or denied connection, fix the cause and call
131
+ * `connect()` again. Add subscriptions to the new connection.
77
132
  *
78
- * A connection that fails permanently (for example, the actor doesn't exist
79
- * or the caller isn't allowed to connect) closes itself and reports the
80
- * error to the client's `onError` handler. Call `connect()` again after
81
- * fixing the cause to get a fresh {@link Connection}, and re-subscribe.
133
+ * @param options - Optional connection settings, such as a stable connection ID.
134
+ * @returns The {@link Connection} for this actor session.
135
+ *
136
+ * @example
137
+ * ```typescript
138
+ * const conn = base44.actors.Chat("session-1").connect({ id: "tab-abc" });
139
+ * conn.subscribe((msg) => console.log(msg));
140
+ * ```
82
141
  */
83
142
  connect(options?: ActorConnectOptions): Connection<N>;
84
143
  }
85
144
  /**
86
- * Client for a single named Actor — call it with an instance id to get an
87
- * {@link ActorRef}. Typed automatically when the actor is registered in
88
- * {@link ActorRegistry}.
145
+ * Selects a session for a named actor.
146
+ *
147
+ * Typed automatically when the actor is registered in {@link ActorRegistry} or
148
+ * {@link ActorNameRegistry}.
89
149
  */
90
150
  export interface ActorClient<N extends string = string> {
151
+ /**
152
+ * Gets a reference to an actor session.
153
+ *
154
+ * Clients that specify the same actor name and session ID join the same session.
155
+ *
156
+ * @param instanceId - Session ID that identifies which session to connect to.
157
+ * @returns A reference to the actor session.
158
+ *
159
+ * @example
160
+ * ```typescript
161
+ * const session = base44.actors.Chat("lobby-1");
162
+ * const conn = session.connect();
163
+ * ```
164
+ */
91
165
  (instanceId: string): ActorRef<N>;
92
166
  }
93
167
  /**
94
- * The actors module provides access to Cloudflare Durable Object-backed
95
- * Actors deployed by the Base44 platform.
168
+ * Provides access to actors and their shared, live sessions.
169
+ *
170
+ * Select an actor by name and session ID, then connect a client to the
171
+ * session. Clients in the same session can exchange realtime messages through the
172
+ * actor. The client works in the browser and in Node.
173
+ *
174
+ * ## Connection flow
175
+ *
176
+ * - Connect to a session with `base44.actors.<ActorName>(sessionId).connect()`.
177
+ * - Subscribe to outgoing messages with {@link Connection.subscribe}.
178
+ * - Send incoming messages with {@link Connection.send}.
179
+ * - Close the connection with {@link Connection.close}.
96
180
  *
181
+ * See [Actors Overview](/developers/backend/resources/actors/overview)
182
+ * for actor concepts and terminology, and the [Actor Class Reference](/developers/backend/resources/actors/reference)
183
+ * for the backend class API.
184
+ *
185
+ * ## Authentication modes
186
+ *
187
+ * This module is available in anonymous or user authentication mode
188
+ * (`base44.actors`). It isn't available with service role authentication. Apps that
189
+ * require login can reject anonymous connections in the actor's `handleConnect()` method.
190
+ *
191
+ * @example
97
192
  * ```typescript
98
- * const conn = base44.actors.MyActor("room-1").connect();
99
- * const sub = conn.subscribe((msg) => console.log(msg)); // typed via ActorRegistry
193
+ * const conn = base44.actors.Chat("session-1").connect({ id: "tab-1" });
194
+ * const sub = conn.subscribe((msg) => console.log(msg));
100
195
  * conn.send({ type: "message", text: "hi" });
101
196
  * sub.unsubscribe();
102
197
  * conn.close();
@@ -41,10 +41,6 @@ function parseRealtimeMessage(dataStr) {
41
41
  return null;
42
42
  }
43
43
  }
44
- const DEFAULT_PAGE_LIMIT = 100;
45
- function isPageOptions(value) {
46
- return typeof value === "object" && value !== null;
47
- }
48
44
  /**
49
45
  * Creates a handler for a specific entity.
50
46
  *
@@ -57,51 +53,34 @@ function isPageOptions(value) {
57
53
  */
58
54
  function createEntityHandler(axios, appId, entityName, getSocket) {
59
55
  const baseURL = `/apps/${appId}/entities/${entityName}`;
60
- const fieldsParam = (fields) => Array.isArray(fields) ? fields.join(",") : fields;
61
- // GET /{entity}: the array form shared by list() and filter()
62
- const readArray = (sort, limit, skip, fields, query) => {
63
- const params = {};
64
- if (query)
65
- params.q = JSON.stringify(query);
66
- if (sort)
67
- params.sort = sort;
68
- if (limit)
69
- params.limit = limit;
70
- if (skip)
71
- params.skip = skip;
72
- if (fields)
73
- params.fields = fieldsParam(fields);
74
- return axios.get(baseURL, { params });
75
- };
76
- // GET /{entity}/v2/list: one cursor page of records or distinct values, shared by list(options) and filter(query, options)
77
- const readPage = (options, query) => {
78
- const params = {};
79
- if (query)
80
- params.q = JSON.stringify(query);
81
- params.limit = options.limit || DEFAULT_PAGE_LIMIT;
82
- if (options.cursor)
83
- params.cursor = options.cursor;
84
- if ("distinct" in options) {
85
- params.distinct = options.distinct;
86
- }
87
- else {
88
- if (options.sort)
89
- params.sort = options.sort;
90
- if (options.fields)
91
- params.fields = fieldsParam(options.fields);
92
- }
93
- return axios.get(`${baseURL}/v2/list`, { params });
94
- };
95
56
  return {
96
- // list(sort, limit, skip, fields) returns an array; list(options) returns one cursor page.
97
- async list(...args) {
98
- const [sort, limit, skip, fields] = args;
99
- return isPageOptions(sort) ? readPage(sort) : readArray(sort, limit, skip, fields);
100
- },
101
- // filter(query, sort, limit, skip, fields) returns an array; filter(query, options) returns one cursor page.
102
- async filter(query, ...args) {
103
- const [sort, limit, skip, fields] = args;
104
- return isPageOptions(sort) ? readPage(sort, query) : readArray(sort, limit, skip, fields, query);
57
+ // List entities with optional pagination and sorting
58
+ async list(sort, limit, skip, fields) {
59
+ const params = {};
60
+ if (sort)
61
+ params.sort = sort;
62
+ if (limit)
63
+ params.limit = limit;
64
+ if (skip)
65
+ params.skip = skip;
66
+ if (fields)
67
+ params.fields = Array.isArray(fields) ? fields.join(",") : fields;
68
+ return axios.get(baseURL, { params });
69
+ },
70
+ // Filter entities based on query
71
+ async filter(query, sort, limit, skip, fields) {
72
+ const params = {
73
+ q: JSON.stringify(query),
74
+ };
75
+ if (sort)
76
+ params.sort = sort;
77
+ if (limit)
78
+ params.limit = limit;
79
+ if (skip)
80
+ params.skip = skip;
81
+ if (fields)
82
+ params.fields = Array.isArray(fields) ? fields.join(",") : fields;
83
+ return axios.get(baseURL, { params });
105
84
  },
106
85
  // Get entity by ID
107
86
  async get(id) {
@@ -131,22 +110,6 @@ function createEntityHandler(axios, appId, entityName, getSocket) {
131
110
  async updateMany(query, data) {
132
111
  return axios.patch(`${baseURL}/update-many`, { query, data });
133
112
  },
134
- // Count entities matching a query
135
- async count(query) {
136
- const params = {};
137
- if (query)
138
- params.q = JSON.stringify(query);
139
- const result = await axios.get(`${baseURL}/count`, { params });
140
- return result.count;
141
- },
142
- // Server-side group-by aggregation
143
- async aggregate(spec) {
144
- return axios.post(`${baseURL}/aggregate`, spec);
145
- },
146
- // Create or update by a natural key
147
- async upsert(records, options) {
148
- return axios.post(`${baseURL}/upsert`, { records, key: options.key });
149
- },
150
113
  // Update multiple entities by ID, each with its own update data
151
114
  async bulkUpdate(data) {
152
115
  return axios.put(`${baseURL}/bulk`, data);
@@ -50,130 +50,6 @@ export interface UpdateManyResult {
50
50
  /** Whether there are more entities matching the query that were not updated in this batch. When `true`, call `updateMany` again with the same query to update the next batch. */
51
51
  has_more: boolean;
52
52
  }
53
- /**
54
- * Options object accepted by {@linkcode EntityHandler.list | list()} and
55
- * {@linkcode EntityHandler.filter | filter()} to read one cursor page.
56
- *
57
- * @typeParam T - Entity record type.
58
- * @typeParam K - The fields to include in each record.
59
- */
60
- export interface EntityListOptions<T, K extends keyof T = keyof T> {
61
- /** Sort parameter, such as `'-created_date'` for descending. Defaults to `'-created_date'`. */
62
- sort?: SortField<T>;
63
- /** Maximum number of records per page, up to 5,000. Defaults to 100. */
64
- limit?: number;
65
- /**
66
- * `next_cursor` from the previous page. Omit or pass `null` for the first page.
67
- *
68
- * The token carries the query, sort and fields of the walk, so a later page needs only
69
- * `cursor` and `limit`. Passing a different query, sort or fields with a cursor is an error.
70
- */
71
- cursor?: string | null;
72
- /** Array of field names to include in each record. Defaults to all fields. */
73
- fields?: K[];
74
- }
75
- /**
76
- * Options object accepted by {@linkcode EntityHandler.list | list()} and
77
- * {@linkcode EntityHandler.filter | filter()} to read the distinct values of one field
78
- * instead of records.
79
- *
80
- * @typeParam T - Entity record type.
81
- * @typeParam K - The field whose distinct values to read.
82
- */
83
- export interface EntityDistinctOptions<T, K extends keyof T = keyof T> {
84
- /** Field whose distinct values to return, in ascending order. Array fields contribute each element. */
85
- distinct: K;
86
- /** Maximum number of values per page, up to 1,000. Defaults to 100. */
87
- limit?: number;
88
- /** `next_cursor` from the previous page. Omit or pass `null` for the first page. The token carries the query and field. */
89
- cursor?: string | null;
90
- }
91
- /**
92
- * One page of records, returned by {@linkcode EntityHandler.list | list()} and
93
- * {@linkcode EntityHandler.filter | filter()} when called with an options object.
94
- *
95
- * @typeParam T - Record type of the items.
96
- */
97
- export interface EntityPage<T> {
98
- /** The page's records in the requested sort order, or the distinct values in ascending order. */
99
- items: T[];
100
- /** Pass as `cursor` to get the next page. `null` on the last page. */
101
- next_cursor: string | null;
102
- /** Whether records remain after this page. */
103
- has_more: boolean;
104
- }
105
- /**
106
- * Time unit for {@linkcode EntityAggregateSpec.dateBucket | dateBucket}.
107
- */
108
- export type EntityDateBucketUnit = "day" | "week" | "month" | "year";
109
- /**
110
- * Describes what {@linkcode EntityHandler.aggregate | aggregate()} computes.
111
- *
112
- * Name the fields to group by and the measures to compute; the server does the work and
113
- * returns one row per group. Field names are the entity's own field names.
114
- *
115
- * @typeParam T - Entity record type.
116
- */
117
- export interface EntityAggregateSpec<T> {
118
- /** Filter applied before grouping, in the same form {@linkcode EntityHandler.filter | filter()} accepts. Defaults to all records. */
119
- query?: EntityFilterQuery<T>;
120
- /** Field, or up to four fields, to group by. Omit to get one total row. */
121
- groupBy?: (keyof T & string) | (keyof T & string)[];
122
- /** Group by a time bucket of a date field. `created_date` and `updated_date` support every unit; date fields of your schema support `day`, `month` and `year`. */
123
- dateBucket?: {
124
- field: keyof T & string;
125
- unit: EntityDateBucketUnit;
126
- };
127
- /** Whether to include the number of records per group as `count`. Defaults to `true`. */
128
- count?: boolean;
129
- /** Field, or fields, to sum. Each appears in the rows as `sum_<field>`. */
130
- sum?: (keyof T & string) | (keyof T & string)[];
131
- /** Field, or fields, to average. Each appears in the rows as `avg_<field>`. */
132
- avg?: (keyof T & string) | (keyof T & string)[];
133
- /** Field, or fields, to take the minimum of. Each appears in the rows as `min_<field>`. */
134
- min?: (keyof T & string) | (keyof T & string)[];
135
- /** Field, or fields, to take the maximum of. Each appears in the rows as `max_<field>`. */
136
- max?: (keyof T & string) | (keyof T & string)[];
137
- /** Field whose distinct values to count per group, returned as `count_distinct_<field>`. */
138
- countDistinct?: keyof T & string;
139
- /** Filter on the computed fields, applied after grouping. For example `{ count: { $gt: 1 } }` keeps only duplicated groups. */
140
- having?: Record<string, any>;
141
- /** Computed or group field to sort the rows by, with a `-` prefix for descending. For example `'-count'`. */
142
- sort?: string;
143
- /** Maximum number of rows, up to 1,000. Defaults to 1,000. */
144
- limit?: number;
145
- }
146
- /**
147
- * Rows returned by {@linkcode EntityHandler.aggregate | aggregate()}.
148
- */
149
- export interface EntityAggregateResult {
150
- /** One row per group: the group fields by name, then `count`, `sum_<field>`, `avg_<field>`, `min_<field>`, `max_<field>` or `count_distinct_<field>`. */
151
- rows: Record<string, any>[];
152
- /** `true` when more groups exist than `limit` allowed. */
153
- truncated: boolean;
154
- }
155
- /**
156
- * Options for {@linkcode EntityHandler.upsert | upsert()}.
157
- *
158
- * @typeParam T - Entity record type.
159
- */
160
- export interface EntityUpsertOptions<T> {
161
- /** Field, or fields, that identify a record. A record whose key values match an existing record updates it; any other record is created. */
162
- key: (keyof T & string) | (keyof T & string)[];
163
- }
164
- /**
165
- * Result returned by {@linkcode EntityHandler.upsert | upsert()}.
166
- *
167
- * @typeParam T - Entity record type.
168
- */
169
- export interface EntityUpsertResult<T = any> {
170
- /** Number of records that were created. */
171
- created: number;
172
- /** Number of existing records that were updated. */
173
- updated: number;
174
- /** The written records, created and updated, as they now exist. */
175
- records: T[];
176
- }
177
53
  /**
178
54
  * Result returned when importing entities from a file.
179
55
  *
@@ -335,18 +211,14 @@ export interface EntityHandler<T = any> {
335
211
  * Retrieves all records of this type with support for sorting,
336
212
  * pagination, and field selection.
337
213
  *
338
- * **Note:** The maximum limit is 5,000 items per request. To read more than
339
- * one page, pass an {@linkcode EntityListOptions | options object} with a
340
- * `cursor` instead of `skip`: every page costs the same however deep you are,
341
- * and records deleted between pages never shift the boundary. `skip` is kept
342
- * for existing code and is deprecated for loops.
214
+ * **Note:** The maximum limit is 5,000 items per request.
343
215
  *
344
216
  * @typeParam K - The fields to include in the response. Defaults to all fields.
345
217
  * @param sort - Sort parameter, such as `'-created_date'` for descending. Defaults to `'-created_date'`.
346
- * @param limit - Maximum number of results to return. Defaults to `5000`.
347
- * @param skip - Number of results to skip for pagination. Defaults to `0`. Deprecated for loops; use a cursor.
218
+ * @param limit - Maximum number of results to return. Defaults to `50`.
219
+ * @param skip - Number of results to skip for pagination. Defaults to `0`.
348
220
  * @param fields - Array of field names to include in the response. Defaults to all fields.
349
- * @returns Promise resolving to an array of records with selected fields. When called with an options object, resolves instead to an {@linkcode EntityPage | EntityPage} with `items`, `next_cursor` and `has_more`; with a `distinct` option the items are the field's values.
221
+ * @returns Promise resolving to an array of records with selected fields.
350
222
  *
351
223
  * @example
352
224
  * ```typescript
@@ -372,39 +244,15 @@ export interface EntityHandler<T = any> {
372
244
  * // Get only specific fields
373
245
  * const fields = await base44.entities.MyEntity.list('-created_date', 10, 0, ['name', 'status']);
374
246
  * ```
375
- *
376
- * @example
377
- * ```typescript
378
- * // Walk every record with a cursor. Pass an options object instead of
379
- * // positional arguments to get a page with `next_cursor` and `has_more`.
380
- * let page = await base44.entities.MyEntity.list({ sort: '-created_date', limit: 1000 });
381
- * await exportRows(page.items);
382
- * while (page.has_more) {
383
- * page = await base44.entities.MyEntity.list({ cursor: page.next_cursor, limit: 1000 });
384
- * await exportRows(page.items);
385
- * }
386
- * ```
387
- *
388
- * @example
389
- * ```typescript
390
- * // Distinct values of one field, instead of records
391
- * const { items: categories } = await base44.entities.Product.list({ distinct: 'category' });
392
- * ```
393
247
  */
394
248
  list<K extends keyof T = keyof T>(sort?: SortField<T>, limit?: number, skip?: number, fields?: K[]): Promise<Pick<T, K>[]>;
395
- list<K extends keyof T>(options: EntityDistinctOptions<T, K>): Promise<EntityPage<T[K]>>;
396
- list<K extends keyof T = keyof T>(options: EntityListOptions<T, K>): Promise<EntityPage<Pick<T, K>>>;
397
249
  /**
398
250
  * Filters records based on a query.
399
251
  *
400
252
  * Retrieves records that match specific criteria with support for
401
253
  * sorting, pagination, and field selection.
402
254
  *
403
- * **Note:** The maximum limit is 5,000 items per request. To read more than
404
- * one page, pass an {@linkcode EntityListOptions | options object} with a
405
- * `cursor` instead of `skip`: every page costs the same however deep you are,
406
- * and records deleted between pages never shift the boundary. `skip` is kept
407
- * for existing code and is deprecated for loops.
255
+ * **Note:** The maximum limit is 5,000 items per request.
408
256
  *
409
257
  * @typeParam K - The fields to include in the response. Defaults to all fields.
410
258
  * @param query - Query object with field-value pairs. Each key should be a field name
@@ -413,10 +261,10 @@ export interface EntityHandler<T = any> {
413
261
  * for exact matches, `null` for null values, arrays as shorthand for matching any of the
414
262
  * provided values, or documented MongoDB query operators for advanced filtering.
415
263
  * @param sort - Sort parameter, such as `'-created_date'` for descending. Defaults to `'-created_date'`.
416
- * @param limit - Maximum number of results to return. Defaults to `5000`.
417
- * @param skip - Number of results to skip for pagination. Defaults to `0`. Deprecated for loops; use a cursor.
264
+ * @param limit - Maximum number of results to return. Defaults to `50`.
265
+ * @param skip - Number of results to skip for pagination. Defaults to `0`.
418
266
  * @param fields - Array of field names to include in the response. Defaults to all fields.
419
- * @returns Promise resolving to an array of filtered records with selected fields. When called with an options object, resolves instead to an {@linkcode EntityPage | EntityPage} with `items`, `next_cursor` and `has_more`; with a `distinct` option the items are the field's values.
267
+ * @returns Promise resolving to an array of filtered records with selected fields.
420
268
  *
421
269
  * @example
422
270
  * ```typescript
@@ -493,34 +341,8 @@ export interface EntityHandler<T = any> {
493
341
  * ['name', 'priority']
494
342
  * );
495
343
  * ```
496
- *
497
- * @example
498
- * ```typescript
499
- * // Walk all matching records with a cursor. Pass an options object as the
500
- * // second argument to get a page with `next_cursor` and `has_more`.
501
- * let page = await base44.entities.Order.filter(
502
- * { status: 'open' },
503
- * { sort: '-created_date', limit: 1000 }
504
- * );
505
- * await exportRows(page.items);
506
- * while (page.has_more) {
507
- * page = await base44.entities.Order.filter({ status: 'open' }, { cursor: page.next_cursor, limit: 1000 });
508
- * await exportRows(page.items);
509
- * }
510
- * ```
511
- *
512
- * @example
513
- * ```typescript
514
- * // Distinct values of one field among the matching records
515
- * const { items: agents } = await base44.entities.Order.filter(
516
- * { status: 'open' },
517
- * { distinct: 'agent_id' }
518
- * );
519
- * ```
520
344
  */
521
345
  filter<K extends keyof T = keyof T>(query: EntityFilterQuery<T>, sort?: SortField<T>, limit?: number, skip?: number, fields?: K[]): Promise<Pick<T, K>[]>;
522
- filter<K extends keyof T>(query: EntityFilterQuery<T>, options: EntityDistinctOptions<T, K>): Promise<EntityPage<T[K]>>;
523
- filter<K extends keyof T = keyof T>(query: EntityFilterQuery<T>, options: EntityListOptions<T, K>): Promise<EntityPage<Pick<T, K>>>;
524
346
  /**
525
347
  * Gets a single record by ID.
526
348
  *
@@ -727,111 +549,6 @@ export interface EntityHandler<T = any> {
727
549
  * ```
728
550
  */
729
551
  updateMany(query: Partial<T>, data: Record<string, Record<string, any>>): Promise<UpdateManyResult>;
730
- /**
731
- * Counts the records that match a query.
732
- *
733
- * Returns the number of records the current user can read, without fetching them.
734
- * Use it for totals, badges and "page N of M" instead of listing records and
735
- * measuring the array.
736
- *
737
- * @param query - Filter query, in the same form {@linkcode filter | filter()} accepts. Defaults to all records.
738
- * @returns Promise resolving to the number of matching records.
739
- *
740
- * @example
741
- * ```typescript
742
- * // How many tasks are still open?
743
- * const open = await base44.entities.Task.count({ status: 'open' });
744
- * ```
745
- *
746
- * @example
747
- * ```typescript
748
- * // Total records in the entity
749
- * const total = await base44.entities.Task.count();
750
- * ```
751
- */
752
- count(query?: EntityFilterQuery<T>): Promise<number>;
753
- /**
754
- * Computes counts, sums, averages, minimums, maximums or distinct counts, grouped by fields.
755
- *
756
- * Use it for dashboards, leaderboards and reports instead of loading every record
757
- * and adding up in the browser. The server groups the records you can read and
758
- * returns one row per group, up to 1,000 rows.
759
- *
760
- * @param spec - What to group by and what to compute. See {@linkcode EntityAggregateSpec | EntityAggregateSpec}.
761
- * @returns Promise resolving to the rows and a `truncated` flag.
762
- *
763
- * @example
764
- * ```typescript
765
- * // Sales per agent this month, biggest first
766
- * const { rows } = await base44.entities.Sale.aggregate({
767
- * query: { sale_date: { $gte: '2026-09-01' } },
768
- * groupBy: 'agent_id',
769
- * sum: 'amount',
770
- * sort: '-sum_amount'
771
- * });
772
- * // rows: [{ agent_id: 'a1', count: 42, sum_amount: 18250 }, ...]
773
- * ```
774
- *
775
- * @example
776
- * ```typescript
777
- * // Records created per day
778
- * const { rows } = await base44.entities.Visit.aggregate({
779
- * dateBucket: { field: 'created_date', unit: 'day' }
780
- * });
781
- * ```
782
- *
783
- * @example
784
- * ```typescript
785
- * // Find duplicated external ids
786
- * const { rows } = await base44.entities.Contact.aggregate({
787
- * groupBy: 'external_id',
788
- * having: { count: { $gt: 1 } }
789
- * });
790
- * ```
791
- *
792
- * @example
793
- * ```typescript
794
- * // Unique visitors per page
795
- * const { rows } = await base44.entities.PageView.aggregate({
796
- * groupBy: 'path',
797
- * countDistinct: 'session_id'
798
- * });
799
- * ```
800
- */
801
- aggregate(spec: EntityAggregateSpec<T>): Promise<EntityAggregateResult>;
802
- /**
803
- * Creates or updates records by a key of your own.
804
- *
805
- * Use this when you sync data from another system: name the field, or fields, that
806
- * identify a record, and the server updates the records whose key already exists and
807
- * creates the rest, in one call. You no longer need to list existing records to check
808
- * for duplicates before writing.
809
- *
810
- * You can upsert up to 500 records per request. When two records in one call share a
811
- * key, the last one wins. Updates merge the given fields into the existing record, like
812
- * {@linkcode update | update()}.
813
- *
814
- * @param records - Array of record data objects. Each must carry a value for every key field.
815
- * @param options - The key field or fields. See {@linkcode EntityUpsertOptions | EntityUpsertOptions}.
816
- * @returns Promise resolving to the counts and the written records.
817
- *
818
- * @example
819
- * ```typescript
820
- * // Sync contacts from a CRM by their CRM id
821
- * const result = await base44.entities.Contact.upsert(
822
- * crmContacts.map(c => ({ crm_id: c.id, name: c.name, email: c.email })),
823
- * { key: 'crm_id' }
824
- * );
825
- * console.log(`${result.created} new, ${result.updated} updated`);
826
- * ```
827
- *
828
- * @example
829
- * ```typescript
830
- * // Compound key
831
- * await base44.entities.Inventory.upsert(rows, { key: ['sku', 'warehouse'] });
832
- * ```
833
- */
834
- upsert(records: Partial<T>[], options: EntityUpsertOptions<T>): Promise<EntityUpsertResult<T>>;
835
552
  /**
836
553
  * Updates the specified records in a single request, each with its own data.
837
554
  *
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@base44-preview/sdk",
3
- "version": "0.8.48-pr.287.fd215cb",
3
+ "version": "0.8.48-pr.289.b9ea964",
4
4
  "description": "JavaScript SDK for Base44 API",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",