@mindstudio-ai/agent 0.1.17 → 0.1.19

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/cli.js CHANGED
@@ -2201,10 +2201,11 @@ var init_query = __esm({
2201
2201
  limit: this._limit,
2202
2202
  offset: this._offset
2203
2203
  });
2204
- return { query, fallbackQuery: null, config: this._config };
2204
+ return { type: "query", query, fallbackQuery: null, config: this._config };
2205
2205
  }
2206
2206
  const fallbackQuery = buildSelect(this._config.tableName);
2207
2207
  return {
2208
+ type: "query",
2208
2209
  query: null,
2209
2210
  fallbackQuery,
2210
2211
  config: this._config,
@@ -2329,12 +2330,96 @@ var init_query = __esm({
2329
2330
  }
2330
2331
  });
2331
2332
 
2333
+ // src/db/mutation.ts
2334
+ var Mutation;
2335
+ var init_mutation = __esm({
2336
+ "src/db/mutation.ts"() {
2337
+ "use strict";
2338
+ Mutation = class _Mutation {
2339
+ /** @internal */
2340
+ _config;
2341
+ /** @internal */
2342
+ _queries;
2343
+ /** @internal */
2344
+ _processResult;
2345
+ /** @internal Non-batchable executor for complex mutations (e.g. removeAll JS fallback). */
2346
+ _executor;
2347
+ constructor(config, queries, processResult) {
2348
+ this._config = config;
2349
+ this._queries = queries;
2350
+ this._processResult = processResult;
2351
+ this._executor = void 0;
2352
+ }
2353
+ /**
2354
+ * Create a non-batchable mutation that wraps an async executor.
2355
+ * Used for operations that require multi-step execution (e.g. removeAll
2356
+ * with a JS-fallback predicate: fetch all rows → filter → delete).
2357
+ *
2358
+ * Works fine when awaited standalone. Throws if passed to db.batch().
2359
+ *
2360
+ * @internal
2361
+ */
2362
+ static fromExecutor(config, executor) {
2363
+ const m = new _Mutation(config, [], () => void 0);
2364
+ Object.defineProperty(m, "_executor", { value: executor });
2365
+ return m;
2366
+ }
2367
+ // -------------------------------------------------------------------------
2368
+ // PromiseLike — executes on await
2369
+ // -------------------------------------------------------------------------
2370
+ then(onfulfilled, onrejected) {
2371
+ return this._execute().then(onfulfilled, onrejected);
2372
+ }
2373
+ // -------------------------------------------------------------------------
2374
+ // Batch compilation — used by db.batch()
2375
+ // -------------------------------------------------------------------------
2376
+ /**
2377
+ * @internal Compile this mutation into SQL for batch execution.
2378
+ * Returns the queries and a result processor.
2379
+ *
2380
+ * Throws if this is a non-batchable mutation (created via fromExecutor).
2381
+ */
2382
+ _compile() {
2383
+ if (this._executor) {
2384
+ throw new Error(
2385
+ "This operation cannot be batched (e.g. removeAll with a predicate that cannot compile to SQL). Await it separately."
2386
+ );
2387
+ }
2388
+ return {
2389
+ type: "mutation",
2390
+ queries: this._queries,
2391
+ config: this._config,
2392
+ processResult: this._processResult
2393
+ };
2394
+ }
2395
+ /**
2396
+ * @internal Process raw SQL results into the typed result.
2397
+ * Used by db.batch() after executing the compiled queries.
2398
+ */
2399
+ static _processResults(results, compiled) {
2400
+ return compiled.processResult(results);
2401
+ }
2402
+ // -------------------------------------------------------------------------
2403
+ // Execution
2404
+ // -------------------------------------------------------------------------
2405
+ async _execute() {
2406
+ if (this._executor) {
2407
+ return this._executor();
2408
+ }
2409
+ const results = await this._config.executeBatch(this._queries);
2410
+ return this._processResult(results);
2411
+ }
2412
+ };
2413
+ }
2414
+ });
2415
+
2332
2416
  // src/db/table.ts
