@riffdb/better-auth 0.2.0 → 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.
Files changed (176) hide show
  1. package/DESIGN.md +90 -14
  2. package/README.md +157 -25
  3. package/dist/adapter.d.ts +7 -1
  4. package/dist/adapter.d.ts.map +1 -1
  5. package/dist/adapter.js +385 -47
  6. package/dist/adapter.js.map +1 -1
  7. package/dist/generated/client.d.ts +267 -26
  8. package/dist/generated/client.d.ts.map +1 -1
  9. package/dist/generated/client.js +479 -69
  10. package/dist/generated/client.js.map +1 -1
  11. package/dist/index.d.ts +3 -1
  12. package/dist/index.d.ts.map +1 -1
  13. package/dist/index.js +3 -1
  14. package/dist/index.js.map +1 -1
  15. package/dist/plugin-dispatch.d.ts +37 -0
  16. package/dist/plugin-dispatch.d.ts.map +1 -0
  17. package/dist/plugin-dispatch.js +293 -0
  18. package/dist/plugin-dispatch.js.map +1 -0
  19. package/dist/profile-contract.d.ts +3 -0
  20. package/dist/profile-contract.d.ts.map +1 -1
  21. package/dist/profile-contract.js +8 -0
  22. package/dist/profile-contract.js.map +1 -1
  23. package/dist/profile-plan.js +1 -1
  24. package/dist/profile-plan.js.map +1 -1
  25. package/dist/profile.d.ts +2 -1
  26. package/dist/profile.d.ts.map +1 -1
  27. package/dist/profile.js +2 -1
  28. package/dist/profile.js.map +1 -1
  29. package/dist/profiles/custom-fields/profile.d.ts +3 -0
  30. package/dist/profiles/custom-fields/profile.d.ts.map +1 -0
  31. package/dist/profiles/custom-fields/profile.js +475 -0
  32. package/dist/profiles/custom-fields/profile.js.map +1 -0
  33. package/dist/profiles/custom-fields/src/generated/client.d.ts +2710 -0
  34. package/dist/profiles/custom-fields/src/generated/client.d.ts.map +1 -0
  35. package/dist/profiles/custom-fields/src/generated/client.js +2663 -0
  36. package/dist/profiles/custom-fields/src/generated/client.js.map +1 -0
  37. package/dist/profiles/runtime/profile.d.ts +3 -0
  38. package/dist/profiles/runtime/profile.d.ts.map +1 -0
  39. package/dist/profiles/runtime/profile.js +1065 -0
  40. package/dist/profiles/runtime/profile.js.map +1 -0
  41. package/dist/profiles/runtime/src/generated/client.d.ts +4274 -0
  42. package/dist/profiles/runtime/src/generated/client.d.ts.map +1 -0
  43. package/dist/profiles/runtime/src/generated/client.js +4607 -0
  44. package/dist/profiles/runtime/src/generated/client.js.map +1 -0
  45. package/dist/runtime-materialize.d.ts +10 -0
  46. package/dist/runtime-materialize.d.ts.map +1 -0
  47. package/dist/runtime-materialize.js +344 -0
  48. package/dist/runtime-materialize.js.map +1 -0
  49. package/dist/runtime-profile.d.ts +34 -0
  50. package/dist/runtime-profile.d.ts.map +1 -0
  51. package/dist/runtime-profile.js +203 -0
  52. package/dist/runtime-profile.js.map +1 -0
  53. package/generated/go/client.go +350 -96
  54. package/generated/mcp/tools.json +3338 -1768
  55. package/generated/python/client.py +603 -26
  56. package/generated/riffdb.application.exact.json +1 -1
  57. package/generated/riffdb.contract.bundle +0 -0
  58. package/generated/rust/client.rs +522 -26
  59. package/package.json +34 -13
  60. package/profiles/custom-fields/generated/go/client.go +2578 -0
  61. package/profiles/custom-fields/generated/mcp/tools.json +15998 -0
  62. package/profiles/custom-fields/generated/python/client.py +5141 -0
  63. package/profiles/custom-fields/generated/riffdb.application.exact.json +1 -0
  64. package/profiles/custom-fields/generated/riffdb.contract.bundle +0 -0
  65. package/profiles/custom-fields/generated/rust/client.rs +7980 -0
  66. package/profiles/custom-fields/profile.ts +474 -0
  67. package/profiles/custom-fields/riffdb/contract.riff +568 -0
  68. package/profiles/custom-fields/riffdb/queries/admin_users_all_email_asc.riffq +24 -0
  69. package/profiles/custom-fields/riffdb/queries/admin_users_contains_asc.riffq +24 -0
  70. package/profiles/custom-fields/riffdb/queries/admin_users_contains_desc.riffq +24 -0
  71. package/profiles/custom-fields/riffdb/queries/admin_users_email_contains_created_desc.riffq +24 -0
  72. package/profiles/custom-fields/riffdb/queries/admin_users_email_contains_image_asc.riffq +24 -0
  73. package/profiles/custom-fields/riffdb/queries/admin_users_ends_with_asc.riffq +24 -0
  74. package/profiles/custom-fields/riffdb/queries/admin_users_ends_with_desc.riffq +24 -0
  75. package/profiles/custom-fields/riffdb/queries/admin_users_starts_with_asc.riffq +24 -0
  76. package/profiles/custom-fields/riffdb/queries/admin_users_starts_with_desc.riffq +24 -0
  77. package/profiles/custom-fields/riffdb/queries/find_account_by_id.riffq +24 -0
  78. package/profiles/custom-fields/riffdb/queries/find_account_by_provider.riffq +26 -0
  79. package/profiles/custom-fields/riffdb/queries/find_accounts_by_user_id.riffq +25 -0
  80. package/profiles/custom-fields/riffdb/queries/find_accounts_by_user_provider.riffq +27 -0
  81. package/profiles/custom-fields/riffdb/queries/find_active_sessions_by_user_id.riffq +23 -0
  82. package/profiles/custom-fields/riffdb/queries/find_credential_account.riffq +25 -0
  83. package/profiles/custom-fields/riffdb/queries/find_expired_verification_ids.riffq +17 -0
  84. package/profiles/custom-fields/riffdb/queries/find_latest_verification.riffq +20 -0
  85. package/profiles/custom-fields/riffdb/queries/find_session_by_id.riffq +20 -0
  86. package/profiles/custom-fields/riffdb/queries/find_session_by_token.riffq +20 -0
  87. package/profiles/custom-fields/riffdb/queries/find_sessions_by_token_set.riffq +20 -0
  88. package/profiles/custom-fields/riffdb/queries/find_sessions_by_user_id.riffq +21 -0
  89. package/profiles/custom-fields/riffdb/queries/find_user_by_email.riffq +16 -0
  90. package/profiles/custom-fields/riffdb/queries/find_user_by_id.riffq +15 -0
  91. package/profiles/custom-fields/riffdb/queries/find_verification_by_id.riffq +19 -0
  92. package/profiles/custom-fields/riffdb/queries/find_verifications_by_identifier.riffq +21 -0
  93. package/profiles/custom-fields/riffdb/queries/profile_account_with_user_by_provider.riffq +31 -0
  94. package/profiles/custom-fields/riffdb/queries/profile_session_with_user_by_id.riffq +14 -0
  95. package/profiles/custom-fields/riffdb/queries/profile_session_with_user_by_token.riffq +14 -0
  96. package/profiles/custom-fields/riffdb/queries/profile_sessions_with_users_by_token_set.riffq +25 -0
  97. package/profiles/custom-fields/riffdb/queries/profile_user_with_accounts_by_email.riffq +19 -0
  98. package/profiles/custom-fields/riffdb/queries/profile_user_with_accounts_by_id.riffq +19 -0
  99. package/profiles/custom-fields/riffdb.application.json +217 -0
  100. package/profiles/custom-fields/riffdb.application.lock.json +1 -0
  101. package/profiles/custom-fields/riffdb.toml +3 -0
  102. package/profiles/custom-fields/src/generated/client.ts +3096 -0
  103. package/profiles/organization-security/materialization.json +3 -0
  104. package/profiles/organization-security/riffdb/contract.riff +12 -0
  105. package/profiles/organization-security/riffdb/queries/find_team_by_id.riffq +1 -1
  106. package/profiles/organization-security/riffdb/queries/find_team_member_by_id.riffq +1 -1
  107. package/profiles/organization-security/riffdb/queries/find_team_member_by_membership_key.riffq +16 -0
  108. package/profiles/organization-security/riffdb/queries/find_team_member_by_team_id.riffq +1 -1
  109. package/profiles/organization-security/riffdb.application.json +5 -0
  110. package/profiles/organization-security.profile.json +27 -1
  111. package/profiles/runtime/generated/go/client.go +4511 -0
  112. package/profiles/runtime/generated/mcp/tools.json +30004 -0
  113. package/profiles/runtime/generated/python/client.py +9337 -0
  114. package/profiles/runtime/generated/riffdb.application.exact.json +1 -0
  115. package/profiles/runtime/generated/riffdb.contract.bundle +0 -0
  116. package/profiles/runtime/generated/rust/client.rs +13297 -0
  117. package/profiles/runtime/profile.ts +1064 -0
  118. package/profiles/runtime/riffdb/contract.riff +1053 -0
  119. package/profiles/runtime/riffdb/queries/admin_users_all_email_asc.riffq +24 -0
  120. package/profiles/runtime/riffdb/queries/admin_users_contains_asc.riffq +24 -0
  121. package/profiles/runtime/riffdb/queries/admin_users_contains_desc.riffq +24 -0
  122. package/profiles/runtime/riffdb/queries/admin_users_email_contains_created_desc.riffq +24 -0
  123. package/profiles/runtime/riffdb/queries/admin_users_email_contains_image_asc.riffq +24 -0
  124. package/profiles/runtime/riffdb/queries/admin_users_ends_with_asc.riffq +24 -0
  125. package/profiles/runtime/riffdb/queries/admin_users_ends_with_desc.riffq +24 -0
  126. package/profiles/runtime/riffdb/queries/admin_users_starts_with_asc.riffq +24 -0
  127. package/profiles/runtime/riffdb/queries/admin_users_starts_with_desc.riffq +24 -0
  128. package/profiles/runtime/riffdb/queries/find_account_by_id.riffq +24 -0
  129. package/profiles/runtime/riffdb/queries/find_account_by_provider.riffq +26 -0
  130. package/profiles/runtime/riffdb/queries/find_accounts_by_user_id.riffq +25 -0
  131. package/profiles/runtime/riffdb/queries/find_accounts_by_user_provider.riffq +27 -0
  132. package/profiles/runtime/riffdb/queries/find_active_sessions_by_user_id.riffq +23 -0
  133. package/profiles/runtime/riffdb/queries/find_credential_account.riffq +25 -0
  134. package/profiles/runtime/riffdb/queries/find_expired_verification_ids.riffq +17 -0
  135. package/profiles/runtime/riffdb/queries/find_latest_verification.riffq +20 -0
  136. package/profiles/runtime/riffdb/queries/find_session_by_id.riffq +20 -0
  137. package/profiles/runtime/riffdb/queries/find_session_by_token.riffq +20 -0
  138. package/profiles/runtime/riffdb/queries/find_sessions_by_token_set.riffq +20 -0
  139. package/profiles/runtime/riffdb/queries/find_sessions_by_user_id.riffq +21 -0
  140. package/profiles/runtime/riffdb/queries/find_user_by_email.riffq +16 -0
  141. package/profiles/runtime/riffdb/queries/find_user_by_id.riffq +15 -0
  142. package/profiles/runtime/riffdb/queries/find_verification_by_id.riffq +19 -0
  143. package/profiles/runtime/riffdb/queries/find_verifications_by_identifier.riffq +21 -0
  144. package/profiles/runtime/riffdb/queries/profile_account_with_user_by_provider.riffq +31 -0
  145. package/profiles/runtime/riffdb/queries/profile_invitation_by_email.riffq +17 -0
  146. package/profiles/runtime/riffdb/queries/profile_invitation_by_id.riffq +17 -0
  147. package/profiles/runtime/riffdb/queries/profile_invitation_by_organization_email_status.riffq +19 -0
  148. package/profiles/runtime/riffdb/queries/profile_invitation_by_organization_id.riffq +17 -0
  149. package/profiles/runtime/riffdb/queries/profile_invitation_by_organization_status.riffq +18 -0
  150. package/profiles/runtime/riffdb/queries/profile_member_by_id.riffq +27 -0
  151. package/profiles/runtime/riffdb/queries/profile_member_by_organization.riffq +20 -0
  152. package/profiles/runtime/riffdb/queries/profile_member_by_organization_created_at_asc.riffq +20 -0
  153. package/profiles/runtime/riffdb/queries/profile_member_by_organization_created_at_desc.riffq +20 -0
  154. package/profiles/runtime/riffdb/queries/profile_member_by_organization_role_asc.riffq +20 -0
  155. package/profiles/runtime/riffdb/queries/profile_member_by_organization_role_desc.riffq +20 -0
  156. package/profiles/runtime/riffdb/queries/profile_member_by_organization_user.riffq +28 -0
  157. package/profiles/runtime/riffdb/queries/profile_member_by_user.riffq +27 -0
  158. package/profiles/runtime/riffdb/queries/profile_organization_by_id.riffq +27 -0
  159. package/profiles/runtime/riffdb/queries/profile_organization_by_slug.riffq +27 -0
  160. package/profiles/runtime/riffdb/queries/profile_session_with_user_by_id.riffq +14 -0
  161. package/profiles/runtime/riffdb/queries/profile_session_with_user_by_token.riffq +14 -0
  162. package/profiles/runtime/riffdb/queries/profile_sessions_with_users_by_token_set.riffq +25 -0
  163. package/profiles/runtime/riffdb/queries/profile_two_factor_by_id.riffq +17 -0
  164. package/profiles/runtime/riffdb/queries/profile_two_factor_by_user.riffq +17 -0
  165. package/profiles/runtime/riffdb/queries/profile_user_with_accounts_by_email.riffq +19 -0
  166. package/profiles/runtime/riffdb/queries/profile_user_with_accounts_by_id.riffq +19 -0
  167. package/profiles/runtime/riffdb/queries/profile_users_by_id_set.riffq +8 -0
  168. package/profiles/runtime/riffdb.application.json +324 -0
  169. package/profiles/runtime/riffdb.application.lock.json +1 -0
  170. package/profiles/runtime/riffdb.toml +3 -0
  171. package/profiles/runtime/src/generated/client.ts +5186 -0
  172. package/riffdb/contract.riff +58 -0
  173. package/riffdb/queries/find_credential_account.riffq +25 -0
  174. package/riffdb.application.json +106 -26
  175. package/riffdb.application.lock.json +1 -1
  176. package/src/generated/client.ts +2746 -0
