@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.
- package/DESIGN.md +90 -14
- package/README.md +157 -25
- package/dist/adapter.d.ts +7 -1
- package/dist/adapter.d.ts.map +1 -1
- package/dist/adapter.js +385 -47
- package/dist/adapter.js.map +1 -1
- package/dist/generated/client.d.ts +267 -26
- package/dist/generated/client.d.ts.map +1 -1
- package/dist/generated/client.js +479 -69
- package/dist/generated/client.js.map +1 -1
- package/dist/index.d.ts +3 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -1
- package/dist/index.js.map +1 -1
- 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 +3 -0
- package/dist/profile-contract.d.ts.map +1 -1
- package/dist/profile-contract.js +8 -0
- package/dist/profile-contract.js.map +1 -1
- package/dist/profile-plan.js +1 -1
- package/dist/profile-plan.js.map +1 -1
- package/dist/profile.d.ts +2 -1
- package/dist/profile.d.ts.map +1 -1
- package/dist/profile.js +2 -1
- package/dist/profile.js.map +1 -1
- 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/generated/go/client.go +350 -96
- package/generated/mcp/tools.json +3338 -1768
- package/generated/python/client.py +603 -26
- package/generated/riffdb.application.exact.json +1 -1
- package/generated/riffdb.contract.bundle +0 -0
- package/generated/rust/client.rs +522 -26
- package/package.json +34 -13
- 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 +3 -0
- package/profiles/organization-security/riffdb/contract.riff +12 -0
- package/profiles/organization-security/riffdb/queries/find_team_by_id.riffq +1 -1
- package/profiles/organization-security/riffdb/queries/find_team_member_by_id.riffq +1 -1
- 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 +1 -1
- package/profiles/organization-security/riffdb.application.json +5 -0
- package/profiles/organization-security.profile.json +27 -1
- 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 +58 -0
- package/riffdb/queries/find_credential_account.riffq +25 -0
- package/riffdb.application.json +106 -26
- package/riffdb.application.lock.json +1 -1
- package/src/generated/client.ts +2746 -0
package/dist/adapter.js
CHANGED
|
@@ -4,7 +4,9 @@ import { createRequire } from "node:module";
|
|
|
4
4
|
import { DriverGeneratedApplicationTransport, } from "@riffdb/client";
|
|
5
5
|
import { createAdapterFactory, } from "better-auth/adapters";
|
|
6
6
|
import { RiffDBBetterAuthCoreClient, } from "./generated/client.js";
|
|
7
|
-
import { BETTER_AUTH_PINNED_VERSION } from "./profile.js";
|
|
7
|
+
import { BETTER_AUTH_PINNED_VERSION, SUPPORTED_BETTER_AUTH_VERSIONS } from "./profile.js";
|
|
8
|
+
import { validateRuntimeProfile, instantiateProfileClient, encodeProfileField, decodeProfileField, storageField } from "./runtime-profile.js";
|
|
9
|
+
import { ProfilePluginDispatcher } from "./plugin-dispatch.js";
|
|
8
10
|
const CORE_SCHEMA_FIELDS = {
|
|
9
11
|
user: ["name", "email", "emailVerified", "image", "createdAt", "updatedAt"],
|
|
10
12
|
session: [
|
|
@@ -60,7 +62,7 @@ function validateConfiguration(config) {
|
|
|
60
62
|
}
|
|
61
63
|
}
|
|
62
64
|
export function assertSupportedBetterAuthInstallation(installedVersion = resolveInstalledBetterAuthVersion()) {
|
|
63
|
-
if (
|
|
65
|
+
if (!SUPPORTED_BETTER_AUTH_VERSIONS.some((version) => version === installedVersion)) {
|
|
64
66
|
fail("invalid_configuration", "betterAuthVersion");
|
|
65
67
|
}
|
|
66
68
|
}
|
|
@@ -84,12 +86,27 @@ function resolveInstalledBetterAuthVersion() {
|
|
|
84
86
|
}
|
|
85
87
|
fail("invalid_configuration", "betterAuthVersion");
|
|
86
88
|
}
|
|
87
|
-
function validateResolvedSchema(options, schema) {
|
|
89
|
+
function validateResolvedSchema(options, schema, profile) {
|
|
88
90
|
if (options.advanced?.database?.generateId !== "uuid") {
|
|
89
91
|
fail("invalid_configuration", "generateId");
|
|
90
92
|
}
|
|
91
|
-
if (
|
|
92
|
-
fail("invalid_configuration", "
|
|
93
|
+
if (options.databaseHooks !== undefined || options.emailAndPassword?.revokeSessionsOnPasswordReset) {
|
|
94
|
+
fail("invalid_configuration", "transactionConfiguration");
|
|
95
|
+
}
|
|
96
|
+
if (profile !== undefined) {
|
|
97
|
+
try {
|
|
98
|
+
validateRuntimeProfile(profile, options, schema);
|
|
99
|
+
}
|
|
100
|
+
catch {
|
|
101
|
+
fail("invalid_configuration", "compiledProfile");
|
|
102
|
+
}
|
|
103
|
+
return;
|
|
104
|
+
}
|
|
105
|
+
for (const plugin of options.plugins ?? []) {
|
|
106
|
+
if (plugin.id !== "next-cookies" || plugin.version !== BETTER_AUTH_PINNED_VERSION || plugin.schema !== undefined) {
|
|
107
|
+
fail("invalid_configuration", "plugins");
|
|
108
|
+
}
|
|
109
|
+
}
|
|
93
110
|
const modelNames = Object.keys(schema).sort();
|
|
94
111
|
const expectedModels = Object.keys(CORE_SCHEMA_FIELDS).sort();
|
|
95
112
|
if (JSON.stringify(modelNames) !== JSON.stringify(expectedModels)) {
|
|
@@ -308,15 +325,41 @@ class CoreDispatcher {
|
|
|
308
325
|
client;
|
|
309
326
|
organizationId;
|
|
310
327
|
resetModelForTesting;
|
|
311
|
-
|
|
328
|
+
profile;
|
|
329
|
+
plugins;
|
|
330
|
+
constructor(client, organizationId, resetModelForTesting, profile) {
|
|
312
331
|
this.client = client;
|
|
313
332
|
this.organizationId = organizationId;
|
|
314
333
|
this.resetModelForTesting = resetModelForTesting;
|
|
334
|
+
this.profile = profile;
|
|
335
|
+
this.plugins = profile === undefined ? undefined : new ProfilePluginDispatcher(profile, client, organizationId);
|
|
336
|
+
}
|
|
337
|
+
fields(model) {
|
|
338
|
+
return this.profile?.plan.models.find((entry) => entry.name === model)?.fields
|
|
339
|
+
.filter((field) => !CORE_SCHEMA_FIELDS[model].includes(field.name)) ?? [];
|
|
340
|
+
}
|
|
341
|
+
encodeExtra(model, data, prefix = "") {
|
|
342
|
+
return Object.fromEntries(this.fields(model).map((field) => [prefix + storageField(field.name), encodeProfileField(field, data[field.name])]));
|
|
343
|
+
}
|
|
344
|
+
decodeExtra(model, row) {
|
|
345
|
+
return Object.fromEntries(this.fields(model).map((field) => [field.name, decodeProfileField(field, row[storageField(field.name)])]));
|
|
346
|
+
}
|
|
347
|
+
mapUser = (row) => ({ ...mapUser(row), ...this.decodeExtra("user", row) });
|
|
348
|
+
mapSession = (row) => ({ ...mapSession(row), ...this.decodeExtra("session", row) });
|
|
349
|
+
mapAccount = (row) => ({ ...mapAccount(row), ...this.decodeExtra("account", row) });
|
|
350
|
+
mapVerification = (row) => ({ ...mapVerification(row), ...this.decodeExtra("verification", row) });
|
|
351
|
+
normalizeCreate(model, data) {
|
|
352
|
+
if (!(model in CORE_SCHEMA_FIELDS))
|
|
353
|
+
return { ...data };
|
|
354
|
+
return { ...data, ...this.decodeExtra(model, this.encodeExtra(model, data)) };
|
|
315
355
|
}
|
|
316
356
|
async create(model, dataValue) {
|
|
317
357
|
const data = asRecord(dataValue, `create ${model}`);
|
|
358
|
+
if (this.plugins?.supports(model))
|
|
359
|
+
return this.plugins.create(model, data);
|
|
318
360
|
if (model === "user") {
|
|
319
361
|
const result = await this.client.createUser({
|
|
362
|
+
...this.encodeExtra("user", data),
|
|
320
363
|
request_id: "",
|
|
321
364
|
organization_id: this.organizationId,
|
|
322
365
|
id: requiredString(data, "id", "create user"),
|
|
@@ -328,10 +371,11 @@ class CoreDispatcher {
|
|
|
328
371
|
updated_at: toTimestamp(requiredDate(data, "updatedAt", "create user")),
|
|
329
372
|
});
|
|
330
373
|
requireOutcome(result, "create user", "UserCreated");
|
|
331
|
-
return { ...data, image: data.image ?? null };
|
|
374
|
+
return { ...this.normalizeCreate(model, data), image: data.image ?? null };
|
|
332
375
|
}
|
|
333
376
|
if (model === "account") {
|
|
334
377
|
const result = await this.client.createAccount({
|
|
378
|
+
...this.encodeExtra("account", data),
|
|
335
379
|
request_id: "",
|
|
336
380
|
organization_id: this.organizationId,
|
|
337
381
|
id: requiredString(data, "id", "create account"),
|
|
@@ -349,11 +393,12 @@ class CoreDispatcher {
|
|
|
349
393
|
updated_at: toTimestamp(requiredDate(data, "updatedAt", "create account")),
|
|
350
394
|
});
|
|
351
395
|
requireOutcome(result, "create account", "AccountCreated");
|
|
352
|
-
return
|
|
396
|
+
return this.normalizeCreate(model, data);
|
|
353
397
|
}
|
|
354
398
|
if (model === "session") {
|
|
355
399
|
const token = requiredString(data, "token", "create session");
|
|
356
400
|
const result = await this.client.createSession({
|
|
401
|
+
...this.encodeExtra("session", data),
|
|
357
402
|
request_id: "",
|
|
358
403
|
organization_id: this.organizationId,
|
|
359
404
|
id: requiredString(data, "id", "create session"),
|
|
@@ -366,10 +411,11 @@ class CoreDispatcher {
|
|
|
366
411
|
updated_at: toTimestamp(requiredDate(data, "updatedAt", "create session")),
|
|
367
412
|
});
|
|
368
413
|
requireOutcome(result, "create session", "SessionCreated");
|
|
369
|
-
return
|
|
414
|
+
return this.normalizeCreate(model, data);
|
|
370
415
|
}
|
|
371
416
|
if (model === "verification") {
|
|
372
417
|
const result = await this.client.createVerification({
|
|
418
|
+
...this.encodeExtra("verification", data),
|
|
373
419
|
request_id: "",
|
|
374
420
|
organization_id: this.organizationId,
|
|
375
421
|
id: requiredString(data, "id", "create verification"),
|
|
@@ -380,11 +426,25 @@ class CoreDispatcher {
|
|
|
380
426
|
updated_at: toTimestamp(requiredDate(data, "updatedAt", "create verification")),
|
|
381
427
|
});
|
|
382
428
|
requireOutcome(result, "create verification", "VerificationCreated");
|
|
383
|
-
return
|
|
429
|
+
return this.normalizeCreate(model, data);
|
|
384
430
|
}
|
|
385
431
|
return fail("unsupported_model", `create ${model}`);
|
|
386
432
|
}
|
|
387
433
|
async findOne(model, where, join) {
|
|
434
|
+
if (this.plugins?.supports(model))
|
|
435
|
+
return (await this.plugins.read(model, where, 1, undefined, 0, join)).rows[0] ?? null;
|
|
436
|
+
if (this.plugins !== undefined && join !== undefined && Object.keys(join).length > 0) {
|
|
437
|
+
const value = await this.plugins.joinedCore(model, where, join, false);
|
|
438
|
+
if (value.outcome === "Missing")
|
|
439
|
+
return null;
|
|
440
|
+
if (model === "user" && value.accounts.length > 32)
|
|
441
|
+
fail("result_bound_exceeded", "user accounts");
|
|
442
|
+
if (model === "user")
|
|
443
|
+
return { ...this.mapUser(value.user),
|
|
444
|
+
account: value.accounts.slice(0, join.account?.limit ?? 100).map(this.mapAccount) };
|
|
445
|
+
return { ...this.mapSession(value.session),
|
|
446
|
+
user: this.mapUser(value.user) };
|
|
447
|
+
}
|
|
388
448
|
assertNoJoin(join, `findOne ${model}`);
|
|
389
449
|
if (model === "user" && exactWhere(where, ["email"])) {
|
|
390
450
|
const result = await this.client.findUserByEmail({
|
|
@@ -392,14 +452,14 @@ class CoreDispatcher {
|
|
|
392
452
|
email: whereValue(where, "email", "findOne user"),
|
|
393
453
|
});
|
|
394
454
|
const row = result.value.users[0];
|
|
395
|
-
return row === undefined ? null : mapUser(row);
|
|
455
|
+
return row === undefined ? null : this.mapUser(row);
|
|
396
456
|
}
|
|
397
457
|
if (model === "user" && exactWhere(where, ["id"])) {
|
|
398
458
|
const result = await this.client.findUserById({
|
|
399
459
|
organization_id: this.organizationId,
|
|
400
460
|
id: whereValue(where, "id", "findOne user"),
|
|
401
461
|
});
|
|
402
|
-
return result.value.outcome === "Missing" ? null : mapUser(result.value.user);
|
|
462
|
+
return result.value.outcome === "Missing" ? null : this.mapUser(result.value.user);
|
|
403
463
|
}
|
|
404
464
|
if (model === "session" && exactWhere(where, ["token"])) {
|
|
405
465
|
const token = whereValue(where, "token", "findOne session");
|
|
@@ -408,7 +468,7 @@ class CoreDispatcher {
|
|
|
408
468
|
token,
|
|
409
469
|
});
|
|
410
470
|
const row = result.value.sessions[0];
|
|
411
|
-
return row === undefined ? null : mapSession(row);
|
|
471
|
+
return row === undefined ? null : this.mapSession(row);
|
|
412
472
|
}
|
|
413
473
|
if (model === "session" && exactWhere(where, ["id"])) {
|
|
414
474
|
const result = await this.client.findSessionById({
|
|
@@ -416,7 +476,7 @@ class CoreDispatcher {
|
|
|
416
476
|
id: whereValue(where, "id", "findOne session"),
|
|
417
477
|
});
|
|
418
478
|
const row = result.value.sessions[0];
|
|
419
|
-
return row === undefined ? null : mapSession(row);
|
|
479
|
+
return row === undefined ? null : this.mapSession(row);
|
|
420
480
|
}
|
|
421
481
|
if (model === "account" && exactWhere(where, ["id"])) {
|
|
422
482
|
const result = await this.client.findAccountById({
|
|
@@ -424,7 +484,7 @@ class CoreDispatcher {
|
|
|
424
484
|
id: whereValue(where, "id", "findOne account"),
|
|
425
485
|
});
|
|
426
486
|
const row = result.value.accounts[0];
|
|
427
|
-
return row === undefined ? null : mapAccount(row);
|
|
487
|
+
return row === undefined ? null : this.mapAccount(row);
|
|
428
488
|
}
|
|
429
489
|
if (model === "account" && exactWhere(where, ["accountId", "providerId"])) {
|
|
430
490
|
const result = await this.client.findAccountByProvider({
|
|
@@ -433,7 +493,17 @@ class CoreDispatcher {
|
|
|
433
493
|
provider_id: whereValue(where, "providerId", "findOne account"),
|
|
434
494
|
});
|
|
435
495
|
const row = result.value.accounts[0];
|
|
436
|
-
return row === undefined ? null : mapAccount(row);
|
|
496
|
+
return row === undefined ? null : this.mapAccount(row);
|
|
497
|
+
}
|
|
498
|
+
if (model === "account" && exactWhere(where, ["userId", "accountId", "providerId"])) {
|
|
499
|
+
const result = await this.client.findCredentialAccount({
|
|
500
|
+
organization_id: this.organizationId,
|
|
501
|
+
user_id: whereValue(where, "userId", "findCredentialAccount"),
|
|
502
|
+
account_id: whereValue(where, "accountId", "findCredentialAccount"),
|
|
503
|
+
provider_id: whereValue(where, "providerId", "findCredentialAccount"),
|
|
504
|
+
});
|
|
505
|
+
const row = result.value.accounts[0];
|
|
506
|
+
return row === undefined ? null : this.mapAccount(row);
|
|
437
507
|
}
|
|
438
508
|
if (model === "verification" && exactWhere(where, ["id"])) {
|
|
439
509
|
const result = await this.client.findVerificationById({
|
|
@@ -443,14 +513,17 @@ class CoreDispatcher {
|
|
|
443
513
|
const value = result.value;
|
|
444
514
|
return value.outcome === "Missing"
|
|
445
515
|
? null
|
|
446
|
-
: mapVerification(value.verification);
|
|
516
|
+
: this.mapVerification(value.verification);
|
|
447
517
|
}
|
|
448
518
|
return fail("unsupported_call_shape", `findOne ${model}`);
|
|
449
519
|
}
|
|
450
520
|
async update(model, where, updateValue) {
|
|
521
|
+
if (this.plugins?.supports(model))
|
|
522
|
+
return this.plugins.update(model, where, asRecord(updateValue, "update"));
|
|
451
523
|
if (model === "account" && exactWhere(where, ["id"])) {
|
|
452
524
|
const update = asRecord(updateValue, "update account");
|
|
453
525
|
const allowed = new Set([
|
|
526
|
+
...this.fields("account").map((field) => field.name),
|
|
454
527
|
"accountId",
|
|
455
528
|
"providerId",
|
|
456
529
|
"accessToken",
|
|
@@ -477,6 +550,7 @@ class CoreDispatcher {
|
|
|
477
550
|
return null;
|
|
478
551
|
const successor = { ...mapAccount(row), ...update };
|
|
479
552
|
const updated = await this.client.updateAccount({
|
|
553
|
+
...this.encodeExtra("account", successor),
|
|
480
554
|
request_id: "",
|
|
481
555
|
organization_id: this.organizationId,
|
|
482
556
|
user_id: row.user_id,
|
|
@@ -505,7 +579,7 @@ class CoreDispatcher {
|
|
|
505
579
|
if (model === "session" &&
|
|
506
580
|
(exactWhere(where, ["id"]) || exactWhere(where, ["token"]))) {
|
|
507
581
|
const update = asRecord(updateValue, "update session");
|
|
508
|
-
const allowed = new Set(["expiresAt", "ipAddress", "userAgent", "updatedAt"]);
|
|
582
|
+
const allowed = new Set(["expiresAt", "ipAddress", "userAgent", "updatedAt", ...this.fields("session").map((field) => field.name)]);
|
|
509
583
|
const fields = Object.keys(update);
|
|
510
584
|
if (fields.length === 0 || fields.some((field) => !allowed.has(field))) {
|
|
511
585
|
fail("unsupported_call_shape", "update session");
|
|
@@ -523,9 +597,10 @@ class CoreDispatcher {
|
|
|
523
597
|
const row = result.value.sessions[0];
|
|
524
598
|
if (row === undefined)
|
|
525
599
|
return null;
|
|
526
|
-
const current = mapSession(row);
|
|
600
|
+
const current = this.mapSession(row);
|
|
527
601
|
const successor = { ...current, ...update };
|
|
528
602
|
const updated = await this.client.updateSession({
|
|
603
|
+
...this.encodeExtra("session", successor),
|
|
529
604
|
request_id: "",
|
|
530
605
|
organization_id: this.organizationId,
|
|
531
606
|
user_id: row.user_id,
|
|
@@ -551,7 +626,7 @@ class CoreDispatcher {
|
|
|
551
626
|
return fail("unsupported_call_shape", `update ${model}`);
|
|
552
627
|
}
|
|
553
628
|
const update = asRecord(updateValue, "update verification");
|
|
554
|
-
const allowed = new Set(["value", "expiresAt", "updatedAt"]);
|
|
629
|
+
const allowed = new Set(["value", "expiresAt", "updatedAt", ...this.fields("verification").map((field) => field.name)]);
|
|
555
630
|
const fields = Object.keys(update);
|
|
556
631
|
if (fields.length === 0 || fields.some((field) => !allowed.has(field))) {
|
|
557
632
|
fail("unsupported_call_shape", "update verification");
|
|
@@ -567,6 +642,7 @@ class CoreDispatcher {
|
|
|
567
642
|
return null;
|
|
568
643
|
const successor = { ...mapVerification(row), ...update };
|
|
569
644
|
const result = await this.client.updateVerification({
|
|
645
|
+
...this.encodeExtra("verification", successor),
|
|
570
646
|
request_id: "",
|
|
571
647
|
organization_id: this.organizationId,
|
|
572
648
|
verification_id: row.verification_id,
|
|
@@ -585,7 +661,7 @@ class CoreDispatcher {
|
|
|
585
661
|
return fail("declared_outcome", "update verification", "VerificationUpdateStale");
|
|
586
662
|
}
|
|
587
663
|
const update = asRecord(updateValue, "update user");
|
|
588
|
-
const allowed = new Set(["name", "email", "emailVerified", "image", "updatedAt"]);
|
|
664
|
+
const allowed = new Set(["name", "email", "emailVerified", "image", "updatedAt", ...this.fields("user").map((field) => field.name)]);
|
|
589
665
|
const fields = Object.keys(update);
|
|
590
666
|
if (fields.length === 0 || fields.some((field) => !allowed.has(field))) {
|
|
591
667
|
fail("unsupported_call_shape", "update user");
|
|
@@ -610,9 +686,10 @@ class CoreDispatcher {
|
|
|
610
686
|
return null;
|
|
611
687
|
const resolved = "outcome" in row ? row.user : row;
|
|
612
688
|
userId = resolved.user_id;
|
|
613
|
-
const current = mapUser(resolved);
|
|
689
|
+
const current = this.mapUser(resolved);
|
|
614
690
|
const successor = { ...current, ...update };
|
|
615
691
|
const result = await this.client.updateUser({
|
|
692
|
+
...this.encodeExtra("user", successor),
|
|
616
693
|
request_id: "",
|
|
617
694
|
organization_id: this.organizationId,
|
|
618
695
|
user_id: userId,
|
|
@@ -633,12 +710,33 @@ class CoreDispatcher {
|
|
|
633
710
|
return fail("declared_outcome", "update user", "UserUpdateStale");
|
|
634
711
|
}
|
|
635
712
|
async findMany(model, where, limit, sortBy, offset, join) {
|
|
713
|
+
if (this.plugins?.supports(model))
|
|
714
|
+
return (await this.plugins.read(model, where, limit, sortBy, offset, join)).rows;
|
|
715
|
+
if (this.plugins !== undefined && join !== undefined && Object.keys(join).length > 0) {
|
|
716
|
+
if (sortBy !== undefined || (offset !== undefined && offset !== 0))
|
|
717
|
+
fail("unsupported_call_shape", "core join window");
|
|
718
|
+
const value = await this.plugins.joinedCore(model, where ?? [], join, true, limit);
|
|
719
|
+
const rows = value[model === "account" ? "accounts" : "sessions"];
|
|
720
|
+
const users = value.users;
|
|
721
|
+
if (rows.length > 32 || users.length > 32)
|
|
722
|
+
fail("result_bound_exceeded", "core join");
|
|
723
|
+
return rows.slice(0, limit).map((row) => ({
|
|
724
|
+
...(model === "account" ? this.mapAccount(row) : this.mapSession(row)),
|
|
725
|
+
user: this.mapUser(users.find((user) => user.user_id === row.user_id) ?? fail("invalid_record_shape", "core join user")),
|
|
726
|
+
}));
|
|
727
|
+
}
|
|
728
|
+
if (model === "user" && this.profile?.plan.plugins.includes("organization") && exactWhereShape(where, [{ field: "id", operator: "in" }])) {
|
|
729
|
+
assertNoJoin(join, "user ID set");
|
|
730
|
+
if (sortBy !== undefined || (offset !== undefined && offset !== 0))
|
|
731
|
+
fail("unsupported_call_shape", "user ID set");
|
|
732
|
+
return this.plugins.usersById(where, limit);
|
|
733
|
+
}
|
|
636
734
|
assertNoJoin(join, `findMany ${model}`);
|
|
637
735
|
if (!Number.isInteger(limit) || limit < 1)
|
|
638
736
|
fail("unsupported_call_shape", `findMany ${model}`);
|
|
639
737
|
if (model === "user") {
|
|
640
738
|
const window = await this.adminUserWindow(where, limit, sortBy, offset);
|
|
641
|
-
return window.users.map(mapUser);
|
|
739
|
+
return window.users.map(this.mapUser);
|
|
642
740
|
}
|
|
643
741
|
if (offset !== undefined && offset !== 0)
|
|
644
742
|
fail("unsupported_call_shape", `findMany ${model}`);
|
|
@@ -652,7 +750,15 @@ class CoreDispatcher {
|
|
|
652
750
|
});
|
|
653
751
|
if (result.nextCursor !== undefined)
|
|
654
752
|
fail("result_bound_exceeded", "findMany account");
|
|
655
|
-
return result.value.accounts.slice(0, limit).map(mapAccount);
|
|
753
|
+
return result.value.accounts.slice(0, limit).map(this.mapAccount);
|
|
754
|
+
}
|
|
755
|
+
if (model === "account" && exactWhere(where, ["providerId", "accountId"]) && sortBy === undefined) {
|
|
756
|
+
if (limit > 100)
|
|
757
|
+
fail("result_bound_exceeded", "findMany provider account");
|
|
758
|
+
const result = await this.client.findAccountByProvider({ organization_id: this.organizationId,
|
|
759
|
+
account_id: whereValue(where, "accountId", "findMany provider account"),
|
|
760
|
+
provider_id: whereValue(where, "providerId", "findMany provider account") });
|
|
761
|
+
return result.value.accounts.map(this.mapAccount);
|
|
656
762
|
}
|
|
657
763
|
if (model === "session" && exactWhere(where, ["userId"]) && sortBy === undefined) {
|
|
658
764
|
const result = await this.client.findSessionsByUserId({
|
|
@@ -662,7 +768,7 @@ class CoreDispatcher {
|
|
|
662
768
|
});
|
|
663
769
|
if (result.nextCursor !== undefined)
|
|
664
770
|
fail("result_bound_exceeded", "findMany session");
|
|
665
|
-
return result.value.sessions.slice(0, limit).map(mapSession);
|
|
771
|
+
return result.value.sessions.slice(0, limit).map(this.mapSession);
|
|
666
772
|
}
|
|
667
773
|
if (model === "session" &&
|
|
668
774
|
exactWhereShape(where, [
|
|
@@ -679,7 +785,7 @@ class CoreDispatcher {
|
|
|
679
785
|
if (result.nextCursor !== undefined) {
|
|
680
786
|
fail("result_bound_exceeded", "findMany active session");
|
|
681
787
|
}
|
|
682
|
-
return result.value.sessions.slice(0, limit).map(mapSession);
|
|
788
|
+
return result.value.sessions.slice(0, limit).map(this.mapSession);
|
|
683
789
|
}
|
|
684
790
|
const tokenSetShape = exactWhereShape(where, [{ field: "token", operator: "in" }]);
|
|
685
791
|
const activeTokenSetShape = exactWhereShape(where, [
|
|
@@ -694,7 +800,7 @@ class CoreDispatcher {
|
|
|
694
800
|
organization_id: this.organizationId,
|
|
695
801
|
tokens,
|
|
696
802
|
});
|
|
697
|
-
return result.value.sessions.slice(0, limit).map(mapSession);
|
|
803
|
+
return result.value.sessions.slice(0, limit).map(this.mapSession);
|
|
698
804
|
}
|
|
699
805
|
if (model === "session" && activeTokenSetShape) {
|
|
700
806
|
return fail("unsupported_call_shape", "findMany session token set with expiry");
|
|
@@ -708,7 +814,7 @@ class CoreDispatcher {
|
|
|
708
814
|
organization_id: this.organizationId,
|
|
709
815
|
identifier: whereValue(where, "identifier", "findMany verification"),
|
|
710
816
|
});
|
|
711
|
-
return result.value.verifications.map(mapVerification);
|
|
817
|
+
return result.value.verifications.map(this.mapVerification);
|
|
712
818
|
}
|
|
713
819
|
if (model === "verification" && exactWhere(where, ["identifier"]) && sortBy !== undefined) {
|
|
714
820
|
return fail("unsupported_call_shape", "findMany verification sort");
|
|
@@ -721,7 +827,7 @@ class CoreDispatcher {
|
|
|
721
827
|
});
|
|
722
828
|
if (result.nextCursor !== undefined)
|
|
723
829
|
fail("result_bound_exceeded", "findMany verification");
|
|
724
|
-
return result.value.verifications.slice(0, limit).map(mapVerification);
|
|
830
|
+
return result.value.verifications.slice(0, limit).map(this.mapVerification);
|
|
725
831
|
}
|
|
726
832
|
return fail("unsupported_call_shape", `findMany ${model}`);
|
|
727
833
|
}
|
|
@@ -772,6 +878,11 @@ class CoreDispatcher {
|
|
|
772
878
|
: (await this.client.adminUsersEndsWithDesc(searchParameters)).value;
|
|
773
879
|
}
|
|
774
880
|
async count(model, where) {
|
|
881
|
+
if (this.plugins?.supports(model)) {
|
|
882
|
+
if (model !== "member" || !exactWhere(where, ["organizationId"]))
|
|
883
|
+
fail("unsupported_call_shape", "plugin count");
|
|
884
|
+
return (await this.plugins.read(model, where, 1)).total;
|
|
885
|
+
}
|
|
775
886
|
if (model !== "user")
|
|
776
887
|
fail("unsupported_call_shape", `count ${model}`);
|
|
777
888
|
const window = await this.adminUserWindow(where, 1, undefined, 0);
|
|
@@ -781,6 +892,13 @@ class CoreDispatcher {
|
|
|
781
892
|
return Number(total);
|
|
782
893
|
}
|
|
783
894
|
async delete(model, where) {
|
|
895
|
+
if (this.plugins?.supports(model)) {
|
|
896
|
+
if (!exactWhere(where, ["id"]))
|
|
897
|
+
fail("unsupported_call_shape", "plugin delete");
|
|
898
|
+
return this.plugins.deleteIds(model, [whereValue(where, "id", "plugin delete")]);
|
|
899
|
+
}
|
|
900
|
+
if (model === "user" && this.profile?.plan.plugins.includes("organization"))
|
|
901
|
+
fail("unsupported_call_shape", "delete user in organization profile");
|
|
784
902
|
if (model === "user" && exactWhere(where, ["id"])) {
|
|
785
903
|
const result = await this.client.deleteUser({
|
|
786
904
|
request_id: "",
|
|
@@ -852,6 +970,16 @@ class CoreDispatcher {
|
|
|
852
970
|
fail("unsupported_call_shape", `delete ${model}`);
|
|
853
971
|
}
|
|
854
972
|
async deleteMany(model, where) {
|
|
973
|
+
if (this.plugins?.supports(model) && where.length > 0) {
|
|
974
|
+
if (!(model === "twoFactor" && (exactWhere(where, ["userId"]) || exactWhere(where, ["id"]))) &&
|
|
975
|
+
!(model === "member" && exactWhere(where, ["id"])))
|
|
976
|
+
fail("unsupported_call_shape", "plugin deleteMany");
|
|
977
|
+
const result = await this.plugins.read(model, where, 100);
|
|
978
|
+
if (result.total > 100)
|
|
979
|
+
fail("result_bound_exceeded", "plugin deleteMany");
|
|
980
|
+
await this.plugins.deleteIds(model, result.rows.map((row) => requiredString(row, "id", "plugin deleteMany")));
|
|
981
|
+
return result.rows.length;
|
|
982
|
+
}
|
|
855
983
|
if (where.length === 0 && this.resetModelForTesting !== undefined) {
|
|
856
984
|
return this.resetModelForTesting(model);
|
|
857
985
|
}
|
|
@@ -951,9 +1079,86 @@ class CoreDispatcher {
|
|
|
951
1079
|
if (result.outcome.outcome === "VerificationConsumeMissing")
|
|
952
1080
|
return null;
|
|
953
1081
|
requireOutcome(result, "consumeOne verification", "VerificationConsumed");
|
|
954
|
-
return mapVerification(result.outcome);
|
|
1082
|
+
return this.mapVerification(result.outcome);
|
|
1083
|
+
}
|
|
1084
|
+
async prepareConsume(id) {
|
|
1085
|
+
const { value } = await this.client.findVerificationById({
|
|
1086
|
+
organization_id: this.organizationId, id,
|
|
1087
|
+
});
|
|
1088
|
+
return value.outcome === "Missing" ? null : {
|
|
1089
|
+
row: this.mapVerification(value.verification), revision: value.verification.revision,
|
|
1090
|
+
};
|
|
1091
|
+
}
|
|
1092
|
+
async commitConsume(snapshot) {
|
|
1093
|
+
const result = await this.client.consumeVerificationSnapshot({
|
|
1094
|
+
request_id: "", organization_id: this.organizationId,
|
|
1095
|
+
verification_id: requiredString(snapshot.row, "id", "consumeOne"),
|
|
1096
|
+
expected_revision: snapshot.revision,
|
|
1097
|
+
});
|
|
1098
|
+
if (result.outcome.outcome === "VerificationConsumeMissing")
|
|
1099
|
+
return false;
|
|
1100
|
+
requireOutcome(result, "consumeOne", "VerificationConsumed");
|
|
1101
|
+
return true;
|
|
1102
|
+
}
|
|
1103
|
+
async commitPasswordReset(snapshot, where, update, cleanup) {
|
|
1104
|
+
const userId = whereValue(where, "userId", "resetPassword");
|
|
1105
|
+
if (!exactWhere(where, ["userId", "providerId", "accountId"]) ||
|
|
1106
|
+
whereValue(where, "providerId", "resetPassword") !== "credential" ||
|
|
1107
|
+
whereValue(where, "accountId", "resetPassword") !== userId ||
|
|
1108
|
+
snapshot.row.value !== userId || cleanup.length !== 0 ||
|
|
1109
|
+
Object.keys(update).some((field) => field !== "password" && field !== "updatedAt")) {
|
|
1110
|
+
fail("unsupported_transaction_shape", "resetPassword");
|
|
1111
|
+
}
|
|
1112
|
+
const password = requiredString(update, "password", "resetPassword");
|
|
1113
|
+
const updatedAt = toTimestamp(requiredDate(update, "updatedAt", "resetPassword"));
|
|
1114
|
+
for (let attempt = 0; attempt < 3; attempt += 1) {
|
|
1115
|
+
const { value } = await this.client.findCredentialAccount({
|
|
1116
|
+
organization_id: this.organizationId, user_id: userId, account_id: userId, provider_id: "credential",
|
|
1117
|
+
});
|
|
1118
|
+
const account = value.accounts[0];
|
|
1119
|
+
if (account === undefined)
|
|
1120
|
+
fail("unsupported_transaction_shape", "resetPassword create account");
|
|
1121
|
+
const result = await this.client.resetCredentialPassword({
|
|
1122
|
+
request_id: "", organization_id: this.organizationId,
|
|
1123
|
+
verification_ids: [requiredString(snapshot.row, "id", "resetPassword")],
|
|
1124
|
+
verification_revision: snapshot.revision,
|
|
1125
|
+
user_id: userId, external_account_id: userId, account_id: account.id,
|
|
1126
|
+
account_revision: account.revision, password, updated_at: updatedAt,
|
|
1127
|
+
});
|
|
1128
|
+
if (result.outcome.outcome === "PasswordAccountStale")
|
|
1129
|
+
continue;
|
|
1130
|
+
requireOutcome(result, "resetPassword", "CredentialPasswordReset");
|
|
1131
|
+
return;
|
|
1132
|
+
}
|
|
1133
|
+
fail("declared_outcome", "resetPassword", "PasswordAccountStale");
|
|
955
1134
|
}
|
|
956
1135
|
async updateMany(model, where, updateValue) {
|
|
1136
|
+
if (model === "account" && exactWhere(where, ["userId", "providerId", "accountId"])) {
|
|
1137
|
+
const userId = whereValue(where, "userId", "update credential password");
|
|
1138
|
+
if (whereValue(where, "providerId", "update credential password") !== "credential" ||
|
|
1139
|
+
whereValue(where, "accountId", "update credential password") !== userId ||
|
|
1140
|
+
Object.keys(updateValue).some((field) => field !== "password" && field !== "updatedAt"))
|
|
1141
|
+
fail("unsupported_call_shape", "update credential password");
|
|
1142
|
+
const password = requiredString(updateValue, "password", "update credential password");
|
|
1143
|
+
const updatedAt = toTimestamp(requiredDate(updateValue, "updatedAt", "update credential password"));
|
|
1144
|
+
for (let attempt = 0; attempt < 3; attempt += 1) {
|
|
1145
|
+
const { value } = await this.client.findCredentialAccount({ organization_id: this.organizationId,
|
|
1146
|
+
user_id: userId, account_id: userId, provider_id: "credential" });
|
|
1147
|
+
const account = value.accounts[0];
|
|
1148
|
+
if (account === undefined)
|
|
1149
|
+
return 0;
|
|
1150
|
+
const result = await this.client.updateCredentialPassword({ request_id: "", organization_id: this.organizationId,
|
|
1151
|
+
user_id: userId, account_id: account.id, external_account_id: userId, expected_revision: account.revision,
|
|
1152
|
+
password, updated_at: updatedAt });
|
|
1153
|
+
if (result.outcome.outcome === "PasswordAccountStale")
|
|
1154
|
+
continue;
|
|
1155
|
+
if (result.outcome.outcome === "PasswordAccountMissing")
|
|
1156
|
+
return 0;
|
|
1157
|
+
requireOutcome(result, "update credential password", "CredentialPasswordUpdated");
|
|
1158
|
+
return 1;
|
|
1159
|
+
}
|
|
1160
|
+
fail("declared_outcome", "update credential password", "PasswordAccountStale");
|
|
1161
|
+
}
|
|
957
1162
|
if (model !== "account" || !exactWhere(where, ["userId", "providerId"])) {
|
|
958
1163
|
return fail("unsupported_call_shape", `updateMany ${model}`);
|
|
959
1164
|
}
|
|
@@ -1018,6 +1223,9 @@ class CoreDispatcher {
|
|
|
1018
1223
|
fail("unsupported_transaction_shape", "transaction signup");
|
|
1019
1224
|
}
|
|
1020
1225
|
const result = await this.client.createSignupGraph({
|
|
1226
|
+
...this.encodeExtra("user", user, "user_"),
|
|
1227
|
+
...this.encodeExtra("session", session, "session_"),
|
|
1228
|
+
...this.encodeExtra("account", account, "account_"),
|
|
1021
1229
|
request_id: "",
|
|
1022
1230
|
organization_id: this.organizationId,
|
|
1023
1231
|
user_id: userId,
|
|
@@ -1057,6 +1265,8 @@ class CoreDispatcher {
|
|
|
1057
1265
|
fail("unsupported_transaction_shape", "transaction OAuth user");
|
|
1058
1266
|
}
|
|
1059
1267
|
const result = await this.client.createOAuthUserGraph({
|
|
1268
|
+
...this.encodeExtra("user", user, "user_"),
|
|
1269
|
+
...this.encodeExtra("account", account, "account_"),
|
|
1060
1270
|
request_id: "",
|
|
1061
1271
|
organization_id: this.organizationId,
|
|
1062
1272
|
user_id: userId,
|
|
@@ -1092,6 +1302,38 @@ class CoreDispatcher {
|
|
|
1092
1302
|
});
|
|
1093
1303
|
requireOutcome(result, "transaction verification consume", "VerificationSetConsumed");
|
|
1094
1304
|
}
|
|
1305
|
+
async increment(model, where, increment, set) {
|
|
1306
|
+
if (!this.plugins?.supports(model))
|
|
1307
|
+
fail("unsupported_call_shape", `incrementOne ${model}`);
|
|
1308
|
+
return this.plugins.increment(model, where, { ...increment }, set === undefined ? {} : { ...set });
|
|
1309
|
+
}
|
|
1310
|
+
async commitMemberActivation(data, where, update) {
|
|
1311
|
+
if (this.plugins === undefined || !exactWhere(where, ["token"]))
|
|
1312
|
+
fail("unsupported_transaction_shape", "member activation");
|
|
1313
|
+
for (let attempt = 0; attempt < 3; attempt += 1) {
|
|
1314
|
+
const { value } = await this.client.findSessionByToken({ organization_id: this.organizationId,
|
|
1315
|
+
token: whereValue(where, "token", "member activation") });
|
|
1316
|
+
const raw = value.sessions[0];
|
|
1317
|
+
if (raw === undefined)
|
|
1318
|
+
fail("declared_outcome", "member activation", "SessionMissing");
|
|
1319
|
+
await this.plugins.createMemberAndActivate(data, this.mapSession(raw), raw, update);
|
|
1320
|
+
return;
|
|
1321
|
+
}
|
|
1322
|
+
}
|
|
1323
|
+
async commitPasswordChange(where, update) {
|
|
1324
|
+
const account = await this.findOne("account", where);
|
|
1325
|
+
if (account === null || account.providerId !== "credential" || account.accountId !== account.userId) {
|
|
1326
|
+
fail("declared_outcome", "changePassword", "PasswordAccountMissing");
|
|
1327
|
+
}
|
|
1328
|
+
const userId = requiredString(account, "userId", "changePassword");
|
|
1329
|
+
const affected = await this.updateMany("account", [
|
|
1330
|
+
{ field: "userId", value: userId, operator: "eq", connector: "AND", mode: "sensitive" },
|
|
1331
|
+
{ field: "accountId", value: userId, operator: "eq", connector: "AND", mode: "sensitive" },
|
|
1332
|
+
{ field: "providerId", value: "credential", operator: "eq", connector: "AND", mode: "sensitive" },
|
|
1333
|
+
], update);
|
|
1334
|
+
if (affected !== 1)
|
|
1335
|
+
fail("declared_outcome", "changePassword", "PasswordAccountMissing");
|
|
1336
|
+
}
|
|
1095
1337
|
}
|
|
1096
1338
|
function genericCreate(implementation) {
|
|
1097
1339
|
return implementation;
|
|
@@ -1115,23 +1357,80 @@ class TransactionRecorder {
|
|
|
1115
1357
|
consumedVerification;
|
|
1116
1358
|
verificationDeleteRows;
|
|
1117
1359
|
verificationDeleteIdentifier;
|
|
1360
|
+
verificationSnapshot;
|
|
1361
|
+
passwordReset;
|
|
1362
|
+
lostConsume = false;
|
|
1363
|
+
organizationDeletion;
|
|
1364
|
+
memberDeletion;
|
|
1365
|
+
sessionActivation;
|
|
1366
|
+
passwordChange;
|
|
1118
1367
|
constructor(dispatcher) {
|
|
1119
1368
|
this.dispatcher = dispatcher;
|
|
1120
1369
|
}
|
|
1121
1370
|
customAdapter() {
|
|
1122
1371
|
return {
|
|
1123
1372
|
create: genericCreate(async ({ model, data }) => {
|
|
1124
|
-
const copied =
|
|
1373
|
+
const copied = this.dispatcher.normalizeCreate(model, data);
|
|
1125
1374
|
this.creates.push({ model, data: copied });
|
|
1126
1375
|
return copied;
|
|
1127
1376
|
}),
|
|
1128
1377
|
findOne: genericFindOne(async ({ model, where, join }) => this.dispatcher.findOne(model, where, join)),
|
|
1129
1378
|
findMany: genericFindMany(async ({ model, where, limit, sortBy, offset, join }) => this.dispatcher.findMany(model, where, limit, sortBy, offset, join)),
|
|
1130
1379
|
count: async () => fail("unsupported_transaction_shape", "transaction count"),
|
|
1131
|
-
update: async (
|
|
1132
|
-
|
|
1133
|
-
|
|
1380
|
+
update: genericUpdate(async ({ model, where, update }) => {
|
|
1381
|
+
if (model === "account" && exactWhere(where, ["id"]) && this.passwordChange === undefined &&
|
|
1382
|
+
typeof update.password === "string" && Object.keys(update).every((field) => field === "password" || field === "updatedAt")) {
|
|
1383
|
+
requiredString(update, "password", "changePassword");
|
|
1384
|
+
requiredDate(update, "updatedAt", "changePassword");
|
|
1385
|
+
const current = await this.dispatcher.findOne("account", where);
|
|
1386
|
+
if (current === null)
|
|
1387
|
+
fail("declared_outcome", "changePassword", "PasswordAccountMissing");
|
|
1388
|
+
this.passwordChange = { where, update };
|
|
1389
|
+
return { ...current, ...update };
|
|
1390
|
+
}
|
|
1391
|
+
if (this.dispatcher.plugins === undefined || model !== "session" || !exactWhere(where, ["token"]) ||
|
|
1392
|
+
this.sessionActivation !== undefined || this.creates.length !== 1 || this.creates[0].model !== "member" ||
|
|
1393
|
+
Object.keys(update).some((field) => field !== "activeOrganizationId" && field !== "updatedAt"))
|
|
1394
|
+
fail("unsupported_transaction_shape", "member activation");
|
|
1395
|
+
const current = await this.dispatcher.findOne("session", where);
|
|
1396
|
+
if (current === null)
|
|
1397
|
+
return null;
|
|
1398
|
+
this.sessionActivation = { where, update };
|
|
1399
|
+
return { ...current, ...update };
|
|
1400
|
+
}),
|
|
1401
|
+
updateMany: async ({ model, where, update }) => {
|
|
1402
|
+
if (model !== "account" || !exactWhere(where, ["userId", "providerId", "accountId"]) ||
|
|
1403
|
+
!this.consumeAttempted || this.passwordReset !== undefined ||
|
|
1404
|
+
Object.keys(update).some((field) => field !== "password" && field !== "updatedAt")) {
|
|
1405
|
+
fail("unsupported_transaction_shape", "transaction updateMany");
|
|
1406
|
+
}
|
|
1407
|
+
this.passwordReset = { where, update };
|
|
1408
|
+
return 1;
|
|
1409
|
+
},
|
|
1410
|
+
delete: async ({ model, where }) => {
|
|
1411
|
+
if (this.dispatcher.plugins === undefined || !exactWhere(where, ["id"]))
|
|
1412
|
+
fail("unsupported_transaction_shape", "transaction delete");
|
|
1413
|
+
const id = whereValue(where, "id", "transaction delete");
|
|
1414
|
+
if (model === "organization" && this.organizationDeletion?.id === id && this.organizationDeletion.models.join(",") === "member,invitation") {
|
|
1415
|
+
this.organizationDeletion.deleted = true;
|
|
1416
|
+
return;
|
|
1417
|
+
}
|
|
1418
|
+
if (model === "member" && this.memberDeletion === undefined && this.organizationDeletion === undefined) {
|
|
1419
|
+
this.memberDeletion = id;
|
|
1420
|
+
return;
|
|
1421
|
+
}
|
|
1422
|
+
fail("unsupported_transaction_shape", "transaction delete");
|
|
1423
|
+
},
|
|
1134
1424
|
deleteMany: async ({ model, where }) => {
|
|
1425
|
+
if (this.dispatcher.plugins !== undefined && ["member", "invitation"].includes(model) && exactWhere(where, ["organizationId"])) {
|
|
1426
|
+
const id = whereValue(where, "organizationId", "organization delete");
|
|
1427
|
+
this.organizationDeletion ??= { id, models: [], deleted: false };
|
|
1428
|
+
if (this.organizationDeletion.id !== id || this.organizationDeletion.deleted ||
|
|
1429
|
+
model !== (this.organizationDeletion.models.length === 0 ? "member" : "invitation") || this.organizationDeletion.models.length >= 2)
|
|
1430
|
+
fail("unsupported_transaction_shape", "organization delete");
|
|
1431
|
+
this.organizationDeletion.models.push(model);
|
|
1432
|
+
return 0; // The upstream graph ignores these counts; one cascade commits them together.
|
|
1433
|
+
}
|
|
1135
1434
|
if (model !== "verification" ||
|
|
1136
1435
|
!exactWhere(where, ["identifier"]) ||
|
|
1137
1436
|
!this.consumeAttempted ||
|
|
@@ -1139,7 +1438,8 @@ class TransactionRecorder {
|
|
|
1139
1438
|
return fail("unsupported_transaction_shape", "transaction deleteMany");
|
|
1140
1439
|
}
|
|
1141
1440
|
this.verificationDeleteIdentifier = whereValue(where, "identifier", "transaction deleteMany verification");
|
|
1142
|
-
this.verificationDeleteRows = await this.dispatcher.findMany("verification", where, 32)
|
|
1441
|
+
this.verificationDeleteRows = (await this.dispatcher.findMany("verification", where, 32))
|
|
1442
|
+
.filter((row) => row.id !== this.consumedVerification?.id);
|
|
1143
1443
|
return this.verificationDeleteRows.length;
|
|
1144
1444
|
},
|
|
1145
1445
|
consumeOne: genericConsumeOne(async ({ model, where }) => {
|
|
@@ -1149,19 +1449,43 @@ class TransactionRecorder {
|
|
|
1149
1449
|
return fail("unsupported_transaction_shape", "transaction consumeOne");
|
|
1150
1450
|
}
|
|
1151
1451
|
this.consumeAttempted = true;
|
|
1152
|
-
|
|
1153
|
-
this.consumedVerification = row;
|
|
1154
|
-
return
|
|
1452
|
+
this.verificationSnapshot = await this.dispatcher.prepareConsume(whereValue(where, "id", "consumeOne"));
|
|
1453
|
+
this.consumedVerification = this.verificationSnapshot?.row ?? null;
|
|
1454
|
+
return this.consumedVerification;
|
|
1155
1455
|
}),
|
|
1156
1456
|
incrementOne: async () => fail("unsupported_transaction_shape", "transaction incrementOne"),
|
|
1157
1457
|
};
|
|
1158
1458
|
}
|
|
1159
1459
|
async commit() {
|
|
1160
1460
|
const hasVerificationMutation = this.consumeAttempted || this.verificationDeleteRows !== undefined;
|
|
1461
|
+
const hasOrganizationMutation = this.organizationDeletion !== undefined || this.memberDeletion !== undefined;
|
|
1462
|
+
if (this.passwordChange !== undefined) {
|
|
1463
|
+
if (hasVerificationMutation || hasOrganizationMutation || this.creates.length > 0 || this.sessionActivation !== undefined)
|
|
1464
|
+
fail("unsupported_transaction_shape", "mixed password change");
|
|
1465
|
+
await this.dispatcher.commitPasswordChange(this.passwordChange.where, this.passwordChange.update);
|
|
1466
|
+
return;
|
|
1467
|
+
}
|
|
1468
|
+
if (hasOrganizationMutation) {
|
|
1469
|
+
if (this.creates.length > 0 || hasVerificationMutation || this.sessionActivation !== undefined ||
|
|
1470
|
+
(this.organizationDeletion !== undefined && this.memberDeletion !== undefined))
|
|
1471
|
+
fail("unsupported_transaction_shape", "mixed organization transaction");
|
|
1472
|
+
if (this.organizationDeletion !== undefined) {
|
|
1473
|
+
if (!this.organizationDeletion.deleted)
|
|
1474
|
+
fail("unsupported_transaction_shape", "incomplete organization deletion");
|
|
1475
|
+
await this.dispatcher.plugins.deleteIds("organization", [this.organizationDeletion.id]);
|
|
1476
|
+
}
|
|
1477
|
+
else
|
|
1478
|
+
await this.dispatcher.plugins.deleteIds("member", [this.memberDeletion]);
|
|
1479
|
+
return;
|
|
1480
|
+
}
|
|
1161
1481
|
if (this.creates.length > 0 && hasVerificationMutation) {
|
|
1162
1482
|
fail("unsupported_transaction_shape", "mixed transaction");
|
|
1163
1483
|
}
|
|
1164
1484
|
if (this.creates.length > 0) {
|
|
1485
|
+
if (this.creates.length === 1 && this.creates[0].model === "member" && this.sessionActivation !== undefined) {
|
|
1486
|
+
await this.dispatcher.commitMemberActivation(this.creates[0].data, this.sessionActivation.where, this.sessionActivation.update);
|
|
1487
|
+
return;
|
|
1488
|
+
}
|
|
1165
1489
|
if (this.creates.length === 2) {
|
|
1166
1490
|
await this.dispatcher.commitOAuthUser(this.creates);
|
|
1167
1491
|
}
|
|
@@ -1174,13 +1498,21 @@ class TransactionRecorder {
|
|
|
1174
1498
|
if (!this.consumeAttempted || this.consumedVerification === undefined) {
|
|
1175
1499
|
fail("unsupported_transaction_shape", "transaction verification consume");
|
|
1176
1500
|
}
|
|
1177
|
-
if (this.
|
|
1501
|
+
if (this.verificationSnapshot == null)
|
|
1178
1502
|
return;
|
|
1179
|
-
if (this.consumedVerification !== null &&
|
|
1503
|
+
if (this.verificationDeleteRows !== undefined && this.consumedVerification !== null &&
|
|
1180
1504
|
this.consumedVerification.identifier !== this.verificationDeleteIdentifier) {
|
|
1181
1505
|
fail("unsupported_transaction_shape", "transaction verification consume");
|
|
1182
1506
|
}
|
|
1183
|
-
if (this.
|
|
1507
|
+
if (this.passwordReset !== undefined) {
|
|
1508
|
+
await this.dispatcher.commitPasswordReset(this.verificationSnapshot, this.passwordReset.where, this.passwordReset.update, this.verificationDeleteRows ?? []);
|
|
1509
|
+
return;
|
|
1510
|
+
}
|
|
1511
|
+
if (!await this.dispatcher.commitConsume(this.verificationSnapshot)) {
|
|
1512
|
+
this.lostConsume = true;
|
|
1513
|
+
return;
|
|
1514
|
+
}
|
|
1515
|
+
if (this.verificationDeleteRows !== undefined && this.verificationDeleteRows.length > 0) {
|
|
1184
1516
|
await this.dispatcher.commitVerificationConsume(this.verificationDeleteRows);
|
|
1185
1517
|
}
|
|
1186
1518
|
}
|
|
@@ -1197,7 +1529,7 @@ function customAdapter(dispatcher) {
|
|
|
1197
1529
|
delete: async ({ model, where }) => dispatcher.delete(model, where),
|
|
1198
1530
|
deleteMany: async ({ model, where }) => dispatcher.deleteMany(model, where),
|
|
1199
1531
|
consumeOne: genericConsumeOne(async ({ model, where }) => dispatcher.consumeOne(model, where)),
|
|
1200
|
-
incrementOne: async ({ model }) =>
|
|
1532
|
+
incrementOne: (async ({ model, where, increment, set }) => dispatcher.increment(model, where, increment, set)),
|
|
1201
1533
|
};
|
|
1202
1534
|
}
|
|
1203
1535
|
const BASE_FACTORY_CONFIG = {
|
|
@@ -1215,10 +1547,14 @@ export function buildRiffDBBetterAuthAdapter(config) {
|
|
|
1215
1547
|
assertSupportedBetterAuthInstallation();
|
|
1216
1548
|
validateConfiguration(config);
|
|
1217
1549
|
return (options) => {
|
|
1218
|
-
|
|
1550
|
+
if (config.profile !== undefined)
|
|
1551
|
+
options = { ...options, advanced: { ...options.advanced,
|
|
1552
|
+
database: { ...options.advanced?.database, joins: true } } };
|
|
1553
|
+
const dispatcher = new CoreDispatcher(config.client.causalSession(), config.organizationId, config.resetModelForTesting, config.profile);
|
|
1219
1554
|
const factory = createAdapterFactory({
|
|
1220
1555
|
config: {
|
|
1221
1556
|
...BASE_FACTORY_CONFIG,
|
|
1557
|
+
adapterName: config.profile?.plan.name ?? BASE_FACTORY_CONFIG.adapterName,
|
|
1222
1558
|
debugLogs: false,
|
|
1223
1559
|
transaction: async (callback) => {
|
|
1224
1560
|
const recorder = new TransactionRecorder(dispatcher);
|
|
@@ -1229,18 +1565,18 @@ export function buildRiffDBBetterAuthAdapter(config) {
|
|
|
1229
1565
|
transaction: false,
|
|
1230
1566
|
},
|
|
1231
1567
|
adapter: ({ options: transactionOptions, schema }) => {
|
|
1232
|
-
validateResolvedSchema(transactionOptions, schema);
|
|
1568
|
+
validateResolvedSchema(transactionOptions, schema, config.profile);
|
|
1233
1569
|
return recorder.customAdapter();
|
|
1234
1570
|
},
|
|
1235
1571
|
});
|
|
1236
1572
|
const transactionAdapter = transactionFactory(options);
|
|
1237
1573
|
const result = await callback(transactionAdapter);
|
|
1238
1574
|
await recorder.commit();
|
|
1239
|
-
return result;
|
|
1575
|
+
return recorder.lostConsume ? null : result;
|
|
1240
1576
|
},
|
|
1241
1577
|
},
|
|
1242
1578
|
adapter: ({ options: resolvedOptions, schema }) => {
|
|
1243
|
-
validateResolvedSchema(resolvedOptions, schema);
|
|
1579
|
+
validateResolvedSchema(resolvedOptions, schema, config.profile);
|
|
1244
1580
|
return customAdapter(dispatcher);
|
|
1245
1581
|
},
|
|
1246
1582
|
});
|
|
@@ -1254,9 +1590,11 @@ export function riffdbAdapter(config) {
|
|
|
1254
1590
|
}
|
|
1255
1591
|
const transport = new DriverGeneratedApplicationTransport(config.driver);
|
|
1256
1592
|
return buildRiffDBBetterAuthAdapter({
|
|
1257
|
-
client: new RiffDBBetterAuthCoreClient(transport, commandAttemptBudget)
|
|
1593
|
+
client: config.profile === undefined ? new RiffDBBetterAuthCoreClient(transport, commandAttemptBudget) :
|
|
1594
|
+
instantiateProfileClient(config.profile, transport, commandAttemptBudget),
|
|
1258
1595
|
organizationId: config.organizationId,
|
|
1259
1596
|
...(config.debugLogs === undefined ? {} : { debugLogs: config.debugLogs }),
|
|
1597
|
+
...(config.profile === undefined ? {} : { profile: config.profile }),
|
|
1260
1598
|
});
|
|
1261
1599
|
}
|
|
1262
1600
|
//# sourceMappingURL=adapter.js.map
|