@better-auth/cli 1.4.0-beta.19 → 1.4.0-beta.20
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/index.mjs +110 -13
- package/package.json +4 -3
package/dist/index.mjs
CHANGED
|
@@ -53,9 +53,12 @@ const generateDrizzleSchema = async ({ options, file, adapter }) => {
|
|
|
53
53
|
if (!databaseType) throw new Error(`Database provider type is undefined during Drizzle schema generation. Please define a \`provider\` in the Drizzle adapter config. Read more at https://better-auth.com/docs/adapters/drizzle`);
|
|
54
54
|
name = convertToSnakeCase(name, adapter.options?.camelCase);
|
|
55
55
|
if (field.references?.field === "id") {
|
|
56
|
-
|
|
56
|
+
const useNumberId$1 = options.advanced?.database?.useNumberId || options.advanced?.database?.generateId === "serial";
|
|
57
|
+
const useUUIDs = options.advanced?.database?.generateId === "uuid";
|
|
58
|
+
if (useNumberId$1) if (databaseType === "pg") return `integer('${name}')`;
|
|
57
59
|
else if (databaseType === "mysql") return `int('${name}')`;
|
|
58
60
|
else return `integer('${name}')`;
|
|
61
|
+
if (useUUIDs && databaseType === "pg") return `uuid('${name}')`;
|
|
59
62
|
if (field.references.field) {
|
|
60
63
|
if (databaseType === "mysql") return `varchar('${name}', { length: 36 })`;
|
|
61
64
|
}
|
|
@@ -72,7 +75,7 @@ const generateDrizzleSchema = async ({ options, file, adapter }) => {
|
|
|
72
75
|
string: {
|
|
73
76
|
sqlite: `text('${name}')`,
|
|
74
77
|
pg: `text('${name}')`,
|
|
75
|
-
mysql: field.unique ? `varchar('${name}', { length: 255 })` : field.references ? `varchar('${name}', { length: 36 })` : `text('${name}')`
|
|
78
|
+
mysql: field.unique ? `varchar('${name}', { length: 255 })` : field.references ? `varchar('${name}', { length: 36 })` : field.sortable ? `varchar('${name}', { length: 255 })` : field.index ? `varchar('${name}', { length: 255 })` : `text('${name}')`
|
|
76
79
|
},
|
|
77
80
|
boolean: {
|
|
78
81
|
sqlite: `integer('${name}', { mode: 'boolean' })`,
|
|
@@ -107,18 +110,38 @@ const generateDrizzleSchema = async ({ options, file, adapter }) => {
|
|
|
107
110
|
}[type][databaseType];
|
|
108
111
|
}
|
|
109
112
|
let id = "";
|
|
110
|
-
|
|
113
|
+
const useNumberId = options.advanced?.database?.useNumberId || options.advanced?.database?.generateId === "serial";
|
|
114
|
+
if (options.advanced?.database?.generateId === "uuid" && databaseType === "pg") id = `uuid("id").default(sql\`pg_catalog.gen_random_uuid()\`).primaryKey()`;
|
|
115
|
+
else if (useNumberId) if (databaseType === "pg") id = `serial("id").primaryKey()`;
|
|
111
116
|
else if (databaseType === "sqlite") id = `integer("id", { mode: "number" }).primaryKey({ autoIncrement: true })`;
|
|
112
117
|
else id = `int("id").autoincrement().primaryKey()`;
|
|
113
118
|
else if (databaseType === "mysql") id = `varchar('id', { length: 36 }).primaryKey()`;
|
|
114
119
|
else if (databaseType === "pg") id = `text('id').primaryKey()`;
|
|
115
120
|
else id = `text('id').primaryKey()`;
|
|
121
|
+
let indexes = [];
|
|
122
|
+
const assignIndexes = (indexes$1) => {
|
|
123
|
+
if (!indexes$1.length) return "";
|
|
124
|
+
let code$1 = [`, (table) => [`];
|
|
125
|
+
for (const index of indexes$1) code$1.push(` ${index.type}("${index.name}").on(table.${index.on}),`);
|
|
126
|
+
code$1.push(`]`);
|
|
127
|
+
return code$1.join("\n");
|
|
128
|
+
};
|
|
116
129
|
const schema = `export const ${modelName} = ${databaseType}Table("${convertToSnakeCase(modelName, adapter.options?.camelCase)}", {
|
|
117
130
|
id: ${id},
|
|
118
131
|
${Object.keys(fields).map((field) => {
|
|
119
132
|
const attr = fields[field];
|
|
120
133
|
const fieldName = attr.fieldName || field;
|
|
121
134
|
let type = getType(fieldName, attr);
|
|
135
|
+
if (attr.index && !attr.unique) indexes.push({
|
|
136
|
+
type: "index",
|
|
137
|
+
name: `${modelName}_${fieldName}_idx`,
|
|
138
|
+
on: fieldName
|
|
139
|
+
});
|
|
140
|
+
else if (attr.index && attr.unique) indexes.push({
|
|
141
|
+
type: "uniqueIndex",
|
|
142
|
+
name: `${modelName}_${fieldName}_uidx`,
|
|
143
|
+
on: fieldName
|
|
144
|
+
});
|
|
122
145
|
if (attr.defaultValue !== null && typeof attr.defaultValue !== "undefined") if (typeof attr.defaultValue === "function") {
|
|
123
146
|
if (attr.type === "date" && attr.defaultValue.toString().includes("new Date()")) if (databaseType === "sqlite") type += `.default(sql\`(cast(unixepoch('subsecond') * 1000 as integer))\`)`;
|
|
124
147
|
else type += `.defaultNow()`;
|
|
@@ -129,7 +152,7 @@ const generateDrizzleSchema = async ({ options, file, adapter }) => {
|
|
|
129
152
|
}
|
|
130
153
|
return `${fieldName}: ${type}${attr.required ? ".notNull()" : ""}${attr.unique ? ".unique()" : ""}${attr.references ? `.references(()=> ${getModelName(tables[attr.references.model]?.modelName || attr.references.model, adapter.options)}.${fields[attr.references.field]?.fieldName || attr.references.field}, { onDelete: '${attr.references.onDelete || "cascade"}' })` : ""}`;
|
|
131
154
|
}).join(",\n ")}
|
|
132
|
-
|
|
155
|
+
}${assignIndexes(indexes)});`;
|
|
133
156
|
code += `\n${schema}\n`;
|
|
134
157
|
}
|
|
135
158
|
return {
|
|
@@ -150,7 +173,8 @@ function generateImport({ databaseType, tables, options }) {
|
|
|
150
173
|
}
|
|
151
174
|
if (hasJson && hasBigint) break;
|
|
152
175
|
}
|
|
153
|
-
const useNumberId = options.advanced?.database?.useNumberId;
|
|
176
|
+
const useNumberId = options.advanced?.database?.useNumberId || options.advanced?.database?.generateId === "serial";
|
|
177
|
+
const useUUIDs = options.advanced?.database?.generateId === "uuid";
|
|
154
178
|
coreImports.push(`${databaseType}Table`);
|
|
155
179
|
coreImports.push(databaseType === "mysql" ? "varchar, text" : databaseType === "pg" ? "text" : "text");
|
|
156
180
|
coreImports.push(hasBigint ? databaseType !== "sqlite" ? "bigint" : "" : "");
|
|
@@ -160,16 +184,24 @@ function generateImport({ databaseType, tables, options }) {
|
|
|
160
184
|
if (!!useNumberId || hasNonBigintNumber) coreImports.push("int");
|
|
161
185
|
if (Object.values(tables).some((table) => Object.values(table.fields).some((field) => typeof field.type !== "string" && Array.isArray(field.type) && field.type.every((x) => typeof x === "string")))) coreImports.push("mysqlEnum");
|
|
162
186
|
} else if (databaseType === "pg") {
|
|
187
|
+
if (useUUIDs) rootImports.push("sql");
|
|
163
188
|
const hasNonBigintNumber = Object.values(tables).some((table) => Object.values(table.fields).some((field) => (field.type === "number" || field.type === "number[]") && !field.bigint));
|
|
164
189
|
const hasFkToId = Object.values(tables).some((table) => Object.values(table.fields).some((field) => field.references?.field === "id"));
|
|
165
|
-
if (hasNonBigintNumber || options.advanced?.database?.useNumberId && hasFkToId) coreImports.push("integer");
|
|
190
|
+
if (hasNonBigintNumber || (options.advanced?.database?.useNumberId || options.advanced?.database?.generateId === "serial") && hasFkToId) coreImports.push("integer");
|
|
166
191
|
} else coreImports.push("integer");
|
|
167
|
-
|
|
192
|
+
if (databaseType === "pg") {
|
|
193
|
+
if (useNumberId) coreImports.push("serial");
|
|
194
|
+
else if (useUUIDs) coreImports.push("uuid");
|
|
195
|
+
}
|
|
168
196
|
if (hasJson) {
|
|
169
197
|
if (databaseType === "pg") coreImports.push("jsonb");
|
|
170
198
|
if (databaseType === "mysql") coreImports.push("json");
|
|
171
199
|
}
|
|
172
200
|
if (databaseType === "sqlite" && Object.values(tables).some((table) => Object.values(table.fields).some((field) => field.type === "date" && field.defaultValue && typeof field.defaultValue === "function" && field.defaultValue.toString().includes("new Date()")))) rootImports.push("sql");
|
|
201
|
+
const hasIndexes = Object.values(tables).some((table) => Object.values(table.fields).some((field) => field.index && !field.unique));
|
|
202
|
+
const hasUniqueIndexes = Object.values(tables).some((table) => Object.values(table.fields).some((field) => field.unique && field.index));
|
|
203
|
+
if (hasIndexes) coreImports.push("index");
|
|
204
|
+
if (hasUniqueIndexes) coreImports.push("uniqueIndex");
|
|
173
205
|
return `${rootImports.length > 0 ? `import { ${rootImports.join(", ")} } from "drizzle-orm";\n` : ""}import { ${coreImports.map((x) => x.trim()).filter((x) => x !== "").join(", ")} } from "drizzle-orm/${databaseType}-core";\n`;
|
|
174
206
|
}
|
|
175
207
|
function getModelName(modelName, options) {
|
|
@@ -211,6 +243,19 @@ const generatePrismaSchema = async ({ adapter, options, file }) => {
|
|
|
211
243
|
}
|
|
212
244
|
}
|
|
213
245
|
}
|
|
246
|
+
const indexedFields = /* @__PURE__ */ new Map();
|
|
247
|
+
for (const table in tables) {
|
|
248
|
+
const fields = tables[table]?.fields;
|
|
249
|
+
const modelName = capitalizeFirstLetter(tables[table]?.modelName || table);
|
|
250
|
+
indexedFields.set(modelName, []);
|
|
251
|
+
for (const field in fields) {
|
|
252
|
+
const attr = fields[field];
|
|
253
|
+
if (attr.index && !attr.unique) {
|
|
254
|
+
const fieldName = attr.fieldName || field;
|
|
255
|
+
indexedFields.get(modelName).push(fieldName);
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
}
|
|
214
259
|
const schema = produceSchema(schemaPrisma, (builder) => {
|
|
215
260
|
for (const table in tables) {
|
|
216
261
|
const originalTableName = table;
|
|
@@ -229,8 +274,13 @@ const generatePrismaSchema = async ({ adapter, options, file }) => {
|
|
|
229
274
|
}
|
|
230
275
|
const prismaModel = builder.findByType("model", { name: modelName });
|
|
231
276
|
if (!prismaModel) if (provider === "mongodb") builder.model(modelName).field("id", "String").attribute("id").attribute(`map("_id")`);
|
|
232
|
-
else
|
|
233
|
-
|
|
277
|
+
else {
|
|
278
|
+
const useNumberId = options.advanced?.database?.useNumberId || options.advanced?.database?.generateId === "serial";
|
|
279
|
+
const useUUIDs = options.advanced?.database?.generateId === "uuid";
|
|
280
|
+
if (useNumberId) builder.model(modelName).field("id", "Int").attribute("id").attribute("default(autoincrement())");
|
|
281
|
+
else if (useUUIDs && provider === "postgresql") builder.model(modelName).field("id", "String").attribute("id").attribute("db.Uuid").attribute("default(dbgenerated(\"pg_catalog.gen_random_uuid()\"))");
|
|
282
|
+
else builder.model(modelName).field("id", "String").attribute("id");
|
|
283
|
+
}
|
|
234
284
|
for (const field in fields) {
|
|
235
285
|
const attr = fields[field];
|
|
236
286
|
const fieldName = attr.fieldName || field;
|
|
@@ -240,14 +290,16 @@ const generatePrismaSchema = async ({ adapter, options, file }) => {
|
|
|
240
290
|
within: prismaModel.properties
|
|
241
291
|
})) continue;
|
|
242
292
|
}
|
|
243
|
-
const
|
|
293
|
+
const useUUIDs = options.advanced?.database?.generateId === "uuid";
|
|
294
|
+
const useNumberId = options.advanced?.database?.useNumberId || options.advanced?.database?.generateId === "serial";
|
|
295
|
+
const fieldBuilder = builder.model(modelName).field(fieldName, field === "id" && useNumberId ? getType({
|
|
244
296
|
isBigint: false,
|
|
245
297
|
isOptional: false,
|
|
246
298
|
type: "number"
|
|
247
299
|
}) : getType({
|
|
248
300
|
isBigint: attr?.bigint || false,
|
|
249
301
|
isOptional: !attr?.required,
|
|
250
|
-
type: attr.references?.field === "id" ?
|
|
302
|
+
type: attr.references?.field === "id" ? useNumberId ? "number" : "string" : attr.type
|
|
251
303
|
}));
|
|
252
304
|
if (field === "id") {
|
|
253
305
|
fieldBuilder.attribute("id");
|
|
@@ -255,13 +307,45 @@ const generatePrismaSchema = async ({ adapter, options, file }) => {
|
|
|
255
307
|
}
|
|
256
308
|
if (attr.unique) builder.model(modelName).blockAttribute(`unique([${fieldName}])`);
|
|
257
309
|
if (attr.defaultValue !== void 0) {
|
|
310
|
+
if (Array.isArray(attr.defaultValue)) {
|
|
311
|
+
if (attr.type === "json") {
|
|
312
|
+
if (Object.prototype.toString.call(attr.defaultValue[0]) === "[object Object]") {
|
|
313
|
+
fieldBuilder.attribute(`default("${JSON.stringify(attr.defaultValue).replace(/\\/g, "\\\\").replace(/"/g, "\\\"")}")`);
|
|
314
|
+
continue;
|
|
315
|
+
}
|
|
316
|
+
let jsonArray = [];
|
|
317
|
+
for (const value of attr.defaultValue) jsonArray.push(value);
|
|
318
|
+
fieldBuilder.attribute(`default("${JSON.stringify(jsonArray).replace(/"/g, "\\\"")}")`);
|
|
319
|
+
continue;
|
|
320
|
+
}
|
|
321
|
+
if (attr.defaultValue.length === 0) {
|
|
322
|
+
fieldBuilder.attribute(`default([])`);
|
|
323
|
+
continue;
|
|
324
|
+
} else if (typeof attr.defaultValue[0] === "string" && attr.type === "string[]") {
|
|
325
|
+
let valueArray = [];
|
|
326
|
+
for (const value of attr.defaultValue) valueArray.push(JSON.stringify(value));
|
|
327
|
+
fieldBuilder.attribute(`default([${valueArray}])`);
|
|
328
|
+
} else if (typeof attr.defaultValue[0] === "number") {
|
|
329
|
+
let valueArray = [];
|
|
330
|
+
for (const value of attr.defaultValue) valueArray.push(`${value}`);
|
|
331
|
+
fieldBuilder.attribute(`default([${valueArray}])`);
|
|
332
|
+
}
|
|
333
|
+
} else if (typeof attr.defaultValue === "object" && !Array.isArray(attr.defaultValue) && attr.defaultValue !== null) {
|
|
334
|
+
if (Object.entries(attr.defaultValue).length === 0) {
|
|
335
|
+
fieldBuilder.attribute(`default("{}")`);
|
|
336
|
+
continue;
|
|
337
|
+
}
|
|
338
|
+
fieldBuilder.attribute(`default("${JSON.stringify(attr.defaultValue).replace(/\\/g, "\\\\").replace(/"/g, "\\\"")}")`);
|
|
339
|
+
}
|
|
258
340
|
if (field === "createdAt") fieldBuilder.attribute("default(now())");
|
|
259
|
-
else if (typeof attr.defaultValue === "
|
|
341
|
+
else if (typeof attr.defaultValue === "string" && provider !== "mysql") fieldBuilder.attribute(`default("${attr.defaultValue}")`);
|
|
342
|
+
else if (typeof attr.defaultValue === "boolean" || typeof attr.defaultValue === "number") fieldBuilder.attribute(`default(${attr.defaultValue})`);
|
|
260
343
|
else if (typeof attr.defaultValue === "function") {}
|
|
261
344
|
}
|
|
262
345
|
if (field === "updatedAt" && attr.onUpdate) fieldBuilder.attribute("updatedAt");
|
|
263
346
|
else if (attr.onUpdate) {}
|
|
264
347
|
if (attr.references) {
|
|
348
|
+
if (useUUIDs && provider === "postgresql") fieldBuilder.attribute(`db.Uuid`);
|
|
265
349
|
const referencedOriginalModelName = attr.references.model;
|
|
266
350
|
const referencedCustomModelName = tables[referencedOriginalModelName]?.modelName || referencedOriginalModelName;
|
|
267
351
|
let action = "Cascade";
|
|
@@ -269,7 +353,8 @@ const generatePrismaSchema = async ({ adapter, options, file }) => {
|
|
|
269
353
|
else if (attr.references.onDelete === "set null") action = "SetNull";
|
|
270
354
|
else if (attr.references.onDelete === "set default") action = "SetDefault";
|
|
271
355
|
else if (attr.references.onDelete === "restrict") action = "Restrict";
|
|
272
|
-
|
|
356
|
+
const relationField = `relation(fields: [${fieldName}], references: [${attr.references.field}], onDelete: ${action})`;
|
|
357
|
+
builder.model(modelName).field(referencedCustomModelName.toLowerCase(), `${capitalizeFirstLetter(referencedCustomModelName)}${!attr.required ? "?" : ""}`).attribute(relationField);
|
|
273
358
|
}
|
|
274
359
|
if (!attr.unique && !attr.references && provider === "mysql" && attr.type === "string") builder.model(modelName).field(fieldName).attribute("db.Text");
|
|
275
360
|
}
|
|
@@ -280,6 +365,18 @@ const generatePrismaSchema = async ({ adapter, options, file }) => {
|
|
|
280
365
|
within: prismaModel?.properties
|
|
281
366
|
})) builder.model(modelName).field(fieldName, `${relatedModel}[]`);
|
|
282
367
|
}
|
|
368
|
+
const indexedFieldsForModel = indexedFields.get(modelName);
|
|
369
|
+
if (indexedFieldsForModel && indexedFieldsForModel.length > 0) for (const fieldName of indexedFieldsForModel) {
|
|
370
|
+
const field = Object.entries(fields).find(([key, attr]) => (attr.fieldName || key) === fieldName)?.[1];
|
|
371
|
+
let indexField = fieldName;
|
|
372
|
+
if (provider === "mysql" && field && field.type === "string") {
|
|
373
|
+
const useNumberId = options.advanced?.database?.useNumberId || options.advanced?.database?.generateId === "serial";
|
|
374
|
+
const useUUIDs = options.advanced?.database?.generateId === "uuid";
|
|
375
|
+
if (field.references?.field === "id" && (useNumberId || useUUIDs)) indexField = `${fieldName}`;
|
|
376
|
+
else indexField = `${fieldName}(length: 191)`;
|
|
377
|
+
}
|
|
378
|
+
builder.model(modelName).blockAttribute(`index([${indexField}])`);
|
|
379
|
+
}
|
|
283
380
|
const hasAttribute = builder.findByType("attribute", {
|
|
284
381
|
name: "map",
|
|
285
382
|
within: prismaModel?.properties
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@better-auth/cli",
|
|
3
|
-
"version": "1.4.0-beta.
|
|
3
|
+
"version": "1.4.0-beta.20",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "The CLI for Better Auth",
|
|
6
6
|
"module": "dist/index.mjs",
|
|
@@ -34,7 +34,7 @@
|
|
|
34
34
|
"tsx": "^4.20.6",
|
|
35
35
|
"type-fest": "^5.2.0",
|
|
36
36
|
"typescript": "^5.9.3",
|
|
37
|
-
"@better-auth/passkey": "1.4.0-beta.
|
|
37
|
+
"@better-auth/passkey": "1.4.0-beta.20"
|
|
38
38
|
},
|
|
39
39
|
"dependencies": {
|
|
40
40
|
"@babel/core": "^7.28.4",
|
|
@@ -62,7 +62,8 @@
|
|
|
62
62
|
"tinyexec": "^0.3.2",
|
|
63
63
|
"yocto-spinner": "^0.2.3",
|
|
64
64
|
"zod": "^4.1.12",
|
|
65
|
-
"better-auth": "1.4.0-beta.
|
|
65
|
+
"better-auth": "1.4.0-beta.20",
|
|
66
|
+
"@better-auth/core": "1.4.0-beta.20"
|
|
66
67
|
},
|
|
67
68
|
"files": [
|
|
68
69
|
"dist"
|