package/DESIGN.md CHANGED
@@ -7,7 +7,7 @@ generation, adapter method mapping, and Better Auth conformance tests. RiffDB
7
7
  owns database semantics, compiled operations, authorization, durability,
8
8
  idempotency, and the Rust-backed TypeScript transport.
9
9
 
10
- ## Better Auth 1.6.29 method inventory
10
+ ## Better Auth 1.7.18 method inventory
11
11
 
12
12
  The adapter project must cover the current `createAdapterFactory` interface:
13
13
 
@@ -34,13 +34,22 @@ matching, independent order, and nullable order are declared in the compiled
34
34
  query. The result page and total therefore share one provider epoch; the
35
35
  adapter neither drains pages nor recounts client-side.
36
36
 
37
- `consumeOne` maps to one atomic delete-and-return compiled command. The same
38
- command executes immediately when Better Auth invokes `consumeOne` inside its
39
- verification cleanup callback, so two racers cannot both observe a token and
40
- the loser receives `null`. Any remaining identifier-scoped verification rows
41
- are removed afterward by the bounded compiled set command. Signup and OAuth
42
- transactions remain single-command atomic graphs; unknown callback shapes fail
43
- closed.
37
+ `consumeOne` maps to one atomic delete-and-return compiled command. In a
38
+ recognized Better Auth verification transaction, the adapter records a bounded
39
+ candidate and its internal revision, then commits `ConsumeVerificationSnapshot`.
40
+ The database validates that revision while deleting; a losing delete racer
41
+ returns `null`, and a changed snapshot fails explicitly. Remaining identifier-
42
+ scoped rows use the separate bounded cleanup command.
43
+
44
+ Better Auth 1.7.18 wraps password reset in a larger transaction. For the
45
+ supported existing-credential graph, `ResetCredentialPassword` consumes the
46
+ recorded verification row and revision-guards the credential password write
47
+ in one compiled command. A stale or missing account leaves the token and
48
+ password unchanged. Basic password changes use the native
49
+ `UpdateCredentialPassword` command with its current credential selector.
50
+ Additional verification rows, credential-account creation,
51
+ and session-revoking reset graphs are unsupported. Signup and OAuth creation
52
+ also remain single-command graphs; unknown callback shapes fail closed.
44
53
 
