@base44-preview/sdk 0.8.26-pr.167.9a82260 → 0.8.26-pr.167.fdb48d8

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, CreateClientConfig, CreateClientOptions, Base44ErrorJSON, };
6
6
  export * from "./types.js";
7
- export type { DeleteManyResult, DeleteResult, EntitiesModule, EntityHandler, EntityRecord, EntityTypeRegistry, 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";
@@ -41,34 +41,6 @@ function parseRealtimeMessage(dataStr) {
41
41
  return null;
42
42
  }
43
43
  }
44
- // In-flight HTTP refetches for oversize realtime events. Lets multiple
45
- // subscribers in the same browser (e.g. several React components subscribed
46
- // to the same entity) share one HTTP call when they all receive the same
47
- // oversize event. Keyed by `${entityName}:${id}:${timestamp}` so distinct
48
- // updates are not collapsed.
49
- const inflightRefetches = new Map();
50
- /**
51
- * Refetches a record over HTTP after the server signaled it had to slim the
52
- * realtime broadcast (`_oversize: true`). Reuses an in-flight promise if
53
- * one exists for the same (entityName, id, timestamp) so concurrent
54
- * subscribers in the same browser fan out to a single HTTP call.
55
- * @internal
56
- */
57
- function refetchTruncated(axios, baseURL, entityName, id, timestamp) {
58
- const key = `${entityName}:${id}:${timestamp}`;
59
- let promise = inflightRefetches.get(key);
60
- if (!promise) {
61
- promise = axios.get(`${baseURL}/${id}`);
62
- inflightRefetches.set(key, promise);
63
- // Clear the cache entry after the promise settles plus a short grace
64
- // window so late subscribers can still piggy-back on the result. Use
65
- // .then(success, failure) instead of .finally to avoid creating an
66
- // unhandled rejection tail when the underlying axios call rejects.
67
- const cleanup = () => setTimeout(() => inflightRefetches.delete(key), 5000);
68
- promise.then(cleanup, cleanup);
69
- }
70
- return promise;
71
- }
72
44
  /**
73
45
  * Creates a handler for a specific entity.
74
46
  *
@@ -158,25 +130,24 @@ function createEntityHandler(axios, appId, entityName, getSocket) {
158
130
  // Get the socket and subscribe to the room
159
131
  const socket = getSocket();
160
132
  const unsubscribe = socket.subscribeToRoom(room, {
161
- update_model: async (msg) => {
133
+ update_model: (msg) => {
162
134
  var _a;
163
135
  const event = parseRealtimeMessage(msg.data);
164
136
  if (!event) {
165
137
  return;
166
138
  }
167
139
  // Server signals oversize broadcasts with `_oversize: true` on
168
- // `data`. The wire payload is bounded for transport; we transparently
169
- // refetch the full record over HTTP so callers always see complete
170
- // data. Skip on delete events the record no longer exists.
140
+ // `data`. The wire payload was slimmed to fit under the realtime
141
+ // transport cap, so big string fields arrive as empty strings (or
142
+ // the whole record collapses to a stub). Surface this to the
143
+ // developer console so they know to fetch the full record on
144
+ // demand (e.g. a follow-up entities.X.get(id) call) instead of
145
+ // rendering the slimmed payload directly. Skip on delete events
146
+ // — the record no longer exists.
171
147
  if (event.type !== "delete" && ((_a = event.data) === null || _a === void 0 ? void 0 : _a._oversize)) {
172
- try {
173
- event.data = await refetchTruncated(axios, baseURL, entityName, event.id, event.timestamp);
174
- }
175
- catch (error) {
176
- console.warn("[Base44 SDK] Failed to refetch oversize entity, falling through with stub payload:", error);
177
- // event.data stays as the `{id, _oversize: true}` stub; user
178
- // code receives partial data — same UX as today's drop-and-stale.
179
- }
148
+ console.error(`[Base44 SDK] Realtime broadcast for ${entityName}#${event.id} was oversize and got slimmed for transport. ` +
149
+ `Fields >10 KB are empty and the rest of the record may be a stub. ` +
150
+ `Call \`entities.${entityName}.get("${event.id}")\` to fetch the full record.`);
180
151
  }
181
152
  try {
182
153
  callback(event);
@@ -84,6 +84,74 @@ export interface ImportResult<T = any> {
84
84
  * ```
85
85
  */
