@base44-preview/sdk 0.8.52-pr.307.064de09 → 0.8.53-pr.308.2df7905

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/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, EntityAggregateResult, EntityAggregateSpec, EntityDateBucket, EntityDistinctOptions, EntityFilterOperators, EntityFilterQuery, EntityFilterValue, EntityHandler, EntityListOptions, EntityPage, EntityRecord, EntityTypeRegistry, EntityUpsertOptions, EntityUpsertResult, 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";
@@ -58,15 +58,15 @@ export interface UpdateManyResult {
58
58
  * @typeParam K - The fields to include in each record.
59
59
  */
60
60
  export interface EntityListOptions<T, K extends keyof T = keyof T> {
61
- /** Sort parameter, such as `'-created_date'` for descending. Defaults to `'-created_date'`. */
61
+ /** Sort parameter, such as `'-priority'` for descending. Defaults to `'-created_date'`. */
62
62
  sort?: SortField<T>;
63
63
  /** Maximum number of records per page, up to 5,000. Defaults to 100. */
64
64
  limit?: number;
65
65
  /**
66
- * `next_cursor` from the previous page. Omit or pass `null` for the first page.
66
+ * The `next_cursor` from the previous page. Omit or pass `null` for the first page.
67
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.
68
+ * The token carries this walk's parameters, so a later page needs only
69
+ * `cursor` and `limit`. Passing different parameters with a cursor is an error.
70
70
  */
71
71
  cursor?: string | null;
72
72
  /** Array of field names to include in each record. Defaults to all fields. */
@@ -81,49 +81,52 @@ export interface EntityListOptions<T, K extends keyof T = keyof T> {
81
81
  * @typeParam K - The field whose distinct values to read.
82
82
  */
83
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. */
84
+ /** Field whose distinct values to return, in ascending order. For an array field like `tags`, this returns the distinct individual tags used across records, not the distinct arrays. */
85
85
  distinct: K;
86
86
  /** Maximum number of values per page, up to 1,000. Defaults to 100. */
87
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. */
88
+ /** The `next_cursor` from the previous page. Omit or pass `null` for the first page. The token carries this lookup's parameters. */
89
89
  cursor?: string | null;
90
90
  }
91
91
  /**
92
- * One page of records, returned by {@linkcode EntityHandler.list | list()} and
93
- * {@linkcode EntityHandler.filter | filter()} when called with an options object.
92
+ * One page of items, with a cursor to continue.
94
93
  *
95
- * @typeParam T - Record type of the items.
94
+ * @typeParam T - Type of the items.
96
95
  */
97
96
  export interface EntityPage<T> {
98
- /** The page's records in the requested sort order, or the distinct values in ascending order. */
97
+ /** The page's items. Without `distinct`, these are records in the requested sort order. With `distinct`, these are that field's distinct values instead of records, in ascending order. */
99
98
  items: T[];
100
- /** Pass as `cursor` to get the next page. `null` on the last page. */
99
+ /** A cursor for the next page, or `null` on the last page. Pass it as `cursor` to keep paging. */
101
100
  next_cursor: string | null;
102
101
  /** Whether records remain after this page. */
103
102
  has_more: boolean;
104
103
  }
105
104
  /**
106
- * Time unit for {@linkcode EntityAggregateSpec.dateBucket | dateBucket}.
105
+ * A time bucket to group a date field by, for {@linkcode EntityAggregateSpec.dateBucket | dateBucket}.
106
+ *
107
+ * @typeParam T - Entity record type.
107
108
  */
108
- export type EntityDateBucketUnit = "day" | "week" | "month" | "year";
109
+ export interface EntityDateBucket<T> {
110
+ /** The date field to bucket by: `created_date`, `updated_date`, or a date field of your schema. */
111
+ field: keyof T & string;
112
+ /** Every date field supports `day`, `month` and `year`. The `created_date` and `updated_date` fields also support `week`. */
113
+ unit: "day" | "week" | "month" | "year";
114
+ }
109
115
  /**
110
116
  * Describes what {@linkcode EntityHandler.aggregate | aggregate()} computes.
111
117
  *
112
- * Name the fields to group by and the measures to compute; the server does the work and
118
+ * Name the fields to group by and the measures to compute, and the server does the work and
113
119
  * returns one row per group. Field names are the entity's own field names.
114
120
  *
115
121
  * @typeParam T - Entity record type.
116
122
  */
117
123
  export interface EntityAggregateSpec<T> {
118
- /** Filter applied before grouping, in the same form {@linkcode EntityHandler.filter | filter()} accepts. Defaults to all records. */
124
+ /** Filter applied before grouping, matching {@linkcode EntityFilterQuery}. Defaults to all records. */
119
125
  query?: EntityFilterQuery<T>;
120
126
  /** Field, or up to four fields, to group by. Omit to get one total row. */
121
127
  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
- };
128
+ /** Group by a time bucket of a date field. */
129
+ dateBucket?: EntityDateBucket<T>;
127
130
  /** Whether to include the number of records per group as `count`. Defaults to `true`. */
128
131
  count?: boolean;
129
132
  /** Field, or fields, to sum. Each appears in the rows as `sum_<field>`. */
@@ -134,9 +137,9 @@ export interface EntityAggregateSpec<T> {
134
137
  min?: (keyof T & string) | (keyof T & string)[];
135
138
  /** Field, or fields, to take the maximum of. Each appears in the rows as `max_<field>`. */
136
139
  max?: (keyof T & string) | (keyof T & string)[];
137
- /** Field whose distinct values to count per group, returned as `count_distinct_<field>`. */
140
+ /** Field whose distinct values to count per group, returned as `count_distinct_<field>`. Unlike `distinct` on `list()`/`filter()`, an array field here counts each whole array as one value, not its individual elements. */
138
141
  countDistinct?: keyof T & string;
139
- /** Filter on the computed fields, applied after grouping. For example `{ count: { $gt: 1 } }` keeps only duplicated groups. */
142
+ /** Filter applied to the computed fields after grouping, not to raw or `groupBy` fields. Supports `$eq`, `$ne`, `$gt`, `$gte`, `$lt`, `$lte`, `$in`, and `$nin`. With more than one key, a row is kept only when every key's condition holds. For example, grouped by `external_id`, `having: { count: { $gt: 1 } }` keeps only the external ids that appear in more than one record. */
140
143
  having?: Record<string, any>;
141
144
  /** Computed or group field to sort the rows by, with a `-` prefix for descending. For example `'-count'`. */
142
145
  sort?: string;
@@ -147,9 +150,9 @@ export interface EntityAggregateSpec<T> {
147
150
  * Rows returned by {@linkcode EntityHandler.aggregate | aggregate()}.
148
151
  */
149
152
  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>`. */
153
+ /** One row per group. Each row has the group fields by name, then `count`, `sum_<field>`, `avg_<field>`, `min_<field>`, `max_<field>` or `count_distinct_<field>`. */
151
154
  rows: Record<string, any>[];
152
- /** `true` when more groups exist than `limit` allowed. */
155
+ /** Set to `true` when more groups exist than `limit` allowed. */
153
156
  truncated: boolean;
154
157
  }
155
158
  /**
@@ -158,7 +161,7 @@ export interface EntityAggregateResult {
158
161
  * @typeParam T - Entity record type.
159
162
  */
160
163
  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. */
164
+ /** Field, or fields, that identify a record. A record whose key values match an existing record updates it, and any other record is created. */
162
165
  key: (keyof T & string) | (keyof T & string)[];
163
166
  }
164
167
  /**
@@ -208,19 +211,6 @@ export interface ImportResult<T = any> {
208
211
  * ```
209
212
  */
210
213
  export type SortField<T> = (keyof T & string) | `+${keyof T & string}` | `-${keyof T & string}`;
211
- /**
212
- * Entity filter query type system.
213
- *
214
- * `EntityFilterQuery<T>` keeps field names tied to the entity schema while
215
- * allowing Base44's documented filtering syntax. Each field can use an exact
216
- * value, `null`, an array shorthand for matching any listed value, or a
217
- * field-level operator object. Root-level `$and`, `$or`, and `$nor` combine
218
- * nested filter queries.
219
- *
220
- * Operator values are typed from the field they filter where possible. For
221
- * example, numeric fields accept numeric comparison values, string fields
222
- * accept `$regex`, and array fields accept `$all` and `$size`.
223
- */
224
214
  /**
225
215
  * Value accepted when filtering an entity field.
226
216
  *
@@ -262,12 +252,30 @@ type EntityFilterArrayOperators<T> = [
262
252
  $size?: number;
263
253
  };
264
254
  /**
265
- * Query object accepted by entity filtering methods.
255
+ * Query object accepted by {@linkcode EntityHandler.filter | filter()},
256
+ * {@linkcode EntityHandler.count | count()}, {@linkcode EntityHandler.deleteMany | deleteMany()},
257
+ * {@linkcode EntityHandler.updateMany | updateMany()}, and the `query` field of
258
+ * `EntityAggregateSpec`.
259
+ *
260
+ * Field keys are typed from the entity schema. Each field can use an exact value, `null`,
261
+ * an array shorthand for matching any of the listed values, or a field-level operator
262
+ * object. Root-level `$and`, `$or`, and `$nor` combine nested filter queries.
266
263
  *
267
- * Field keys are typed from the entity schema. `$and`, `$or`, and `$nor`
268
- * combine nested filter queries at the root level.
264
+ * Operator values are typed from the field they filter where possible. For example,
265
+ * numeric fields accept numeric comparison values, string fields accept `$regex`, and
266
+ * array fields accept `$all` and `$size`.
269
267
  *
270
268
  * @typeParam T - Entity record type.
269
+ *
270
+ * @example
271
+ * ```typescript
272
+ * // Exact match, a comparison operator, and a nested $or
273
+ * const query: EntityFilterQuery<Task> = {
274
+ * status: 'open',
275
+ * priority: { $gte: 3 },
276
+ * $or: [{ assignee: 'me' }, { team: 'core' }]
277
+ * };
278
+ * ```
271
279
  */
272
280
  export type EntityFilterQuery<T> = {
273
281
  [K in keyof T]?: EntityFilterValue<T[K]>;
@@ -330,23 +338,81 @@ export type EntityRecord = {
330
338
  */
331
339
  export interface EntityHandler<T = any> {
332
340
  /**
333
- * Lists records with optional pagination and sorting.
341
+ * Lists one cursor page of records, sorted and optionally field-selected.
342
+ *
343
+ * Pass `cursor` from the previous page's `next_cursor` to keep paging, or omit it
344
+ * for the first page. Records added or deleted between pages never shift the boundary.
345
+ *
346
+ * @typeParam K - The fields to include in each record. Defaults to all fields.
347
+ * @param options - Paging options.
348
+ * @returns Promise resolving to a page of records.
349
+ *
350
+ * @example
351
+ * ```typescript
352
+ * // Get one page of records
353
+ * const page = await base44.entities.MyEntity.list({ limit: 10 });
354
+ * console.log(page.items);
355
+ * ```
356
+ *
357
+ * @example
358
+ * ```typescript
359
+ * // Sort records
360
+ * const page = await base44.entities.MyEntity.list({ sort: '-priority', limit: 10 });
361
+ * ```
362
+ *
363
+ * @example
364
+ * ```typescript
365
+ * // Only return specific fields
366
+ * const page = await base44.entities.MyEntity.list({ fields: ['name', 'status'], limit: 10 });
367
+ * ```
368
+ *
369
+ * @example
370
+ * ```typescript
371
+ * // Walk every record with a cursor
372
+ * const allItems = [];
373
+ * let page = await base44.entities.MyEntity.list({ sort: '-created_date', limit: 1000 });
374
+ * allItems.push(...page.items);
375
+ * while (page.has_more) {
376
+ * page = await base44.entities.MyEntity.list({ cursor: page.next_cursor, limit: 1000 });
377
+ * allItems.push(...page.items);
378
+ * }
379
+ * ```
380
+ */
381
+ list<K extends keyof T = keyof T>(options: EntityListOptions<T, K>): Promise<EntityPage<Pick<T, K>>>;
382
+ /**
383
+ * Lists one cursor page of a single field's distinct values, instead of records.
334
384
  *
335
- * Retrieves all records of this type with support for sorting,
336
- * pagination, and field selection.
385
+ * @typeParam K - The field whose distinct values to read.
386
+ * @param options - Paging options naming the field to read.
387
+ * @returns Promise resolving to a page of distinct values.
337
388
  *
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.
389
+ * @example
390
+ * ```typescript
391
+ * // Regular field
392
+ * const { items: categories } = await base44.entities.Product.list({ distinct: 'category' });
393
+ * // categories: ['books', 'electronics', 'toys']
394
+ * ```
395
+ *
396
+ * @example
397
+ * ```typescript
398
+ * // Array field
399
+ * // Each tag counts once, not each array
400
+ * const { items: tags } = await base44.entities.Product.list({ distinct: 'tags' });
401
+ * // tags: ['bestseller', 'clearance', 'new']
402
+ * ```
403
+ */
404
+ list<K extends keyof T>(options: EntityDistinctOptions<T, K>): Promise<EntityPage<T[K]>>;
405
+ /**
406
+ * Lists records as an array, using `skip` for pagination.
407
+ *
408
+ * Kept for existing code. Prefer a cursor for pagination instead.
343
409
  *
344
410
  * @typeParam K - The fields to include in the response. Defaults to all fields.
345
- * @param sort - Sort parameter, such as `'-created_date'` for descending. Defaults to `'-created_date'`.
411
+ * @param sort - Sort parameter, such as `'-priority'` for descending. Defaults to `'-created_date'`.
346
412
  * @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.
413
+ * @param skip - Number of results to skip for pagination. Defaults to `0`. Prefer a cursor for loops instead.
348
414
  * @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.
415
+ * @returns Promise resolving to an array of records with selected fields.
350
416
  *
351
417
  * @example
352
418
  * ```typescript
@@ -372,51 +438,101 @@ export interface EntityHandler<T = any> {
372
438
  * // Get only specific fields
373
439
  * const fields = await base44.entities.MyEntity.list('-created_date', 10, 0, ['name', 'status']);
374
440
  * ```
441
+ */
442
+ list<K extends keyof T = keyof T>(sort?: SortField<T>, limit?: number, skip?: number, fields?: K[]): Promise<Pick<T, K>[]>;
443
+ /**
444
+ * Filters and returns one cursor page of matching records, sorted and
445
+ * optionally field-selected.
446
+ *
447
+ * Pass `cursor` from the previous page's `next_cursor` to keep paging, or omit it
448
+ * for the first page. Records added or deleted between pages never shift the boundary.
449
+ *
450
+ * @typeParam K - The fields to include in each record. Defaults to all fields.
451
+ * @param query - Query matching {@linkcode EntityFilterQuery}. Field names are
452
+ * case-sensitive, and records matching every field are returned.
453
+ * @param options - Paging options.
454
+ * @returns Promise resolving to a page of matching records.
375
455
  *
376
456
  * @example
377
457
  * ```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);
458
+ * // Get one page of matching records
459
+ * const page = await base44.entities.Order.filter({ status: 'open' }, { limit: 10 });
460
+ * console.log(page.items);
461
+ * ```
462
+ *
463
+ * @example
464
+ * ```typescript
465
+ * // Sort matching records
466
+ * const page = await base44.entities.Order.filter({ status: 'open' }, { sort: '-priority', limit: 10 });
467
+ * ```
468
+ *
469
+ * @example
470
+ * ```typescript
471
+ * // Only return specific fields
472
+ * const page = await base44.entities.Order.filter({ status: 'open' }, { fields: ['status', 'region'], limit: 10 });
473
+ * ```
474
+ *
475
+ * @example
476
+ * ```typescript
477
+ * // Walk all matching records with a cursor
478
+ * const allOrders = [];
479
+ * let page = await base44.entities.Order.filter(
480
+ * { status: 'open' },
481
+ * { sort: '-created_date', limit: 1000 }
482
+ * );
483
+ * allOrders.push(...page.items);
382
484
  * while (page.has_more) {
383
- * page = await base44.entities.MyEntity.list({ cursor: page.next_cursor, limit: 1000 });
384
- * await exportRows(page.items);
485
+ * page = await base44.entities.Order.filter({ status: 'open' }, { cursor: page.next_cursor, limit: 1000 });
486
+ * allOrders.push(...page.items);
385
487
  * }
386
488
  * ```
489
+ */
490
+ filter<K extends keyof T = keyof T>(query: EntityFilterQuery<T>, options: EntityListOptions<T, K>): Promise<EntityPage<Pick<T, K>>>;
491
+ /**
492
+ * Filters and returns one cursor page of a single field's distinct values
493
+ * among matching records.
494
+ *
495
+ * @typeParam K - The field whose distinct values to read.
496
+ * @param query - Query matching {@linkcode EntityFilterQuery}. Field names are
497
+ * case-sensitive, and records matching every field are returned.
498
+ * @param options - Paging options naming the field to read.
499
+ * @returns Promise resolving to a page of distinct values.
387
500
  *
388
501
  * @example
389
502
  * ```typescript
390
- * // Distinct values of one field, instead of records
391
- * const { items: categories } = await base44.entities.Product.list({ distinct: 'category' });
503
+ * // Regular field
504
+ * const { items: regions } = await base44.entities.Order.filter(
505
+ * { status: 'open' },
506
+ * { distinct: 'region' }
507
+ * );
508
+ * // regions: ['east', 'north', 'west']
509
+ * ```
510
+ *
511
+ * @example
512
+ * ```typescript
513
+ * // Array field
514
+ * // Each tag counts once, not each array
515
+ * const { items: tags } = await base44.entities.Order.filter(
516
+ * { status: 'open' },
517
+ * { distinct: 'tags' }
518
+ * );
519
+ * // tags: ['gift', 'international', 'rush']
392
520
  * ```
393
521
  */
394
- 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>>>;
522
+ filter<K extends keyof T>(query: EntityFilterQuery<T>, options: EntityDistinctOptions<T, K>): Promise<EntityPage<T[K]>>;
397
523
  /**
398
- * Filters records based on a query.
399
- *
400
- * Retrieves records that match specific criteria with support for
401
- * sorting, pagination, and field selection.
524
+ * Filters records as an array, using `skip` for pagination.
402
525
  *
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.
526
+ * Kept for existing code. Prefer a cursor for pagination instead.
408
527
  *
409
528
  * @typeParam K - The fields to include in the response. Defaults to all fields.
410
- * @param query - Query object with field-value pairs. Each key should be a field name
411
- * from your entity schema, and each value is the criteria to match. Records matching all
412
- * specified criteria are returned. Field names are case-sensitive. Use field-value pairs
413
- * for exact matches, `null` for null values, arrays as shorthand for matching any of the
414
- * provided values, or documented MongoDB query operators for advanced filtering.
415
- * @param sort - Sort parameter, such as `'-created_date'` for descending. Defaults to `'-created_date'`.
529
+ * @param query - Query matching {@linkcode EntityFilterQuery}. Field names are
530
+ * case-sensitive, and records matching every field are returned.
531
+ * @param sort - Sort parameter, such as `'-priority'` for descending. Defaults to `'-created_date'`.
416
532
  * @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.
533
+ * @param skip - Number of results to skip for pagination. Defaults to `0`. Prefer a cursor for loops instead.
418
534
  * @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.
535
+ * @returns Promise resolving to an array of filtered records with selected fields.
420
536
  *
421
537
  * @example
422
538
  * ```typescript
@@ -493,34 +609,8 @@ export interface EntityHandler<T = any> {
493
609
  * ['name', 'priority']
494
610
  * );
495
611
  * ```
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
612
  */
521
613
  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
614
  /**
525
615
  * Gets a single record by ID.
526
616
  *
@@ -612,9 +702,7 @@ export interface EntityHandler<T = any> {
612
702
  *
613
703
  * Permanently removes all records that match the provided query.
614
704
  *
615
- * @param query - Query object with field-value pairs. Each key should be a field name
616
- * from your entity schema, and each value is the criteria to match. Records matching all
617
- * specified criteria will be deleted. Field names are case-sensitive.
705
+ * @param query - Query matching {@linkcode EntityFilterQuery}. Every matching record is deleted.
618
706
  * @returns Promise resolving to the deletion result.
619
707
  *
620
708
  * @example
@@ -664,12 +752,7 @@ export interface EntityHandler<T = any> {
664
752
  * To update a single record by ID, use {@linkcode update | update()} instead. To update
665
753
  * multiple specific records with different data each, use {@linkcode bulkUpdate | bulkUpdate()}.
666
754
  *
667
- * @param query - Query object to filter which records to update. Use field-value
668
- * pairs for exact matches, or
669
- * [MongoDB query operators](https://www.mongodb.com/docs/manual/reference/operator/query/)
670
- * for advanced filtering. Supported query operators include `$eq`, `$ne`, `$gt`,
671
- * `$gte`, `$lt`, `$lte`, `$in`, `$nin`, `$and`, `$or`, `$not`, `$nor`,
672
- * `$exists`, `$regex`, `$all`, `$elemMatch`, and `$size`.
755
+ * @param query - Query matching {@linkcode EntityFilterQuery}, selecting which records to update.
673
756
  * @param data - Update operation object containing one or more
674
757
  * [MongoDB update operators](https://www.mongodb.com/docs/manual/reference/operator/update/).
675
758
  * Each field may only appear in one operator per call.
@@ -731,23 +814,30 @@ export interface EntityHandler<T = any> {
731
814
  * Counts the records that match a query.
732
815
  *
733
816
  * 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.
817
+ * Use it for totals, badges and "page N of M".
736
818
  *
737
- * @param query - Filter query, in the same form {@linkcode filter | filter()} accepts. Defaults to all records.
819
+ * @param query - Query matching {@linkcode EntityFilterQuery}. Defaults to all records.
738
820
  * @returns Promise resolving to the number of matching records.
739
821
  *
740
822
  * @example
741
823
  * ```typescript
742
- * // How many tasks are still open?
824
+ * // Count matching records
743
825
  * const open = await base44.entities.Task.count({ status: 'open' });
744
826
  * ```
745
827
  *
746
828
  * @example
747
829
  * ```typescript
748
- * // Total records in the entity
830
+ * // Count all records
749
831
  * const total = await base44.entities.Task.count();
750
832
  * ```
833
+ *
834
+ * @example
835
+ * ```typescript
836
+ * // Page N of M
837
+ * const pageSize = 20;
838
+ * const total = await base44.entities.Task.count({ status: 'open' });
839
+ * const totalPages = Math.ceil(total / pageSize);
840
+ * ```
751
841
  */
752
842
  count(query?: EntityFilterQuery<T>): Promise<number>;
753
843
  /**
@@ -757,7 +847,7 @@ export interface EntityHandler<T = any> {
757
847
  * and adding up in the browser. The server groups the records you can read and
758
848
  * returns one row per group, up to 1,000 rows.
759
849
  *
760
- * @param spec - What to group by and what to compute. See {@linkcode EntityAggregateSpec | EntityAggregateSpec}.
850
+ * @param spec - What to group by and what to compute.
761
851
  * @returns Promise resolving to the rows and a `truncated` flag.
762
852
  *
763
853
  * @example
@@ -769,58 +859,78 @@ export interface EntityHandler<T = any> {
769
859
  * sum: 'amount',
770
860
  * sort: '-sum_amount'
771
861
  * });
772
- * // rows: [{ agent_id: 'a1', count: 42, sum_amount: 18250 }, ...]
862
+ * // rows: [
863
+ * // { agent_id: 'a1', count: 42, sum_amount: 18250 },
864
+ * // { agent_id: 'a2', count: 37, sum_amount: 15400 },
865
+ * // ...
866
+ * // ]
773
867
  * ```
774
868
  *
775
869
  * @example
776
870
  * ```typescript
777
- * // Records created per day
778
- * const { rows } = await base44.entities.Visit.aggregate({
871
+ * // Tasks created per day
872
+ * const { rows } = await base44.entities.Task.aggregate({
779
873
  * dateBucket: { field: 'created_date', unit: 'day' }
780
874
  * });
875
+ * // rows: [
876
+ * // { created_date: '2026-09-01', count: 8 },
877
+ * // { created_date: '2026-09-02', count: 11 },
878
+ * // ...
879
+ * // ]
781
880
  * ```
782
881
  *
783
882
  * @example
784
883
  * ```typescript
785
884
  * // Find duplicated external ids
786
- * const { rows } = await base44.entities.Contact.aggregate({
885
+ * const { rows } = await base44.entities.Order.aggregate({
787
886
  * groupBy: 'external_id',
788
887
  * having: { count: { $gt: 1 } }
789
888
  * });
889
+ * // rows: [
890
+ * // { external_id: 'ext-42', count: 3 },
891
+ * // { external_id: 'ext-77', count: 2 }
892
+ * // ]
790
893
  * ```
791
894
  *
792
895
  * @example
793
896
  * ```typescript
794
- * // Unique visitors per page
795
- * const { rows } = await base44.entities.PageView.aggregate({
796
- * groupBy: 'path',
797
- * countDistinct: 'session_id'
897
+ * // Unique customers per product
898
+ * const { rows } = await base44.entities.Order.aggregate({
899
+ * groupBy: 'product_id',
900
+ * countDistinct: 'customer_id'
798
901
  * });
902
+ * // rows: [
903
+ * // { product_id: 'p1', count_distinct_customer_id: 86 },
904
+ * // { product_id: 'p2', count_distinct_customer_id: 34 }
905
+ * // ]
799
906
  * ```
800
907
  */
801
908
  aggregate(spec: EntityAggregateSpec<T>): Promise<EntityAggregateResult>;
802
909
  /**
803
- * Creates or updates records by a key of your own.
910
+ * Creates or updates records by a key you define, instead of by `id`.
804
911
  *
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.
912
+ * Use this whenever records have a natural key, such as an ID from another system or a
913
+ * one-per-user record keyed by `user_id`, so you don't have to look up each record first
914
+ * to decide between create and update. Name the field, or fields, that identify a record,
915
+ * and the server updates the records whose key already exists and creates the rest, in
916
+ * one call.
809
917
  *
810
918
  * You can upsert up to 500 records per request. When two records in one call share a
811
919
  * key, the last one wins. Updates merge the given fields into the existing record, like
812
920
  * {@linkcode update | update()}.
813
921
  *
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}.
922
+ * @param records - Array of record data objects. Each must carry a value, not an object or
923
+ * array, for every field named in `options.key`, to find or create by. Other fields are
924
+ * optional, and only the ones you include are merged into a matched record, like `update()`.
925
+ * @param options - The key field or fields.
816
926
  * @returns Promise resolving to the counts and the written records.
817
927
  *
818
928
  * @example
819
929
  * ```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' }
930
+ * // Sync by sku
931
+ * const result = await base44.entities.Product.upsert(
932
+ * supplierCatalog.map(p => ({ sku: p.sku, name: p.name, price: p.price })),
933
+ * { key: 'sku' }
824
934
  * );
825
935
  * console.log(`${result.created} new, ${result.updated} updated`);
826
936
  * ```
@@ -828,7 +938,11 @@ export interface EntityHandler<T = any> {
828
938
  * @example
829
939
  * ```typescript
830
940
  * // Compound key
831
- * await base44.entities.Inventory.upsert(rows, { key: ['sku', 'warehouse'] });
941
+ * const result = await base44.entities.Inventory.upsert(
942
+ * warehouseFeed.map(row => ({ sku: row.sku, warehouse: row.warehouseCode, quantity: row.qty })),
943
+ * { key: ['sku', 'warehouse'] }
944
+ * );
945
+ * console.log(`${result.created} new, ${result.updated} updated`);
832
946
  * ```
833
947
  */
834
948
  upsert(records: Partial<T>[], options: EntityUpsertOptions<T>): Promise<EntityUpsertResult<T>>;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@base44-preview/sdk",
3
- "version": "0.8.52-pr.307.064de09",
3
+ "version": "0.8.53-pr.308.2df7905",
4
4
  "description": "JavaScript SDK for Base44 API",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",