2333
2417
  var Table;
2334
2418
  var init_table = __esm({
2335
2419
  "src/db/table.ts"() {
2336
2420
  "use strict";
2337
2421
  init_query();
2422
+ init_mutation();
2338
2423
  init_predicate();
2339
2424
  init_sql();
2340
2425
  Table = class {
@@ -2399,7 +2484,7 @@ var init_table = __esm({
2399
2484
  sortBy(accessor) {
2400
2485
  return new Query(this._config).sortBy(accessor);
2401
2486
  }
2402
- async push(data) {
2487
+ push(data) {
2403
2488
  const isArray = Array.isArray(data);
2404
2489
  const items = isArray ? data : [data];
2405
2490
  const queries = items.map(
@@ -2409,71 +2494,76 @@ var init_table = __esm({
2409
2494
  this._config.columns
2410
2495
  )
2411
2496
  );
2412
- const results = await this._config.executeBatch(queries);
2413
- const rows = results.map((r) => {
2414
- if (r.rows.length > 0) {
2415
- return deserializeRow(
2416
- r.rows[0],
2417
- this._config.columns
2418
- );
2419
- }
2420
- return void 0;
2497
+ return new Mutation(this._config, queries, (results) => {
2498
+ const rows = results.map((r) => {
2499
+ if (r.rows.length > 0) {
2500
+ return deserializeRow(
2501
+ r.rows[0],
2502
+ this._config.columns
2503
+ );
2504
+ }
2505
+ return void 0;
2506
+ });
2507
+ return isArray ? rows : rows[0];
2421
2508
  });
2422
- return isArray ? rows : rows[0];
2423
2509
  }
2424
2510
  /**
2425
2511
  * Update a row by ID. Only the provided fields are changed.
2426
2512
  * Returns the updated row via `UPDATE ... RETURNING *`.
2427
2513
  */
2428
- async update(id, data) {
2514
+ update(id, data) {
2429
2515
  const query = buildUpdate(
2430
2516
  this._config.tableName,
2431
2517
  id,
2432
2518
  data,
2433
2519
  this._config.columns
2434
2520
  );
2435
- const results = await this._config.executeBatch([query]);
2436
- return deserializeRow(
2437
- results[0].rows[0],
2438
- this._config.columns
2521
+ return new Mutation(
2522
+ this._config,
2523
+ [query],
2524
+ (results) => deserializeRow(
2525
+ results[0].rows[0],
2526
+ this._config.columns
2527
+ )
2439
2528
  );
2440
2529
  }
2441
- async remove(id) {
2530
+ remove(id) {
2442
2531
  const query = buildDelete(this._config.tableName, `id = ?`, [id]);
2443
- await this._config.executeBatch([query]);
2532
+ return new Mutation(this._config, [query], () => void 0);
2444
2533
  }
2445
2534
  /**
2446
2535
  * Remove all rows matching a predicate. Returns the count removed.
2447
2536
  */
2448
- async removeAll(predicate) {
2537
+ removeAll(predicate) {
2449
2538
  const compiled = compilePredicate(predicate);
2450
2539
  if (compiled.type === "sql") {
2451
2540
  const query = buildDelete(this._config.tableName, compiled.where);
2452
- const results = await this._config.executeBatch([query]);
2453
- return results[0].changes;
2454
- }
2455
- console.warn(
2456
- `[mindstudio] removeAll predicate on ${this._config.tableName} could not be compiled to SQL \u2014 fetching all rows first`
2457
- );
2458
- const allQuery = buildSelect(this._config.tableName);
2459
- const allResults = await this._config.executeBatch([allQuery]);
2460
- const allRows = allResults[0].rows.map(
2461
- (r) => deserializeRow(
2462
- r,
2463
- this._config.columns
2464
- )
2465
- );
2466
- const matching = allRows.filter((row) => predicate(row));
2467
- if (matching.length === 0) return 0;
2468
- const deleteQueries = matching.filter((row) => row.id).map((row) => buildDelete(this._config.tableName, `id = ?`, [row.id]));
2469
- if (deleteQueries.length > 0) {
2470
- await this._config.executeBatch(deleteQueries);
2541
+ return new Mutation(this._config, [query], (results) => results[0].changes);
2471
2542
  }
2472
- return matching.length;
2543
+ return Mutation.fromExecutor(this._config, async () => {
2544
+ console.warn(
2545
+ `[mindstudio] removeAll predicate on ${this._config.tableName} could not be compiled to SQL \u2014 fetching all rows first`
2546
+ );
2547
+ const allQuery = buildSelect(this._config.tableName);
2548
+ const allResults = await this._config.executeBatch([allQuery]);
2549
+ const allRows = allResults[0].rows.map(
2550
+ (r) => deserializeRow(
2551
+ r,
2552
+ this._config.columns
2553
+ )
2554
+ );
2555
+ const matching = allRows.filter((row) => predicate(row));
2556
+ if (matching.length === 0) return 0;
2557
+ const deleteQueries = matching.filter((row) => row.id).map((row) => buildDelete(this._config.tableName, `id = ?`, [row.id]));
2558
+ if (deleteQueries.length > 0) {
2559
+ await this._config.executeBatch(deleteQueries);
2560
+ }
2561
+ return matching.length;
2562
+ });
2473
2563
  }
2474
- async clear() {
2564
+ clear() {
2475
2565
  const query = buildDelete(this._config.tableName);
2476
- await this._config.executeBatch([query]);
2566
+ return new Mutation(this._config, [query], () => void 0);
2477
2567
  }
2478
2568
  };
2479
2569
  }
@@ -2501,44 +2591,64 @@ function createDb(databases, executeBatch) {
2501
2591
  ago: (ms) => Date.now() - ms,
2502
2592
  fromNow: (ms) => Date.now() + ms,
2503
2593
  // --- Batch execution ---
2504
- batch: ((...queries) => {
2594
+ batch: ((...operations) => {
2505
2595
  return (async () => {
2506
- const compiled = queries.map((q) => {
2507
- if (!(q instanceof Query)) {
2508
- throw new MindStudioError(
2509
- "db.batch() only accepts Query objects (from .filter(), .sortBy(), etc.)",
2510
- "invalid_batch_query",
2511
- 400
2512
- );
2596
+ const compiled = operations.map((op) => {
2597
+ if (op instanceof Query) {
2598
+ return op._compile();
2599
+ }
2600
+ if (op instanceof Mutation) {
2601
+ return op._compile();
2513
2602
  }
2514
- return q._compile();
2603
+ throw new MindStudioError(
2604
+ "db.batch() only accepts Query and Mutation objects (from .filter(), .update(), .push(), etc.)",
2605
+ "invalid_batch_operation",
2606
+ 400
2607
+ );
2515
2608
  });
2516
2609
  const groups = /* @__PURE__ */ new Map();
2517
2610
  for (let i = 0; i < compiled.length; i++) {
2518
2611
  const c = compiled[i];
2519
2612
  const dbId = c.config.databaseId;
2520
- const sqlQuery = c.query ?? c.fallbackQuery;
2521
2613
  if (!groups.has(dbId)) groups.set(dbId, []);
2522
- groups.get(dbId).push({ index: i, sqlQuery });
2614
+ if (c.type === "query") {
2615
+ const sqlQuery = c.query ?? c.fallbackQuery;
2616
+ groups.get(dbId).push({ opIndex: i, sqlQueries: [sqlQuery] });
2617
+ } else {
2618
+ groups.get(dbId).push({ opIndex: i, sqlQueries: c.queries });
2619
+ }
2523
2620
  }
2524
- const allResults = new Array(compiled.length);
2621
+ const opResults = /* @__PURE__ */ new Map();
2525
2622
  await Promise.all(
2526
2623
  Array.from(groups.entries()).map(async ([dbId, entries]) => {
2527
- const sqlQueries = entries.map((e) => e.sqlQuery);
2528
- const results = await executeBatch(dbId, sqlQueries);
2529
- for (let i = 0; i < entries.length; i++) {
2530
- allResults[entries[i].index] = results[i];
2624
+ const flatQueries = [];
2625
+ const slices = [];
2626
+ for (const entry of entries) {
2627
+ slices.push({
2628
+ opIndex: entry.opIndex,
2629
+ start: flatQueries.length,
2630
+ count: entry.sqlQueries.length
2631
+ });
2632
+ flatQueries.push(...entry.sqlQueries);
2633
+ }
2634
+ const results = await executeBatch(dbId, flatQueries);
2635
+ for (const { opIndex, start, count } of slices) {
2636
+ opResults.set(opIndex, results.slice(start, start + count));
2531
2637
  }
2532
2638
  })
2533
2639
  );
2534
2640
  return compiled.map((c, i) => {
2535
- const result = allResults[i];
2536
- if (!c.query && c.predicates?.length) {
2537
- console.warn(
2538
- `[mindstudio] db.batch(): filter on ${c.config.tableName} could not be compiled to SQL \u2014 processing in JS`
2539
- );
2641
+ const results = opResults.get(i);
2642
+ if (c.type === "query") {
2643
+ if (!c.query && c.predicates?.length) {
2644
+ console.warn(
2645
+ `[mindstudio] db.batch(): filter on ${c.config.tableName} could not be compiled to SQL \u2014 processing in JS`
2646
+ );
2647
+ }
2648
+ return Query._processResults(results[0], c);
2649
+ } else {
2650
+ return Mutation._processResults(results, c);
2540
2651
  }
2541
- return Query._processResults(result, c);
2542
2652
  });
2543
2653
  })();
2544
2654
  })
@@ -2597,6 +2707,7 @@ var init_db = __esm({
2597
2707
  init_errors();
2598
2708
  init_table();
2599
2709
  init_query();
2710
+ init_mutation();
2600
2711
  init_table();
2601
2712
  }
2602
2713
  });
@@ -4282,15 +4393,24 @@ function summarizeInput(input) {
4282
4393
  }
4283
4394
  async function cmdAsk(question, options) {
4284
4395
  try {
4396
+ let lineBuffer = "";
4285
4397
  const response = await runAsk(question, options, (event) => {
4286
4398
  switch (event.type) {
4287
4399
  case "text":
4288
- process.stderr.write(event.text);
4400
+ lineBuffer += event.text;
4401
+ while (lineBuffer.includes("\n")) {
4402
+ const idx = lineBuffer.indexOf("\n");
4403
+ process.stderr.write(lineBuffer.slice(0, idx + 1));
4404
+ lineBuffer = lineBuffer.slice(idx + 1);
4405
+ }
4289
4406
  break;
4290
4407
  case "tool_start":
4408
+ if (lineBuffer) {
4409
+ process.stderr.write(lineBuffer + "\n");
4410
+ lineBuffer = "";
4411
+ }
4291
4412
  process.stderr.write(
4292
- `
4293
- ${ansi.cyan("\u27E1")} ${ansi.bold(event.name)} ${ansi.dim(summarizeInput(event.input))}
4413
+ ` ${ansi.cyan("\u27E1")} ${ansi.bold(event.name)} ${ansi.dim(summarizeInput(event.input))}
4294
4414
  `
4295
4415
  );
4296
4416
  break;
@@ -4298,6 +4418,9 @@ async function cmdAsk(question, options) {
4298
4418
  break;
4299
4419
  }
4300
4420
  });
4421
+ if (lineBuffer) {
4422
+ process.stderr.write(lineBuffer);
4423
+ }
4301
4424
  if (process.stdout.isTTY) {
4302
4425
  process.stderr.write("\n");
4303
4426
  } else {
@@ -4389,7 +4512,7 @@ async function startMcpServer(options) {
4389
4512
  capabilities: { tools: {} },
4390
4513
  serverInfo: {
4391
4514
  name: "mindstudio-agent",
4392
- version: "0.1.17"
4515
+ version: "0.1.19"
4393
4516
  },
4394
4517
  instructions: 'Welcome to MindStudio \u2014 a platform with 200+ AI models, 850+ third-party integrations, and pre-built agents.\n\nGetting started:\n1. Call `ask` with any question about the SDK \u2014 it knows every action, model, and connector and returns working code with real model IDs and config options. Examples: ask("generate an image with FLUX"), ask("what models support vision?"), ask("how do I send a Slack message?").\n2. Call `changeName` to set your display name \u2014 use your name or whatever your user calls you. This is how you\'ll appear in MindStudio request logs.\n3. If you have a profile picture or icon, call `uploadFile` to upload it, then `changeProfilePicture` with the returned URL.\n4. For manual browsing, call `listActions` to discover all available actions.\n\nThen use the tools to generate text, images, video, audio, search the web, work with data sources, run agents, and more.\n\nImportant:\n- AI-powered actions (text generation, image generation, video, audio, etc.) cost money. Before running these, call `estimateActionCost` and confirm with the user before proceeding \u2014 unless they\'ve explicitly told you to go ahead.\n- Not all agents from `listAgents` are configured for API use. Do not try to run an agent just because it appears in the list \u2014 it will likely fail. Only run agents the user specifically asks you to run.'
4395
4518
  });
@@ -5323,7 +5446,7 @@ function isNewerVersion(current, latest) {
5323
5446
  return false;
5324
5447
  }
5325
5448
  async function checkForUpdate() {
5326
- const currentVersion = "0.1.17";
5449
+ const currentVersion = "0.1.19";
5327
5450
  if (!currentVersion) return null;
5328
5451
  try {
5329
5452
  const { loadConfig: loadConfig2, saveConfig: saveConfig2 } = await Promise.resolve().then(() => (init_config(), config_exports));
@@ -5352,7 +5475,7 @@ async function checkForUpdate() {
5352
5475
  }
5353
5476
  }
5354
5477
  function printUpdateNotice(latestVersion) {
5355
- const currentVersion = "0.1.17";
5478
+ const currentVersion = "0.1.19";
5356
5479
  process.stderr.write(
5357
5480
  `
5358
5481
  ${ansi2.cyanBright("Update available")} ${ansi2.gray(currentVersion + " \u2192")} ${ansi2.cyanBold(latestVersion)}
@@ -5427,7 +5550,7 @@ async function cmdLogin(options) {
5427
5550
  process.stderr.write("\n");
5428
5551
  printLogo();
5429
5552
  process.stderr.write("\n");
5430
- const ver = "0.1.17";
5553
+ const ver = "0.1.19";
5431
5554
  process.stderr.write(
5432
5555
  ` ${ansi2.bold("MindStudio Agent")} ${ver ? " " + ansi2.gray("v" + ver) : ""}
5433
5556
  `
@@ -5513,6 +5636,9 @@ async function cmdLogin(options) {
5513
5636
  ${ansi2.bold("Using with Claude Code?")} Run once to enable the MCP server:
5514
5637
  ${ansi2.cyan("claude mcp add mindstudio -- mindstudio mcp")}
5515
5638
 
5639
+ ${ansi2.bold("Need help?")} Ask the SDK anything:
5640
+ ${ansi2.cyan('mindstudio ask "how do I generate an image?"')}
5641
+
5516
5642
  `
5517
5643
  );
5518
5644
  return;
@@ -5735,6 +5861,12 @@ async function main() {
5735
5861
  const command = positionals[0];
5736
5862
  const updatePromise = command !== "mcp" && command !== "login" ? checkForUpdate() : Promise.resolve(null);
5737
5863
  try {
5864
+ if (command === "version" || command === "-v") {
5865
+ process.stdout.write(
5866
+ "0.1.19\n"
5867
+ );
5868
+ return;
5869
+ }
5738
5870
  if (command === "login") {
5739
5871
  await cmdLogin({
5740
5872
  baseUrl: values["base-url"]
package/dist/index.d.ts CHANGED
@@ -726,6 +726,7 @@ declare class Query<T> implements PromiseLike<T[]> {
726
726
  * (fast path) or a fallback SELECT * with JS processing metadata.
727
727
  */
728
728
  interface CompiledQuery<T> {
729
+ type: 'query';
729
730
  /** Compiled SQL query, or null if JS fallback needed. */
730
731
  query: SqlQuery | null;
731
732
  /** SELECT * fallback query, or null if SQL compiled. */
@@ -744,12 +745,76 @@ interface CompiledQuery<T> {
744
745
  offset?: number;
745
746
  }
746
747
 
748
+ /**
749
+ * Mutation<T> — a lazy write operation backed by SQLite.
750
+ *
751
+ * Created by Table write methods (push, update, remove, removeAll, clear).
752
+ * Like Query, implements PromiseLike so `await` triggers execution. Unlike
753
+ * Query, there's no chaining — a Mutation is a fixed set of SQL statements
754
+ * with a result processor.
755
+ *
756
+ * ## Batch support
757
+ *
758
+ * `db.batch()` calls `_compile()` to extract the SQL without executing,
759
+ * then bundles it with other operations into a single round trip. After
760
+ * execution, `_processResults()` deserializes the raw SQL results.
761
+ *
762
+ * ## Non-batchable mutations
763
+ *
764
+ * Some mutations (e.g. `removeAll` with a JS-fallback predicate) require
765
+ * multi-step execution that can't be expressed as a fixed SQL batch.
766
+ * These are created via `Mutation.fromExecutor()` and work fine when
767
+ * awaited standalone, but throw if passed to `db.batch()`.
768
+ */
769
+
770
+ interface CompiledMutation<TResult> {
771
+ type: 'mutation';
772
+ queries: SqlQuery[];
773
+ config: TableConfig;
774
+ processResult: (results: SqlResult[]) => TResult;
775
+ }
776
+ declare class Mutation<TResult> implements PromiseLike<TResult> {
777
+ /** @internal */
778
+ private readonly _config;
779
+ /** @internal */
780
+ private readonly _queries;
781
+ /** @internal */
782
+ private readonly _processResult;
783
+ /** @internal Non-batchable executor for complex mutations (e.g. removeAll JS fallback). */
784
+ private readonly _executor;
785
+ constructor(config: TableConfig, queries: SqlQuery[], processResult: (results: SqlResult[]) => TResult);
786
+ /**
787
+ * Create a non-batchable mutation that wraps an async executor.
788
+ * Used for operations that require multi-step execution (e.g. removeAll
789
+ * with a JS-fallback predicate: fetch all rows → filter → delete).
790
+ *
791
+ * Works fine when awaited standalone. Throws if passed to db.batch().
792
+ *
793
+ * @internal
794
+ */
795
+ static fromExecutor<T>(config: TableConfig, executor: () => Promise<T>): Mutation<T>;
796
+ then<T1 = TResult, T2 = never>(onfulfilled?: ((value: TResult) => T1 | PromiseLike<T1>) | null, onrejected?: ((reason: unknown) => T2 | PromiseLike<T2>) | null): Promise<T1 | T2>;
797
+ /**
798
+ * @internal Compile this mutation into SQL for batch execution.
799
+ * Returns the queries and a result processor.
800
+ *
801
+ * Throws if this is a non-batchable mutation (created via fromExecutor).
802
+ */
803
+ _compile(): CompiledMutation<TResult>;
804
+ /**
805
+ * @internal Process raw SQL results into the typed result.
806
+ * Used by db.batch() after executing the compiled queries.
807
+ */
808
+ static _processResults<T>(results: SqlResult[], compiled: CompiledMutation<T>): T;
809
+ private _execute;
810
+ }
811
+
747
812
  /**
748
813
  * Table<T> — a typed persistent collection backed by SQLite.
749
814
  *
750
815
  * Created via `db.defineTable<T>(name)`. Every method either returns a
751
- * chainable Query<T> (for lazy reads) or a Promise (for terminal reads
752
- * and writes).
816
+ * chainable Query<T> (for lazy reads), a Mutation<T> (for lazy writes),
817
+ * or a Promise (for terminal reads).
753
818
  *
754
819
  * ## Write operations use RETURNING
755
820
  *
@@ -781,19 +846,19 @@ declare class Table<T> {
781
846
  * Uses `INSERT ... RETURNING *` so the created row comes back in a
782
847
  * single round trip — no separate SELECT needed.
783
848
  */
784
- push(data: PushInput<T>): Promise<T>;
785
- push(data: PushInput<T>[]): Promise<T[]>;
849
+ push(data: PushInput<T>): Mutation<T>;
850
+ push(data: PushInput<T>[]): Mutation<T[]>;
786
851
  /**
787
852
  * Update a row by ID. Only the provided fields are changed.
788
853
  * Returns the updated row via `UPDATE ... RETURNING *`.
789
854
  */
790
- update(id: string, data: UpdateInput<T>): Promise<T>;
791
- remove(id: string): Promise<void>;
855
+ update(id: string, data: UpdateInput<T>): Mutation<T>;
856
+ remove(id: string): Mutation<void>;
792
857
  /**
793
858
  * Remove all rows matching a predicate. Returns the count removed.
794
859
  */
795
- removeAll(predicate: Predicate<T>): Promise<number>;
796
- clear(): Promise<void>;
860
+ removeAll(predicate: Predicate<T>): Mutation<number>;
861
+ clear(): Mutation<void>;
797
862
  }
798
863
 
799
864
  /**
@@ -904,18 +969,21 @@ interface Db {
904
969
  /** Returns a unix timestamp for (now + duration). Use with days/hours/minutes. */
905
970
  fromNow(ms: number): number;
906
971
  /**
907
- * Execute multiple queries in a single round trip. All queries run on
908
- * the same database connection, eliminating per-query HTTP overhead.
972
+ * Execute multiple reads and writes in a single round trip. All
973
+ * operations run on the same database connection, eliminating
974
+ * per-operation HTTP overhead. Writes execute in argument order.
909
975
  *
910
- * Accepts Query objects (lazy, not yet executed). Compiles them to SQL,
976
+ * Accepts Query objects (reads) and Mutation objects (writes from
977
+ * push, update, remove, removeAll, clear). Compiles them to SQL,
911
978
  * sends all in one batch request, and returns typed results.
912
979
  *
913
980
  * @example
914
981
  * ```ts
915
- * const [orders, approvals, vendors] = await db.batch(
916
- * Orders.filter(o => o.status === 'active').take(10),
917
- * Approvals.filter(a => a.status === 'pending').take(25),
918
- * Vendors.sortBy(v => v.createdAt).reverse().take(5),
982
+ * // Mixed reads and writes in one round trip
983
+ * const [, newCard, cards] = await db.batch(
984
+ * Cards.update(card1.id, { position: 1 }),
985
+ * Cards.push({ title: 'New', columnId, position: 0 }),
986
+ * Cards.filter(c => c.columnId === columnId),
919
987
  * );
920
988
  * ```
921
989
  */