86
86
  export type SortField<T> = (keyof T & string) | `+${keyof T & string}` | `-${keyof T & string}`;
87
+ /**
88
+ * Entity filter query type system.
89
+ *
90
+ * `EntityFilterQuery<T>` keeps field names tied to the entity schema while
91
+ * allowing Base44's documented filtering syntax. Each field can use an exact
92
+ * value, `null`, an array shorthand for matching any listed value, or a
93
+ * field-level operator object. Root-level `$and`, `$or`, and `$nor` combine
94
+ * nested filter queries.
95
+ *
96
+ * Operator values are typed from the field they filter where possible. For
97
+ * example, numeric fields accept numeric comparison values, string fields
98
+ * accept `$regex`, and array fields accept `$all` and `$size`.
99
+ */
100
+ /**
101
+ * Value accepted when filtering an entity field.
102
+ *
103
+ * Supports exact matches, `null`, array shorthand for matching any of the
104
+ * provided values, and documented MongoDB-style query operators.
105
+ *
106
+ * @typeParam T - Field value type.
107
+ */
108
+ export type EntityFilterValue<T> = EntityFilterComparable<T> | EntityFilterComparable<T>[] | EntityFilterOperators<T>;
109
+ /**
110
+ * MongoDB-style query operators accepted for a single entity field.
111
+ *
112
+ * @typeParam T - Field value type.
113
+ */
114
+ export type EntityFilterOperators<T> = EntityFilterCommonOperators<T> & {
115
+ /** Negates another field-level filter expression. */
116
+ $not?: EntityFilterCommonOperators<T>;
117
+ };
118
+ type EntityFilterComparable<T> = Exclude<T, undefined> | null;
119
+ type EntityFilterCommonOperators<T> = {
120
+ $eq?: EntityFilterComparable<T>;
121
+ $ne?: EntityFilterComparable<T>;
122
+ $gt?: EntityFilterComparable<T>;
123
+ $gte?: EntityFilterComparable<T>;
124
+ $lt?: EntityFilterComparable<T>;
125
+ $lte?: EntityFilterComparable<T>;
126
+ $in?: EntityFilterComparable<T>[];
127
+ $nin?: EntityFilterComparable<T>[];
128
+ $exists?: boolean;
129
+ } & EntityFilterStringOperators<T> & EntityFilterArrayOperators<T>;
130
+ type EntityFilterStringOperators<T> = Extract<Exclude<T, undefined | null>, string> extends never ? {} : {
131
+ $regex?: string;
132
+ };
133
+ type EntityFilterArrayElement<T> = T extends readonly (infer U)[] ? U : never;
134
+ type EntityFilterArrayOperators<T> = [
135
+ EntityFilterArrayElement<Exclude<T, undefined | null>>
136
+ ] extends [never] ? {} : {
137
+ $all?: EntityFilterArrayElement<Exclude<T, undefined | null>>[];
138
+ $size?: number;
139
+ };
140
+ /**
141
+ * Query object accepted by entity filtering methods.
142
+ *
143
+ * Field keys are typed from the entity schema. `$and`, `$or`, and `$nor`
144
+ * combine nested filter queries at the root level.
145
+ *
146
+ * @typeParam T - Entity record type.
147
+ */
148
+ export type EntityFilterQuery<T> = {
149
+ [K in keyof T]?: EntityFilterValue<T[K]>;
150
+ } & {
151
+ $and?: EntityFilterQuery<T>[];
152
+ $or?: EntityFilterQuery<T>[];
153
+ $nor?: EntityFilterQuery<T>[];
154
+ };
87
155
  /**
88
156
  * Fields added by the server to every entity record, such as `id`, `created_date`, `updated_date`, and `created_by`.
89
157
  */
