@better-auth/core 1.7.0-rc.1 → 1.7.0-rc.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/api/index.d.mts +28 -28
- package/dist/async_hooks/index.d.mts +0 -1
- package/dist/async_hooks/pure.index.d.mts +0 -1
- package/dist/context/endpoint-context.d.mts +1 -1
- package/dist/context/global.d.mts +0 -1
- package/dist/context/global.mjs +1 -1
- package/dist/context/request-state.d.mts +0 -1
- package/dist/context/request-state.mjs +8 -5
- package/dist/context/transaction.d.mts +8 -3
- package/dist/context/transaction.mjs +27 -10
- package/dist/db/adapter/factory.d.mts +3 -5
- package/dist/db/adapter/factory.mjs +7 -5
- package/dist/db/adapter/get-default-field-name.d.mts +2 -9
- package/dist/db/adapter/get-default-model-name.d.mts +1 -5
- package/dist/db/adapter/get-default-model-name.mjs +6 -5
- package/dist/db/adapter/get-field-attributes.d.mts +4 -11
- package/dist/db/adapter/get-field-name.d.mts +2 -9
- package/dist/db/adapter/get-id-field.d.mts +4 -12
- package/dist/db/adapter/get-model-name.d.mts +1 -5
- package/dist/db/adapter/index.d.mts +7 -32
- package/dist/db/adapter/types.d.mts +5 -17
- package/dist/db/adapter/utils.d.mts +0 -1
- package/dist/db/database-index.d.mts +44 -0
- package/dist/db/database-index.mjs +168 -0
- package/dist/db/get-tables.d.mts +7 -1
- package/dist/db/get-tables.mjs +47 -6
- package/dist/db/index.d.mts +3 -3
- package/dist/db/index.mjs +2 -2
- package/dist/db/internal.d.mts +3 -0
- package/dist/db/internal.mjs +3 -0
- package/dist/db/plugin.d.mts +4 -3
- package/dist/db/schema/account.d.mts +16 -3
- package/dist/db/schema/account.mjs +35 -2
- package/dist/db/schema/rate-limit.d.mts +1 -1
- package/dist/db/schema/rate-limit.mjs +9 -0
- package/dist/db/schema/session.d.mts +1 -1
- package/dist/db/schema/shared.d.mts +0 -1
- package/dist/db/schema/user.d.mts +1 -1
- package/dist/db/schema/verification.d.mts +1 -1
- package/dist/db/type.d.mts +17 -9
- package/dist/env/logger.d.mts +25 -25
- package/dist/error/codes.d.mts +0 -1
- package/dist/error/index.d.mts +0 -1
- package/dist/index.d.mts +1 -1
- package/dist/instrumentation/attributes.d.mts +0 -1
- package/dist/instrumentation/pure.index.d.mts +0 -1
- package/dist/instrumentation/tracer.mjs +1 -1
- package/dist/oauth2/authorization-params.d.mts +0 -1
- package/dist/oauth2/client-assertion.d.mts +3 -13
- package/dist/oauth2/client-credentials-token.d.mts +3 -17
- package/dist/oauth2/client-credentials-token.mjs +1 -4
- package/dist/oauth2/create-authorization-url.d.mts +3 -21
- package/dist/oauth2/dpop.d.mts +2 -23
- package/dist/oauth2/dpop.mjs +1 -1
- package/dist/oauth2/index.d.mts +2 -2
- package/dist/oauth2/oauth-provider.d.mts +85 -36
- package/dist/oauth2/refresh-access-token.d.mts +3 -19
- package/dist/oauth2/refresh-access-token.mjs +3 -9
- package/dist/oauth2/reject-redirects.mjs +1 -1
- package/dist/oauth2/token-endpoint-auth.d.mts +0 -1
- package/dist/oauth2/utils.d.mts +0 -1
- package/dist/oauth2/utils.mjs +2 -3
- package/dist/oauth2/validate-authorization-code.d.mts +5 -29
- package/dist/oauth2/verify-id-token.d.mts +3 -2
- package/dist/oauth2/verify-id-token.mjs +3 -3
- package/dist/oauth2/verify.d.mts +5 -7
- package/dist/oauth2/verify.mjs +2 -2
- package/dist/social-providers/apple.d.mts +9 -24
- package/dist/social-providers/apple.mjs +2 -1
- package/dist/social-providers/atlassian.d.mts +18 -19
- package/dist/social-providers/atlassian.mjs +1 -1
- package/dist/social-providers/cognito.d.mts +33 -22
- package/dist/social-providers/cognito.mjs +2 -2
- package/dist/social-providers/discord.d.mts +7 -20
- package/dist/social-providers/discord.mjs +1 -1
- package/dist/social-providers/dropbox.d.mts +7 -22
- package/dist/social-providers/dropbox.mjs +1 -1
- package/dist/social-providers/facebook.d.mts +19 -27
- package/dist/social-providers/facebook.mjs +6 -17
- package/dist/social-providers/figma.d.mts +7 -22
- package/dist/social-providers/figma.mjs +1 -1
- package/dist/social-providers/github.d.mts +7 -23
- package/dist/social-providers/github.mjs +1 -1
- package/dist/social-providers/gitlab.d.mts +6 -43
- package/dist/social-providers/gitlab.mjs +1 -1
- package/dist/social-providers/google.d.mts +10 -32
- package/dist/social-providers/google.mjs +2 -1
- package/dist/social-providers/huggingface.d.mts +7 -22
- package/dist/social-providers/huggingface.mjs +1 -1
- package/dist/social-providers/index.d.mts +229 -787
- package/dist/social-providers/kakao.d.mts +8 -33
- package/dist/social-providers/kakao.mjs +1 -1
- package/dist/social-providers/kick.d.mts +7 -22
- package/dist/social-providers/kick.mjs +1 -1
- package/dist/social-providers/line.d.mts +8 -44
- package/dist/social-providers/line.mjs +4 -6
- package/dist/social-providers/linear.d.mts +7 -21
- package/dist/social-providers/linear.mjs +1 -1
- package/dist/social-providers/linkedin.d.mts +7 -21
- package/dist/social-providers/linkedin.mjs +1 -1
- package/dist/social-providers/microsoft-entra-id.d.mts +8 -18
- package/dist/social-providers/microsoft-entra-id.mjs +18 -2
- package/dist/social-providers/naver.d.mts +27 -42
- package/dist/social-providers/naver.mjs +1 -1
- package/dist/social-providers/notion.d.mts +7 -21
- package/dist/social-providers/notion.mjs +1 -1
- package/dist/social-providers/paybin.d.mts +8 -23
- package/dist/social-providers/paybin.mjs +2 -1
- package/dist/social-providers/paypal.d.mts +8 -33
- package/dist/social-providers/paypal.mjs +1 -1
- package/dist/social-providers/polar.d.mts +7 -22
- package/dist/social-providers/polar.mjs +1 -1
- package/dist/social-providers/railway.d.mts +7 -22
- package/dist/social-providers/railway.mjs +1 -1
- package/dist/social-providers/reddit.d.mts +7 -20
- package/dist/social-providers/reddit.mjs +1 -1
- package/dist/social-providers/roblox.d.mts +7 -20
- package/dist/social-providers/roblox.mjs +1 -1
- package/dist/social-providers/salesforce.d.mts +7 -22
- package/dist/social-providers/salesforce.mjs +1 -1
- package/dist/social-providers/slack.d.mts +7 -20
- package/dist/social-providers/slack.mjs +1 -1
- package/dist/social-providers/spotify.d.mts +7 -22
- package/dist/social-providers/spotify.mjs +1 -1
- package/dist/social-providers/tiktok.d.mts +10 -22
- package/dist/social-providers/tiktok.mjs +1 -1
- package/dist/social-providers/twitch.d.mts +7 -20
- package/dist/social-providers/twitch.mjs +1 -1
- package/dist/social-providers/twitter.d.mts +29 -26
- package/dist/social-providers/twitter.mjs +1 -1
- package/dist/social-providers/vercel.d.mts +7 -22
- package/dist/social-providers/vercel.mjs +1 -1
- package/dist/social-providers/vk.d.mts +8 -24
- package/dist/social-providers/vk.mjs +5 -6
- package/dist/social-providers/wechat.d.mts +7 -19
- package/dist/social-providers/wechat.mjs +1 -1
- package/dist/social-providers/zoom.d.mts +9 -25
- package/dist/social-providers/zoom.mjs +1 -1
- package/dist/types/context.d.mts +16 -9
- package/dist/types/cookie.d.mts +0 -1
- package/dist/types/helper.d.mts +1 -1
- package/dist/types/index.d.mts +1 -1
- package/dist/types/init-options.d.mts +37 -26
- package/dist/types/plugin-client.d.mts +1 -3
- package/dist/types/plugin.d.mts +2 -2
- package/dist/utils/async.d.mts +0 -1
- package/dist/utils/db.d.mts +1 -0
- package/dist/utils/deprecate.d.mts +0 -1
- package/dist/utils/error-codes.d.mts +2 -2
- package/dist/utils/host.d.mts +27 -1
- package/dist/utils/host.mjs +1 -1
- package/dist/utils/ip.d.mts +1 -0
- package/dist/utils/ip.mjs +1 -1
- package/dist/utils/is-api-error.d.mts +0 -1
- package/dist/utils/redirect-uri.d.mts +0 -1
- package/package.json +10 -2
- package/src/context/request-state.ts +26 -6
- package/src/context/transaction.ts +37 -18
- package/src/db/adapter/factory.ts +24 -18
- package/src/db/adapter/get-default-model-name.ts +23 -14
- package/src/db/database-index.ts +351 -0
- package/src/db/get-tables.ts +89 -9
- package/src/db/index.ts +4 -0
- package/src/db/internal.ts +12 -0
- package/src/db/plugin.ts +3 -1
- package/src/db/schema/account.ts +27 -1
- package/src/db/schema/user.ts +1 -1
- package/src/db/type.ts +12 -0
- package/src/oauth2/index.ts +3 -0
- package/src/oauth2/oauth-provider.ts +94 -36
- package/src/oauth2/verify-id-token.ts +4 -2
- package/src/social-providers/apple.ts +2 -1
- package/src/social-providers/atlassian.ts +1 -1
- package/src/social-providers/cognito.ts +2 -2
- package/src/social-providers/discord.ts +1 -1
- package/src/social-providers/dropbox.ts +1 -1
- package/src/social-providers/facebook.ts +21 -28
- package/src/social-providers/figma.ts +1 -1
- package/src/social-providers/github.ts +1 -1
- package/src/social-providers/gitlab.ts +1 -1
- package/src/social-providers/google.ts +2 -1
- package/src/social-providers/huggingface.ts +1 -1
- package/src/social-providers/kakao.ts +1 -1
- package/src/social-providers/kick.ts +1 -1
- package/src/social-providers/line.ts +7 -12
- package/src/social-providers/linear.ts +1 -1
- package/src/social-providers/linkedin.ts +1 -1
- package/src/social-providers/microsoft-entra-id.ts +3 -2
- package/src/social-providers/naver.ts +1 -1
- package/src/social-providers/notion.ts +1 -1
- package/src/social-providers/paybin.ts +2 -1
- package/src/social-providers/paypal.ts +1 -1
- package/src/social-providers/polar.ts +1 -1
- package/src/social-providers/railway.ts +1 -1
- package/src/social-providers/reddit.ts +1 -1
- package/src/social-providers/roblox.ts +1 -1
- package/src/social-providers/salesforce.ts +1 -1
- package/src/social-providers/slack.ts +1 -1
- package/src/social-providers/spotify.ts +1 -1
- package/src/social-providers/tiktok.ts +2 -2
- package/src/social-providers/twitch.ts +1 -1
- package/src/social-providers/twitter.ts +1 -1
- package/src/social-providers/vercel.ts +1 -1
- package/src/social-providers/vk.ts +2 -2
- package/src/social-providers/wechat.ts +1 -1
- package/src/social-providers/zoom.ts +1 -1
- package/src/types/context.ts +21 -14
- package/src/types/init-options.ts +15 -14
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { DBFieldAttribute, DBTableIndex } from "./type.mjs";
|
|
2
|
+
//#region src/db/database-index.d.ts
|
|
3
|
+
declare function getPortableDatabaseIdentifierKey(identifier: string): string;
|
|
4
|
+
/** A table-level index resolved to physical database columns. */
|
|
5
|
+
interface ResolvedDBTableIndex extends Omit<DBTableIndex, "fields"> {
|
|
6
|
+
/** Physical database column names, in index order. */
|
|
7
|
+
columns: readonly [string, ...string[]];
|
|
8
|
+
name: string;
|
|
9
|
+
}
|
|
10
|
+
interface DBTableIndexSource {
|
|
11
|
+
fields: Readonly<Record<string, DBFieldAttribute>>;
|
|
12
|
+
indexes: readonly DBTableIndex[] | undefined;
|
|
13
|
+
tableName: string;
|
|
14
|
+
}
|
|
15
|
+
type BoundedDatabaseIndexDialect = "mssql" | "mysql";
|
|
16
|
+
/** Returns the stable database name for a table-level index. */
|
|
17
|
+
declare function getDatabaseIndexName(tableName: string, index: DBTableIndex): string;
|
|
18
|
+
/** Returns the database name used by legacy field-level index metadata. */
|
|
19
|
+
declare function getDatabaseFieldIndexName(tableName: string, columnName: string, unique: boolean): string;
|
|
20
|
+
/** Resolves logical index fields to their configured database column names. */
|
|
21
|
+
declare function resolveDatabaseTableIndexes({ fields, indexes, tableName }: {
|
|
22
|
+
fields: Readonly<Record<string, DBFieldAttribute>>;
|
|
23
|
+
indexes: readonly DBTableIndex[] | undefined;
|
|
24
|
+
tableName: string;
|
|
25
|
+
}): readonly ResolvedDBTableIndex[];
|
|
26
|
+
/**
|
|
27
|
+
* Returns a safe generated string length for a column across all of its table
|
|
28
|
+
* indexes in byte-limited SQL dialects.
|
|
29
|
+
*/
|
|
30
|
+
declare function getDatabaseIndexStringLength({ columnName, dialect, fields, indexes }: {
|
|
31
|
+
columnName: string;
|
|
32
|
+
dialect: BoundedDatabaseIndexDialect;
|
|
33
|
+
fields: Readonly<Record<string, DBFieldAttribute>>;
|
|
34
|
+
indexes: readonly ResolvedDBTableIndex[];
|
|
35
|
+
}): number | undefined;
|
|
36
|
+
/**
|
|
37
|
+
* Resolves and validates every table index as one portable database schema.
|
|
38
|
+
*
|
|
39
|
+
* Index names are schema-wide because SQLite and PostgreSQL do not scope them
|
|
40
|
+
* to an individual table.
|
|
41
|
+
*/
|
|
42
|
+
declare function resolveDatabaseSchemaIndexes(sources: readonly DBTableIndexSource[]): ReadonlyMap<string, readonly ResolvedDBTableIndex[]>;
|
|
43
|
+
//#endregion
|
|
44
|
+
export { BoundedDatabaseIndexDialect, DBTableIndexSource, ResolvedDBTableIndex, getDatabaseFieldIndexName, getDatabaseIndexName, getDatabaseIndexStringLength, getPortableDatabaseIdentifierKey, resolveDatabaseSchemaIndexes, resolveDatabaseTableIndexes };
|
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
import { BetterAuthError } from "../error/index.mjs";
|
|
2
|
+
//#region src/db/database-index.ts
|
|
3
|
+
const MAX_DATABASE_INDEX_NAME_BYTES = 63;
|
|
4
|
+
const MAX_DATABASE_INDEX_FIELDS = 16;
|
|
5
|
+
function getPortableDatabaseIdentifierKey(identifier) {
|
|
6
|
+
return identifier.toLowerCase();
|
|
7
|
+
}
|
|
8
|
+
function getUtf8ByteLength(value) {
|
|
9
|
+
return new TextEncoder().encode(value).length;
|
|
10
|
+
}
|
|
11
|
+
function truncateUtf8(value, maxBytes) {
|
|
12
|
+
let result = "";
|
|
13
|
+
let byteLength = 0;
|
|
14
|
+
for (const character of value) {
|
|
15
|
+
const characterByteLength = getUtf8ByteLength(character);
|
|
16
|
+
if (byteLength + characterByteLength > maxBytes) break;
|
|
17
|
+
result += character;
|
|
18
|
+
byteLength += characterByteLength;
|
|
19
|
+
}
|
|
20
|
+
return result;
|
|
21
|
+
}
|
|
22
|
+
function getStableIndexNameHash(value) {
|
|
23
|
+
let hash = 2166136261;
|
|
24
|
+
for (let index = 0; index < value.length; index++) {
|
|
25
|
+
hash ^= value.charCodeAt(index);
|
|
26
|
+
hash = Math.imul(hash, 16777619);
|
|
27
|
+
}
|
|
28
|
+
return (hash >>> 0).toString(16).padStart(8, "0");
|
|
29
|
+
}
|
|
30
|
+
/** Returns the stable database name for a table-level index. */
|
|
31
|
+
function getDatabaseIndexName(tableName, index) {
|
|
32
|
+
if (index.name !== void 0) {
|
|
33
|
+
if (index.name.trim().length === 0) throw new BetterAuthError("Database index names must contain at least one visible character.");
|
|
34
|
+
if (!/^[A-Za-z_][A-Za-z0-9_]*$/.test(index.name)) throw new BetterAuthError("Database index names must start with a letter or underscore and contain only letters, numbers, and underscores.");
|
|
35
|
+
if (getUtf8ByteLength(index.name) > MAX_DATABASE_INDEX_NAME_BYTES) throw new BetterAuthError(`Database index names must be at most ${MAX_DATABASE_INDEX_NAME_BYTES} UTF-8 bytes.`);
|
|
36
|
+
return index.name;
|
|
37
|
+
}
|
|
38
|
+
const indexKind = index.unique ? "uidx" : "idx";
|
|
39
|
+
const generatedName = `${tableName}_${index.fields.join("_")}_${indexKind}`;
|
|
40
|
+
if (getUtf8ByteLength(generatedName) <= MAX_DATABASE_INDEX_NAME_BYTES) return generatedName;
|
|
41
|
+
const suffix = `_${getStableIndexNameHash(generatedName)}_${indexKind}`;
|
|
42
|
+
return `${truncateUtf8(generatedName.slice(0, -indexKind.length - 1), MAX_DATABASE_INDEX_NAME_BYTES - getUtf8ByteLength(suffix))}${suffix}`;
|
|
43
|
+
}
|
|
44
|
+
/** Returns the database name used by legacy field-level index metadata. */
|
|
45
|
+
function getDatabaseFieldIndexName(tableName, columnName, unique) {
|
|
46
|
+
return getDatabaseIndexName(tableName, {
|
|
47
|
+
fields: [columnName],
|
|
48
|
+
unique
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
/** Resolves logical index fields to their configured database column names. */
|
|
52
|
+
function resolveDatabaseTableIndexes({ fields, indexes, tableName }) {
|
|
53
|
+
const resolvedIndexes = (indexes ?? []).map((index) => {
|
|
54
|
+
if (index.fields.length === 0) throw new BetterAuthError(`Index on table "${tableName}" must include at least one field.`);
|
|
55
|
+
if (index.fields.length > MAX_DATABASE_INDEX_FIELDS) throw new BetterAuthError(`Index on table "${tableName}" can include at most ${MAX_DATABASE_INDEX_FIELDS} fields so it works across supported databases.`);
|
|
56
|
+
if (new Set(index.fields).size !== index.fields.length) throw new BetterAuthError(`Index on table "${tableName}" contains the same field more than once.`);
|
|
57
|
+
if (index.unique && index.fields.some((fieldName) => fields[fieldName]?.required === false)) throw new BetterAuthError(`Unique index on table "${tableName}" can only include required fields so its behavior is consistent across databases.`);
|
|
58
|
+
const unsupportedField = index.fields.find((fieldName) => {
|
|
59
|
+
const fieldType = fields[fieldName]?.type;
|
|
60
|
+
return fieldType === "json" || fieldType === "string[]" || fieldType === "number[]";
|
|
61
|
+
});
|
|
62
|
+
if (unsupportedField) throw new BetterAuthError(`Index on table "${tableName}" references field "${unsupportedField}", whose type is not portably indexable.`);
|
|
63
|
+
const resolveFieldName = (fieldName) => {
|
|
64
|
+
const field = fields[fieldName];
|
|
65
|
+
if (!field) throw new BetterAuthError(`Index on table "${tableName}" references unknown field "${fieldName}".`);
|
|
66
|
+
return field.fieldName || fieldName;
|
|
67
|
+
};
|
|
68
|
+
const [firstField, ...remainingFields] = index.fields;
|
|
69
|
+
const columns = [resolveFieldName(firstField), ...remainingFields.map(resolveFieldName)];
|
|
70
|
+
if (new Set(columns.map(getPortableDatabaseIdentifierKey)).size !== columns.length) throw new BetterAuthError(`Index on table "${tableName}" resolves more than one field to the same database column.`);
|
|
71
|
+
return {
|
|
72
|
+
columns,
|
|
73
|
+
name: getDatabaseIndexName(tableName, {
|
|
74
|
+
...index,
|
|
75
|
+
fields: columns
|
|
76
|
+
}),
|
|
77
|
+
unique: index.unique
|
|
78
|
+
};
|
|
79
|
+
});
|
|
80
|
+
const definitionsByName = /* @__PURE__ */ new Map();
|
|
81
|
+
const deduplicatedIndexes = [];
|
|
82
|
+
for (const index of resolvedIndexes) {
|
|
83
|
+
const definition = JSON.stringify([index.columns, index.unique ?? false]);
|
|
84
|
+
const identifierKey = getPortableDatabaseIdentifierKey(index.name);
|
|
85
|
+
const existingDefinition = definitionsByName.get(identifierKey);
|
|
86
|
+
if (existingDefinition && existingDefinition !== definition) throw new BetterAuthError(`Database index name "${index.name}" identifies more than one index on table "${tableName}".`);
|
|
87
|
+
if (existingDefinition) continue;
|
|
88
|
+
definitionsByName.set(identifierKey, definition);
|
|
89
|
+
deduplicatedIndexes.push(index);
|
|
90
|
+
}
|
|
91
|
+
return deduplicatedIndexes;
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* Returns a safe generated string length for a column across all of its table
|
|
95
|
+
* indexes in byte-limited SQL dialects.
|
|
96
|
+
*/
|
|
97
|
+
function getDatabaseIndexStringLength({ columnName, dialect, fields, indexes }) {
|
|
98
|
+
const fieldsByColumn = new Map(Object.entries(fields).map(([fieldName, field]) => [field.fieldName || fieldName, field]));
|
|
99
|
+
const containingIndexes = indexes.filter((index) => index.columns.includes(columnName));
|
|
100
|
+
if (containingIndexes.length === 0) return void 0;
|
|
101
|
+
const byteBudget = dialect === "mysql" ? 3072 : 1700;
|
|
102
|
+
const bytesPerCharacter = dialect === "mysql" ? 4 : 1;
|
|
103
|
+
const defaultLength = dialect === "mysql" ? 191 : 255;
|
|
104
|
+
return containingIndexes.reduce((length, index) => {
|
|
105
|
+
const stringColumnCount = index.columns.filter((column) => {
|
|
106
|
+
const type = fieldsByColumn.get(column)?.type;
|
|
107
|
+
return type === "string" || Array.isArray(type);
|
|
108
|
+
}).length;
|
|
109
|
+
if (stringColumnCount === 0) return length;
|
|
110
|
+
const nonStringColumnBytes = (index.columns.length - stringColumnCount) * 16;
|
|
111
|
+
const safeLength = Math.floor(Math.max(1, byteBudget - nonStringColumnBytes) / bytesPerCharacter / stringColumnCount);
|
|
112
|
+
return Math.min(length, safeLength);
|
|
113
|
+
}, defaultLength);
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* Resolves and validates every table index as one portable database schema.
|
|
117
|
+
*
|
|
118
|
+
* Index names are schema-wide because SQLite and PostgreSQL do not scope them
|
|
119
|
+
* to an individual table.
|
|
120
|
+
*/
|
|
121
|
+
function resolveDatabaseSchemaIndexes(sources) {
|
|
122
|
+
const mergedSourcesByTable = /* @__PURE__ */ new Map();
|
|
123
|
+
for (const source of sources) {
|
|
124
|
+
const existingSource = mergedSourcesByTable.get(source.tableName);
|
|
125
|
+
if (existingSource) {
|
|
126
|
+
if (existingSource.indexes.length > 0 || (source.indexes?.length ?? 0) > 0) throw new BetterAuthError(`Database schema resolves more than one indexed logical table to "${source.tableName}". Define table-level indexes through one logical schema key instead of aliasing multiple keys to the same database table.`);
|
|
127
|
+
Object.assign(existingSource.fields, source.fields);
|
|
128
|
+
continue;
|
|
129
|
+
}
|
|
130
|
+
const mergedSource = {
|
|
131
|
+
fields: {},
|
|
132
|
+
indexes: [],
|
|
133
|
+
tableName: source.tableName
|
|
134
|
+
};
|
|
135
|
+
Object.assign(mergedSource.fields, source.fields);
|
|
136
|
+
mergedSource.indexes.push(...source.indexes ?? []);
|
|
137
|
+
mergedSourcesByTable.set(source.tableName, mergedSource);
|
|
138
|
+
}
|
|
139
|
+
const indexesByTable = /* @__PURE__ */ new Map();
|
|
140
|
+
const indexOwnerByName = /* @__PURE__ */ new Map();
|
|
141
|
+
const tableNamesByIdentifier = new Map([...mergedSourcesByTable.keys()].map((tableName) => [getPortableDatabaseIdentifierKey(tableName), tableName]));
|
|
142
|
+
const fieldIndexOwnerByName = /* @__PURE__ */ new Map();
|
|
143
|
+
for (const source of mergedSourcesByTable.values()) for (const [fieldName, field] of Object.entries(source.fields)) {
|
|
144
|
+
if (!field.index && !field.unique) continue;
|
|
145
|
+
const indexName = getDatabaseFieldIndexName(source.tableName, field.fieldName || fieldName, field.unique ?? false);
|
|
146
|
+
const identifierKey = getPortableDatabaseIdentifierKey(indexName);
|
|
147
|
+
if (tableNamesByIdentifier.has(identifierKey)) throw new BetterAuthError(`Database index name "${indexName}" conflicts with a table name. Index and table names must be unique across the schema.`);
|
|
148
|
+
const existingOwner = fieldIndexOwnerByName.get(identifierKey);
|
|
149
|
+
if (existingOwner) throw new BetterAuthError(`Database field-level index name "${indexName}" is used by both table "${existingOwner}" and table "${source.tableName}".`);
|
|
150
|
+
fieldIndexOwnerByName.set(identifierKey, source.tableName);
|
|
151
|
+
}
|
|
152
|
+
for (const source of mergedSourcesByTable.values()) {
|
|
153
|
+
const resolvedIndexes = resolveDatabaseTableIndexes(source);
|
|
154
|
+
indexesByTable.set(source.tableName, [...resolvedIndexes]);
|
|
155
|
+
for (const index of resolvedIndexes) {
|
|
156
|
+
const identifierKey = getPortableDatabaseIdentifierKey(index.name);
|
|
157
|
+
if (tableNamesByIdentifier.has(identifierKey)) throw new BetterAuthError(`Database index name "${index.name}" conflicts with a table name. Index and table names must be unique across the schema.`);
|
|
158
|
+
const fieldIndexOwner = fieldIndexOwnerByName.get(identifierKey);
|
|
159
|
+
if (fieldIndexOwner) throw new BetterAuthError(`Database index name "${index.name}" is already reserved by field-level index metadata on table "${fieldIndexOwner}". Remove the duplicate table-level index or give it a distinct name.`);
|
|
160
|
+
const indexOwner = indexOwnerByName.get(identifierKey);
|
|
161
|
+
if (indexOwner && indexOwner !== source.tableName) throw new BetterAuthError(`Database index name "${index.name}" is used by both table "${indexOwner}" and table "${source.tableName}". Index names must be unique across the schema.`);
|
|
162
|
+
indexOwnerByName.set(identifierKey, source.tableName);
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
return indexesByTable;
|
|
166
|
+
}
|
|
167
|
+
//#endregion
|
|
168
|
+
export { getDatabaseFieldIndexName, getDatabaseIndexName, getDatabaseIndexStringLength, getPortableDatabaseIdentifierKey, resolveDatabaseSchemaIndexes, resolveDatabaseTableIndexes };
|
package/dist/db/get-tables.d.mts
CHANGED
|
@@ -1,6 +1,12 @@
|
|
|
1
1
|
import { BetterAuthDBSchema } from "./type.mjs";
|
|
2
|
+
import { ResolvedDBTableIndex } from "./database-index.mjs";
|
|
2
3
|
import { BetterAuthOptions } from "../types/init-options.mjs";
|
|
4
|
+
import "../types/index.mjs";
|
|
3
5
|
//#region src/db/get-tables.d.ts
|
|
6
|
+
declare function getAuthTablesWithResolvedIndexes(options: BetterAuthOptions): {
|
|
7
|
+
indexesByTable: ReadonlyMap<string, readonly ResolvedDBTableIndex[]>;
|
|
8
|
+
tables: BetterAuthDBSchema;
|
|
9
|
+
};
|
|
4
10
|
declare const getAuthTables: (options: BetterAuthOptions) => BetterAuthDBSchema;
|
|
5
11
|
//#endregion
|
|
6
|
-
export { getAuthTables };
|
|
12
|
+
export { getAuthTables, getAuthTablesWithResolvedIndexes };
|
package/dist/db/get-tables.mjs
CHANGED
|
@@ -1,5 +1,21 @@
|
|
|
1
|
+
import { resolveDatabaseSchemaIndexes } from "./database-index.mjs";
|
|
1
2
|
//#region src/db/get-tables.ts
|
|
2
|
-
|
|
3
|
+
function mergeTableIndexes(...indexCollections) {
|
|
4
|
+
const indexes = [];
|
|
5
|
+
const seenIndexDefinitions = /* @__PURE__ */ new Set();
|
|
6
|
+
for (const index of indexCollections.flatMap((collection) => collection ?? [])) {
|
|
7
|
+
const definition = JSON.stringify([
|
|
8
|
+
index.name ?? null,
|
|
9
|
+
index.fields,
|
|
10
|
+
index.unique ?? false
|
|
11
|
+
]);
|
|
12
|
+
if (seenIndexDefinitions.has(definition)) continue;
|
|
13
|
+
seenIndexDefinitions.add(definition);
|
|
14
|
+
indexes.push(index);
|
|
15
|
+
}
|
|
16
|
+
return indexes;
|
|
17
|
+
}
|
|
18
|
+
const buildAuthTables = (options) => {
|
|
3
19
|
const pluginSchema = (options.plugins ?? []).reduce((acc, plugin) => {
|
|
4
20
|
const schema = plugin.schema;
|
|
5
21
|
if (!schema) return acc;
|
|
@@ -8,6 +24,7 @@ const getAuthTables = (options) => {
|
|
|
8
24
|
...acc[key]?.fields,
|
|
9
25
|
...value.fields
|
|
10
26
|
},
|
|
27
|
+
indexes: mergeTableIndexes(acc[key]?.indexes, value.indexes),
|
|
11
28
|
modelName: value.modelName || key,
|
|
12
29
|
disableMigrations: value.disableMigration ?? acc[key]?.disableMigrations
|
|
13
30
|
};
|
|
@@ -40,6 +57,7 @@ const getAuthTables = (options) => {
|
|
|
40
57
|
const { user, session, account, verification, ...pluginTables } = pluginSchema;
|
|
41
58
|
const verificationTable = { verification: {
|
|
42
59
|
modelName: options.verification?.modelName || "verification",
|
|
60
|
+
indexes: verification?.indexes,
|
|
43
61
|
fields: {
|
|
44
62
|
identifier: {
|
|
45
63
|
type: "string",
|
|
@@ -77,6 +95,7 @@ const getAuthTables = (options) => {
|
|
|
77
95
|
} };
|
|
78
96
|
const sessionTable = { session: {
|
|
79
97
|
modelName: options.session?.modelName || "session",
|
|
98
|
+
indexes: session?.indexes,
|
|
80
99
|
fields: {
|
|
81
100
|
expiresAt: {
|
|
82
101
|
type: "date",
|
|
@@ -115,7 +134,7 @@ const getAuthTables = (options) => {
|
|
|
115
134
|
type: "string",
|
|
116
135
|
fieldName: options.session?.fields?.userId || "userId",
|
|
117
136
|
references: {
|
|
118
|
-
model:
|
|
137
|
+
model: "user",
|
|
119
138
|
field: "id",
|
|
120
139
|
onDelete: "cascade"
|
|
121
140
|
},
|
|
@@ -130,6 +149,7 @@ const getAuthTables = (options) => {
|
|
|
130
149
|
return {
|
|
131
150
|
user: {
|
|
132
151
|
modelName: options.user?.modelName || "user",
|
|
152
|
+
indexes: user?.indexes,
|
|
133
153
|
fields: {
|
|
134
154
|
name: {
|
|
135
155
|
type: "string",
|
|
@@ -177,11 +197,20 @@ const getAuthTables = (options) => {
|
|
|
177
197
|
...!options.secondaryStorage || options.session?.storeSessionInDatabase ? sessionTable : {},
|
|
178
198
|
account: {
|
|
179
199
|
modelName: options.account?.modelName || "account",
|
|
200
|
+
indexes: mergeTableIndexes([{
|
|
201
|
+
fields: ["issuer", "providerAccountId"],
|
|
202
|
+
unique: true
|
|
203
|
+
}], account?.indexes),
|
|
180
204
|
fields: {
|
|
181
|
-
|
|
205
|
+
issuer: {
|
|
206
|
+
type: "string",
|
|
207
|
+
required: true,
|
|
208
|
+
fieldName: options.account?.fields?.issuer || "issuer"
|
|
209
|
+
},
|
|
210
|
+
providerAccountId: {
|
|
182
211
|
type: "string",
|
|
183
212
|
required: true,
|
|
184
|
-
fieldName: options.account?.fields?.
|
|
213
|
+
fieldName: options.account?.fields?.providerAccountId || "providerAccountId"
|
|
185
214
|
},
|
|
186
215
|
providerId: {
|
|
187
216
|
type: "string",
|
|
@@ -191,7 +220,7 @@ const getAuthTables = (options) => {
|
|
|
191
220
|
userId: {
|
|
192
221
|
type: "string",
|
|
193
222
|
references: {
|
|
194
|
-
model:
|
|
223
|
+
model: "user",
|
|
195
224
|
field: "id",
|
|
196
225
|
onDelete: "cascade"
|
|
197
226
|
},
|
|
@@ -262,5 +291,17 @@ const getAuthTables = (options) => {
|
|
|
262
291
|
...shouldAddRateLimitTable ? rateLimitTable : {}
|
|
263
292
|
};
|
|
264
293
|
};
|
|
294
|
+
function getAuthTablesWithResolvedIndexes(options) {
|
|
295
|
+
const tables = buildAuthTables(options);
|
|
296
|
+
return {
|
|
297
|
+
indexesByTable: resolveDatabaseSchemaIndexes(Object.values(tables).filter((table) => !("disableMigrations" in table) || !table.disableMigrations).map((table) => ({
|
|
298
|
+
fields: table.fields,
|
|
299
|
+
indexes: "indexes" in table ? table.indexes : void 0,
|
|
300
|
+
tableName: table.modelName
|
|
301
|
+
}))),
|
|
302
|
+
tables
|
|
303
|
+
};
|
|
304
|
+
}
|
|
305
|
+
const getAuthTables = (options) => getAuthTablesWithResolvedIndexes(options).tables;
|
|
265
306
|
//#endregion
|
|
266
|
-
export { getAuthTables };
|
|
307
|
+
export { getAuthTables, getAuthTablesWithResolvedIndexes };
|
package/dist/db/index.d.mts
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import { BaseModelNames, BetterAuthDBSchema, DBFieldAttribute, DBFieldAttributeConfig, DBFieldType, DBPrimitive, InferDBFieldInput, InferDBFieldOutput, InferDBFieldsFromOptions, InferDBFieldsFromOptionsInput, InferDBFieldsFromPlugins, InferDBFieldsFromPluginsInput, InferDBFieldsInput, InferDBFieldsOutput, InferDBValueType, ModelNames, SecondaryStorage } from "./type.mjs";
|
|
1
|
+
import { BaseModelNames, BetterAuthDBSchema, DBFieldAttribute, DBFieldAttributeConfig, DBFieldType, DBPrimitive, DBTableIndex, InferDBFieldInput, InferDBFieldOutput, InferDBFieldsFromOptions, InferDBFieldsFromOptionsInput, InferDBFieldsFromPlugins, InferDBFieldsFromPluginsInput, InferDBFieldsInput, InferDBFieldsOutput, InferDBValueType, ModelNames, SecondaryStorage } from "./type.mjs";
|
|
2
2
|
import { getAuthTables } from "./get-tables.mjs";
|
|
3
3
|
import { BetterAuthPluginDBSchema } from "./plugin.mjs";
|
|
4
4
|
import { BaseRateLimit, RateLimit, rateLimitSchema } from "./schema/rate-limit.mjs";
|
|
5
5
|
import { BaseSession, Session, sessionSchema } from "./schema/session.mjs";
|
|
6
6
|
import { BaseUser, User, userSchema } from "./schema/user.mjs";
|
|
7
7
|
import { BaseVerification, Verification, verificationSchema } from "./schema/verification.mjs";
|
|
8
|
-
import { Account, BaseAccount, accountSchema } from "./schema/account.mjs";
|
|
8
|
+
import { Account, AccountKey, BaseAccount, accountSchema, createLocalAccountIssuer, createOAuthAccountIssuer } from "./schema/account.mjs";
|
|
9
9
|
import { coreSchema } from "./schema/shared.mjs";
|
|
10
|
-
export { type Account, type BaseAccount, type BaseModelNames, type BaseRateLimit, type BaseSession, type BaseUser, type BaseVerification, type BetterAuthDBSchema, type BetterAuthPluginDBSchema, type DBFieldAttribute, type DBFieldAttributeConfig, type DBFieldType, type DBPrimitive, type InferDBFieldInput, type InferDBFieldOutput, type InferDBFieldsFromOptions, type InferDBFieldsFromOptionsInput, type InferDBFieldsFromPlugins, type InferDBFieldsFromPluginsInput, type InferDBFieldsInput, type InferDBFieldsOutput, type InferDBValueType, type ModelNames, type RateLimit, type SecondaryStorage, type Session, type User, type Verification, accountSchema, coreSchema, getAuthTables, rateLimitSchema, sessionSchema, userSchema, verificationSchema };
|
|
10
|
+
export { type Account, type AccountKey, type BaseAccount, type BaseModelNames, type BaseRateLimit, type BaseSession, type BaseUser, type BaseVerification, type BetterAuthDBSchema, type BetterAuthPluginDBSchema, type DBFieldAttribute, type DBFieldAttributeConfig, type DBFieldType, type DBPrimitive, type DBTableIndex, type InferDBFieldInput, type InferDBFieldOutput, type InferDBFieldsFromOptions, type InferDBFieldsFromOptionsInput, type InferDBFieldsFromPlugins, type InferDBFieldsFromPluginsInput, type InferDBFieldsInput, type InferDBFieldsOutput, type InferDBValueType, type ModelNames, type RateLimit, type SecondaryStorage, type Session, type User, type Verification, accountSchema, coreSchema, createLocalAccountIssuer, createOAuthAccountIssuer, getAuthTables, rateLimitSchema, sessionSchema, userSchema, verificationSchema };
|
package/dist/db/index.mjs
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { getAuthTables } from "./get-tables.mjs";
|
|
2
2
|
import { coreSchema } from "./schema/shared.mjs";
|
|
3
|
-
import { accountSchema } from "./schema/account.mjs";
|
|
3
|
+
import { accountSchema, createLocalAccountIssuer, createOAuthAccountIssuer } from "./schema/account.mjs";
|
|
4
4
|
import { rateLimitSchema } from "./schema/rate-limit.mjs";
|
|
5
5
|
import { sessionSchema } from "./schema/session.mjs";
|
|
6
6
|
import { userSchema } from "./schema/user.mjs";
|
|
7
7
|
import { verificationSchema } from "./schema/verification.mjs";
|
|
8
|
-
export { accountSchema, coreSchema, getAuthTables, rateLimitSchema, sessionSchema, userSchema, verificationSchema };
|
|
8
|
+
export { accountSchema, coreSchema, createLocalAccountIssuer, createOAuthAccountIssuer, getAuthTables, rateLimitSchema, sessionSchema, userSchema, verificationSchema };
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import { BoundedDatabaseIndexDialect, DBTableIndexSource, ResolvedDBTableIndex, getDatabaseFieldIndexName, getDatabaseIndexName, getDatabaseIndexStringLength, getPortableDatabaseIdentifierKey, resolveDatabaseSchemaIndexes, resolveDatabaseTableIndexes } from "./database-index.mjs";
|
|
2
|
+
import { getAuthTablesWithResolvedIndexes } from "./get-tables.mjs";
|
|
3
|
+
export { type BoundedDatabaseIndexDialect, type DBTableIndexSource, type ResolvedDBTableIndex, getAuthTablesWithResolvedIndexes, getDatabaseFieldIndexName, getDatabaseIndexName, getDatabaseIndexStringLength, getPortableDatabaseIdentifierKey, resolveDatabaseSchemaIndexes, resolveDatabaseTableIndexes };
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import { getDatabaseFieldIndexName, getDatabaseIndexName, getDatabaseIndexStringLength, getPortableDatabaseIdentifierKey, resolveDatabaseSchemaIndexes, resolveDatabaseTableIndexes } from "./database-index.mjs";
|
|
2
|
+
import { getAuthTablesWithResolvedIndexes } from "./get-tables.mjs";
|
|
3
|
+
export { getAuthTablesWithResolvedIndexes, getDatabaseFieldIndexName, getDatabaseIndexName, getDatabaseIndexStringLength, getPortableDatabaseIdentifierKey, resolveDatabaseSchemaIndexes, resolveDatabaseTableIndexes };
|
package/dist/db/plugin.d.mts
CHANGED
|
@@ -1,12 +1,13 @@
|
|
|
1
|
-
import { DBFieldAttribute } from "./type.mjs";
|
|
2
|
-
|
|
1
|
+
import { DBFieldAttribute, DBTableIndex } from "./type.mjs";
|
|
3
2
|
//#region src/db/plugin.d.ts
|
|
4
3
|
type BetterAuthPluginDBSchema = { [table in string]: {
|
|
5
4
|
fields: {
|
|
6
5
|
[field: string]: DBFieldAttribute;
|
|
7
6
|
};
|
|
7
|
+
/** Table-level indexes, including compound indexes. */
|
|
8
|
+
indexes?: readonly DBTableIndex[] | undefined;
|
|
8
9
|
disableMigration?: boolean | undefined;
|
|
9
10
|
modelName?: string | undefined;
|
|
10
|
-
} };
|
|
11
|
+
}; };
|
|
11
12
|
//#endregion
|
|
12
13
|
export { BetterAuthPluginDBSchema };
|
|
@@ -1,15 +1,16 @@
|
|
|
1
1
|
import { InferDBFieldsFromOptions, InferDBFieldsFromPlugins } from "../type.mjs";
|
|
2
2
|
import { Prettify } from "../../types/helper.mjs";
|
|
3
3
|
import { BetterAuthOptions } from "../../types/init-options.mjs";
|
|
4
|
+
import "../../types/index.mjs";
|
|
4
5
|
import * as z from "zod";
|
|
5
|
-
|
|
6
6
|
//#region src/db/schema/account.d.ts
|
|
7
7
|
declare const accountSchema: z.ZodObject<{
|
|
8
8
|
id: z.ZodString;
|
|
9
9
|
createdAt: z.ZodDefault<z.ZodDate>;
|
|
10
10
|
updatedAt: z.ZodDefault<z.ZodDate>;
|
|
11
11
|
providerId: z.ZodString;
|
|
12
|
-
|
|
12
|
+
issuer: z.ZodString;
|
|
13
|
+
providerAccountId: z.ZodString;
|
|
13
14
|
userId: z.ZodCoercedString<unknown>;
|
|
14
15
|
accessToken: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
15
16
|
refreshToken: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
@@ -20,9 +21,21 @@ declare const accountSchema: z.ZodObject<{
|
|
|
20
21
|
password: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
21
22
|
}, z.core.$strip>;
|
|
22
23
|
type BaseAccount = z.infer<typeof accountSchema>;
|
|
24
|
+
/** The stable provider-side key used to recognize an account. */
|
|
25
|
+
type AccountKey = Readonly<Pick<BaseAccount, "issuer" | "providerAccountId">>;
|
|
26
|
+
/**
|
|
27
|
+
* Creates the synthetic issuer used by providers without an issuer of their own.
|
|
28
|
+
*/
|
|
29
|
+
declare function createLocalAccountIssuer(providerId: string): string;
|
|
30
|
+
/**
|
|
31
|
+
* Creates the synthetic issuer used by OAuth providers without an issuer of
|
|
32
|
+
* their own. OAuth identities use a distinct namespace so a provider ID
|
|
33
|
+
* cannot collide with an internal local authentication method.
|
|
34
|
+
*/
|
|
35
|
+
declare function createOAuthAccountIssuer(providerId: string): string;
|
|
23
36
|
/**
|
|
24
37
|
* Account schema type used by better-auth, note that it's possible that account could have additional fields
|
|
25
38
|
*/
|
|
26
39
|
type Account<DBOptions extends BetterAuthOptions["account"] = BetterAuthOptions["account"], Plugins extends BetterAuthOptions["plugins"] = BetterAuthOptions["plugins"]> = Prettify<BaseAccount & InferDBFieldsFromOptions<DBOptions> & InferDBFieldsFromPlugins<"account", Plugins>>;
|
|
27
40
|
//#endregion
|
|
28
|
-
export { Account, BaseAccount, accountSchema };
|
|
41
|
+
export { Account, AccountKey, BaseAccount, accountSchema, createLocalAccountIssuer, createOAuthAccountIssuer };
|
|
@@ -3,15 +3,48 @@ import * as z from "zod";
|
|
|
3
3
|
//#region src/db/schema/account.ts
|
|
4
4
|
const accountSchema = coreSchema.extend({
|
|
5
5
|
providerId: z.string(),
|
|
6
|
-
|
|
6
|
+
issuer: z.string(),
|
|
7
|
+
providerAccountId: z.string(),
|
|
7
8
|
userId: z.coerce.string(),
|
|
8
9
|
accessToken: z.string().nullish(),
|
|
9
10
|
refreshToken: z.string().nullish(),
|
|
10
11
|
idToken: z.string().nullish(),
|
|
12
|
+
/**
|
|
13
|
+
* Access token expires at
|
|
14
|
+
*/
|
|
11
15
|
accessTokenExpiresAt: z.date().nullish(),
|
|
16
|
+
/**
|
|
17
|
+
* Refresh token expires at
|
|
18
|
+
*/
|
|
12
19
|
refreshTokenExpiresAt: z.date().nullish(),
|
|
20
|
+
/**
|
|
21
|
+
* The set of OAuth scopes the user has granted to this account, stored
|
|
22
|
+
* as a comma-separated list. Represents the accumulated grant rather
|
|
23
|
+
* than the latest token's `scope` claim, since per RFC 6749 Section 1.5 a
|
|
24
|
+
* token's scope may be narrower than the user's grant.
|
|
25
|
+
*/
|
|
13
26
|
scope: z.string().nullish(),
|
|
27
|
+
/**
|
|
28
|
+
* Password is only stored in the credential provider
|
|
29
|
+
*/
|
|
14
30
|
password: z.string().nullish()
|
|
15
31
|
});
|
|
32
|
+
function encodeAccountIssuerProviderId(providerId) {
|
|
33
|
+
return encodeURIComponent(providerId);
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Creates the synthetic issuer used by providers without an issuer of their own.
|
|
37
|
+
*/
|
|
38
|
+
function createLocalAccountIssuer(providerId) {
|
|
39
|
+
return `local:${encodeAccountIssuerProviderId(providerId)}`;
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Creates the synthetic issuer used by OAuth providers without an issuer of
|
|
43
|
+
* their own. OAuth identities use a distinct namespace so a provider ID
|
|
44
|
+
* cannot collide with an internal local authentication method.
|
|
45
|
+
*/
|
|
46
|
+
function createOAuthAccountIssuer(providerId) {
|
|
47
|
+
return `local:oauth:${encodeAccountIssuerProviderId(providerId)}`;
|
|
48
|
+
}
|
|
16
49
|
//#endregion
|
|
17
|
-
export { accountSchema };
|
|
50
|
+
export { accountSchema, createLocalAccountIssuer, createOAuthAccountIssuer };
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { InferDBFieldsFromOptions, InferDBFieldsFromPlugins } from "../type.mjs";
|
|
2
2
|
import { Prettify } from "../../types/helper.mjs";
|
|
3
3
|
import { BetterAuthOptions } from "../../types/init-options.mjs";
|
|
4
|
+
import "../../types/index.mjs";
|
|
4
5
|
import * as z from "zod";
|
|
5
|
-
|
|
6
6
|
//#region src/db/schema/rate-limit.d.ts
|
|
7
7
|
declare const rateLimitSchema: z.ZodObject<{
|
|
8
8
|
key: z.ZodString;
|
|
@@ -1,8 +1,17 @@
|
|
|
1
1
|
import * as z from "zod";
|
|
2
2
|
//#region src/db/schema/rate-limit.ts
|
|
3
3
|
const rateLimitSchema = z.object({
|
|
4
|
+
/**
|
|
5
|
+
* The key to use for rate limiting
|
|
6
|
+
*/
|
|
4
7
|
key: z.string(),
|
|
8
|
+
/**
|
|
9
|
+
* The number of requests made
|
|
10
|
+
*/
|
|
5
11
|
count: z.number(),
|
|
12
|
+
/**
|
|
13
|
+
* The last request time in milliseconds
|
|
14
|
+
*/
|
|
6
15
|
lastRequest: z.number()
|
|
7
16
|
});
|
|
8
17
|
//#endregion
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { InferDBFieldsFromOptions, InferDBFieldsFromPlugins } from "../type.mjs";
|
|
2
2
|
import { Prettify } from "../../types/helper.mjs";
|
|
3
3
|
import { BetterAuthOptions } from "../../types/init-options.mjs";
|
|
4
|
+
import "../../types/index.mjs";
|
|
4
5
|
import * as z from "zod";
|
|
5
|
-
|
|
6
6
|
//#region src/db/schema/session.d.ts
|
|
7
7
|
declare const sessionSchema: z.ZodObject<{
|
|
8
8
|
id: z.ZodString;
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { InferDBFieldsFromOptions, InferDBFieldsFromPlugins } from "../type.mjs";
|
|
2
2
|
import { Prettify } from "../../types/helper.mjs";
|
|
3
3
|
import { BetterAuthOptions } from "../../types/init-options.mjs";
|
|
4
|
+
import "../../types/index.mjs";
|
|
4
5
|
import * as z from "zod";
|
|
5
|
-
|
|
6
6
|
//#region src/db/schema/user.d.ts
|
|
7
7
|
declare const userSchema: z.ZodObject<{
|
|
8
8
|
id: z.ZodString;
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { InferDBFieldsFromOptions, InferDBFieldsFromPlugins } from "../type.mjs";
|
|
2
2
|
import { Prettify } from "../../types/helper.mjs";
|
|
3
3
|
import { BetterAuthOptions } from "../../types/init-options.mjs";
|
|
4
|
+
import "../../types/index.mjs";
|
|
4
5
|
import * as z from "zod";
|
|
5
|
-
|
|
6
6
|
//#region src/db/schema/verification.d.ts
|
|
7
7
|
declare const verificationSchema: z.ZodObject<{
|
|
8
8
|
id: z.ZodString;
|
package/dist/db/type.d.mts
CHANGED
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
import { Awaitable, LiteralString, UnionToIntersection } from "../types/helper.mjs";
|
|
2
2
|
import { BetterAuthOptions } from "../types/init-options.mjs";
|
|
3
|
+
import "../types/index.mjs";
|
|
3
4
|
import { StandardSchemaV1 } from "@standard-schema/spec";
|
|
4
|
-
|
|
5
5
|
//#region src/db/type.d.ts
|
|
6
6
|
type BaseModelNames = "user" | "account" | "session" | "verification";
|
|
7
7
|
type ModelNames<T extends string = LiteralString> = BaseModelNames | T | "rate-limit";
|
|
8
8
|
type InferDBValueType<T extends DBFieldType> = T extends "string" ? string : T extends "number" ? number : T extends "boolean" ? boolean : T extends "date" ? Date : T extends "json" ? Record<string, any> : T extends `${infer U}[]` ? U extends "string" ? string[] : number[] : T extends Array<any> ? T[number] : never;
|
|
9
9
|
type InferDBFieldOutput<T extends DBFieldAttribute> = T["returned"] extends false ? never : T["required"] extends false ? InferDBValueType<T["type"]> | undefined | null : InferDBValueType<T["type"]>;
|
|
10
10
|
type InferDBFieldInput<T extends DBFieldAttribute> = InferDBValueType<T["type"]>;
|
|
11
|
-
type InferDBFieldsInput<Field> = Field extends Record<infer Key, DBFieldAttribute> ? { [key in Key as Field[key]["required"] extends false ? never : Field[key]["defaultValue"] extends string | number | boolean | Date ? never : Field[key]["input"] extends false ? never : key]: InferDBFieldInput<Field[key]
|
|
12
|
-
type InferDBFieldsOutput<Fields extends Record<string, DBFieldAttribute>> = Fields extends Record<infer Key, DBFieldAttribute> ? { [key in Key as Fields[key]["returned"] extends false ? never : Fields[key]["required"] extends false ? Fields[key]["defaultValue"] extends boolean | string | number | Date ? key : never : key]: InferDBFieldOutput<Fields[key]
|
|
11
|
+
type InferDBFieldsInput<Field> = Field extends Record<infer Key, DBFieldAttribute> ? { [key in Key as Field[key]["required"] extends false ? never : Field[key]["defaultValue"] extends string | number | boolean | Date ? never : Field[key]["input"] extends false ? never : key]: InferDBFieldInput<Field[key]>; } & { [key in Key as Field[key]["input"] extends false ? never : key]?: InferDBFieldInput<Field[key]> | undefined | null; } : {};
|
|
12
|
+
type InferDBFieldsOutput<Fields extends Record<string, DBFieldAttribute>> = Fields extends Record<infer Key, DBFieldAttribute> ? { [key in Key as Fields[key]["returned"] extends false ? never : Fields[key]["required"] extends false ? Fields[key]["defaultValue"] extends boolean | string | number | Date ? key : never : key]: InferDBFieldOutput<Fields[key]>; } & { [key in Key as Fields[key]["returned"] extends false ? never : Fields[key]["required"] extends false ? Fields[key]["defaultValue"] extends boolean | string | number | Date ? never : key : never]?: InferDBFieldOutput<Fields[key]> | null; } : never;
|
|
13
13
|
type InferDBFieldsFromOptionsInput<DBOptions extends BetterAuthOptions["session"] | BetterAuthOptions["user"] | BetterAuthOptions["verification"] | BetterAuthOptions["account"] | BetterAuthOptions["rateLimit"]> = DBOptions extends {
|
|
14
14
|
additionalFields: Record<string, DBFieldAttribute>;
|
|
15
15
|
} ? InferDBFieldsInput<DBOptions["additionalFields"]> : {};
|
|
@@ -19,12 +19,12 @@ type InferDBFieldsFromOptions<DBOptions extends BetterAuthOptions["session"] | B
|
|
|
19
19
|
type InferDBFieldsFromPluginsInput<ModelName extends string, Plugins extends unknown[] | undefined> = Plugins extends [] ? {} : Plugins extends [infer P, ...infer Rest] ? P extends {
|
|
20
20
|
schema: { [key in ModelName]: {
|
|
21
21
|
fields: infer Fields;
|
|
22
|
-
} };
|
|
22
|
+
}; };
|
|
23
23
|
} ? Fields extends Record<string, DBFieldAttribute> ? UnionToIntersection<InferDBFieldsInput<Fields> & InferDBFieldsFromPluginsInput<ModelName, Rest>> : InferDBFieldsFromPluginsInput<ModelName, Rest> : InferDBFieldsFromPluginsInput<ModelName, Rest> : {};
|
|
24
24
|
type InferDBFieldsFromPlugins<ModelName extends string, Plugins extends unknown[] | undefined> = Plugins extends [] ? {} : Plugins extends [infer P, ...infer Rest] ? P extends {
|
|
25
25
|
schema: { [key in ModelName]: {
|
|
26
26
|
fields: infer Fields;
|
|
27
|
-
} };
|
|
27
|
+
}; };
|
|
28
28
|
} ? Fields extends Record<string, DBFieldAttribute> ? UnionToIntersection<InferDBFieldsOutput<Fields> & InferDBFieldsFromPlugins<ModelName, Rest>> : InferDBFieldsFromPlugins<ModelName, Rest> : InferDBFieldsFromPlugins<ModelName, Rest> : {};
|
|
29
29
|
type DBFieldType = "string" | "number" | "boolean" | "date" | "json" | `${"string" | "number"}[]` | Array<LiteralString>;
|
|
30
30
|
type DBPrimitive = string | number | boolean | Date | null | undefined | string[] | number[] | (Record<string, unknown> | unknown[]);
|
|
@@ -115,6 +115,15 @@ type DBFieldAttributeConfig = {
|
|
|
115
115
|
type DBFieldAttribute<T extends DBFieldType = DBFieldType> = {
|
|
116
116
|
type: T;
|
|
117
117
|
} & DBFieldAttributeConfig;
|
|
118
|
+
/** A database index spanning one or more logical schema fields. */
|
|
119
|
+
interface DBTableIndex {
|
|
120
|
+
/** One to sixteen logical field names included in the index, in index order. */
|
|
121
|
+
fields: readonly [string, ...string[]];
|
|
122
|
+
/** Portable database index name of at most 63 UTF-8 bytes. */
|
|
123
|
+
name?: string | undefined;
|
|
124
|
+
/** Whether the indexed field tuple must be unique. */
|
|
125
|
+
unique?: boolean | undefined;
|
|
126
|
+
}
|
|
118
127
|
type BetterAuthDBSchema = Record<string, {
|
|
119
128
|
/**
|
|
120
129
|
* The name of the table in the database
|
|
@@ -124,6 +133,8 @@ type BetterAuthDBSchema = Record<string, {
|
|
|
124
133
|
* The fields of the table
|
|
125
134
|
*/
|
|
126
135
|
fields: Record<string, DBFieldAttribute>;
|
|
136
|
+
/** Table-level indexes, including compound indexes. */
|
|
137
|
+
indexes?: readonly DBTableIndex[] | undefined;
|
|
127
138
|
/**
|
|
128
139
|
* Whether to disable migrations for this table
|
|
129
140
|
* @default false
|
|
@@ -162,17 +173,14 @@ interface SecondaryStorage {
|
|
|
162
173
|
/**
|
|
163
174
|
* Key to store
|
|
164
175
|
*/
|
|
165
|
-
|
|
166
176
|
key: string,
|
|
167
177
|
/**
|
|
168
178
|
* Value to store
|
|
169
179
|
*/
|
|
170
|
-
|
|
171
180
|
value: string,
|
|
172
181
|
/**
|
|
173
182
|
* Time to live in seconds
|
|
174
183
|
*/
|
|
175
|
-
|
|
176
184
|
ttl?: number | undefined) => Awaitable<void | null | unknown>;
|
|
177
185
|
/**
|
|
178
186
|
*
|
|
@@ -181,4 +189,4 @@ interface SecondaryStorage {
|
|
|
181
189
|
delete: (key: string) => Awaitable<void | null | string>;
|
|
182
190
|
}
|
|
183
191
|
//#endregion
|
|
184
|
-
export { BaseModelNames, BetterAuthDBSchema, DBFieldAttribute, DBFieldAttributeConfig, DBFieldType, DBPrimitive, InferDBFieldInput, InferDBFieldOutput, InferDBFieldsFromOptions, InferDBFieldsFromOptionsInput, InferDBFieldsFromPlugins, InferDBFieldsFromPluginsInput, InferDBFieldsInput, InferDBFieldsOutput, InferDBValueType, ModelNames, SecondaryStorage };
|
|
192
|
+
export { BaseModelNames, BetterAuthDBSchema, DBFieldAttribute, DBFieldAttributeConfig, DBFieldType, DBPrimitive, DBTableIndex, InferDBFieldInput, InferDBFieldOutput, InferDBFieldsFromOptions, InferDBFieldsFromOptionsInput, InferDBFieldsFromPlugins, InferDBFieldsFromPluginsInput, InferDBFieldsInput, InferDBFieldsOutput, InferDBValueType, ModelNames, SecondaryStorage };
|