45
54
  Mutable core records carry internal monotonically increasing revisions. The
46
55
  adapter reads that compiler-owned revision, sends it to an exact update
@@ -92,7 +101,7 @@ tests. This separation makes the profile customizable without turning schema
92
101
  generation into a generic database or weakening the application-facing safety
93
102
  boundary. The generation adapter rejects every runtime method.
94
103
 
95
- ## Materialization
104
+ ## Planning materialization
96
105
 
97
106
  `materializeRiffDBBetterAuthProfile` turns a reviewed plan into the first two
98
107
  of those artifacts: one contract and one named query per accepted call shape,
@@ -133,7 +142,7 @@ needs one of them enforced changes the aggregate assignment by hand.
133
142
  representative plan, regenerated by `npm run profiles:materialize` and verified
134
143
  byte-for-byte by `npm run profiles:check`. It ships its own `riffdb.toml`, so
135
144
  the claim made about it is checkable directly: `riffdb application check` in
136
- that directory compiles the contract and all nineteen queries.
145
+ that directory compiles the contract and all twenty queries.
137
146
 
138
147
  References:
139
148
 
@@ -143,7 +152,73 @@ References:
143
152
  - <https://github.com/yultyyev/better-auth-firestore>
144
153
  - <https://github.com/datar-platform/better-auth-dynamodb>
