@base44/sdk 0.8.22 → 0.8.23

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
@@ -92,9 +92,13 @@ export function createClient(config) {
92
92
  interceptResponses: false,
93
93
  onError: options === null || options === void 0 ? void 0 : options.onError,
94
94
  });
95
+ const serviceRoleHeaders = {
96
+ ...headers,
97
+ ...(token ? { "on-behalf-of": `Bearer ${token}` } : {}),
98
+ };
95
99
  const serviceRoleAxiosClient = createAxiosClient({
96
100
  baseURL: `${serverUrl}/api`,
97
- headers,
101
+ headers: serviceRoleHeaders,
98
102
  token: serviceToken,
99
103
  onError: options === null || options === void 0 ? void 0 : options.onError,
100
104
  });
@@ -158,7 +162,7 @@ export function createClient(config) {
158
162
  getSocket,
159
163
  }),
160
164
  integrations: createIntegrationsModule(serviceRoleAxiosClient, appId),
161
- sso: createSsoModule(serviceRoleAxiosClient, appId, token),
165
+ sso: createSsoModule(serviceRoleAxiosClient, appId),
162
166
  connectors: createConnectorsModule(serviceRoleAxiosClient, appId),
163
167
  functions: createFunctionsModule(serviceRoleFunctionsAxiosClient, appId, {
164
168
  getAuthHeaders: () => {
@@ -33,6 +33,14 @@ export function createConnectorsModule(axios, appId) {
33
33
  connectionConfig: (_a = data.connection_config) !== null && _a !== void 0 ? _a : null,
34
34
  };
35
35
  },
36
+ async getCurrentAppUserAccessToken(connectorId) {
37
+ if (!connectorId || typeof connectorId !== "string") {
38
+ throw new Error("Connector ID is required and must be a string");
39
+ }
40
+ const response = await axios.get(`/apps/${appId}/app-user-auth/connectors/${connectorId}/token`);
41
+ const data = response;
42
+ return data.access_token;
43
+ },
36
44
  };
37
45
  }
38
46
  /**
@@ -45,14 +53,6 @@ export function createConnectorsModule(axios, appId) {
45
53
  */
