@protobase/server 0.41.1 → 0.43.0

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.
Files changed (56) hide show
  1. package/dist/aggregate-groups.js +1 -1
  2. package/dist/aggregate-service.js +3 -3
  3. package/dist/aggregate-splits.js +1 -1
  4. package/dist/ai/generate-route.js +1 -1
  5. package/dist/assistant/batch-approval.js +55 -0
  6. package/dist/assistant/batch-write-args.js +63 -0
  7. package/dist/assistant/batch-write-tool.d.ts +7 -0
  8. package/dist/assistant/batch-write-tool.js +115 -0
  9. package/dist/assistant/delete-record-tool.d.ts +6 -0
  10. package/dist/assistant/delete-record-tool.js +76 -0
  11. package/dist/assistant/record-tool-args.js +14 -1
  12. package/dist/assistant/record-tools.js +16 -8
  13. package/dist/assistant/records.d.ts +20 -1
  14. package/dist/assistant/records.js +19 -5
  15. package/dist/assistant/write-record-tools.d.ts +4 -6
  16. package/dist/assistant/write-record-tools.js +12 -13
  17. package/dist/assistant/write-tool-limits.d.ts +6 -0
  18. package/dist/assistant/write-tool-limits.js +15 -0
  19. package/dist/batch/reorder.js +1 -1
  20. package/dist/batch/run-batch.d.ts +26 -0
  21. package/dist/batch/run-batch.js +2 -2
  22. package/dist/batch/schema.d.ts +221 -0
  23. package/dist/comments/mentionable.js +1 -1
  24. package/dist/comments/read-comments.js +1 -1
  25. package/dist/create-admin.js +1 -1
  26. package/dist/error-handler.js +1 -1
  27. package/dist/files/download.js +4 -4
  28. package/dist/files/present.js +1 -1
  29. package/dist/functions/records.d.ts +2 -7
  30. package/dist/functions/records.js +5 -18
  31. package/dist/history/read-history.js +3 -3
  32. package/dist/index.d.ts +8 -3
  33. package/dist/index.js +4 -2
  34. package/dist/jobs/run-job.d.ts +1 -1
  35. package/dist/list-photos.js +2 -2
  36. package/dist/list-service.js +3 -3
  37. package/dist/map-service.js +1 -1
  38. package/dist/mcp/mcp-tools.d.ts +3 -6
  39. package/dist/mcp/mcp-tools.js +3 -1
  40. package/dist/package.js +1 -1
  41. package/dist/read-service.js +7 -4
  42. package/dist/realtime/change-checker.js +1 -1
  43. package/dist/records.d.ts +5 -0
  44. package/dist/rest/rest-context.js +1 -1
  45. package/dist/reveal-service.js +1 -1
  46. package/dist/routes/batch.js +1 -1
  47. package/dist/routes/collection.js +1 -1
  48. package/dist/routes/record.js +4 -5
  49. package/dist/row-permissions.js +1 -1
  50. package/dist/sql-parts.d.ts +4 -0
  51. package/dist/sql-parts.js +1 -1
  52. package/dist/write-pipeline.js +5 -5
  53. package/dist/write-shared.d.ts +13 -0
  54. package/dist/write-shared.js +2 -2
  55. package/dist/write-update.js +1 -1
  56. package/package.json +4 -4
@@ -1,10 +1,11 @@
1
1
  import { notFound } from "./problem.js";
2
2
  import { requestAccess, requireOperation, visibleFields, writableFields } from "./request-access.js";
3
- import { presentFiles } from "./files/present.js";
3
+ import { readTransaction } from "./transactions.js";
4
4
  import { pickFields } from "./rows.js";
5
5
  import { fetchReadable } from "./fetch-readable.js";
6
+ import { presentFiles } from "./files/present.js";
7
+ import { deletedRows } from "./params.js";
6
8
  import { rowPermissions } from "./row-permissions.js";
7
- import { readTransaction } from "./transactions.js";
8
9
  //#region src/read-service.ts