145
154
 
146
- ## First-profile exclusions
155
+ ## Executable runtime profiles
156
+
157
+ `materializeRiffDBBetterAuthRuntimeProfile` extends the reviewed core sources
158
+ with a finite operation catalogue and emits `profile.ts`. After source review,
159
+ `riffdb application lock --write` generates its named client and exact immutable
160
+ identity. The adapter accepts that bound module, compares its schema plan with
161
+ the resolved Better Auth schema, and instantiates the generated client. It never
162
+ accepts a JSON schema as executable storage or a caller-supplied CRUD callback.
163
+
164
+ The runtime generator currently accepts scalar custom user fields and the
165
+ reviewed default organization and two-factor schemas. Baseline fields,
166
+ references, requiredness, and secret classification cannot be overridden.
167
+ Organization teams, dynamic access control, and mutation hooks are rejected.
168
+ Additional plugins and call shapes need a reviewed compiler implementation.
169
+ `nextCookies` is a reviewed integration plugin and adds no storage schema; its
170
+ ID is excluded from storage plans while runtime validation checks its version.
171
+
172
+ The sample applications live in `profiles/custom-fields/` and `profiles/runtime/`.
173
+ They have separate locks and generated clients. Source freshness, compilation,
174
+ package contents, and official real-service authentication conformance are
175
+ checked for all advertised profiles. The custom-field profile runs the official
176
+ additional-fields test against a contract already carrying that field.
177
+
178
+ Runtime profiles place all entities under one tenant aggregate. This intentionally
179
+ serializes same-tenant commands and lets member and invitation rows retain both
180
+ user and organization references. Compiled reads hydrate related rows through
181
+ bounded dependent batches in the same snapshot; the adapter only associates
182
+ those returned identities. It enables native joins for these profiles and
183
+ rejects unmatched joins before querying, rather than invoking factory fallback
184
+ join queries.
185
+
186
+ The current compiler refuses a command binding two entities carrying cascade
187
+ policies, even when they are read parents. Therefore the organization profile
188
+ omits user deletion and rejects `user.deleteUser.enabled`; organization deletion
189
+ cascades both memberships and invitations atomically. This is a limitation of
190
+ this layout and compiler surface, not permission to remove either reference.
191
+ The core and custom-field profiles retain their compiled user cascade.
192
+
193
+ Organization capacity is authoritative: member and invitation creation mutate
194
+ the organization's internal counters with a guard below 100, and individual
195
+ deletions release capacity atomically. The organization delete graph has at most
196
+ 201 rows. Membership creation plus session activation during invitation
197
+ acceptance is another single compiled graph. Invitation status guards admit
198
+ one racer; upstream Better Auth owns its higher-level acceptance and compensation
199
+ flow around that graph.
200
+
201
+ Native 2FA commands increment failure counters, set locks under a threshold
202
+ guard, reset expired locks, and replace backup codes under an exact old-value
203
+ guard. An internal millisecond field tracks the optional lock timestamp in the
204
+ same commands, so the expiry comparison stays a native scalar predicate. Every
205
+ secret result leaf has an explicit `reveals` declaration. No counter or backup-
206
+ code path invokes Better Auth's generic mutation fallback.
207
+
208
+ Profile changes require explicit data migration review. The shared tenant
209
+ aggregate and plugin fields cannot reinterpret an installed core profile.
210
+ Internal revisions, capacity counters, required fields, reference targets, and
211
+ secret authority must be initialized and verified before adopting a new lock.
212
+ No automatic migration or mixed-profile runtime is supplied.
213
+
214
+ The broader planning materializer still supports schema exploration for teams.
215
+ Better Auth 1.7's optional unique `teamMember.membershipKey` needs an explicit
216
+ `requireUniqueValues` review: RiffDB cannot enforce a nullable unique field.
217
+ The planning fixture requires a non-null key on every row and reports that
218
+ stronger storage requirement. It cannot accept legacy null-key rows and is not
219
+ an advertised runtime profile.
220
+
221
+ ## Default core profile exclusions
147
222
 
