@riffdb/better-auth 0.0.0-stage → 0.2.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/DESIGN.md +273 -0
- package/LICENSE-APACHE +201 -0
- package/LICENSE-MIT +27 -0
- package/README.md +323 -2
- package/dist/adapter.d.ts +34 -0
- package/dist/adapter.d.ts.map +1 -0
- package/dist/adapter.js +1600 -0
- package/dist/adapter.js.map +1 -0
- package/dist/generated/client.d.ts +2166 -0
- package/dist/generated/client.d.ts.map +1 -0
- package/dist/generated/client.js +2454 -0
- package/dist/generated/client.js.map +1 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +7 -0
- package/dist/index.js.map +1 -0
- package/dist/plugin-dispatch.d.ts +37 -0
- package/dist/plugin-dispatch.d.ts.map +1 -0
- package/dist/plugin-dispatch.js +293 -0
- package/dist/plugin-dispatch.js.map +1 -0
- package/dist/profile-contract.d.ts +63 -0
- package/dist/profile-contract.d.ts.map +1 -0
- package/dist/profile-contract.js +543 -0
- package/dist/profile-contract.js.map +1 -0
- package/dist/profile-plan.d.ts +69 -0
- package/dist/profile-plan.d.ts.map +1 -0
- package/dist/profile-plan.js +180 -0
- package/dist/profile-plan.js.map +1 -0
- package/dist/profile.d.ts +48 -0
- package/dist/profile.d.ts.map +1 -0
- package/dist/profile.js +132 -0
- package/dist/profile.js.map +1 -0
- package/dist/profiles/custom-fields/profile.d.ts +3 -0
- package/dist/profiles/custom-fields/profile.d.ts.map +1 -0
- package/dist/profiles/custom-fields/profile.js +475 -0
- package/dist/profiles/custom-fields/profile.js.map +1 -0
- package/dist/profiles/custom-fields/src/generated/client.d.ts +2710 -0
- package/dist/profiles/custom-fields/src/generated/client.d.ts.map +1 -0
- package/dist/profiles/custom-fields/src/generated/client.js +2663 -0
- package/dist/profiles/custom-fields/src/generated/client.js.map +1 -0
- package/dist/profiles/runtime/profile.d.ts +3 -0
- package/dist/profiles/runtime/profile.d.ts.map +1 -0
- package/dist/profiles/runtime/profile.js +1065 -0
- package/dist/profiles/runtime/profile.js.map +1 -0
- package/dist/profiles/runtime/src/generated/client.d.ts +4274 -0
- package/dist/profiles/runtime/src/generated/client.d.ts.map +1 -0
- package/dist/profiles/runtime/src/generated/client.js +4607 -0
- package/dist/profiles/runtime/src/generated/client.js.map +1 -0
- package/dist/runtime-materialize.d.ts +10 -0
- package/dist/runtime-materialize.d.ts.map +1 -0
- package/dist/runtime-materialize.js +344 -0
- package/dist/runtime-materialize.js.map +1 -0
- package/dist/runtime-profile.d.ts +34 -0
- package/dist/runtime-profile.d.ts.map +1 -0
- package/dist/runtime-profile.js +203 -0
- package/dist/runtime-profile.js.map +1 -0
- package/dist/testing.d.ts +11 -0
- package/dist/testing.d.ts.map +1 -0
- package/dist/testing.js +12 -0
- package/dist/testing.js.map +1 -0
- package/generated/go/client.go +2250 -0
- package/generated/mcp/tools.json +13922 -0
- package/generated/python/client.py +4454 -0
- package/generated/riffdb.application.exact.json +1 -0
- package/generated/riffdb.contract.bundle +0 -0
- package/generated/rust/client.rs +6524 -0
- package/package.json +83 -4
- package/profiles/custom-fields/generated/go/client.go +2578 -0
- package/profiles/custom-fields/generated/mcp/tools.json +15998 -0
- package/profiles/custom-fields/generated/python/client.py +5141 -0
- package/profiles/custom-fields/generated/riffdb.application.exact.json +1 -0
- package/profiles/custom-fields/generated/riffdb.contract.bundle +0 -0
- package/profiles/custom-fields/generated/rust/client.rs +7980 -0
- package/profiles/custom-fields/profile.ts +474 -0
- package/profiles/custom-fields/riffdb/contract.riff +568 -0
- package/profiles/custom-fields/riffdb/queries/admin_users_all_email_asc.riffq +24 -0
- package/profiles/custom-fields/riffdb/queries/admin_users_contains_asc.riffq +24 -0
- package/profiles/custom-fields/riffdb/queries/admin_users_contains_desc.riffq +24 -0
- package/profiles/custom-fields/riffdb/queries/admin_users_email_contains_created_desc.riffq +24 -0
- package/profiles/custom-fields/riffdb/queries/admin_users_email_contains_image_asc.riffq +24 -0
- package/profiles/custom-fields/riffdb/queries/admin_users_ends_with_asc.riffq +24 -0
- package/profiles/custom-fields/riffdb/queries/admin_users_ends_with_desc.riffq +24 -0
- package/profiles/custom-fields/riffdb/queries/admin_users_starts_with_asc.riffq +24 -0
- package/profiles/custom-fields/riffdb/queries/admin_users_starts_with_desc.riffq +24 -0
- package/profiles/custom-fields/riffdb/queries/find_account_by_id.riffq +24 -0
- package/profiles/custom-fields/riffdb/queries/find_account_by_provider.riffq +26 -0
- package/profiles/custom-fields/riffdb/queries/find_accounts_by_user_id.riffq +25 -0
- package/profiles/custom-fields/riffdb/queries/find_accounts_by_user_provider.riffq +27 -0
- package/profiles/custom-fields/riffdb/queries/find_active_sessions_by_user_id.riffq +23 -0
- package/profiles/custom-fields/riffdb/queries/find_credential_account.riffq +25 -0
- package/profiles/custom-fields/riffdb/queries/find_expired_verification_ids.riffq +17 -0
- package/profiles/custom-fields/riffdb/queries/find_latest_verification.riffq +20 -0
- package/profiles/custom-fields/riffdb/queries/find_session_by_id.riffq +20 -0
- package/profiles/custom-fields/riffdb/queries/find_session_by_token.riffq +20 -0
- package/profiles/custom-fields/riffdb/queries/find_sessions_by_token_set.riffq +20 -0
- package/profiles/custom-fields/riffdb/queries/find_sessions_by_user_id.riffq +21 -0
- package/profiles/custom-fields/riffdb/queries/find_user_by_email.riffq +16 -0
- package/profiles/custom-fields/riffdb/queries/find_user_by_id.riffq +15 -0
- package/profiles/custom-fields/riffdb/queries/find_verification_by_id.riffq +19 -0
- package/profiles/custom-fields/riffdb/queries/find_verifications_by_identifier.riffq +21 -0
- package/profiles/custom-fields/riffdb/queries/profile_account_with_user_by_provider.riffq +31 -0
- package/profiles/custom-fields/riffdb/queries/profile_session_with_user_by_id.riffq +14 -0
- package/profiles/custom-fields/riffdb/queries/profile_session_with_user_by_token.riffq +14 -0
- package/profiles/custom-fields/riffdb/queries/profile_sessions_with_users_by_token_set.riffq +25 -0
- package/profiles/custom-fields/riffdb/queries/profile_user_with_accounts_by_email.riffq +19 -0
- package/profiles/custom-fields/riffdb/queries/profile_user_with_accounts_by_id.riffq +19 -0
- package/profiles/custom-fields/riffdb.application.json +217 -0
- package/profiles/custom-fields/riffdb.application.lock.json +1 -0
- package/profiles/custom-fields/riffdb.toml +3 -0
- package/profiles/custom-fields/src/generated/client.ts +3096 -0
- package/profiles/organization-security/materialization.json +51 -0
- package/profiles/organization-security/riffdb/contract.riff +778 -0
- package/profiles/organization-security/riffdb/queries/find_account_by_id.riffq +18 -0
- package/profiles/organization-security/riffdb/queries/find_invitation_by_email.riffq +17 -0
- package/profiles/organization-security/riffdb/queries/find_invitation_by_id.riffq +18 -0
- package/profiles/organization-security/riffdb/queries/find_invitation_by_organization_id.riffq +17 -0
- package/profiles/organization-security/riffdb/queries/find_member_by_id.riffq +18 -0
- package/profiles/organization-security/riffdb/queries/find_member_by_user_id.riffq +17 -0
- package/profiles/organization-security/riffdb/queries/find_organization_by_id.riffq +16 -0
- package/profiles/organization-security/riffdb/queries/find_organization_by_slug.riffq +16 -0
- package/profiles/organization-security/riffdb/queries/find_session_by_id.riffq +18 -0
- package/profiles/organization-security/riffdb/queries/find_session_by_token.riffq +16 -0
- package/profiles/organization-security/riffdb/queries/find_team_by_id.riffq +18 -0
- package/profiles/organization-security/riffdb/queries/find_team_member_by_id.riffq +18 -0
- package/profiles/organization-security/riffdb/queries/find_team_member_by_membership_key.riffq +16 -0
- package/profiles/organization-security/riffdb/queries/find_team_member_by_team_id.riffq +17 -0
- package/profiles/organization-security/riffdb/queries/find_two_factor_by_id.riffq +18 -0
- package/profiles/organization-security/riffdb/queries/find_two_factor_by_secret.riffq +17 -0
- package/profiles/organization-security/riffdb/queries/find_user_by_email.riffq +16 -0
- package/profiles/organization-security/riffdb/queries/find_user_by_id.riffq +16 -0
- package/profiles/organization-security/riffdb/queries/find_verification_by_id.riffq +16 -0
- package/profiles/organization-security/riffdb/queries/find_verification_by_identifier.riffq +17 -0
- package/profiles/organization-security/riffdb.application.json +172 -0
- package/profiles/organization-security/riffdb.toml +7 -0
- package/profiles/organization-security.profile.json +980 -0
- package/profiles/runtime/generated/go/client.go +4511 -0
- package/profiles/runtime/generated/mcp/tools.json +30004 -0
- package/profiles/runtime/generated/python/client.py +9337 -0
- package/profiles/runtime/generated/riffdb.application.exact.json +1 -0
- package/profiles/runtime/generated/riffdb.contract.bundle +0 -0
- package/profiles/runtime/generated/rust/client.rs +13297 -0
- package/profiles/runtime/profile.ts +1064 -0
- package/profiles/runtime/riffdb/contract.riff +1053 -0
- package/profiles/runtime/riffdb/queries/admin_users_all_email_asc.riffq +24 -0
- package/profiles/runtime/riffdb/queries/admin_users_contains_asc.riffq +24 -0
- package/profiles/runtime/riffdb/queries/admin_users_contains_desc.riffq +24 -0
- package/profiles/runtime/riffdb/queries/admin_users_email_contains_created_desc.riffq +24 -0
- package/profiles/runtime/riffdb/queries/admin_users_email_contains_image_asc.riffq +24 -0
- package/profiles/runtime/riffdb/queries/admin_users_ends_with_asc.riffq +24 -0
- package/profiles/runtime/riffdb/queries/admin_users_ends_with_desc.riffq +24 -0
- package/profiles/runtime/riffdb/queries/admin_users_starts_with_asc.riffq +24 -0
- package/profiles/runtime/riffdb/queries/admin_users_starts_with_desc.riffq +24 -0
- package/profiles/runtime/riffdb/queries/find_account_by_id.riffq +24 -0
- package/profiles/runtime/riffdb/queries/find_account_by_provider.riffq +26 -0
- package/profiles/runtime/riffdb/queries/find_accounts_by_user_id.riffq +25 -0
- package/profiles/runtime/riffdb/queries/find_accounts_by_user_provider.riffq +27 -0
- package/profiles/runtime/riffdb/queries/find_active_sessions_by_user_id.riffq +23 -0
- package/profiles/runtime/riffdb/queries/find_credential_account.riffq +25 -0
- package/profiles/runtime/riffdb/queries/find_expired_verification_ids.riffq +17 -0
- package/profiles/runtime/riffdb/queries/find_latest_verification.riffq +20 -0
- package/profiles/runtime/riffdb/queries/find_session_by_id.riffq +20 -0
- package/profiles/runtime/riffdb/queries/find_session_by_token.riffq +20 -0
- package/profiles/runtime/riffdb/queries/find_sessions_by_token_set.riffq +20 -0
- package/profiles/runtime/riffdb/queries/find_sessions_by_user_id.riffq +21 -0
- package/profiles/runtime/riffdb/queries/find_user_by_email.riffq +16 -0
- package/profiles/runtime/riffdb/queries/find_user_by_id.riffq +15 -0
- package/profiles/runtime/riffdb/queries/find_verification_by_id.riffq +19 -0
- package/profiles/runtime/riffdb/queries/find_verifications_by_identifier.riffq +21 -0
- package/profiles/runtime/riffdb/queries/profile_account_with_user_by_provider.riffq +31 -0
- package/profiles/runtime/riffdb/queries/profile_invitation_by_email.riffq +17 -0
- package/profiles/runtime/riffdb/queries/profile_invitation_by_id.riffq +17 -0
- package/profiles/runtime/riffdb/queries/profile_invitation_by_organization_email_status.riffq +19 -0
- package/profiles/runtime/riffdb/queries/profile_invitation_by_organization_id.riffq +17 -0
- package/profiles/runtime/riffdb/queries/profile_invitation_by_organization_status.riffq +18 -0
- package/profiles/runtime/riffdb/queries/profile_member_by_id.riffq +27 -0
- package/profiles/runtime/riffdb/queries/profile_member_by_organization.riffq +20 -0
- package/profiles/runtime/riffdb/queries/profile_member_by_organization_created_at_asc.riffq +20 -0
- package/profiles/runtime/riffdb/queries/profile_member_by_organization_created_at_desc.riffq +20 -0
- package/profiles/runtime/riffdb/queries/profile_member_by_organization_role_asc.riffq +20 -0
- package/profiles/runtime/riffdb/queries/profile_member_by_organization_role_desc.riffq +20 -0
- package/profiles/runtime/riffdb/queries/profile_member_by_organization_user.riffq +28 -0
- package/profiles/runtime/riffdb/queries/profile_member_by_user.riffq +27 -0
- package/profiles/runtime/riffdb/queries/profile_organization_by_id.riffq +27 -0
- package/profiles/runtime/riffdb/queries/profile_organization_by_slug.riffq +27 -0
- package/profiles/runtime/riffdb/queries/profile_session_with_user_by_id.riffq +14 -0
- package/profiles/runtime/riffdb/queries/profile_session_with_user_by_token.riffq +14 -0
- package/profiles/runtime/riffdb/queries/profile_sessions_with_users_by_token_set.riffq +25 -0
- package/profiles/runtime/riffdb/queries/profile_two_factor_by_id.riffq +17 -0
- package/profiles/runtime/riffdb/queries/profile_two_factor_by_user.riffq +17 -0
- package/profiles/runtime/riffdb/queries/profile_user_with_accounts_by_email.riffq +19 -0
- package/profiles/runtime/riffdb/queries/profile_user_with_accounts_by_id.riffq +19 -0
- package/profiles/runtime/riffdb/queries/profile_users_by_id_set.riffq +8 -0
- package/profiles/runtime/riffdb.application.json +324 -0
- package/profiles/runtime/riffdb.application.lock.json +1 -0
- package/profiles/runtime/riffdb.toml +3 -0
- package/profiles/runtime/src/generated/client.ts +5186 -0
- package/riffdb/contract.riff +547 -0
- package/riffdb/queries/admin_users_all_email_asc.riffq +24 -0
- package/riffdb/queries/admin_users_contains_asc.riffq +24 -0
- package/riffdb/queries/admin_users_contains_desc.riffq +24 -0
- package/riffdb/queries/admin_users_email_contains_created_desc.riffq +24 -0
- package/riffdb/queries/admin_users_email_contains_image_asc.riffq +24 -0
- package/riffdb/queries/admin_users_ends_with_asc.riffq +24 -0
- package/riffdb/queries/admin_users_ends_with_desc.riffq +24 -0
- package/riffdb/queries/admin_users_starts_with_asc.riffq +24 -0
- package/riffdb/queries/admin_users_starts_with_desc.riffq +24 -0
- package/riffdb/queries/find_account_by_id.riffq +24 -0
- package/riffdb/queries/find_account_by_provider.riffq +26 -0
- package/riffdb/queries/find_accounts_by_user_id.riffq +25 -0
- package/riffdb/queries/find_accounts_by_user_provider.riffq +27 -0
- package/riffdb/queries/find_active_sessions_by_user_id.riffq +23 -0
- package/riffdb/queries/find_credential_account.riffq +25 -0
- package/riffdb/queries/find_expired_verification_ids.riffq +17 -0
- package/riffdb/queries/find_latest_verification.riffq +20 -0
- package/riffdb/queries/find_session_by_id.riffq +20 -0
- package/riffdb/queries/find_session_by_token.riffq +20 -0
- package/riffdb/queries/find_sessions_by_token_set.riffq +20 -0
- package/riffdb/queries/find_sessions_by_user_id.riffq +21 -0
- package/riffdb/queries/find_user_by_email.riffq +16 -0
- package/riffdb/queries/find_user_by_id.riffq +15 -0
- package/riffdb/queries/find_verification_by_id.riffq +19 -0
- package/riffdb/queries/find_verifications_by_identifier.riffq +21 -0
- package/riffdb.application.json +187 -0
- package/riffdb.application.lock.json +1 -0
- package/scripts/real-riffdb-runner.mjs +333 -0
- package/src/generated/client.ts +2746 -0
package/README.md
CHANGED
|
@@ -1,3 +1,324 @@
|
|
|
1
|
-
#
|
|
1
|
+
# `@riffdb/better-auth`
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
An external Better Auth database adapter for RiffDB.
|
|
4
|
+
|
|
5
|
+
Status: core and compiled runtime profiles are implemented for Better Auth
|
|
6
|
+
`1.7.18`. The default core profile, a custom-field profile, and an organization
|
|
7
|
+
plus 2FA profile run through Better Auth's official authentication-flow suite
|
|
8
|
+
against a real TLS loopback RiffDB service. The custom-field profile also runs
|
|
9
|
+
the official additional-fields test.
|
|
10
|
+
|
|
11
|
+
`nextCookies()` is supported with each profile. Organizations and 2FA require
|
|
12
|
+
an explicitly selected, deployed compiled profile. Teams and dynamic access
|
|
13
|
+
control remain unsupported. The organization profile also rejects user deletion;
|
|
14
|
+
its stored member and invitation references remain enforced.
|
|
15
|
+
|
|
16
|
+
## Architecture boundary
|
|
17
|
+
|
|
18
|
+
Better Auth-specific code lives in this repository, never in RiffDB. The
|
|
19
|
+
adapter dispatches only to generated named RiffDB commands and queries from a
|
|
20
|
+
reviewed compiled profile. It does not expose generic CRUD, accept arbitrary
|
|
21
|
+
transaction callbacks, perform client-side authorization filtering, or
|
|
22
|
+
silently fall back for unknown models, fields, joins, predicates, or plugins.
|
|
23
|
+
|
|
24
|
+
The default core runtime profile is deliberately exact:
|
|
25
|
+
|
|
26
|
+
- Better Auth `1.7.18`;
|
|
27
|
+
- the four default core models and their default field names;
|
|
28
|
+
- UUID identifiers for every model;
|
|
29
|
+
- the reviewed `nextCookies()` integration, with no storage plugins or additional fields; and
|
|
30
|
+
- the bundled `RiffDBBetterAuthCore` contract and `BetterAuthServer` role.
|
|
31
|
+
|
|
32
|
+
Unsupported configuration fails before any RiffDB request. A custom or plugin
|
|
33
|
+
profile requires its own generated contract, named operations, client facade,
|
|
34
|
+
and conformance tests. `materializeRiffDBBetterAuthRuntimeProfile` emits the
|
|
35
|
+
reviewable runtime sources and binding; RiffDB compiles and locks their client.
|
|
36
|
+
Adapter construction also verifies that the resolved
|
|
37
|
+
`better-auth` installation is exactly `1.7.18`; package-manager overrides do
|
|
38
|
+
not bypass that runtime check. Secret-bearing Better Auth debug logging is
|
|
39
|
+
rejected rather than forwarded to the factory logger.
|
|
40
|
+
|
|
41
|
+
## Runtime use
|
|
42
|
+
|
|
43
|
+
```ts
|
|
44
|
+
import { DriverApplicationTransport } from "@riffdb/client";
|
|
45
|
+
import { betterAuth } from "better-auth";
|
|
46
|
+
import { riffdbAdapter } from "@riffdb/better-auth";
|
|
47
|
+
|
|
48
|
+
const driver = await DriverApplicationTransport.connect({
|
|
49
|
+
socketPath,
|
|
50
|
+
identity,
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
export const auth = betterAuth({
|
|
54
|
+
database: riffdbAdapter({
|
|
55
|
+
driver,
|
|
56
|
+
organizationId: "018f5f7e-7b0c-7d9a-8f14-77f42f53c851",
|
|
57
|
+
}),
|
|
58
|
+
advanced: { database: { generateId: "uuid" } },
|
|
59
|
+
emailAndPassword: { enabled: true },
|
|
60
|
+
});
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
The caller owns the RiffDB driver connection and application-defined
|
|
64
|
+
organization ID. Better Auth continues to own users, sessions, passwords,
|
|
65
|
+
sign-in, OAuth, and reset flows. The package contains the exact RiffDB
|
|
66
|
+
application source, lock, contract bundle, and generated artifacts required to
|
|
67
|
+
deploy the core profile. Better Auth development dependencies stay exactly
|
|
68
|
+
pinned. Supported versions are explicit; a scheduled registry check flags new
|
|
69
|
+
stable releases for schema, call-shape, and conformance review.
|
|
70
|
+
|
|
71
|
+
For Next.js Server Actions, import `nextCookies` from `better-auth/next-js`
|
|
72
|
+
and add `nextCookies()` as the last plugin in the Better Auth configuration.
|
|
73
|
+
It can accompany the default core profile or the compiled profiles below.
|
|
74
|
+
Cookie propagation, RSC refresh suppression, and Server Action refresh behavior
|
|
75
|
+
are covered by integration tests using the official plugin and mocked Next.js
|
|
76
|
+
request helpers.
|
|
77
|
+
|
|
78
|
+
## Organization and 2FA runtime profile
|
|
79
|
+
|
|
80
|
+
Deploy `profiles/runtime/riffdb.application.json` and its exact lock before
|
|
81
|
+
connecting the driver. Select its binding explicitly:
|
|
82
|
+
|
|
83
|
+
```ts
|
|
84
|
+
import profile from "@riffdb/better-auth/profiles/organization-security";
|
|
85
|
+
import { organization, twoFactor } from "better-auth/plugins";
|
|
86
|
+
|
|
87
|
+
const auth = betterAuth({
|
|
88
|
+
database: riffdbAdapter({ driver, organizationId: tenantId, profile }),
|
|
89
|
+
advanced: { database: { generateId: "uuid" } },
|
|
90
|
+
emailAndPassword: { enabled: true },
|
|
91
|
+
user: {
|
|
92
|
+
additionalFields: {
|
|
93
|
+
locale: { type: "string", required: false },
|
|
94
|
+
dateField: { type: "date", required: false },
|
|
95
|
+
},
|
|
96
|
+
},
|
|
97
|
+
plugins: [
|
|
98
|
+
organization({ membershipLimit: 100, invitationLimit: 100 }),
|
|
99
|
+
twoFactor(),
|
|
100
|
+
],
|
|
101
|
+
});
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
These are example profile fields; `dateField` also serves the upstream
|
|
105
|
+
conformance test. Generate a separate reviewed profile to use a different field
|
|
106
|
+
inventory. The standalone custom-field example is available at
|
|
107
|
+
`@riffdb/better-auth/profiles/custom-fields` and deploys from
|
|
108
|
+
`profiles/custom-fields/` without storage plugins.
|
|
109
|
+
|
|
110
|
+
The adapter's `organizationId` is the application's RiffDB tenant partition.
|
|
111
|
+
The organization plugin's `organizationId` identifies an auth organization
|
|
112
|
+
inside that partition. They are separate identifiers.
|
|
113
|
+
|
|
114
|
+
The organization profile supports organization creation/update/listing, active
|
|
115
|
+
organization sessions, membership listing/counts/roles/removal, invitations and
|
|
116
|
+
guarded status transitions, and atomic organization/dependent deletion.
|
|
117
|
+
Membership creation and session activation during invitation acceptance share
|
|
118
|
+
one compiled command. Native capacity guards admit at most 100 live memberships
|
|
119
|
+
and 100 retained invitations per organization; deleting an individual record
|
|
120
|
+
releases its capacity. Lists are bounded at 100, membership offsets at 4096,
|
|
121
|
+
and user hydration sets at 32. Member pages support the compiled default role
|
|
122
|
+
order, role ascending/descending, and creation-time ascending/descending.
|
|
123
|
+
Other member filters and sorts are rejected.
|
|
124
|
+
|
|
125
|
+
2FA supports TOTP enrollment/verification, OTP challenges, backup codes,
|
|
126
|
+
challenge consumption, and account lockout. Failure increments, expired-lock
|
|
127
|
+
reset, backup-code replacement, and invitation status transitions use native
|
|
128
|
+
compiled commands. Tests cover TOTP enrollment, backup-code and invitation
|
|
129
|
+
races, challenge replay, lockout counters, capacity contention, and reset rollback.
|
|
130
|
+
|
|
131
|
+
Teams, dynamic access control, organization mutation hooks, renamed storage,
|
|
132
|
+
plugin-model custom fields, user deletion in organization profiles, and
|
|
133
|
+
`revokeSessionsOnPasswordReset` are rejected. Password changes that request
|
|
134
|
+
`revokeOtherSessions` also require a separately compiled transaction graph.
|
|
135
|
+
Organization limits must be integers from 1 through 100. Custom runtime fields
|
|
136
|
+
currently support scalar strings, booleans, safe integers, and dates on `user`;
|
|
137
|
+
custom indexes, uniqueness,
|
|
138
|
+
and references require a separately implemented profile. Credential password
|
|
139
|
+
reset supports an existing credential account and one verification row per
|
|
140
|
+
identifier. Additional transaction graphs fail closed.
|
|
141
|
+
|
|
142
|
+
## Implemented core surface
|
|
143
|
+
|
|
144
|
+
The core profile supports:
|
|
145
|
+
|
|
146
|
+
- atomic email/password signup and OAuth user/account creation;
|
|
147
|
+
- user, account, session, and verification create/read/update/delete paths;
|
|
148
|
+
- revision-guarded partial updates with bounded stale retries;
|
|
149
|
+
- atomic delete-and-return single-use verification consumption;
|
|
150
|
+
- bounded dependent and cascade deletion;
|
|
151
|
+
- active-session, token-set, provider-account, and verification queries;
|
|
152
|
+
- exact user counts with an optional UUID or bounded email text predicate; and
|
|
153
|
+
- bounded user windows with numeric offsets and compiled email, creation-time,
|
|
154
|
+
or nullable-image ordering.
|
|
155
|
+
|
|
156
|
+
User windows accept at most 100 results and an offset no greater than 4096.
|
|
157
|
+
Email search supports `contains`, `starts_with`, and `ends_with`; every accepted
|
|
158
|
+
filter/order combination maps to a distinct generated RiffQL query. Unsupported
|
|
159
|
+
counts, fields, filters, orderings, joins, transaction graphs, and increments
|
|
160
|
+
fail closed.
|
|
161
|
+
|
|
162
|
+
Token-set session reads use one bounded compiled membership query. Combining a
|
|
163
|
+
token set with an expiry cutoff remains unsupported until that exact compound
|
|
164
|
+
predicate has its own reviewed named query. Verification listing accepts its
|
|
165
|
+
compiled default order, plus `createdAt desc` with `limit: 1`; every other
|
|
166
|
+
verification sort is rejected before a RiffDB request.
|
|
167
|
+
|
|
168
|
+
Secret account credentials, session tokens, and verification values are read
|
|
169
|
+
by named RiffQL queries whose exact returned leaves carry compiler-checked
|
|
170
|
+
`reveals` declarations. The generated role receives authority only for those
|
|
171
|
+
leaves. These reads remain queries, while commands are reserved for writes and
|
|
172
|
+
atomic state transitions. Secret-output queries are excluded from generated
|
|
173
|
+
MCP tools by RiffDB.
|
|
174
|
+
|
|
175
|
+
## Planning a custom profile
|
|
176
|
+
|
|
177
|
+
`riffdbProfileAdapter` integrates with Better Auth's `createSchema` hook and
|
|
178
|
+
does not require a live database. It resolves the complete Better Auth schema,
|
|
179
|
+
including plugin models and additional fields, into a deterministic bounded
|
|
180
|
+
profile plan:
|
|
181
|
+
|
|
182
|
+
```ts
|
|
183
|
+
import { betterAuth } from "better-auth";
|
|
184
|
+
import { organization, twoFactor } from "better-auth/plugins";
|
|
185
|
+
import { riffdbProfileAdapter } from "@riffdb/better-auth";
|
|
186
|
+
|
|
187
|
+
export const auth = betterAuth({
|
|
188
|
+
database: riffdbProfileAdapter({
|
|
189
|
+
name: "BetterAuthOrganizationSecurity",
|
|
190
|
+
contractLineage: "BetterAuthOrganizationSecurity",
|
|
191
|
+
applicationRole: "BetterAuthServer",
|
|
192
|
+
output: "riffdb/better-auth.profile.json",
|
|
193
|
+
}),
|
|
194
|
+
advanced: { database: { generateId: "uuid" } },
|
|
195
|
+
user: {
|
|
196
|
+
additionalFields: {
|
|
197
|
+
locale: { type: "string", required: false },
|
|
198
|
+
},
|
|
199
|
+
},
|
|
200
|
+
plugins: [organization({ teams: { enabled: true } }), twoFactor()],
|
|
201
|
+
});
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
With that generation-only config, run the Better Auth CLI version matching the
|
|
205
|
+
pinned runtime:
|
|
206
|
+
|
|
207
|
+
```bash
|
|
208
|
+
npx auth@1.7.18 generate --config ./auth.profile.ts --yes
|
|
209
|
+
```
|
|
210
|
+
|
|
211
|
+
The output records resolved storage names, field types, required/unique/index
|
|
212
|
+
metadata, references, secret classification, default/update behavior, plugin
|
|
213
|
+
IDs, and finite profile bounds. It is an input to reviewed RiffDB profile
|
|
214
|
+
materialization, not a dynamically executable schema or migration. Runtime
|
|
215
|
+
methods on the generation-only adapter always fail.
|
|
216
|
+
|
|
217
|
+
The checked-in
|
|
218
|
+
[`profiles/organization-security.profile.json`](./profiles/organization-security.profile.json)
|
|
219
|
+
is a reproducible organization, teams, two-factor, and custom-user-field
|
|
220
|
+
example. Regenerate or verify it with:
|
|
221
|
+
|
|
222
|
+
```bash
|
|
223
|
+
npm run profiles:write
|
|
224
|
+
npm run profiles:check
|
|
225
|
+
```
|
|
226
|
+
|
|
227
|
+
## Materializing an executable profile
|
|
228
|
+
|
|
229
|
+
Pass the reviewed plan to `materializeRiffDBBetterAuthRuntimeProfile(plan)`.
|
|
230
|
+
Write the returned `files` under a new application directory, review the
|
|
231
|
+
contract, queries, and `profile.ts`, then run `riffdb application lock --write`
|
|
232
|
+
in that directory. Compile `profile.ts` and the generated TypeScript client
|
|
233
|
+
with your application and pass its default export as `riffdbAdapter({ profile,
|
|
234
|
+
driver, organizationId })`. A JSON plan alone cannot be passed to the adapter.
|
|
235
|
+
Runtime construction compares the resolved schema and reviewed plugins with
|
|
236
|
+
the bound plan before requests. Binding also checks compiler-owned command and
|
|
237
|
+
result schemas, so a stale client cannot silently omit a new optional field.
|
|
238
|
+
The generated client and driver enforce the exact compiled application and
|
|
239
|
+
operation identities.
|
|
240
|
+
|
|
241
|
+
The planning fixture also reports its explicit non-null requirement for the
|
|
242
|
+
optional unique team membership key; it cannot accept legacy null-key rows.
|
|
243
|
+
|
|
244
|
+
The executable generator accepts the core schema plus the reviewed organization
|
|
245
|
+
and 2FA schemas. The broader `materializeRiffDBBetterAuthProfile` remains a
|
|
246
|
+
planning tool: its teams example reports unenforced references and is not an
|
|
247
|
+
executable runtime profile.
|
|
248
|
+
|
|
249
|
+
Regenerate the executable examples with `npm run profiles:runtime`, review
|
|
250
|
+
the source diff, and write each application's lock explicitly. `npm run
|
|
251
|
+
profiles:check` verifies source freshness, compiler locks, and generated clients.
|
|
252
|
+
|
|
253
|
+
A different profile is a different compiled application identity. There is no
|
|
254
|
+
automatic switch or reinterpretation of existing core data. For existing
|
|
255
|
+
installations, plan and review an explicit data migration, including identifier
|
|
256
|
+
mapping, required/default fields, references, secrets, and capacity counts.
|
|
257
|
+
Deploy the matching contract, operations, role, and client together. Never point
|
|
258
|
+
a new binding at an old lock. Runtime profile examples are intended for fresh
|
|
259
|
+
installations until an application-specific migration has been reviewed.
|
|
260
|
+
|
|
261
|
+
## Local development
|
|
262
|
+
|
|
263
|
+
```bash
|
|
264
|
+
npm ci --ignore-scripts
|
|
265
|
+
npm run check
|
|
266
|
+
```
|
|
267
|
+
|
|
268
|
+
The lock is pinned to `@riffdb/client@0.2.1` and `@riffdb/cli@0.2.1`.
|
|
269
|
+
|
|
270
|
+
`npm run check` performs strict type checking, semantic and upstream tests,
|
|
271
|
+
profile-artifact freshness, a production build, and a package dry run.
|
|
272
|
+
|
|
273
|
+
## Real loopback conformance
|
|
274
|
+
|
|
275
|
+
Run the official suite against isolated TLS services and Rust driver hosts:
|
|
276
|
+
|
|
277
|
+
```bash
|
|
278
|
+
npm run test:loopback
|
|
279
|
+
```
|
|
280
|
+
|
|
281
|
+
This runs the core, custom-field, and organization/2FA profiles. It requires
|
|
282
|
+
`riffdbd` and `riffdb-driverd` from the immutable RiffDB build in
|
|
283
|
+
`.github/riffdb-revision` on PATH. `RIFFDB_CLI`, `RIFFDB_SERVER_BIN`, and
|
|
284
|
+
`RIFFDB_DRIVERD` can select exact local binaries. The published RiffDB `0.2.1`
|
|
285
|
+
release bundle includes the CLI and service, but omits the driver host. Build
|
|
286
|
+
that host from a separate RiffDB checkout at the full revision recorded in
|
|
287
|
+
`.github/riffdb-revision`:
|
|
288
|
+
|
|
289
|
+
```bash
|
|
290
|
+
# In that separate, pinned RiffDB checkout:
|
|
291
|
+
RUSTC_WRAPPER= cargo build --locked --release -p riffdb-driver-host --bin riffdb-driverd
|
|
292
|
+
|
|
293
|
+
# Back in this adapter checkout, with riffdbd on PATH:
|
|
294
|
+
RIFFDB_DRIVERD=/path/to/riffdb/target/release/riffdb-driverd npm run test:loopback
|
|
295
|
+
```
|
|
296
|
+
|
|
297
|
+
Release CI verifies the bundle checksum and revision, then builds the driver
|
|
298
|
+
from that same revision. Certificates, capabilities, sockets, and databases
|
|
299
|
+
are disposable and removed at the end. The official
|
|
300
|
+
harness's cleanup hook is scoped to that disposable service; it is never a
|
|
301
|
+
public delete-all operation.
|
|
302
|
+
|
|
303
|
+
The original `scripts/real-riffdb-runner.mjs` also remains available to an
|
|
304
|
+
external harness supplying its ten exact driver-identity arguments.
|
|
305
|
+
|
|
306
|
+
See [DESIGN.md](./DESIGN.md) for the method and safety inventory. The adapter
|
|
307
|
+
follows Better Auth's
|
|
308
|
+
[database-adapter guide](https://better-auth.com/docs/guides/create-a-db-adapter)
|
|
309
|
+
and uses its official pinned conformance utilities.
|
|
310
|
+
|
|
311
|
+
|
|
312
|
+
## RiffDB compatibility CI
|
|
313
|
+
|
|
314
|
+
This adapter owns its RiffDB compatibility checks. Pull requests compile the
|
|
315
|
+
application sources and verify existing locks and generated artifacts against
|
|
316
|
+
the full commit in `.github/riffdb-revision`. Scheduled checks use RiffDB
|
|
317
|
+
`main`; manual dispatch accepts a full commit or `main`. Failures are reported
|
|
318
|
+
here and do not block RiffDB itself. The job also runs `npm run check` and
|
|
319
|
+
`npm run test:loopback`, including the official Better Auth suite for every
|
|
320
|
+
advertised runtime profile.
|
|
321
|
+
|
|
322
|
+
To upgrade, update the pin, migrate sources as needed, review the result of
|
|
323
|
+
`riffdb application lock --write`, and verify with `riffdb application check`.
|
|
324
|
+
Commit the pin and migration together in this repository.
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { type DriverApplicationTransport } from "@riffdb/client";
|
|
2
|
+
import { type AdapterFactory, type DBAdapterDebugLogOption } from "better-auth/adapters";
|
|
3
|
+
import type { BetterAuthOptions } from "better-auth";
|
|
4
|
+
import { RiffDBBetterAuthCoreClient } from "./generated/client.js";
|
|
5
|
+
import { type RiffDBCompiledProfile } from "./runtime-profile.js";
|
|
6
|
+
export type RiffDBBetterAuthCallErrorCode = "invalid_configuration" | "unsupported_model" | "unsupported_call_shape" | "unsupported_transaction_shape" | "result_bound_exceeded" | "invalid_record_shape" | "declared_outcome";
|
|
7
|
+
export declare class RiffDBBetterAuthCallError extends Error {
|
|
8
|
+
readonly code: RiffDBBetterAuthCallErrorCode;
|
|
9
|
+
readonly operation: string;
|
|
10
|
+
readonly outcome?: string | undefined;
|
|
11
|
+
constructor(code: RiffDBBetterAuthCallErrorCode, operation: string, outcome?: string | undefined);
|
|
12
|
+
}
|
|
13
|
+
export interface RiffDBBetterAuthAdapterConfig {
|
|
14
|
+
readonly driver: DriverApplicationTransport;
|
|
15
|
+
readonly organizationId: string;
|
|
16
|
+
readonly commandAttemptBudget?: number;
|
|
17
|
+
readonly debugLogs?: DBAdapterDebugLogOption;
|
|
18
|
+
readonly profile?: RiffDBCompiledProfile;
|
|
19
|
+
}
|
|
20
|
+
type CoreClient = Omit<RiffDBBetterAuthCoreClient, "causalSession" | "withReadAfterCommit"> & {
|
|
21
|
+
causalSession(): CoreClient;
|
|
22
|
+
};
|
|
23
|
+
interface InternalAdapterConfig {
|
|
24
|
+
readonly client: CoreClient;
|
|
25
|
+
readonly organizationId: string;
|
|
26
|
+
readonly debugLogs?: DBAdapterDebugLogOption;
|
|
27
|
+
readonly resetModelForTesting?: (model: string) => number | Promise<number>;
|
|
28
|
+
readonly profile?: RiffDBCompiledProfile;
|
|
29
|
+
}
|
|
30
|
+
export declare function assertSupportedBetterAuthInstallation(installedVersion?: string): void;
|
|
31
|
+
export declare function buildRiffDBBetterAuthAdapter(config: InternalAdapterConfig): AdapterFactory<BetterAuthOptions>;
|
|
32
|
+
export declare function riffdbAdapter(config: RiffDBBetterAuthAdapterConfig): AdapterFactory<BetterAuthOptions>;
|
|
33
|
+
export {};
|
|
34
|
+
//# sourceMappingURL=adapter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"adapter.d.ts","sourceRoot":"","sources":["../src/adapter.ts"],"names":[],"mappings":"AAIA,OAAO,EAEL,KAAK,0BAA0B,EAChC,MAAM,gBAAgB,CAAC;AACxB,OAAO,EAEL,KAAK,cAAc,EAInB,KAAK,uBAAuB,EAE7B,MAAM,sBAAsB,CAAC;AAC9B,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAErD,OAAO,EACL,0BAA0B,EAe3B,MAAM,uBAAuB,CAAC;AAE/B,OAAO,EACL,KAAK,qBAAqB,EAAE,MAAM,sBAAsB,CAAC;AAkD3D,MAAM,MAAM,6BAA6B,GACrC,uBAAuB,GACvB,mBAAmB,GACnB,wBAAwB,GACxB,+BAA+B,GAC/B,uBAAuB,GACvB,sBAAsB,GACtB,kBAAkB,CAAC;AAEvB,qBAAa,yBAA0B,SAAQ,KAAK;aAEhC,IAAI,EAAE,6BAA6B;aACnC,SAAS,EAAE,MAAM;aACjB,OAAO,CAAC,EAAE,MAAM;IAHlC,YACkB,IAAI,EAAE,6BAA6B,EACnC,SAAS,EAAE,MAAM,EACjB,OAAO,CAAC,EAAE,MAAM,YAAA,EAQjC;CACF;AAED,MAAM,WAAW,6BAA6B;IAC5C,QAAQ,CAAC,MAAM,EAAE,0BAA0B,CAAC;IAC5C,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAC;IAChC,QAAQ,CAAC,oBAAoB,CAAC,EAAE,MAAM,CAAC;IACvC,QAAQ,CAAC,SAAS,CAAC,EAAE,uBAAuB,CAAC;IAC7C,QAAQ,CAAC,OAAO,CAAC,EAAE,qBAAqB,CAAC;CAC1C;AAED,KAAK,UAAU,GAAG,IAAI,CAAC,0BAA0B,EAAE,eAAe,GAAG,qBAAqB,CAAC,GAAG;IAC5F,aAAa,IAAI,UAAU,CAAC;CAC7B,CAAC;AAEF,UAAU,qBAAqB;IAC7B,QAAQ,CAAC,MAAM,EAAE,UAAU,CAAC;IAC5B,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAC;IAChC,QAAQ,CAAC,SAAS,CAAC,EAAE,uBAAuB,CAAC;IAC7C,QAAQ,CAAC,oBAAoB,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IAC5E,QAAQ,CAAC,OAAO,CAAC,EAAE,qBAAqB,CAAC;CAC1C;AAuBD,wBAAgB,qCAAqC,CACnD,gBAAgB,SAAsC,GACrD,IAAI,CAIN;AAqnDD,wBAAgB,4BAA4B,CAC1C,MAAM,EAAE,qBAAqB,GAC5B,cAAc,CAAC,iBAAiB,CAAC,CA2CnC;AAED,wBAAgB,aAAa,CAC3B,MAAM,EAAE,6BAA6B,GACpC,cAAc,CAAC,iBAAiB,CAAC,CAanC"}
|