@@ -189,7 +257,9 @@ export interface EntityHandler<T = any> {
189
257
  * @typeParam K - The fields to include in the response. Defaults to all fields.
190
258
  * @param query - Query object with field-value pairs. Each key should be a field name
191
259
  * from your entity schema, and each value is the criteria to match. Records matching all
192
- * specified criteria are returned. Field names are case-sensitive.
260
+ * specified criteria are returned. Field names are case-sensitive. Use field-value pairs
261
+ * for exact matches, `null` for null values, arrays as shorthand for matching any of the
262
+ * provided values, or documented MongoDB query operators for advanced filtering.
193
263
  * @param sort - Sort parameter, such as `'-created_date'` for descending. Defaults to `'-created_date'`.
194
264
  * @param limit - Maximum number of results to return. Defaults to `50`.
195
265
  * @param skip - Number of results to skip for pagination. Defaults to `0`.
@@ -215,6 +285,42 @@ export interface EntityHandler<T = any> {
215
285
  *
216
286
  * @example
217
287
  * ```typescript
288
+ * // Filter by any matching value
289
+ * const records = await base44.entities.MyEntity.filter({
290
+ * external_id: ['item-1', 'item-2']
291
+ * });
292
+ * ```
293
+ *
294
+ * @example
295
+ * ```typescript
296
+ * // Filter with query operators
297
+ * const popularRecords = await base44.entities.MyEntity.filter({
298
+ * count: { $gte: 100 },
299
+ * external_id: { $in: ['item-1', 'item-2'] }
300
+ * });
301
+ * ```
302
+ *
303
+ * @example
304
+ * ```typescript
305
+ * // Filter with logical operators
306
+ * const records = await base44.entities.MyEntity.filter({
307
+ * $or: [
308
+ * { name: 'Example item' },
309
+ * { slug: 'example-item' }
310
+ * ]
311
+ * });
312
+ * ```
313
+ *
314
+ * @example
315
+ * ```typescript
316
+ * // Filter null values
317
+ * const recordsWithoutDescription = await base44.entities.MyEntity.filter({
318
+ * description: null
319
+ * });
320
+ * ```
321
+ *
322
+ * @example
323
+ * ```typescript
218
324
  * // Filter with sorting and pagination
219
325
  * const results = await base44.entities.MyEntity.filter(
220
326
  * { status: 'active' },
@@ -236,7 +342,7 @@ export interface EntityHandler<T = any> {
236
342
  * );
237
343
  * ```
238
344
  */
239
- filter<K extends keyof T = keyof T>(query: Partial<T>, sort?: SortField<T>, limit?: number, skip?: number, fields?: K[]): Promise<Pick<T, K>[]>;
345
+ filter<K extends keyof T = keyof T>(query: EntityFilterQuery<T>, sort?: SortField<T>, limit?: number, skip?: number, fields?: K[]): Promise<Pick<T, K>[]>;
240
346
  /**
241
347
  * Gets a single record by ID.
242
348
  *
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@base44-preview/sdk",
3
- "version": "0.8.26-pr.167.9a82260",
3
+ "version": "0.8.26-pr.167.fdb48d8",
4
4
  "description": "JavaScript SDK for Base44 API",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -11,7 +11,8 @@
11
11
  "scripts": {
12
12
  "build": "tsc",
13
13
  "lint": "eslint src",
14
- "test": "vitest run",
14
+ "test": "npm run test:types && vitest run",
15
+ "test:types": "tsc --noEmit -p tsconfig.type-tests.json",
15
16
  "test:unit": "vitest run tests/unit",
16
17
  "test:e2e": "vitest run tests/e2e",
17
18
  "test:watch": "vitest",