148
223
  - renamed models or fields;
149
224
  - additional user/session fields;
@@ -154,11 +229,14 @@ References:
154
229
  - Better Auth database hooks that imply additional database mutations; and
155
230
  - secondary storage implemented by RiffDB.
156
231
 
232
+ These exclusions describe the default core profile; the executable profiles
233
+ above provide reviewed extensions. Each addition needs an explicit bounded contract and semantic tests.
234
+
157
235
  ## Closed RiffDB blockers
158
236
 
159
237
  The loopback conformance run deploys the exact contract and role and connects
160
238
  through `riffdb-driverd`. The initial empty `FindUserByEmail` result carries the
161
- valid application head `0`; `@riffdb/client@0.2.0` preserves it
239
+ valid application head `0`; `@riffdb/client@0.2.1` preserves it
162
240
  as `0n`. The adapter does not issue an unrelated warmup write, so the first
163
241
  application-visible mutation remains the compiled signup graph.
164
242
 
@@ -181,8 +259,6 @@ independent ordering, and explicit null placement. The generated TypeScript
181
259
  client also emits only reachable compact decoders, so it compiles under strict
182
260
  consumer `noUnusedLocals` settings without generated-source suppressions.
183
261
 
184
- These exclusions describe the first profile, not permanent product limits.
185
- Each addition needs an explicit bounded contract and semantic tests.
186
262
 