9
10
  /**
10
11
  * `edit` for fields the caller may change on this record, `read` for the rest (sensitive ones included); hidden fields
@@ -18,11 +19,13 @@ const fieldModes = (access, canUpdate) => {
18
19
  };
19
20
  /**
20
21
  * The record with this key as the caller may see it: readable fields only, inside the caller's tenant and row filter.
21
- * A key outside the tenant, outside the row filter, or failing a record-level read rule is a plain 404.
22
+ * A key outside the tenant, outside the row filter, or failing a record-level read rule is a plain 404. `showDeleted`
23
+ * also finds a soft-deleted record, and is refused on a resource without a soft delete once the caller may read it.
22
24
  */
23
- const readRecord = async (deps, entry, session, key, deleted = "hide") => {
25
+ const readRecord = async (deps, entry, session, key, showDeleted = false) => {
24
26
  const access = await requestAccess(deps, entry, session);
25
27
  requireOperation(access, "read");
28
+ const deleted = deletedRows(access.full, showDeleted);
26
29
  const names = Object.keys(access.model.fields);
27
30
  const found = await readTransaction(deps.db, deps.statementTimeoutMs, async (trx) => {
28
31
  const current = await fetchReadable(trx, access, key, deleted, {
@@ -1,5 +1,5 @@
1
- import { readTransaction } from "../transactions.js";
2
1
  import { quoteIdent, tableSql } from "../changes/capture-sql.js";
2
+ import { readTransaction } from "../transactions.js";
3
3
  import { callerSettings } from "../rest/caller-settings.js";
4
4
  import { filterSql } from "./change-filter.js";
5
5
  import { decodeKey, encodeKey } from "@protobase/schema/internal";
@@ -0,0 +1,5 @@
1
+ import "./types.js";
2
+ import "./registry.js";
3
+ import "./sql-parts.js";
4
+ import { FieldModel } from "@protobase/schema";
5
+ import { Db } from "@protobase/query";
@@ -1,5 +1,5 @@
1
- import { readTransaction, writeTransaction } from "../transactions.js";
2
1
  import { wakeDispatch } from "../changes/actor.js";
2
+ import { readTransaction, writeTransaction } from "../transactions.js";
3
3
  import { callerSettings } from "./caller-settings.js";
4
4
  import { restError } from "./rest-error.js";
5
5
  //#region src/rest/rest-context.ts
@@ -1,9 +1,9 @@
1
1
  import { badRequest, notFound } from "./problem.js";
2
2
  import { tenantScope } from "./tenant.js";
3
3
  import { requestAccess, requireOperation } from "./request-access.js";
4
+ import { readTransaction } from "./transactions.js";
4
5
  import { bindingOf } from "./encryption/binding.js";
5
6
  import { fetchReadable } from "./fetch-readable.js";
6
- import { readTransaction } from "./transactions.js";
7
7
  import { openText } from "./encryption/envelope-open.js";
8
8
  import { encodeKey } from "@protobase/schema/internal";
9
9
  //#region src/reveal-service.ts
@@ -1,6 +1,6 @@
1
+ import { runBatch } from "../batch/run-batch.js";
1
2
  import { parseParams } from "../params.js";
2
3
  import { batchBody } from "../batch/schema.js";
3
- import { runBatch } from "../batch/run-batch.js";
4
4
  import { Hono } from "hono";
5
5
  //#region src/routes/batch.ts
6
6
  /**
@@ -1,5 +1,5 @@
1
- import { listRecords } from "../list-service.js";
2
1
  import { runWrite } from "../write-pipeline.js";
2
+ import { listRecords } from "../list-service.js";
3
3
  import { facets, numericHistogram, timeSeries } from "../aggregate-service.js";
4
4
  import { aggregate } from "../aggregate-groups.js";
5
5
  import { mapRecords } from "../map-service.js";
@@ -1,9 +1,9 @@
1
1
  import { notFound } from "../problem.js";
2
- import { keyFromPath } from "../key.js";
3
- import { deletedRows, selectedFields } from "../params.js";
4
2
  import { pickFields } from "../rows.js";
5
- import { readRecord } from "../read-service.js";
6
3
  import { runWrite } from "../write-pipeline.js";
4
+ import { keyFromPath } from "../key.js";
5
+ import { selectedFields } from "../params.js";
6
+ import { readRecord } from "../read-service.js";
7
7
  import { auditOrigin } from "../audit/origin.js";
8
8
  import { returnPreference } from "./preferences.js";
9
9
  import { resolveTarget } from "./target.js";
@@ -22,8 +22,7 @@ const recordRoutes = (deps) => {
22
22
  if (c.req.param("key").endsWith(":history")) return c.json(await readHistory(deps, entry, c.get("session"), keyFromPath(c, entry, ":history"), c.req.query()));
23
23
  if (c.req.param("key").endsWith(":comments")) return c.json(await readComments(deps, entry, c.get("session"), keyFromPath(c, entry, ":comments"), c.req.query()));
24
24
  if (c.req.param("key").endsWith(":mentionable")) return c.json(await mentionable(deps, entry, c.get("session"), keyFromPath(c, entry, ":mentionable"), c.req.query()));
25
- const deleted = deletedRows(entry.model, c.req.query("show_deleted") === "true");
26
- const found = await readRecord(deps, entry, c.get("session"), keyFromPath(c, entry), deleted);
25
+ const found = await readRecord(deps, entry, c.get("session"), keyFromPath(c, entry), c.req.query("show_deleted") === "true");
27
26
  const columns = selectedFields({
28
27
  ...entry.model,
29
28
  fields: Object.fromEntries(Object.keys(found.record).map((name) => [name, entry.model.fields[name]]))
@@ -3,8 +3,8 @@ import { recordDecision } from "./request-access.js";
3
3
  import { aliasedColumn, columnId, scopeConditions, tableId, whereClause } from "./sql-parts.js";
4
4
  import { fetchRecord } from "./records.js";
5
5
  import { parentGuard } from "./parent-access.js";
6
- import { compileFilter } from "@protobase/query";
7
6
  import { sql } from "kysely";
7
+ import { compileFilter } from "@protobase/query";
8
8
  //#region src/row-permissions.ts
9
9
  const keyOf = (access, row) => JSON.stringify(access.full.primaryKey.map((name) => String(row[name])));
10
10
  const matching = async (trx, access, rows, filter) => {
@@ -0,0 +1,4 @@
1
+ import "./types.js";
2
+ import "./registry.js";
3
+ import { FieldModel, ResourceModel } from "@protobase/schema";
4
+ import "kysely";
package/dist/sql-parts.js CHANGED
@@ -1,5 +1,5 @@
1
- import { compileFilter } from "@protobase/query";
2
1
  import { sql } from "kysely";
2
+ import { compileFilter } from "@protobase/query";
3
3
  //#region src/sql-parts.ts
4
4
  const etagAlias = "__pb_etag";
5
5
  const tableId = (model) => {
@@ -1,16 +1,16 @@
1
1
  import { HttpProblem, badRequest } from "./problem.js";
2
2
  import { tenantScope } from "./tenant.js";
3
3
  import { requestAccess, requireOperation, targetFilter, writableFields } from "./request-access.js";
4
+ import { actorSettings, wakeDispatch } from "./changes/actor.js";
5
+ import { isDatabaseError } from "./error-handler.js";
6
+ import { writeTransaction } from "./transactions.js";
4
7
  import { bindingOf, pendingBinding } from "./encryption/binding.js";
5
8
  import { deleteRecord, fetchRecord, insertRecord, restoreRecord, updateRecord } from "./records.js";
6
- import { writeTransaction } from "./transactions.js";
7
- import { blockedDelete } from "./blocked-delete.js";
8
- import { isDatabaseError } from "./error-handler.js";
9
9
  import { attachFiles } from "./files/attach.js";
10
+ import { assertWritten, checkParents, checkPrecondition, decide, denied, firstKeyField, keyOf, missing, notifier, shown } from "./write-shared.js";
11
+ import { blockedDelete } from "./blocked-delete.js";
10
12
  import { encryptedValuesOf, hasEncryptedValues, sealValues } from "./encryption/seal-values.js";
11
- import { actorSettings, wakeDispatch } from "./changes/actor.js";
12
13
  import { validateBody } from "./validate-body.js";
13
- import { assertWritten, checkParents, checkPrecondition, decide, denied, firstKeyField, keyOf, missing, notifier, shown } from "./write-shared.js";
14
14
  import { applyUpdate, planUpdate } from "./write-update.js";
15
15
  import { checkRankAfter } from "./rank-after.js";
16
16
  //#region src/write-pipeline.ts
@@ -0,0 +1,13 @@
1
+ import { Row } from "./types.js";
2
+ import "./registry.js";
3
+ import "./deps.js";
4
+ import "./records.js";
5
+ import "./request-access.js";
6
+ import "@protobase/schema";
7
+ import { Db } from "@protobase/query";
8
+ //#region src/write-shared.d.ts
9
+ export type WriteResult = {
10
+ record: Row;
11
+ etag: string;
12
+ };
13
+ //#endregion
@@ -3,11 +3,11 @@ import { forbidden, notFound, preconditionFailed, preconditionRequired } from ".
3
3
  import { tenantScope } from "./tenant.js";
4
4
  import { andFilters, recordDecision } from "./request-access.js";
5
5
  import { ifMatchSatisfied } from "./etag.js";
6
- import { presentFiles } from "./files/present.js";
7
6
  import { pickFields } from "./rows.js";
8
7
  import { fetchRecord } from "./records.js";
9
- import { parentGuard } from "./parent-access.js";
10
8
  import { scheduleRemovedFiles } from "./files/attach.js";
9
+ import { parentGuard } from "./parent-access.js";
10
+ import { presentFiles } from "./files/present.js";
11
11
  //#region src/write-shared.ts
12
12
  const missing = (entry) => notFound(`No ${entry.name} with this key`);
13
13
  const checkPrecondition = (current, ifMatch, required) => {
@@ -4,9 +4,9 @@ import { targetFilter } from "./request-access.js";
4
4
  import { bindingOf } from "./encryption/binding.js";
5
5
  import { fetchRecord, updateRecord } from "./records.js";
6
6
  import { attachFiles } from "./files/attach.js";
7
+ import { assertWritten, checkParents, checkPrecondition, decide, denied, firstKeyField, missing, notifier } from "./write-shared.js";
7
8
  import { sealValues } from "./encryption/seal-values.js";
8
9
  import { validateBody } from "./validate-body.js";
9
- import { assertWritten, checkParents, checkPrecondition, decide, denied, firstKeyField, missing, notifier } from "./write-shared.js";
10
10
  //#region src/write-update.ts
11
11
  /**
12
12
  * Everything an update needs before it writes: the row (locked, inside the caller's tenant and row filters), the ETag
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@protobase/server",
3
- "version": "0.41.1",
3
+ "version": "0.43.0",
4
4
  "description": "The Protobase REST API as a Hono app, with Better Auth sign-in.",
5
5
  "license": "Apache-2.0",
6
6
  "repository": {
@@ -36,9 +36,9 @@
36
36
  "@better-auth/passkey": "^1.7.12",
37
37
  "@better-auth/sso": "^1.7.12",
38
38
  "@modelcontextprotocol/server": "^2.3.1",
39
- "@protobase/layout": "0.41.1",
40
- "@protobase/query": "0.41.1",
41
- "@protobase/schema": "0.41.1",
39
+ "@protobase/layout": "0.43.0",
40
+ "@protobase/query": "0.43.0",
41
+ "@protobase/schema": "0.43.0",
42
42
  "@react-email/render": "^2.1.0",
43
43
  "@scalar/hono-api-reference": "^0.12.10",
44
44
  "@sentry/core": "^11.7.0",