@protobase/server 0.33.4 → 0.34.1
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/assistant/query-tools.js +1 -1
- package/dist/auth/jwt.d.ts +15 -1
- package/dist/auth/jwt.js +41 -5
- package/dist/better-auth/authenticator.d.ts +16 -1
- package/dist/better-auth/authenticator.js +41 -24
- package/dist/better-auth/create-auth.d.ts +3063 -363
- package/dist/better-auth/create-auth.js +39 -20
- package/dist/better-auth/mcp/connected-apps.d.ts +13 -0
- package/dist/better-auth/mcp/connected-apps.js +86 -0
- package/dist/better-auth/mcp/consent-check.js +38 -0
- package/dist/better-auth/mcp/consent-reference.js +16 -0
- package/dist/better-auth/mcp/discovery-routes.js +19 -0
- package/dist/better-auth/mcp/grant-reference.js +25 -0
- package/dist/better-auth/mcp/mcp-plugins.d.ts +13 -0
- package/dist/better-auth/mcp/mcp-plugins.js +107 -0
- package/dist/better-auth/mcp/mcp-token-claims.js +39 -0
- package/dist/better-auth/mcp/request-defaults.js +57 -0
- package/dist/better-auth/mcp/revoke-grants.js +75 -0
- package/dist/better-auth/mcp/setup-gate.js +38 -0
- package/dist/better-auth/mcp/signed-query-guard.js +29 -0
- package/dist/better-auth/new-account-password.d.ts +6 -0
- package/dist/better-auth/new-account-password.js +6 -3
- package/dist/better-auth/origins.d.ts +7 -0
- package/dist/better-auth/origins.js +8 -1
- package/dist/better-auth/password-reset.js +4 -3
- package/dist/better-auth/policy-plugin.js +1 -24
- package/dist/better-auth/sign-in-enforcement.js +6 -1
- package/dist/better-auth/sign-in-setup.js +38 -0
- package/dist/better-auth/sign-up/sign-up-plugin.js +1 -1
- package/dist/better-auth/snake-case-names.js +102 -1
- package/dist/better-auth/staff-checks.js +9 -2
- package/dist/better-auth/staff-plugin.js +9 -2
- package/dist/better-auth/status-route.js +2 -1
- package/dist/better-auth/token-claims.js +19 -0
- package/dist/better-auth/users.d.ts +4 -1
- package/dist/better-auth/users.js +6 -1
- package/dist/check-roles.js +1 -1
- package/dist/create-admin.js +8 -0
- package/dist/deps.d.ts +1 -0
- package/dist/encryption/apply.d.ts +40 -0
- package/dist/encryption/apply.js +99 -0
- package/dist/encryption/binding.d.ts +2 -0
- package/dist/encryption/binding.js +53 -0
- package/dist/encryption/capture-off.js +12 -0
- package/dist/encryption/cascading-keys.d.ts +9 -0
- package/dist/encryption/cascading-keys.js +21 -0
- package/dist/encryption/envelope-open.d.ts +5 -0
- package/dist/encryption/envelope-open.js +57 -0
- package/dist/encryption/envelope-seal.js +38 -0
- package/dist/encryption/keyring.js +60 -0
- package/dist/encryption/mask-stored.js +16 -0
- package/dist/encryption/rebind-check.js +28 -0
- package/dist/encryption/remnants.js +53 -0
- package/dist/encryption/runtime.d.ts +1 -0
- package/dist/encryption/runtime.js +18 -0
- package/dist/encryption/scan.d.ts +4 -0
- package/dist/encryption/scan.js +61 -0
- package/dist/encryption/seal-values.js +30 -0
- package/dist/encryption/shared-columns.js +19 -0
- package/dist/encryption/status.d.ts +39 -0
- package/dist/encryption/status.js +92 -0
- package/dist/encryption/stored-value.js +16 -0
- package/dist/encryption/tools.d.ts +26 -0
- package/dist/encryption/tools.js +34 -0
- package/dist/forms/check-forms.js +1 -1
- package/dist/gotrue/user-routes.js +6 -0
- package/dist/index.d.ts +10 -5
- package/dist/index.js +4 -2
- package/dist/records.js +3 -3
- package/dist/request-access.js +9 -5
- package/dist/rest/encrypted-columns.js +37 -0
- package/dist/rest/table-routes.js +25 -13
- package/dist/reveal-service.js +17 -3
- package/dist/types.d.ts +5 -0
- package/dist/validate-body.js +4 -2
- package/dist/webhooks/subscriber-view.js +14 -1
- package/dist/write-pipeline.js +14 -2
- package/dist/write-shared.js +7 -3
- package/dist/write-update.js +12 -2
- package/package.json +11 -7
package/dist/write-pipeline.js
CHANGED
|
@@ -1,11 +1,13 @@
|
|
|
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 {
|
|
4
|
+
import { bindingOf, pendingBinding } from "./encryption/binding.js";
|
|
5
|
+
import { deleteRecord, fetchRecord, insertRecord, restoreRecord, updateRecord } from "./records.js";
|
|
5
6
|
import { writeTransaction } from "./transactions.js";
|
|
6
7
|
import { blockedDelete } from "./blocked-delete.js";
|
|
7
8
|
import { isDatabaseError } from "./error-handler.js";
|
|
8
9
|
import { attachFiles } from "./files/attach.js";
|
|
10
|
+
import { encryptedValuesOf, hasEncryptedValues, sealValues } from "./encryption/seal-values.js";
|
|
9
11
|
import { actorSettings, wakeDispatch } from "./changes/actor.js";
|
|
10
12
|
import { validateBody } from "./validate-body.js";
|
|
11
13
|
import { assertWritten, checkParents, checkPrecondition, decide, denied, firstKeyField, keyOf, missing, notifier, shown } from "./write-shared.js";
|
|
@@ -21,6 +23,14 @@ const withOwner = (access, values) => {
|
|
|
21
23
|
[owner]: caller
|
|
22
24
|
};
|
|
23
25
|
};
|
|
26
|
+
const bindEncrypted = async (trx, deps, access, row, inserted, shape) => {
|
|
27
|
+
const { entry, full } = access;
|
|
28
|
+
if (!hasEncryptedValues(full, row)) return inserted;
|
|
29
|
+
const values = sealValues(deps.encryption, full, encryptedValuesOf(full, row), (field) => bindingOf(full, field, inserted.record));
|
|
30
|
+
const bound = await updateRecord(trx, entry, keyOf(access, inserted.record), tenantScope(entry, access.session)?.tenantValue, values, shape);
|
|
31
|
+
if (!bound) throw new Error(`A ${entry.name} record was created whose key the API cannot address, so its encrypted fields cannot be bound to it`);
|
|
32
|
+
return bound;
|
|
33
|
+
};
|
|
24
34
|
const create = async (trx, deps, access, body) => {
|
|
25
35
|
const { entry, full } = access;
|
|
26
36
|
const scope = tenantScope(entry, access.session);
|
|
@@ -33,7 +43,9 @@ const create = async (trx, deps, access, body) => {
|
|
|
33
43
|
const filter = await decide(access, "create", void 0, row);
|
|
34
44
|
const parents = checkParents(trx, access, "create");
|
|
35
45
|
await parents(row);
|
|
36
|
-
const
|
|
46
|
+
const shape = { etagFields: Object.keys(access.model.fields) };
|
|
47
|
+
const inserted = await insertRecord(trx, entry, sealValues(deps.encryption, full, row, (field) => pendingBinding(full, field)), shape);
|
|
48
|
+
const created = await bindEncrypted(trx, deps, access, row, inserted, shape);
|
|
37
49
|
await assertWritten(trx, access, created, "create", access.resolved.rowFilter.create, filter);
|
|
38
50
|
await parents(created.record);
|
|
39
51
|
if (full.position) await checkRankAfter(trx, deps, access, full.position.field, [{
|
package/dist/write-shared.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { maskEncrypted } from "./encryption/mask-stored.js";
|
|
1
2
|
import { forbidden, notFound, preconditionFailed, preconditionRequired } from "./problem.js";
|
|
2
3
|
import { tenantScope } from "./tenant.js";
|
|
3
4
|
import { andFilters, recordDecision } from "./request-access.js";
|
|
@@ -44,7 +45,10 @@ const assertWritten = async (trx, access, written, operation, ...filters) => {
|
|
|
44
45
|
fields: [firstKeyField(access)]
|
|
45
46
|
})) throw denied(access.entry, `leave in that state (${operation})`);
|
|
46
47
|
};
|
|
47
|
-
/**
|
|
48
|
+
/**
|
|
49
|
+
* The caller sees the readable fields only, files as objects with their URL; hooks get the whole record, a set encrypted
|
|
50
|
+
* field as `encrypted`.
|
|
51
|
+
*/
|
|
48
52
|
const shown = async (access, written) => ({
|
|
49
53
|
record: (await presentFiles(access, [pickFields(written.record, Object.keys(access.model.fields))]))[0],
|
|
50
54
|
etag: written.etag
|
|
@@ -58,8 +62,8 @@ const notifier = (deps, access) => async (trx, kind, before, after) => {
|
|
|
58
62
|
user: session.user,
|
|
59
63
|
...session.tenant !== void 0 && { tenant: session.tenant },
|
|
60
64
|
...session.anonymous && { anonymous: true },
|
|
61
|
-
...before && { before },
|
|
62
|
-
...after && { after }
|
|
65
|
+
...before && { before: maskEncrypted(access.full, before) },
|
|
66
|
+
...after && { after: maskEncrypted(access.full, after) }
|
|
63
67
|
};
|
|
64
68
|
for (const hook of deps.hooks) await hook(event, trx);
|
|
65
69
|
await scheduleRemovedFiles(access, kind, before, after);
|
package/dist/write-update.js
CHANGED
|
@@ -1,7 +1,10 @@
|
|
|
1
|
+
import { badRequest } from "./problem.js";
|
|
1
2
|
import { tenantScope } from "./tenant.js";
|
|
2
3
|
import { targetFilter } from "./request-access.js";
|
|
4
|
+
import { bindingOf } from "./encryption/binding.js";
|
|
3
5
|
import { fetchRecord, updateRecord } from "./records.js";
|
|
4
6
|
import { attachFiles } from "./files/attach.js";
|
|
7
|
+
import { sealValues } from "./encryption/seal-values.js";
|
|
5
8
|
import { validateBody } from "./validate-body.js";
|
|
6
9
|
import { assertWritten, checkParents, checkPrecondition, decide, denied, firstKeyField, missing, notifier } from "./write-shared.js";
|
|
7
10
|
//#region src/write-update.ts
|
|
@@ -40,11 +43,18 @@ const planUpdate = async (trx, access, key, body, ifMatch, required = true) => {
|
|
|
40
43
|
parents
|
|
41
44
|
};
|
|
42
45
|
};
|
|
46
|
+
const refuseKeyChange = (access, plan) => {
|
|
47
|
+
const { full, entry } = access;
|
|
48
|
+
if (!Object.values(full.fields).some((field) => field.encrypted)) return;
|
|
49
|
+
if (full.primaryKey.some((name) => Object.hasOwn(plan.values, name) && String(plan.values[name]) !== String(plan.current.record[name]))) throw badRequest("key-change-unsupported", `The key of a ${entry.name} record cannot change: its encrypted fields are bound to it`);
|
|
50
|
+
};
|
|
43
51
|
/** Writes a planned update, checks the row as written against the filters, and runs the hooks. */
|
|
44
52
|
const applyUpdate = async (trx, deps, access, key, plan) => {
|
|
45
|
-
const { entry } = access;
|
|
53
|
+
const { entry, full } = access;
|
|
54
|
+
refuseKeyChange(access, plan);
|
|
46
55
|
const tenant = tenantScope(entry, access.session)?.tenantValue;
|
|
47
|
-
const
|
|
56
|
+
const values = sealValues(deps.encryption, full, plan.values, (field) => bindingOf(full, field, plan.current.record));
|
|
57
|
+
const updated = await updateRecord(trx, entry, key, tenant, values, { etagFields: Object.keys(access.model.fields) });
|
|
48
58
|
await assertWritten(trx, access, updated, "update", access.resolved.rowFilter.update, plan.filter);
|
|
49
59
|
await plan.parents(updated.record);
|
|
50
60
|
await notifier(deps, access)(trx, "update", plan.current.record, updated.record);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@protobase/server",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.34.1",
|
|
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": {
|
|
@@ -30,18 +30,22 @@
|
|
|
30
30
|
"access": "public"
|
|
31
31
|
},
|
|
32
32
|
"dependencies": {
|
|
33
|
-
"@better-auth/
|
|
34
|
-
"@better-auth/
|
|
35
|
-
"@
|
|
36
|
-
"@
|
|
37
|
-
"@
|
|
33
|
+
"@better-auth/cimd": "^1.7.12",
|
|
34
|
+
"@better-auth/mcp": "^1.7.12",
|
|
35
|
+
"@better-auth/oauth-provider": "^1.7.12",
|
|
36
|
+
"@better-auth/passkey": "^1.7.12",
|
|
37
|
+
"@better-auth/sso": "^1.7.12",
|
|
38
|
+
"@protobase/layout": "0.34.1",
|
|
39
|
+
"@protobase/query": "0.34.1",
|
|
40
|
+
"@protobase/schema": "0.34.1",
|
|
38
41
|
"@react-email/render": "^2.1.0",
|
|
39
42
|
"@scalar/hono-api-reference": "^0.12.10",
|
|
40
43
|
"@sentry/core": "^11.7.0",
|
|
41
44
|
"@simplewebauthn/server": "^13.3.1",
|
|
42
45
|
"altcha-lib": "^2.6.0",
|
|
43
46
|
"bcryptjs": "^3.0.3",
|
|
44
|
-
"better-auth": "^1.7.
|
|
47
|
+
"better-auth": "^1.7.12",
|
|
48
|
+
"better-call": "1.4.4",
|
|
45
49
|
"cron-parser": "^5.10.1",
|
|
46
50
|
"file-type": "^22.1.1",
|
|
47
51
|
"hono": "^4.13.13",
|