187
263
  ## Secrets and authority
188
264
 
package/README.md CHANGED
@@ -2,13 +2,16 @@
2
2
 
3
3
  An external Better Auth database adapter for RiffDB.
4
4
 
5
- Status: v0.2.0. The core runtime profile is implemented and
6
- passes Better Auth's pinned authentication-flow suite plus a real RiffDB
7
- loopback suite. Profile planning is implemented for custom fields and plugins,
8
- and a reviewed plan now materializes into a RiffDB contract, named queries, and
9
- application source that compile. Binding a materialized profile to a running
10
- adapter instance is not implemented: the adapter still dispatches only to the
11
- core profile's generated client.
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.
12
15
 
13
16
  ## Architecture boundary
14
17
 
@@ -18,19 +21,20 @@ reviewed compiled profile. It does not expose generic CRUD, accept arbitrary
18
21
  transaction callbacks, perform client-side authorization filtering, or
19
22
  silently fall back for unknown models, fields, joins, predicates, or plugins.
20
23
 
21
- The shipped runtime profile is deliberately exact:
24
+ The default core runtime profile is deliberately exact:
22
25
 
23
- - Better Auth `1.6.29`;
26
+ - Better Auth `1.7.18`;
24
27
  - the four default core models and their default field names;
25
28
  - UUID identifiers for every model;
