better-auth 0.0.2-beta.7 → 0.0.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/access.d.ts +4 -0
- package/dist/access.js +126 -0
- package/dist/access.js.map +1 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +553 -0
- package/dist/cli.js.map +1 -0
- package/dist/client/plugins.d.ts +2436 -0
- package/dist/client/plugins.js +411 -0
- package/dist/client/plugins.js.map +1 -0
- package/dist/client-A2Mt04KQ.d.ts +3503 -0
- package/dist/client.d.ts +1433 -0
- package/dist/client.js +693 -0
- package/dist/client.js.map +1 -0
- package/dist/helper-B5_2Vzba.d.ts +14 -0
- package/dist/index-Dg4eEXZW.d.ts +24 -0
- package/dist/index-W5nXvJ-p.d.ts +1498 -0
- package/dist/index.d.ts +6 -4
- package/dist/index.js +2195 -1191
- package/dist/index.js.map +1 -1
- package/dist/next-js.d.ts +14 -0
- package/dist/next-js.js +14 -0
- package/dist/next-js.js.map +1 -0
- package/dist/plugins.d.ts +892 -49
- package/dist/plugins.js +3951 -253
- package/dist/plugins.js.map +1 -1
- package/dist/preact.d.ts +8 -0
- package/dist/preact.js +294 -0
- package/dist/preact.js.map +1 -0
- package/dist/react.d.ts +14 -0
- package/dist/react.js +314 -0
- package/dist/react.js.map +1 -0
- package/dist/schema-BOszzrbQ.d.ts +792 -0
- package/dist/social.d.ts +4 -0
- package/dist/social.js +509 -0
- package/dist/social.js.map +1 -0
- package/dist/solid-start.d.ts +18 -0
- package/dist/solid-start.js +14 -0
- package/dist/solid-start.js.map +1 -0
- package/dist/solid.d.ts +2790 -0
- package/dist/solid.js +306 -0
- package/dist/solid.js.map +1 -0
- package/dist/statement-COylZd3J.d.ts +81 -0
- package/dist/svelte-kit.d.ts +10 -7
- package/dist/svelte-kit.js +12 -17
- package/dist/svelte-kit.js.map +1 -1
- package/dist/svelte.d.ts +2791 -0
- package/dist/svelte.js +304 -0
- package/dist/svelte.js.map +1 -0
- package/dist/type-DbMyI3b5.d.ts +5724 -0
- package/dist/types.d.ts +7 -0
- package/dist/types.js +1 -0
- package/dist/types.js.map +1 -0
- package/dist/vue.d.ts +14 -0
- package/dist/vue.js +311 -0
- package/dist/vue.js.map +1 -0
- package/package.json +80 -54
- package/LICENSE +0 -21
- package/dist/actions.d.ts +0 -33
- package/dist/actions.js +0 -1373
- package/dist/actions.js.map +0 -1
- package/dist/adapters/drizzle-adapter.d.ts +0 -10
- package/dist/adapters/drizzle-adapter.js +0 -1095
- package/dist/adapters/drizzle-adapter.js.map +0 -1
- package/dist/adapters/memory.d.ts +0 -8
- package/dist/adapters/memory.js +0 -136
- package/dist/adapters/memory.js.map +0 -1
- package/dist/adapters/mongodb-adapter.d.ts +0 -9
- package/dist/adapters/mongodb-adapter.js +0 -97
- package/dist/adapters/mongodb-adapter.js.map +0 -1
- package/dist/adapters/prisma-adapter.d.ts +0 -7
- package/dist/adapters/prisma-adapter.js +0 -144
- package/dist/adapters/prisma-adapter.js.map +0 -1
- package/dist/adapters/redis-adapter.d.ts +0 -7
- package/dist/adapters/redis-adapter.js +0 -65
- package/dist/adapters/redis-adapter.js.map +0 -1
- package/dist/adapters.d.ts +0 -3
- package/dist/adapters.js +0 -206
- package/dist/adapters.js.map +0 -1
- package/dist/h3.d.ts +0 -10
- package/dist/h3.js +0 -326
- package/dist/h3.js.map +0 -1
- package/dist/hono.d.ts +0 -10
- package/dist/hono.js +0 -25
- package/dist/hono.js.map +0 -1
- package/dist/index-UcTu1vUg.d.ts +0 -107
- package/dist/next.d.ts +0 -17
- package/dist/next.js +0 -26
- package/dist/next.js.map +0 -1
- package/dist/options-CH15FEBw.d.ts +0 -1562
- package/dist/providers.d.ts +0 -3
- package/dist/providers.js +0 -653
- package/dist/providers.js.map +0 -1
- package/dist/routes/session.d.ts +0 -39
- package/dist/routes/session.js +0 -128
- package/dist/routes/session.js.map +0 -1
- package/dist/types-DAxaMWCy.d.ts +0 -136
package/dist/access.d.ts
ADDED
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
export { A as AccessControl, a as AuthortizeResponse, P as ParsingError, R as Role, S as StatementsPrimitive, b as SubArray, c as Subset, d as adminAc, e as createAccessControl, f as defaultAc, g as defaultRoles, h as defaultStatements, m as memberAc, o as ownerAc } from './statement-COylZd3J.js';
|
|
2
|
+
export { p as permissionFromString } from './index-Dg4eEXZW.js';
|
|
3
|
+
import './helper-B5_2Vzba.js';
|
|
4
|
+
import 'zod';
|
package/dist/access.js
ADDED
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
// src/plugins/organization/access/src/access.ts
|
|
2
|
+
var ParsingError = class extends Error {
|
|
3
|
+
path;
|
|
4
|
+
constructor(message, path) {
|
|
5
|
+
super(message);
|
|
6
|
+
this.path = path;
|
|
7
|
+
}
|
|
8
|
+
};
|
|
9
|
+
var AccessControl = class {
|
|
10
|
+
constructor(s) {
|
|
11
|
+
this.s = s;
|
|
12
|
+
this.statements = s;
|
|
13
|
+
}
|
|
14
|
+
statements;
|
|
15
|
+
newRole(statements) {
|
|
16
|
+
return new Role(statements);
|
|
17
|
+
}
|
|
18
|
+
};
|
|
19
|
+
var Role = class _Role {
|
|
20
|
+
statements;
|
|
21
|
+
constructor(statements) {
|
|
22
|
+
this.statements = statements;
|
|
23
|
+
}
|
|
24
|
+
authorize(request, connector) {
|
|
25
|
+
for (const [requestedResource, requestedActions] of Object.entries(
|
|
26
|
+
request
|
|
27
|
+
)) {
|
|
28
|
+
const allowedActions = this.statements[requestedResource];
|
|
29
|
+
if (!allowedActions) {
|
|
30
|
+
return {
|
|
31
|
+
success: false,
|
|
32
|
+
error: `You are not allowed to access resource: ${requestedResource}`
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
const success = connector === "OR" ? requestedActions.some(
|
|
36
|
+
(requestedAction) => allowedActions.includes(requestedAction)
|
|
37
|
+
) : requestedActions.every(
|
|
38
|
+
(requestedAction) => allowedActions.includes(requestedAction)
|
|
39
|
+
);
|
|
40
|
+
if (success) {
|
|
41
|
+
return { success };
|
|
42
|
+
}
|
|
43
|
+
return {
|
|
44
|
+
success: false,
|
|
45
|
+
error: `unauthorized to access resource "${requestedResource}"`
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
return {
|
|
49
|
+
success: false,
|
|
50
|
+
error: "Not authorized"
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
static fromString(s) {
|
|
54
|
+
const statements = JSON.parse(s);
|
|
55
|
+
if (typeof statements !== "object") {
|
|
56
|
+
throw new ParsingError("statements is not an object", ".");
|
|
57
|
+
}
|
|
58
|
+
for (const [resource, actions] of Object.entries(statements)) {
|
|
59
|
+
if (typeof resource !== "string") {
|
|
60
|
+
throw new ParsingError("invalid resource identifier", resource);
|
|
61
|
+
}
|
|
62
|
+
if (!Array.isArray(actions)) {
|
|
63
|
+
throw new ParsingError("actions is not an array", resource);
|
|
64
|
+
}
|
|
65
|
+
for (let i = 0; i < actions.length; i++) {
|
|
66
|
+
if (typeof actions[i] !== "string") {
|
|
67
|
+
throw new ParsingError("action is not a string", `${resource}[${i}]`);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
return new _Role(statements);
|
|
72
|
+
}
|
|
73
|
+
toString() {
|
|
74
|
+
return JSON.stringify(this.statements);
|
|
75
|
+
}
|
|
76
|
+
};
|
|
77
|
+
|
|
78
|
+
// src/plugins/organization/access/statement.ts
|
|
79
|
+
var createAccessControl = (statements) => {
|
|
80
|
+
return new AccessControl(statements);
|
|
81
|
+
};
|
|
82
|
+
var defaultStatements = {
|
|
83
|
+
organization: ["update", "delete"],
|
|
84
|
+
member: ["create", "update", "delete"],
|
|
85
|
+
invitation: ["create", "cancel"]
|
|
86
|
+
};
|
|
87
|
+
var defaultAc = createAccessControl(defaultStatements);
|
|
88
|
+
var adminAc = defaultAc.newRole({
|
|
89
|
+
organization: ["update"],
|
|
90
|
+
invitation: ["create", "cancel"],
|
|
91
|
+
member: ["create", "update", "delete"]
|
|
92
|
+
});
|
|
93
|
+
var ownerAc = defaultAc.newRole({
|
|
94
|
+
organization: ["update", "delete"],
|
|
95
|
+
member: ["create", "update", "delete"],
|
|
96
|
+
invitation: ["create", "cancel"]
|
|
97
|
+
});
|
|
98
|
+
var memberAc = defaultAc.newRole({
|
|
99
|
+
organization: [],
|
|
100
|
+
member: [],
|
|
101
|
+
invitation: []
|
|
102
|
+
});
|
|
103
|
+
var defaultRoles = {
|
|
104
|
+
admin: adminAc,
|
|
105
|
+
owner: ownerAc,
|
|
106
|
+
member: memberAc
|
|
107
|
+
};
|
|
108
|
+
|
|
109
|
+
// src/plugins/organization/access/utils.ts
|
|
110
|
+
var permissionFromString = (permission) => {
|
|
111
|
+
return Role.fromString(permission ?? "");
|
|
112
|
+
};
|
|
113
|
+
export {
|
|
114
|
+
AccessControl,
|
|
115
|
+
ParsingError,
|
|
116
|
+
Role,
|
|
117
|
+
adminAc,
|
|
118
|
+
createAccessControl,
|
|
119
|
+
defaultAc,
|
|
120
|
+
defaultRoles,
|
|
121
|
+
defaultStatements,
|
|
122
|
+
memberAc,
|
|
123
|
+
ownerAc,
|
|
124
|
+
permissionFromString
|
|
125
|
+
};
|
|
126
|
+
//# sourceMappingURL=access.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/plugins/organization/access/src/access.ts","../src/plugins/organization/access/statement.ts","../src/plugins/organization/access/utils.ts"],"sourcesContent":["import type { StatementsPrimitive as Statements, Subset } from \"./types\";\n\nexport class ParsingError extends Error {\n\tpublic readonly path: string;\n\tconstructor(message: string, path: string) {\n\t\tsuper(message);\n\t\tthis.path = path;\n\t}\n}\n\ntype Connector = \"OR\" | \"AND\";\n\nexport class AccessControl<TStatements extends Statements = Statements> {\n\tprivate readonly statements: TStatements;\n\tconstructor(private readonly s: TStatements) {\n\t\tthis.statements = s;\n\t}\n\tpublic newRole<K extends keyof TStatements>(\n\t\tstatements: Subset<K, TStatements>,\n\t) {\n\t\treturn new Role<Subset<K, TStatements>>(statements);\n\t}\n}\n\nexport type AuthortizeResponse =\n\t| { success: false; error: string }\n\t| { success: true; error?: never };\n\nexport class Role<TStatements extends Statements> {\n\tpublic readonly statements: TStatements;\n\n\tconstructor(statements: TStatements) {\n\t\tthis.statements = statements;\n\t}\n\n\tpublic authorize<K extends keyof TStatements>(\n\t\trequest: Subset<K, TStatements>,\n\t\tconnector?: Connector,\n\t): AuthortizeResponse {\n\t\tfor (const [requestedResource, requestedActions] of Object.entries(\n\t\t\trequest,\n\t\t)) {\n\t\t\tconst allowedActions = this.statements[requestedResource];\n\t\t\tif (!allowedActions) {\n\t\t\t\treturn {\n\t\t\t\t\tsuccess: false,\n\t\t\t\t\terror: `You are not allowed to access resource: ${requestedResource}`,\n\t\t\t\t};\n\t\t\t}\n\t\t\tconst success =\n\t\t\t\tconnector === \"OR\"\n\t\t\t\t\t? (requestedActions as string[]).some((requestedAction) =>\n\t\t\t\t\t\t\tallowedActions.includes(requestedAction),\n\t\t\t\t\t\t)\n\t\t\t\t\t: (requestedActions as string[]).every((requestedAction) =>\n\t\t\t\t\t\t\tallowedActions.includes(requestedAction),\n\t\t\t\t\t\t);\n\t\t\tif (success) {\n\t\t\t\treturn { success };\n\t\t\t}\n\t\t\treturn {\n\t\t\t\tsuccess: false,\n\t\t\t\terror: `unauthorized to access resource \"${requestedResource}\"`,\n\t\t\t};\n\t\t}\n\t\treturn {\n\t\t\tsuccess: false,\n\t\t\terror: \"Not authorized\",\n\t\t};\n\t}\n\n\tstatic fromString<TStatements extends Statements>(s: string) {\n\t\tconst statements = JSON.parse(s) as TStatements;\n\n\t\tif (typeof statements !== \"object\") {\n\t\t\tthrow new ParsingError(\"statements is not an object\", \".\");\n\t\t}\n\t\tfor (const [resource, actions] of Object.entries(statements)) {\n\t\t\tif (typeof resource !== \"string\") {\n\t\t\t\tthrow new ParsingError(\"invalid resource identifier\", resource);\n\t\t\t}\n\t\t\tif (!Array.isArray(actions)) {\n\t\t\t\tthrow new ParsingError(\"actions is not an array\", resource);\n\t\t\t}\n\t\t\tfor (let i = 0; i < actions.length; i++) {\n\t\t\t\tif (typeof actions[i] !== \"string\") {\n\t\t\t\t\tthrow new ParsingError(\"action is not a string\", `${resource}[${i}]`);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn new Role<TStatements>(statements);\n\t}\n\n\tpublic toString(): string {\n\t\treturn JSON.stringify(this.statements);\n\t}\n}\n","import { AccessControl } from \"./src/access\";\nimport type { StatementsPrimitive } from \"./src/types\";\n\nexport const createAccessControl = <S extends StatementsPrimitive>(\n\tstatements: S,\n) => {\n\treturn new AccessControl<S>(statements);\n};\n\nexport const defaultStatements = {\n\torganization: [\"update\", \"delete\"],\n\tmember: [\"create\", \"update\", \"delete\"],\n\tinvitation: [\"create\", \"cancel\"],\n} as const;\n\nexport const defaultAc = createAccessControl(defaultStatements);\n\nexport const adminAc = defaultAc.newRole({\n\torganization: [\"update\"],\n\tinvitation: [\"create\", \"cancel\"],\n\tmember: [\"create\", \"update\", \"delete\"],\n});\n\nexport const ownerAc = defaultAc.newRole({\n\torganization: [\"update\", \"delete\"],\n\tmember: [\"create\", \"update\", \"delete\"],\n\tinvitation: [\"create\", \"cancel\"],\n});\n\nexport const memberAc = defaultAc.newRole({\n\torganization: [],\n\tmember: [],\n\tinvitation: [],\n});\n\nexport const defaultRoles = {\n\tadmin: adminAc,\n\towner: ownerAc,\n\tmember: memberAc,\n};\n","import { Role } from \"./src/access\";\n\nexport const permissionFromString = (permission?: string) => {\n\treturn Role.fromString(permission ?? \"\");\n};\n"],"mappings":"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","names":[]}
|
package/dist/cli.d.ts
ADDED
package/dist/cli.js
ADDED
|
@@ -0,0 +1,553 @@
|
|
|
1
|
+
// src/cli/index.ts
|
|
2
|
+
import { Command as Command2 } from "commander";
|
|
3
|
+
import "dotenv/config";
|
|
4
|
+
|
|
5
|
+
// src/cli/commands/migrate.ts
|
|
6
|
+
import { Command } from "commander";
|
|
7
|
+
|
|
8
|
+
// src/cli/get-config.ts
|
|
9
|
+
import path from "node:path";
|
|
10
|
+
import jiti from "jiti";
|
|
11
|
+
|
|
12
|
+
// src/utils/logger.ts
|
|
13
|
+
import { createConsola } from "consola";
|
|
14
|
+
var consola = createConsola({
|
|
15
|
+
formatOptions: {
|
|
16
|
+
date: false
|
|
17
|
+
}
|
|
18
|
+
});
|
|
19
|
+
var createLogger = (options) => {
|
|
20
|
+
return {
|
|
21
|
+
log: (...args) => {
|
|
22
|
+
!options?.disabled && consola.log("", ...args);
|
|
23
|
+
},
|
|
24
|
+
error: (...args) => {
|
|
25
|
+
!options?.disabled && consola.error("", ...args);
|
|
26
|
+
},
|
|
27
|
+
warn: (...args) => {
|
|
28
|
+
!options?.disabled && consola.warn("", ...args);
|
|
29
|
+
},
|
|
30
|
+
info: (...args) => {
|
|
31
|
+
!options?.disabled && consola.info("", ...args);
|
|
32
|
+
},
|
|
33
|
+
debug: (...args) => {
|
|
34
|
+
!options?.disabled && consola.debug("", ...args);
|
|
35
|
+
},
|
|
36
|
+
box: (...args) => {
|
|
37
|
+
!options?.disabled && consola.box("", ...args);
|
|
38
|
+
},
|
|
39
|
+
success: (...args) => {
|
|
40
|
+
!options?.disabled && consola.success("", ...args);
|
|
41
|
+
},
|
|
42
|
+
break: (...args) => {
|
|
43
|
+
!options?.disabled && console.log("\n");
|
|
44
|
+
}
|
|
45
|
+
};
|
|
46
|
+
};
|
|
47
|
+
var logger = createLogger();
|
|
48
|
+
|
|
49
|
+
// src/cli/get-config.ts
|
|
50
|
+
var possiblePaths = ["auth.ts", "auth.config.ts"];
|
|
51
|
+
possiblePaths = [
|
|
52
|
+
...possiblePaths,
|
|
53
|
+
...possiblePaths.map((it) => `lib/${it}`),
|
|
54
|
+
...possiblePaths.map((it) => `utils/${it}`)
|
|
55
|
+
];
|
|
56
|
+
possiblePaths = [...possiblePaths, ...possiblePaths.map((it) => `src/${it}`)];
|
|
57
|
+
async function getConfig({
|
|
58
|
+
cwd,
|
|
59
|
+
configPath
|
|
60
|
+
}) {
|
|
61
|
+
try {
|
|
62
|
+
let configFile = null;
|
|
63
|
+
if (configPath) {
|
|
64
|
+
const config = await jiti(cwd).import(
|
|
65
|
+
path.join(cwd, configPath),
|
|
66
|
+
{}
|
|
67
|
+
);
|
|
68
|
+
if (!config) {
|
|
69
|
+
return null;
|
|
70
|
+
}
|
|
71
|
+
configFile = config.auth.options;
|
|
72
|
+
}
|
|
73
|
+
for (const possiblePath of possiblePaths) {
|
|
74
|
+
try {
|
|
75
|
+
const config = await jiti(path.join(cwd, possiblePath)).import(
|
|
76
|
+
path.join(cwd, possiblePath),
|
|
77
|
+
{}
|
|
78
|
+
);
|
|
79
|
+
if (config) {
|
|
80
|
+
configFile = config.auth?.options || config.default?.options || null;
|
|
81
|
+
if (!configFile) {
|
|
82
|
+
logger.error("[#better-auth]: Couldn't read your auth config.");
|
|
83
|
+
logger.break();
|
|
84
|
+
logger.info(
|
|
85
|
+
"[#better-auth]: Make sure to default export your auth instance or to export as a variable named auth."
|
|
86
|
+
);
|
|
87
|
+
process.exit(1);
|
|
88
|
+
}
|
|
89
|
+
break;
|
|
90
|
+
}
|
|
91
|
+
} catch (e) {
|
|
92
|
+
if (!(e instanceof Error && e.message.includes("Cannot find module"))) {
|
|
93
|
+
logger.error(e);
|
|
94
|
+
process.exit(1);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
return configFile;
|
|
99
|
+
} catch (e) {
|
|
100
|
+
return null;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
// src/cli/commands/migrate.ts
|
|
105
|
+
import { z } from "zod";
|
|
106
|
+
import { existsSync } from "fs";
|
|
107
|
+
import path2 from "path";
|
|
108
|
+
|
|
109
|
+
// src/adapters/kysely.ts
|
|
110
|
+
import Database from "better-sqlite3";
|
|
111
|
+
import { Kysely } from "kysely";
|
|
112
|
+
import {
|
|
113
|
+
MysqlDialect,
|
|
114
|
+
PostgresDialect,
|
|
115
|
+
SqliteDialect
|
|
116
|
+
} from "kysely";
|
|
117
|
+
import { createPool } from "mysql2";
|
|
118
|
+
import pg from "pg";
|
|
119
|
+
var { Pool } = pg;
|
|
120
|
+
var getDialect = (config) => {
|
|
121
|
+
if (!config.database) {
|
|
122
|
+
return null;
|
|
123
|
+
}
|
|
124
|
+
let dialect = null;
|
|
125
|
+
if ("provider" in config.database) {
|
|
126
|
+
const provider = config.database.provider;
|
|
127
|
+
const connectionString = config.database.url.trim();
|
|
128
|
+
if (provider === "postgres") {
|
|
129
|
+
const pool = new Pool({
|
|
130
|
+
connectionString
|
|
131
|
+
});
|
|
132
|
+
dialect = new PostgresDialect({
|
|
133
|
+
pool
|
|
134
|
+
});
|
|
135
|
+
}
|
|
136
|
+
if (provider === "mysql") {
|
|
137
|
+
const params = new URL(connectionString);
|
|
138
|
+
const pool = createPool({
|
|
139
|
+
host: params.hostname,
|
|
140
|
+
user: params.username,
|
|
141
|
+
password: params.password,
|
|
142
|
+
database: params.pathname.split("/")[1],
|
|
143
|
+
port: Number(params.port)
|
|
144
|
+
});
|
|
145
|
+
dialect = new MysqlDialect({ pool });
|
|
146
|
+
}
|
|
147
|
+
if (provider === "sqlite") {
|
|
148
|
+
const db = new Database(connectionString);
|
|
149
|
+
dialect = new SqliteDialect({
|
|
150
|
+
database: db
|
|
151
|
+
});
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
return dialect;
|
|
155
|
+
};
|
|
156
|
+
var createKyselyAdapter = (config) => {
|
|
157
|
+
const dialect = getDialect(config);
|
|
158
|
+
if (!dialect) {
|
|
159
|
+
return null;
|
|
160
|
+
}
|
|
161
|
+
const db = new Kysely({
|
|
162
|
+
dialect
|
|
163
|
+
});
|
|
164
|
+
return db;
|
|
165
|
+
};
|
|
166
|
+
var getDatabaseType = (config) => {
|
|
167
|
+
if ("provider" in config.database) {
|
|
168
|
+
return config.database.provider;
|
|
169
|
+
}
|
|
170
|
+
if ("dialect" in config.database) {
|
|
171
|
+
if (config.database.dialect instanceof PostgresDialect) {
|
|
172
|
+
return "postgres";
|
|
173
|
+
}
|
|
174
|
+
if (config.database.dialect instanceof MysqlDialect) {
|
|
175
|
+
return "mysql";
|
|
176
|
+
}
|
|
177
|
+
if (config.database.dialect instanceof SqliteDialect) {
|
|
178
|
+
return "sqlite";
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
return "sqlite";
|
|
182
|
+
};
|
|
183
|
+
|
|
184
|
+
// src/cli/commands/migrate.ts
|
|
185
|
+
import ora from "ora";
|
|
186
|
+
import chalk from "chalk";
|
|
187
|
+
import prompts from "prompts";
|
|
188
|
+
|
|
189
|
+
// src/adapters/get-tables.ts
|
|
190
|
+
var getAuthTables = (options) => {
|
|
191
|
+
const pluginSchema = options.plugins?.reduce((acc, plugin) => {
|
|
192
|
+
const schema = plugin.schema;
|
|
193
|
+
return {
|
|
194
|
+
...acc,
|
|
195
|
+
...schema
|
|
196
|
+
};
|
|
197
|
+
}, {});
|
|
198
|
+
return {
|
|
199
|
+
...pluginSchema,
|
|
200
|
+
user: {
|
|
201
|
+
tableName: options.user?.modelName || "user",
|
|
202
|
+
fields: {
|
|
203
|
+
name: {
|
|
204
|
+
type: "string"
|
|
205
|
+
},
|
|
206
|
+
email: {
|
|
207
|
+
type: "string"
|
|
208
|
+
},
|
|
209
|
+
emailVerified: {
|
|
210
|
+
type: "boolean",
|
|
211
|
+
defaultValue: () => false
|
|
212
|
+
},
|
|
213
|
+
image: {
|
|
214
|
+
type: "string",
|
|
215
|
+
required: false
|
|
216
|
+
},
|
|
217
|
+
createdAt: {
|
|
218
|
+
type: "date",
|
|
219
|
+
defaultValue: () => /* @__PURE__ */ new Date()
|
|
220
|
+
},
|
|
221
|
+
updatedAt: {
|
|
222
|
+
type: "date",
|
|
223
|
+
defaultValue: () => /* @__PURE__ */ new Date()
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
},
|
|
227
|
+
session: {
|
|
228
|
+
tableName: options.session?.modelName || "session",
|
|
229
|
+
fields: {
|
|
230
|
+
expiresAt: {
|
|
231
|
+
type: "date"
|
|
232
|
+
},
|
|
233
|
+
ipAddress: {
|
|
234
|
+
type: "string",
|
|
235
|
+
required: false
|
|
236
|
+
},
|
|
237
|
+
userAgent: {
|
|
238
|
+
type: "string",
|
|
239
|
+
required: false
|
|
240
|
+
},
|
|
241
|
+
userId: {
|
|
242
|
+
type: "string",
|
|
243
|
+
references: {
|
|
244
|
+
model: "user",
|
|
245
|
+
field: "id",
|
|
246
|
+
onDelete: "cascade"
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
},
|
|
251
|
+
account: {
|
|
252
|
+
tableName: options.account?.modelName || "account",
|
|
253
|
+
fields: {
|
|
254
|
+
accountId: {
|
|
255
|
+
type: "string"
|
|
256
|
+
},
|
|
257
|
+
providerId: {
|
|
258
|
+
type: "string"
|
|
259
|
+
},
|
|
260
|
+
userId: {
|
|
261
|
+
type: "string",
|
|
262
|
+
references: {
|
|
263
|
+
model: "user",
|
|
264
|
+
field: "id",
|
|
265
|
+
onDelete: "cascade"
|
|
266
|
+
}
|
|
267
|
+
},
|
|
268
|
+
accessToken: {
|
|
269
|
+
type: "string",
|
|
270
|
+
required: false
|
|
271
|
+
},
|
|
272
|
+
refreshToken: {
|
|
273
|
+
type: "string",
|
|
274
|
+
required: false
|
|
275
|
+
},
|
|
276
|
+
idToken: {
|
|
277
|
+
type: "string",
|
|
278
|
+
required: false
|
|
279
|
+
},
|
|
280
|
+
accessTokenExpiresAt: {
|
|
281
|
+
type: "date",
|
|
282
|
+
required: false
|
|
283
|
+
},
|
|
284
|
+
refreshTokenExpiresAt: {
|
|
285
|
+
type: "date",
|
|
286
|
+
required: false
|
|
287
|
+
},
|
|
288
|
+
password: {
|
|
289
|
+
type: "string",
|
|
290
|
+
required: false
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
};
|
|
295
|
+
};
|
|
296
|
+
|
|
297
|
+
// src/cli/utils/get-schema.ts
|
|
298
|
+
function getPluginTable(config) {
|
|
299
|
+
const pluginsMigrations = config.plugins?.flatMap(
|
|
300
|
+
(plugin) => Object.keys(plugin.schema || {}).map((key) => {
|
|
301
|
+
const schema = plugin.schema || {};
|
|
302
|
+
const table = schema[key];
|
|
303
|
+
if (table?.disableMigration) {
|
|
304
|
+
return;
|
|
305
|
+
}
|
|
306
|
+
return {
|
|
307
|
+
tableName: key,
|
|
308
|
+
fields: table?.fields
|
|
309
|
+
};
|
|
310
|
+
}).filter((value) => value !== void 0)
|
|
311
|
+
) || [];
|
|
312
|
+
return pluginsMigrations;
|
|
313
|
+
}
|
|
314
|
+
function getSchema(config) {
|
|
315
|
+
const baseSchema = getAuthTables(config);
|
|
316
|
+
const pluginSchema = getPluginTable(config);
|
|
317
|
+
const schema = [
|
|
318
|
+
...pluginSchema,
|
|
319
|
+
baseSchema.user,
|
|
320
|
+
baseSchema.session,
|
|
321
|
+
baseSchema.account
|
|
322
|
+
].reduce((acc, curr) => {
|
|
323
|
+
acc[curr.tableName] = {
|
|
324
|
+
fields: {
|
|
325
|
+
...acc[curr.tableName]?.fields,
|
|
326
|
+
...curr.fields
|
|
327
|
+
}
|
|
328
|
+
};
|
|
329
|
+
return acc;
|
|
330
|
+
}, {});
|
|
331
|
+
return schema;
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
// src/cli/utils/get-migration.ts
|
|
335
|
+
var postgresMap = {
|
|
336
|
+
string: ["character varying", "text"],
|
|
337
|
+
number: [
|
|
338
|
+
"integer",
|
|
339
|
+
"bigint",
|
|
340
|
+
"smallint",
|
|
341
|
+
"numeric",
|
|
342
|
+
"real",
|
|
343
|
+
"double precision"
|
|
344
|
+
],
|
|
345
|
+
boolean: ["boolean"],
|
|
346
|
+
date: ["timestamp", "date"]
|
|
347
|
+
};
|
|
348
|
+
var mysqlMap = {
|
|
349
|
+
string: ["varchar", "text"],
|
|
350
|
+
number: [
|
|
351
|
+
"integer",
|
|
352
|
+
"int",
|
|
353
|
+
"bigint",
|
|
354
|
+
"smallint",
|
|
355
|
+
"decimal",
|
|
356
|
+
"float",
|
|
357
|
+
"double"
|
|
358
|
+
],
|
|
359
|
+
boolean: ["boolean"],
|
|
360
|
+
date: ["date", "datetime"]
|
|
361
|
+
};
|
|
362
|
+
var sqliteMap = {
|
|
363
|
+
string: ["TEXT"],
|
|
364
|
+
number: ["INTEGER", "REAL"],
|
|
365
|
+
boolean: ["INTEGER", "BOOLEAN"],
|
|
366
|
+
// 0 or 1
|
|
367
|
+
date: ["DATE", "INTEGER"]
|
|
368
|
+
};
|
|
369
|
+
var map = {
|
|
370
|
+
postgres: postgresMap,
|
|
371
|
+
mysql: mysqlMap,
|
|
372
|
+
sqlite: sqliteMap
|
|
373
|
+
};
|
|
374
|
+
function matchType(columnDataType, fieldType, dbType) {
|
|
375
|
+
const types = map[dbType];
|
|
376
|
+
const type = types[fieldType].map((t) => t.toLowerCase());
|
|
377
|
+
const matches = type.includes(columnDataType.toLowerCase());
|
|
378
|
+
return matches;
|
|
379
|
+
}
|
|
380
|
+
async function getMigrations(config) {
|
|
381
|
+
const betterAuthSchema = getSchema(config);
|
|
382
|
+
const dbType = getDatabaseType(config);
|
|
383
|
+
const db = createKyselyAdapter(config);
|
|
384
|
+
if (!db) {
|
|
385
|
+
logger.error("Invalid database configuration.");
|
|
386
|
+
process.exit(1);
|
|
387
|
+
}
|
|
388
|
+
const tableMetadata = await db.introspection.getTables();
|
|
389
|
+
const toBeCreated = [];
|
|
390
|
+
const toBeAdded = [];
|
|
391
|
+
for (const [key, value] of Object.entries(betterAuthSchema)) {
|
|
392
|
+
const table = tableMetadata.find((t) => t.name === key);
|
|
393
|
+
if (!table) {
|
|
394
|
+
const tIndex = toBeCreated.findIndex((t) => t.table === key);
|
|
395
|
+
if (tIndex === -1) {
|
|
396
|
+
toBeCreated.push({
|
|
397
|
+
table: key,
|
|
398
|
+
fields: value.fields
|
|
399
|
+
});
|
|
400
|
+
} else {
|
|
401
|
+
toBeCreated[tIndex].fields = {
|
|
402
|
+
...toBeCreated[tIndex].fields,
|
|
403
|
+
...value.fields
|
|
404
|
+
};
|
|
405
|
+
}
|
|
406
|
+
continue;
|
|
407
|
+
}
|
|
408
|
+
let toBeAddedFields = {};
|
|
409
|
+
for (const [fieldName, field] of Object.entries(value.fields)) {
|
|
410
|
+
const column = table.columns.find((c) => c.name === fieldName);
|
|
411
|
+
if (!column) {
|
|
412
|
+
toBeAddedFields[fieldName] = field;
|
|
413
|
+
continue;
|
|
414
|
+
}
|
|
415
|
+
if (matchType(column.dataType, field.type, dbType)) {
|
|
416
|
+
continue;
|
|
417
|
+
} else {
|
|
418
|
+
logger.warn(
|
|
419
|
+
`Field ${fieldName} in table ${key} has a different type in the database. Expected ${field.type} but got ${column.dataType}.`
|
|
420
|
+
);
|
|
421
|
+
}
|
|
422
|
+
}
|
|
423
|
+
if (Object.keys(toBeAddedFields).length > 0) {
|
|
424
|
+
toBeAdded.push({
|
|
425
|
+
table: key,
|
|
426
|
+
fields: toBeAddedFields
|
|
427
|
+
});
|
|
428
|
+
}
|
|
429
|
+
}
|
|
430
|
+
const typeMap = {
|
|
431
|
+
string: "text",
|
|
432
|
+
boolean: "boolean",
|
|
433
|
+
number: "integer",
|
|
434
|
+
date: "date"
|
|
435
|
+
};
|
|
436
|
+
const migrations = [];
|
|
437
|
+
if (toBeAdded.length) {
|
|
438
|
+
for (const table of toBeAdded) {
|
|
439
|
+
logger.info(`Adding fields to table ${table.table}`);
|
|
440
|
+
for (const [fieldName, field] of Object.entries(table.fields)) {
|
|
441
|
+
logger.info(`Adding field ${fieldName} with type ${field.type}`);
|
|
442
|
+
const type = typeMap[field.type];
|
|
443
|
+
const exec = db.schema.alterTable(table.table).addColumn(fieldName, type, (col) => {
|
|
444
|
+
col = field.required !== false ? col.notNull() : col;
|
|
445
|
+
if (field.references) {
|
|
446
|
+
col = col.references(
|
|
447
|
+
`${field.references.model}.${field.references.field}`
|
|
448
|
+
);
|
|
449
|
+
}
|
|
450
|
+
return col;
|
|
451
|
+
});
|
|
452
|
+
migrations.push(exec);
|
|
453
|
+
}
|
|
454
|
+
}
|
|
455
|
+
}
|
|
456
|
+
if (toBeCreated.length) {
|
|
457
|
+
for (const table of toBeCreated) {
|
|
458
|
+
let dbT = db.schema.createTable(table.table).addColumn("id", "text", (col) => col.primaryKey());
|
|
459
|
+
for (const [fieldName, field] of Object.entries(table.fields)) {
|
|
460
|
+
const type = typeMap[field.type];
|
|
461
|
+
dbT = dbT.addColumn(fieldName, type, (col) => {
|
|
462
|
+
col = field.required !== false ? col.notNull() : col;
|
|
463
|
+
if (field.references) {
|
|
464
|
+
col = col.references(
|
|
465
|
+
`${field.references.model}.${field.references.field}`
|
|
466
|
+
);
|
|
467
|
+
}
|
|
468
|
+
return col;
|
|
469
|
+
});
|
|
470
|
+
}
|
|
471
|
+
migrations.push(dbT);
|
|
472
|
+
}
|
|
473
|
+
}
|
|
474
|
+
async function runMigrations() {
|
|
475
|
+
return await Promise.all(migrations.map((m) => m.execute()));
|
|
476
|
+
}
|
|
477
|
+
return { toBeCreated, toBeAdded, runMigrations };
|
|
478
|
+
}
|
|
479
|
+
|
|
480
|
+
// src/cli/commands/migrate.ts
|
|
481
|
+
var migrate = new Command("migrate").option(
|
|
482
|
+
"-c, --cwd <cwd>",
|
|
483
|
+
"the working directory. defaults to the current directory.",
|
|
484
|
+
process.cwd()
|
|
485
|
+
).option(
|
|
486
|
+
"--config <config>",
|
|
487
|
+
"the path to the configuration file. defaults to the first configuration file found."
|
|
488
|
+
).action(async (opts) => {
|
|
489
|
+
const options = z.object({
|
|
490
|
+
cwd: z.string(),
|
|
491
|
+
config: z.string().optional()
|
|
492
|
+
}).parse(opts);
|
|
493
|
+
const cwd = path2.resolve(options.cwd);
|
|
494
|
+
if (!existsSync(cwd)) {
|
|
495
|
+
logger.error(`The directory "${cwd}" does not exist.`);
|
|
496
|
+
process.exit(1);
|
|
497
|
+
}
|
|
498
|
+
const config = await getConfig({
|
|
499
|
+
cwd,
|
|
500
|
+
configPath: options.config
|
|
501
|
+
});
|
|
502
|
+
if (!config) {
|
|
503
|
+
logger.error("No configuration file found.");
|
|
504
|
+
return;
|
|
505
|
+
}
|
|
506
|
+
const db = createKyselyAdapter(config);
|
|
507
|
+
if (!db) {
|
|
508
|
+
logger.error("Invalid database configuration.");
|
|
509
|
+
process.exit(1);
|
|
510
|
+
}
|
|
511
|
+
const spinner = ora("preparing migration...").start();
|
|
512
|
+
const { toBeAdded, toBeCreated, runMigrations } = await getMigrations(config);
|
|
513
|
+
if (!toBeAdded.length && !toBeCreated.length) {
|
|
514
|
+
spinner.stop();
|
|
515
|
+
logger.success("\u{1F680} No migrations needed.");
|
|
516
|
+
process.exit(0);
|
|
517
|
+
}
|
|
518
|
+
spinner.stop();
|
|
519
|
+
logger.info(`\u{1F511} The migration will affect the following:`);
|
|
520
|
+
for (const table of [...toBeAdded, ...toBeCreated]) {
|
|
521
|
+
logger.info(
|
|
522
|
+
"->",
|
|
523
|
+
chalk.magenta(Object.keys(table.fields).join(", ")),
|
|
524
|
+
chalk.white("fields on"),
|
|
525
|
+
chalk.yellow(`${table.table}`),
|
|
526
|
+
chalk.white("table.")
|
|
527
|
+
);
|
|
528
|
+
}
|
|
529
|
+
const { migrate: migrate2 } = await prompts({
|
|
530
|
+
type: "confirm",
|
|
531
|
+
name: "migrate",
|
|
532
|
+
message: "Are you sure you want to run these migrations?",
|
|
533
|
+
initial: false
|
|
534
|
+
});
|
|
535
|
+
if (!migrate2) {
|
|
536
|
+
logger.info("Migration cancelled.");
|
|
537
|
+
process.exit(0);
|
|
538
|
+
}
|
|
539
|
+
spinner?.start("migrating...");
|
|
540
|
+
await runMigrations();
|
|
541
|
+
spinner.stop();
|
|
542
|
+
logger.success("\u{1F680} migration was completed successfully!");
|
|
543
|
+
process.exit(0);
|
|
544
|
+
});
|
|
545
|
+
|
|
546
|
+
// src/cli/index.ts
|
|
547
|
+
async function main() {
|
|
548
|
+
const program = new Command2().name("better-auth");
|
|
549
|
+
program.addCommand(migrate);
|
|
550
|
+
program.parse();
|
|
551
|
+
}
|
|
552
|
+
main();
|
|
553
|
+
//# sourceMappingURL=cli.js.map
|