46
54
  export function createUserConnectorsModule(axios, appId) {
47
55
  return {
48
- async getCurrentAppUserAccessToken(connectorId) {
49
- if (!connectorId || typeof connectorId !== "string") {
50
- throw new Error("Connector ID is required and must be a string");
51
- }
52
- const response = await axios.get(`/apps/${appId}/app-user-auth/connectors/${connectorId}/token`);
53
- const data = response;
54
- return data.access_token;
55
- },
56
56
  async connectAppUser(connectorId) {
57
57
  if (!connectorId || typeof connectorId !== "string") {
58
58
  throw new Error("Connector ID is required and must be a string");
@@ -223,20 +223,6 @@ export interface ConnectorsModule {
223
223
  * ```
224
224
  */
225
225
  getConnection(integrationType: ConnectorIntegrationType): Promise<ConnectorConnectionResponse>;
226
- }
227
- /**
228
- * User-scoped connectors module for managing app-user OAuth connections.
229
- *
230
- * This module provides methods for app-user OAuth flows: initiating an OAuth connection,
231
- * retrieving the end user's access token, and disconnecting the end user's connection.
232
- *
233
- * Unlike {@link ConnectorsModule | ConnectorsModule} which manages app-scoped tokens,
234
- * this module manages tokens scoped to individual end users. Methods are keyed on
235
- * the connector ID (the OrgConnector's database ID) rather than the integration type.
236
- *
237
- * Available via `base44.connectors`.
238
- */
239
- export interface UserConnectorsModule {
240
226
  /**
241
227
  * Retrieves an OAuth access token for an end user's connection to a specific connector.
242
228
  *
@@ -249,7 +235,7 @@ export interface UserConnectorsModule {
249
235
  * @example
250
236
  * ```typescript
251
237
  * // Get the end user's access token for a connector
252
- * const token = await base44.connectors.getCurrentAppUserAccessToken('abc123def');
238
+ * const token = await base44.asServiceRole.connectors.getCurrentAppUserAccessToken('abc123def');
253
239
  *
254
240
  * const response = await fetch('https://www.googleapis.com/calendar/v3/calendars/primary/events', {
255
241
  * headers: { 'Authorization': `Bearer ${token}` }
@@ -257,6 +243,20 @@ export interface UserConnectorsModule {
257
243
  * ```
258
244
  */
259
245
  getCurrentAppUserAccessToken(connectorId: string): Promise<string>;
246
+ }
247
+ /**
248
+ * User-scoped connectors module for managing app-user OAuth connections.
249
+ *
250
+ * This module provides methods for app-user OAuth flows: initiating an OAuth connection,
251
+ * retrieving the end user's access token, and disconnecting the end user's connection.
252
+ *
253
+ * Unlike {@link ConnectorsModule | ConnectorsModule} which manages app-scoped tokens,
254
+ * this module manages tokens scoped to individual end users. Methods are keyed on
255
+ * the connector ID (the OrgConnector's database ID) rather than the integration type.
256
+ *
257
+ * Available via `base44.connectors`.
258
+ */
259
+ export interface UserConnectorsModule {
260
260
  /**
261
261
  * Initiates the app-user OAuth flow for a specific connector.
262
262
  *
@@ -40,7 +40,7 @@ export interface DeleteManyResult {
40
40
  deleted: number;
41
41
  }
42
42
  /**
43
- * Result returned when updating multiple entities via a query.
43
+ * Result returned when updating multiple entities using a query.
44
44
  */
45
45
  export interface UpdateManyResult {
46
46
  /** Whether the operation was successful. */
@@ -279,6 +279,11 @@ export interface EntityHandler<T = any> {
279
279
  * Updates a record by ID with the provided data. Only the fields
280
280
  * included in the data object will be updated.
281
281
  *
282
+ * To update a single record by ID, use this method. To apply the same
283
+ * update to many records matching a query, use {@linkcode updateMany | updateMany()}.
284
+ * To update multiple specific records with different data each, use
285
+ * {@linkcode bulkUpdate | bulkUpdate()}.
286
+ *
282
287
  * @param id - The unique identifier of the record to update.
283
288
  * @param data - Object containing the fields to update.
284
289
  * @returns Promise resolving to the updated record.
@@ -360,29 +365,39 @@ export interface EntityHandler<T = any> {
360
365
  */
361
366
  bulkCreate(data: Partial<T>[]): Promise<T[]>;
362
367
  /**
363
- * Updates multiple records matching a query using a MongoDB update operator.
368
+ * Applies the same update to all records that match a query.
364
369
  *
365
- * Applies the same update operation to all records matching the query.
366
- * The `data` parameter must contain one or more MongoDB update operators
367
- * (e.g., `$set`, `$inc`, `$push`). Multiple operators can be combined in a
368
- * single call, but each field may only appear in one operator.
370
+ * Use this when you need to make the same change across all records that
371
+ * match specific criteria. For example, you could set every completed order
372
+ * to "archived", or increment a counter on all active users.
369
373
  *
370
- * Results are batched in groups of up to 500 when `has_more` is `true`
374
+ * Results are batched in groups of up to 500. When `has_more` is `true`
371
375
  * in the response, call `updateMany` again with the same query to update
372
- * the next batch.
373
- *
374
- * @param query - Query object to filter which records to update. Records matching all
375
- * specified criteria will be updated.
376
- * @param data - Update operation object containing one or more MongoDB update operators.
376
+ * the next batch. Make sure the query excludes already-updated records
377
+ * so you don't re-process the same entities on each iteration. For
378
+ * example, filter by `status: 'pending'` when setting status to `'processed'`.
379
+ *
380
+ * To update a single record by ID, use {@linkcode update | update()} instead. To update
381
+ * multiple specific records with different data each, use {@linkcode bulkUpdate | bulkUpdate()}.
382
+ *
383
+ * @param query - Query object to filter which records to update. Use field-value
384
+ * pairs for exact matches, or
385
+ * [MongoDB query operators](https://www.mongodb.com/docs/manual/reference/operator/query/)
386
+ * for advanced filtering. Supported query operators include `$eq`, `$ne`, `$gt`,
387
+ * `$gte`, `$lt`, `$lte`, `$in`, `$nin`, `$and`, `$or`, `$not`, `$nor`,
388
+ * `$exists`, `$regex`, `$all`, `$elemMatch`, and `$size`.
389
+ * @param data - Update operation object containing one or more
390
+ * [MongoDB update operators](https://www.mongodb.com/docs/manual/reference/operator/update/).
377
391
  * Each field may only appear in one operator per call.
378
- * Supported operators: `$set`, `$rename`, `$unset`, `$inc`, `$mul`, `$min`, `$max`,
379
- * `$currentDate`, `$addToSet`, `$push`, `$pull`.
392
+ * Supported update operators include `$set`, `$rename`, `$unset`, `$inc`, `$mul`, `$min`, `$max`,
393
+ * `$currentDate`, `$addToSet`, `$push`, and `$pull`.
380
394
  * @returns Promise resolving to the update result.
381
395
  *
382
396
  * @example
383
397
  * ```typescript
384
- * // Set status to 'archived' for all completed records
385
- * const result = await base44.entities.MyEntity.updateMany(
398
+ * // Basic usage
399
+ * // Archive all completed orders
400
+ * const result = await base44.entities.Order.updateMany(
386
401
  * { status: 'completed' },
387
402
  * { $set: { status: 'archived' } }
388
403
  * );
@@ -391,8 +406,19 @@ export interface EntityHandler<T = any> {
391
406
  *
392
407
  * @example
393
408
  * ```typescript
394
- * // Combine multiple operators in a single call
395
- * const result = await base44.entities.MyEntity.updateMany(
409
+ * // Multiple query operators
410
+ * // Flag urgent items that haven't been handled yet
411
+ * const result = await base44.entities.Task.updateMany(
412
+ * { priority: { $in: ['high', 'critical'] }, status: { $ne: 'done' } },
413
+ * { $set: { flagged: true } }
414
+ * );
415
+ * ```
416
+ *
417
+ * @example
418
+ * ```typescript
419
+ * // Multiple update operators
420
+ * // Close out sales records and bump the view count
421
+ * const result = await base44.entities.Deal.updateMany(
396
422
  * { category: 'sales' },
397
423
  * { $set: { status: 'done' }, $inc: { view_count: 1 } }
398
424
  * );
@@ -400,11 +426,14 @@ export interface EntityHandler<T = any> {
400
426
  *
401
427
  * @example
402
428
  * ```typescript
403
- * // Handle batched updates for large datasets
429
+ * // Batched updates
430
+ * // Process all pending items in batches of 500.
431
+ * // The query filters by 'pending', so updated records (now 'processed')
432
+ * // are automatically excluded from the next batch.
404
433
  * let hasMore = true;
405
434
  * let totalUpdated = 0;
406
435
  * while (hasMore) {
407
- * const result = await base44.entities.MyEntity.updateMany(
436
+ * const result = await base44.entities.Job.updateMany(
408
437
  * { status: 'pending' },
409
438
  * { $set: { status: 'processed' } }
410
439
  * );
@@ -415,27 +444,42 @@ export interface EntityHandler<T = any> {
415
444
  */
416
445
  updateMany(query: Partial<T>, data: Record<string, Record<string, any>>): Promise<UpdateManyResult>;
417
446
  /**
418
- * Updates multiple records in a single request, each with its own update data.
447
+ * Updates the specified records in a single request, each with its own data.
419
448
  *
420
- * Unlike `updateMany` which applies the same update to all matching records,
421
- * `bulkUpdate` allows different updates for each record. Each item in the
422
- * array must include an `id` field identifying which record to update.
449
+ * Use this when you already know which records to update and each one needs
450
+ * different field values. For example, you could update the status and amount
451
+ * on three separate invoices in one call.
423
452
  *
424
- * **Note:** Maximum 500 items per request.
453
+ * You can update up to 500 records per request.
425
454
  *
426
- * @param data - Array of update objects (max 500). Each object must have an `id` field
427
- * and any number of fields to update.
428
- * @returns Promise resolving to an array of updated records.
455
+ * To apply the same update to all records matching a query, use
456
+ * {@linkcode updateMany | updateMany()}. To update a single record by ID, use
457
+ * {@linkcode update | update()}.
458
+ *
459
+ * @param data - Array of objects to update. Each object must contain an `id` field identifying which record to update and any fields to change.
460
+ * @returns Promise resolving to an array of the updated records.
429
461
  *
430
462
  * @example
431
463
  * ```typescript
432
- * // Update multiple records with different data
433
- * const updated = await base44.entities.MyEntity.bulkUpdate([
434
- * { id: 'entity-1', status: 'paid', amount: 999 },
435
- * { id: 'entity-2', status: 'cancelled' },
436
- * { id: 'entity-3', name: 'Renamed Item' }
464
+ * // Basic usage
465
+ * // Update three invoices with different statuses and amounts
466
+ * const updated = await base44.entities.Invoice.bulkUpdate([
467
+ * { id: 'inv-1', status: 'paid', amount: 999 },
468
+ * { id: 'inv-2', status: 'cancelled' },
469
+ * { id: 'inv-3', amount: 450 }
437
470
  * ]);
438
471
  * ```
472
+ *
473
+ * @example
474
+ * ```typescript
475
+ * // More than 500 items
476
+ * // Reassign each task to a different owner in batches
477
+ * const allUpdates = reassignments.map(r => ({ id: r.taskId, owner: r.newOwner }));
478
+ * for (let i = 0; i < allUpdates.length; i += 500) {
479
+ * const batch = allUpdates.slice(i, i + 500);
480
+ * await base44.entities.Task.bulkUpdate(batch);
481
+ * }
482
+ * ```
439
483
  */
440
484
  bulkUpdate(data: (Partial<T> & {
441
485
  id: string;
@@ -17,7 +17,9 @@ export type FunctionName = keyof FunctionNameRegistry extends never ? string : k
17
17
  /**
18
18
  * Options for {@linkcode FunctionsModule.fetch}.
19
19
  *
20
- * Uses native `fetch` options directly.
20
+ * Alias of the native [`RequestInit`](https://developer.mozilla.org/en-US/docs/Web/API/RequestInit) type.
21
+ * Any option accepted by the browser `fetch` API is valid (`method`, `headers`, `body`, `signal`, etc.).
22
+ * Auth headers are merged in automatically; you do not need to set them.
21
23
  */
22
24
  export type FunctionsFetchInit = RequestInit;
23
25
  /**
@@ -48,11 +50,13 @@ export interface FunctionsModule {
48
50
  /**
49
51
  * Invokes a custom backend function by name.
50
52
  *
51
- * Calls a custom backend function deployed to the app.
53
+ * Sends a POST request to a custom backend function deployed to the app.
52
54
  * The function receives the provided data as named parameters and returns
53
55
  * the result. If any parameter is a `File` object, the request will automatically be
54
56
  * sent as `multipart/form-data`. Otherwise, it will be sent as JSON.
55
57
  *
58
+ * For streaming responses, non-POST methods, or raw response access, use {@linkcode fetch | fetch()} instead.
59
+ *
56
60
  * @param functionName - The name of the function to invoke.
57
61
  * @param data - An object containing named parameters for the function.
58
62
  * @returns Promise resolving to the function's response. The `data` property contains the data returned by the function, if there is any.
@@ -85,19 +89,62 @@ export interface FunctionsModule {
85
89
  /**
86
90
  * Performs a direct HTTP request to a backend function path and returns the native `Response`.
87
91
  *
88
- * Use this method when you need low-level control over the request/response that the higher-level
89
- * `invoke()` abstraction doesn't provide, such as:
90
- * - Streaming responses (SSE, chunked text, NDJSON)
91
- * - Custom HTTP methods (PUT, PATCH, DELETE, etc.)
92
- * - Custom headers or request configuration
93
- * - Access to raw response metadata (status, headers)
94
- * - Direct control over request/response bodies
92
+ * Use `fetch()` when you need low-level control that {@linkcode invoke | invoke()} doesn't provide, such as:
93
+ * - Streaming responses, like SSE, chunked text, or NDJSON
94
+ * - Custom HTTP methods, like PUT, PATCH, or DELETE
95
+ * - Raw response access, including status codes, headers, and binary bodies
96
+ *
97
+ * @param path - Function path. Leading slash is optional, so `/chat` and `chat` are equivalent. For example, `'/streaming_demo'` or `'reports/export'`.
98
+ * @param init - Optional [`RequestInit`](https://developer.mozilla.org/en-US/docs/Web/API/RequestInit) options such as `method`, `headers`, `body`, and `signal`. Auth headers are added automatically.
99
+ * @returns Promise resolving to a native [`Response`](https://developer.mozilla.org/en-US/docs/Web/API/Response).
100
+ *
101
+ * @example
102
+ * ```typescript
103
+ * // Stream an SSE response
104
+ * const response = await base44.functions.fetch('/chat', {
105
+ * method: 'POST',
106
+ * headers: { 'Content-Type': 'application/json' },
107
+ * body: JSON.stringify({ prompt: 'Hello!' }),
108
+ * });
109
+ *
110
+ * const reader = response.body!.getReader();
111
+ * const decoder = new TextDecoder();
95
112
  *
96
- * Requests are sent to `/api/functions/<path>`.
113
+ * while (true) {
114
+ * const { done, value } = await reader.read();
115
+ * if (done) break;
116
+ * console.log(decoder.decode(value, { stream: true }));
117
+ * }
118
+ * ```
97
119
  *
98
- * @param path - Function path, e.g. `/streaming_demo` or `/streaming_demo/deep/path`
99
- * @param init - Native fetch options.
100
- * @returns Promise resolving to a native fetch `Response`
120
+ * @example
121
+ * ```typescript
122
+ * // PUT request
123
+ * const response = await base44.functions.fetch('/users/profile', {
124
+ * method: 'PUT',
125
+ * headers: { 'Content-Type': 'application/json' },
126
+ * body: JSON.stringify({ name: 'Jane', role: 'admin' }),
127
+ * });
128
+ *
129
+ * if (!response.ok) {
130
+ * throw new Error(`Request failed: ${response.status}`);
131
+ * }
132
+ *
133
+ * const updated = await response.json();
134
+ * ```
135
+ *
136
+ * @example
137
+ * ```typescript
138
+ * // Download a binary file
139
+ * const response = await base44.functions.fetch('/export/report');
140
+ * const blob = await response.blob();
141
+ *
142
+ * const url = URL.createObjectURL(blob);
143
+ * const a = document.createElement('a');
144
+ * a.href = url;
145
+ * a.download = 'report.pdf';
146
+ * a.click();
147
+ * ```
101
148
  */
102
149
  fetch(path: string, init?: FunctionsFetchInit): Promise<Response>;
103
150
  }
@@ -9,4 +9,4 @@ import { SsoModule } from "./sso.types";
9
9
  * @returns SSO module with authentication methods
10
10
  * @internal
11
11
  */
12
- export declare function createSsoModule(axios: AxiosInstance, appId: string, userToken?: string): SsoModule;
12
+ export declare function createSsoModule(axios: AxiosInstance, appId: string): SsoModule;
@@ -7,17 +7,12 @@
7
7
  * @returns SSO module with authentication methods
8
8
  * @internal
9
9
  */
10
- export function createSsoModule(axios, appId, userToken) {
10
+ export function createSsoModule(axios, appId) {
11
11
  return {
12
12
  // Get SSO access token for a specific user
13
13
  async getAccessToken(userid) {
14
14
  const url = `/apps/${appId}/auth/sso/accesstoken/${userid}`;
15
- // Prepare headers with both tokens if available
16
- const headers = {};
17
- if (userToken) {
18
- headers["on-behalf-of"] = `Bearer ${userToken}`;
19
- }
20
- return axios.get(url, { headers });
15
+ return axios.get(url);
21
16
  },
22
17
  };
23
18
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@base44/sdk",
3
- "version": "0.8.22",
3
+ "version": "0.8.23",
4
4
  "description": "JavaScript SDK for Base44 API",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",