26
- - no runtime plugins or additional fields; and
29
+ - the reviewed `nextCookies()` integration, with no storage plugins or additional fields; and
27
30
  - the bundled `RiffDBBetterAuthCore` contract and `BetterAuthServer` role.
28
31
 
29
32
  Unsupported configuration fails before any RiffDB request. A custom or plugin
30
33
  profile requires its own generated contract, named operations, client facade,
31
- and conformance tests; `npm run profiles:materialize` generates the first two
32
- from a reviewed plan. Adapter construction also verifies that the resolved
33
- `better-auth` installation is exactly `1.6.29`; package-manager overrides do
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
34
38
  not bypass that runtime check. Secret-bearing Better Auth debug logging is
35
39
  rejected rather than forwarded to the factory logger.
36
40
 
@@ -60,7 +64,80 @@ The caller owns the RiffDB driver connection and application-defined
60
64
  organization ID. Better Auth continues to own users, sessions, passwords,
61
65
  sign-in, OAuth, and reset flows. The package contains the exact RiffDB
62
66
  application source, lock, contract bundle, and generated artifacts required to
63
- deploy the core profile.
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.
64
141
 
65
142
  ## Implemented core surface
66
143
 
@@ -128,7 +205,7 @@ With that generation-only config, run the Better Auth CLI version matching the
128
205
  pinned runtime:
129
206
 
130
207
  ```bash
131
- npx auth@1.6.29 generate --config ./auth.profile.ts --yes
208
+ npx auth@1.7.18 generate --config ./auth.profile.ts --yes
132
209
  ```
133
210
 
134
211
  The output records resolved storage names, field types, required/unique/index
@@ -147,31 +224,84 @@ npm run profiles:write
147
224
  npm run profiles:check
148
225
  ```
149
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
+
150
261
  ## Local development
151
262
 
152
263
  ```bash
153
- npm install
264
+ npm ci --ignore-scripts
154
265
  npm run check
155
266
  ```
156
267
 
157
- The lock is pinned to `@riffdb/client@0.2.0` and `@riffdb/cli@0.2.0`.
268
+ The lock is pinned to `@riffdb/client@0.2.1` and `@riffdb/cli@0.2.1`.
158
269
 
159
270
  `npm run check` performs strict type checking, semantic and upstream tests,
160
271
  profile-artifact freshness, a production build, and a package dry run.
161
272
 
162
273
  ## Real loopback conformance
163
274
 
164
- Run the real service/driver flow with:
275
+ Run the official suite against isolated TLS services and Rust driver hosts:
165
276
 
166
277
  ```bash
167
- riffdb dev --run
278
+ npm run test:loopback
168
279
  ```
169
280
 
170
- The included runner exercises signup, sign-in, password reset and replay
171
- rejection, user/session/account/verification mutation paths, atomic OAuth
172
- creation, exact counts, bounded search/offset windows, nullable ordering,
173
- dependent cleanup, and read-after-commit fencing against the Rust service and
174
- driver host.
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.
175
305
 
176
306
  See [DESIGN.md](./DESIGN.md) for the method and safety inventory. The adapter
177
307
  follows Better Auth's
@@ -185,7 +315,9 @@ This adapter owns its RiffDB compatibility checks. Pull requests compile the
185
315
  application sources and verify existing locks and generated artifacts against
186
316
  the full commit in `.github/riffdb-revision`. Scheduled checks use RiffDB
187
317
  `main`; manual dispatch accepts a full commit or `main`. Failures are reported
188
- here and do not block RiffDB itself. Framework conformance remains separate.
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.
189
321
 
190
322
  To upgrade, update the pin, migrate sources as needed, review the result of
191
323
  `riffdb application lock --write`, and verify with `riffdb application check`.
package/dist/adapter.d.ts CHANGED
@@ -2,6 +2,7 @@ import { type DriverApplicationTransport } from "@riffdb/client";
2
2
  import { type AdapterFactory, type DBAdapterDebugLogOption } from "better-auth/adapters";
3
3
  import type { BetterAuthOptions } from "better-auth";
4
4
  import { RiffDBBetterAuthCoreClient } from "./generated/client.js";
5
+ import { type RiffDBCompiledProfile } from "./runtime-profile.js";
5
6
  export type RiffDBBetterAuthCallErrorCode = "invalid_configuration" | "unsupported_model" | "unsupported_call_shape" | "unsupported_transaction_shape" | "result_bound_exceeded" | "invalid_record_shape" | "declared_outcome";
6
7
  export declare class RiffDBBetterAuthCallError extends Error {
7
8
  readonly code: RiffDBBetterAuthCallErrorCode;
@@ -14,12 +15,17 @@ export interface RiffDBBetterAuthAdapterConfig {
14
15
  readonly organizationId: string;
15
16
  readonly commandAttemptBudget?: number;
16
17
  readonly debugLogs?: DBAdapterDebugLogOption;
18
+ readonly profile?: RiffDBCompiledProfile;
17
19
  }
20
+ type CoreClient = Omit<RiffDBBetterAuthCoreClient, "causalSession" | "withReadAfterCommit"> & {
21
+ causalSession(): CoreClient;
22
+ };
18
23
  interface InternalAdapterConfig {
19
- readonly client: RiffDBBetterAuthCoreClient;
24
+ readonly client: CoreClient;
20
25
  readonly organizationId: string;
21
26
  readonly debugLogs?: DBAdapterDebugLogOption;
22
27
  readonly resetModelForTesting?: (model: string) => number | Promise<number>;
28
+ readonly profile?: RiffDBCompiledProfile;
23
29
  }
24
30
  export declare function assertSupportedBetterAuthInstallation(installedVersion?: string): void;
25
31
  export declare function buildRiffDBBetterAuthAdapter(config: InternalAdapterConfig): AdapterFactory<BetterAuthOptions>;
@@ -1 +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;AAkD/B,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;CAC9C;AAED,UAAU,qBAAqB;IAC7B,QAAQ,CAAC,MAAM,EAAE,0BAA0B,CAAC;IAC5C,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;CAC7E;AAuBD,wBAAgB,qCAAqC,CACnD,gBAAgB,SAAsC,GACrD,IAAI,CAIN;AAo0CD,wBAAgB,4BAA4B,CAC1C,MAAM,EAAE,qBAAqB,GAC5B,cAAc,CAAC,iBAAiB,CAAC,CAuCnC;AAED,wBAAgB,aAAa,CAC3B,MAAM,EAAE,6BAA6B,GACpC,cAAc,CAAC,iBAAiB,CAAC,CAWnC"}
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"}