create-absolutejs 0.18.0 → 0.19.0
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/CHANGELOG.md +10 -0
- package/changelog.json +14 -0
- package/dist/commands/migrateDatabase.d.ts +6 -0
- package/dist/commands/migrateDatabase.js +53 -0
- package/dist/data.d.ts +1 -1
- package/dist/data.js +1 -0
- package/dist/generators/configurations/generateDrizzleConfig.d.ts +5 -3
- package/dist/generators/configurations/generateDrizzleConfig.js +40 -14
- package/dist/generators/configurations/generateEnv.js +6 -0
- package/dist/generators/configurations/generatePackageJson.js +30 -3
- package/dist/generators/db/drizzleTargets.d.ts +5 -0
- package/dist/generators/db/drizzleTargets.js +27 -0
- package/dist/generators/db/generateDatabaseTypes.js +10 -6
- package/dist/generators/db/generateDockerContainer.d.ts +5 -0
- package/dist/generators/db/generateDockerContainer.js +22 -4
- package/dist/generators/db/generateDrizzleSchema.js +65 -81
- package/dist/generators/db/handlerTemplates.d.ts +4 -4
- package/dist/generators/db/handlerTemplates.js +7 -10
- package/dist/generators/db/scaffoldDatabase.js +17 -4
- package/dist/generators/db/scaffoldDocker.d.ts +2 -1
- package/dist/generators/db/scaffoldDocker.js +7 -3
- package/dist/generators/project/generateDBBlock.js +11 -2
- package/dist/generators/project/generateImportsBlock.js +11 -6
- package/dist/generators/project/generateServer.js +2 -1
- package/dist/index.js +2 -1
- package/dist/messages.d.ts +2 -1
- package/dist/messages.js +2 -1
- package/dist/questions/authOption.js +4 -1
- package/dist/questions/databaseEngine.d.ts +1 -1
- package/dist/scaffold.d.ts +1 -0
- package/dist/scaffold.js +21 -3
- package/dist/templates/configurations/eslint.config.example.mjs +80 -41
- package/dist/templates/db/migrations/cockroach-count-history/20260926210314_init/migration.sql +5 -0
- package/dist/templates/db/migrations/cockroach-count-history/20260926210314_init/snapshot.json +69 -0
- package/dist/templates/db/migrations/cockroach-users/20260926210315_init/migration.sql +5 -0
- package/dist/templates/db/migrations/cockroach-users/20260926210315_init/snapshot.json +62 -0
- package/dist/templates/db/migrations/mssql-count-history/20260926210316_init/migration.sql +6 -0
- package/dist/templates/db/migrations/mssql-count-history/20260926210316_init/snapshot.json +64 -0
- package/dist/templates/db/migrations/mssql-users/20260926210317_init/migration.sql +6 -0
- package/dist/templates/db/migrations/mssql-users/20260926210317_init/snapshot.json +70 -0
- package/dist/templates/db/migrations/mysql-count-history/20260926210318_init/migration.sql +5 -0
- package/dist/templates/db/migrations/mysql-count-history/20260926210318_init/snapshot.json +61 -0
- package/dist/templates/db/migrations/mysql-users/20260926210319_init/migration.sql +5 -0
- package/dist/templates/db/migrations/mysql-users/20260926210319_init/snapshot.json +61 -0
- package/dist/templates/db/migrations/postgresql-count-history/20260926210320_init/migration.sql +5 -0
- package/dist/templates/db/migrations/postgresql-count-history/20260926210320_init/snapshot.json +71 -0
- package/dist/templates/db/migrations/postgresql-users/20260926210320_init/migration.sql +5 -0
- package/dist/templates/db/migrations/postgresql-users/20260926210320_init/snapshot.json +62 -0
- package/dist/templates/db/migrations/singlestore-count-history/20260926210321_init/migration.sql +5 -0
- package/dist/templates/db/migrations/singlestore-count-history/20260926210321_init/snapshot.json +61 -0
- package/dist/templates/db/migrations/singlestore-users/20260926210322_init/migration.sql +5 -0
- package/dist/templates/db/migrations/singlestore-users/20260926210322_init/snapshot.json +61 -0
- package/dist/templates/db/migrations/sqlite-count-history/20260926210323_init/migration.sql +5 -0
- package/dist/templates/db/migrations/sqlite-count-history/20260926210323_init/snapshot.json +50 -0
- package/dist/templates/db/migrations/sqlite-users/20260926210324_init/migration.sql +5 -0
- package/dist/templates/db/migrations/sqlite-users/20260926210324_init/snapshot.json +50 -0
- package/dist/templates/db/migrations/turso-count-history/20260926210324_init/migration.sql +5 -0
- package/dist/templates/db/migrations/turso-count-history/20260926210324_init/snapshot.json +50 -0
- package/dist/templates/db/migrations/turso-users/20260926210325_init/migration.sql +5 -0
- package/dist/templates/db/migrations/turso-users/20260926210325_init/snapshot.json +50 -0
- package/dist/templates/git/gitignore +0 -3
- package/dist/typeGuards.js +2 -2
- package/dist/utils/parseCommandLineOptions.js +16 -25
- package/dist/utils/validateDatabaseSelection.d.ts +11 -0
- package/dist/utils/validateDatabaseSelection.js +31 -0
- package/package.json +3 -1
- package/dist/templates/configurations/drizzle.config.ts +0 -13
|
@@ -269,14 +269,12 @@ const mysqlDrizzleQueryOperations = {
|
|
|
269
269
|
.where(eq(schema.countHistory.uid, uid));
|
|
270
270
|
|
|
271
271
|
return newHistory;`,
|
|
272
|
-
insertUser: `
|
|
273
|
-
.insert(schema.users)
|
|
274
|
-
.values({ auth_sub: authSub, metadata: userIdentity });
|
|
272
|
+
insertUser: `await db.insert(schema.users).values(newUserData);
|
|
275
273
|
|
|
276
274
|
const [newUser] = await db
|
|
277
275
|
.select()
|
|
278
276
|
.from(schema.users)
|
|
279
|
-
.where(eq(schema.users.auth_sub,
|
|
277
|
+
.where(eq(schema.users.auth_sub, newUserData.auth_sub));
|
|
280
278
|
|
|
281
279
|
if (!newUser) throw new Error('Failed to create user');
|
|
282
280
|
return newUser;`,
|
|
@@ -337,16 +335,15 @@ const mysqlPlanetScaleQueryOperations = {
|
|
|
337
335
|
`
|
|
338
336
|
};
|
|
339
337
|
const driverConfigurations = {
|
|
338
|
+
'cockroachdb:drizzle:local': {
|
|
339
|
+
importLines: `import { eq } from 'drizzle-orm'
|
|
340
|
+
import { schema } from '../../../db/schema'`,
|
|
341
|
+
queries: drizzleQueryOperations
|
|
342
|
+
},
|
|
340
343
|
'cockroachdb:sql:local': {
|
|
341
344
|
importLines: ``,
|
|
342
345
|
queries: postgresSqlQueryOperations
|
|
343
346
|
},
|
|
344
|
-
'gel:drizzle:local': {
|
|
345
|
-
importLines: `import { eq } from 'drizzle-orm'
|
|
346
|
-
import { schema } from '../../../db/schema'
|
|
347
|
-
`,
|
|
348
|
-
queries: drizzleQueryOperations
|
|
349
|
-
},
|
|
350
347
|
'gel:sql:local': {
|
|
351
348
|
importLines: ``,
|
|
352
349
|
queries: gelClientQueryOperations
|
|
@@ -1,9 +1,11 @@
|
|
|
1
|
-
import { mkdirSync, writeFileSync } from 'fs';
|
|
2
|
-
import { join } from 'path';
|
|
1
|
+
import { cpSync, mkdirSync, writeFileSync } from 'fs';
|
|
2
|
+
import { dirname, join } from 'path';
|
|
3
|
+
import { fileURLToPath } from 'url';
|
|
3
4
|
import { dim, yellow } from 'picocolors';
|
|
4
5
|
import { isDrizzleDialect } from '../../typeGuards';
|
|
5
6
|
import { checkSqliteInstalled } from '../../utils/checkSqliteInstalled';
|
|
6
7
|
import { createDrizzleConfig } from '../configurations/generateDrizzleConfig';
|
|
8
|
+
import { getDrizzleKitDialect, getMigrationTemplateName } from './drizzleTargets';
|
|
7
9
|
import { generateDatabaseTypes } from './generateDatabaseTypes';
|
|
8
10
|
import { generateDrizzleSchema } from './generateDrizzleSchema';
|
|
9
11
|
import { generateDBHandlers } from './generateHandlers';
|
|
@@ -50,7 +52,10 @@ export const scaffoldDatabase = async ({ projectName, databaseEngine, databaseHo
|
|
|
50
52
|
supportsRelationalSchema(databaseEngine)) {
|
|
51
53
|
writeFileSync(join(projectDatabaseDirectory, 'schema.sql'), generateRelationalSchema(databaseEngine, authOption));
|
|
52
54
|
}
|
|
53
|
-
|
|
55
|
+
/* Drizzle projects get their tables from the committed initial migration
|
|
56
|
+
(`db:migrate`), never from hand-written DDL, so the migration history and
|
|
57
|
+
the database always agree. */
|
|
58
|
+
if (databaseEngine === 'sqlite' && orm !== 'drizzle') {
|
|
54
59
|
// The sqlite3 CLI is a developer convenience (a db shell), never a
|
|
55
60
|
// scaffold requirement — seeding goes through bun:sqlite below, which
|
|
56
61
|
// ships with the runtime. The check only nudges interactive users;
|
|
@@ -72,6 +77,7 @@ export const scaffoldDatabase = async ({ projectName, databaseEngine, databaseHo
|
|
|
72
77
|
const result = await scaffoldDocker({
|
|
73
78
|
authOption,
|
|
74
79
|
databaseEngine,
|
|
80
|
+
initializeSchema: orm !== 'drizzle',
|
|
75
81
|
projectDatabaseDirectory,
|
|
76
82
|
projectName,
|
|
77
83
|
verifyLocalDatabase
|
|
@@ -87,7 +93,14 @@ export const scaffoldDatabase = async ({ projectName, databaseEngine, databaseHo
|
|
|
87
93
|
databaseEngine
|
|
88
94
|
});
|
|
89
95
|
writeFileSync(join(projectDatabaseDirectory, 'schema.ts'), drizzleSchema);
|
|
90
|
-
createDrizzleConfig({
|
|
96
|
+
createDrizzleConfig({
|
|
97
|
+
databaseDirectory,
|
|
98
|
+
databaseEngine,
|
|
99
|
+
databaseHost,
|
|
100
|
+
projectName
|
|
101
|
+
});
|
|
102
|
+
const templatesDirectory = join(dirname(fileURLToPath(import.meta.url)), '..', '..', 'templates');
|
|
103
|
+
cpSync(join(templatesDirectory, 'db', 'migrations', getMigrationTemplateName(getDrizzleKitDialect(databaseEngine, databaseHost), usesAuth)), join(projectDatabaseDirectory, 'migrations'), { recursive: true });
|
|
91
104
|
const drizzleTypes = generateDatabaseTypes({
|
|
92
105
|
authOption,
|
|
93
106
|
databaseEngine,
|
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
import { AuthOption, DatabaseEngine } from '../../types';
|
|
2
2
|
type ScaffoldDockerProps = {
|
|
3
|
+
initializeSchema?: boolean;
|
|
3
4
|
verifyLocalDatabase?: boolean;
|
|
4
5
|
databaseEngine: DatabaseEngine;
|
|
5
6
|
projectDatabaseDirectory: string;
|
|
6
7
|
authOption: AuthOption;
|
|
7
8
|
projectName: string;
|
|
8
9
|
};
|
|
9
|
-
export declare const scaffoldDocker: ({ databaseEngine, projectDatabaseDirectory, projectName, authOption, verifyLocalDatabase }: ScaffoldDockerProps) => Promise<{
|
|
10
|
+
export declare const scaffoldDocker: ({ databaseEngine, projectDatabaseDirectory, projectName, authOption, initializeSchema, verifyLocalDatabase }: ScaffoldDockerProps) => Promise<{
|
|
10
11
|
dockerFreshInstall: boolean;
|
|
11
12
|
}>;
|
|
12
13
|
export {};
|
|
@@ -5,7 +5,7 @@ import { $ } from 'bun';
|
|
|
5
5
|
import { green, red } from 'picocolors';
|
|
6
6
|
import { checkDockerInstalled, ensureDockerDaemonRunning, resolveDockerExe, shutdownDockerDaemon } from '../../utils/checkDockerInstalled';
|
|
7
7
|
import { countHistoryTables, initTemplates, userTables } from './dockerInitTemplates';
|
|
8
|
-
import { generateDockerContainer } from './generateDockerContainer';
|
|
8
|
+
import { generateDockerContainer, getDockerInitScript } from './generateDockerContainer';
|
|
9
9
|
const initDockerSchema = async ({ authOption, databaseEngine, docker, projectName, spin }) => {
|
|
10
10
|
const dbKey = databaseEngine;
|
|
11
11
|
const { wait, cli } = initTemplates[dbKey];
|
|
@@ -33,7 +33,7 @@ const verifyDockerContainer = async ({ databaseEngine, docker, projectName, spin
|
|
|
33
33
|
.cwd(projectName)
|
|
34
34
|
.quiet();
|
|
35
35
|
};
|
|
36
|
-
export const scaffoldDocker = async ({ databaseEngine, projectDatabaseDirectory, projectName, authOption, verifyLocalDatabase = true }) => {
|
|
36
|
+
export const scaffoldDocker = async ({ databaseEngine, projectDatabaseDirectory, projectName, authOption, initializeSchema = true, verifyLocalDatabase = true }) => {
|
|
37
37
|
if (databaseEngine === undefined ||
|
|
38
38
|
databaseEngine === 'none' ||
|
|
39
39
|
databaseEngine === 'sqlite') {
|
|
@@ -41,6 +41,10 @@ export const scaffoldDocker = async ({ databaseEngine, projectDatabaseDirectory,
|
|
|
41
41
|
}
|
|
42
42
|
const dbContainer = generateDockerContainer(databaseEngine);
|
|
43
43
|
writeFileSync(join(projectDatabaseDirectory, 'docker-compose.db.yml'), dbContainer, 'utf-8');
|
|
44
|
+
const initScript = getDockerInitScript(databaseEngine);
|
|
45
|
+
if (initScript) {
|
|
46
|
+
writeFileSync(join(projectDatabaseDirectory, initScript.fileName), initScript.sql, 'utf-8');
|
|
47
|
+
}
|
|
44
48
|
if (!verifyLocalDatabase)
|
|
45
49
|
return { dockerFreshInstall: false };
|
|
46
50
|
const { freshInstall } = await checkDockerInstalled(databaseEngine);
|
|
@@ -48,7 +52,7 @@ export const scaffoldDocker = async ({ databaseEngine, projectDatabaseDirectory,
|
|
|
48
52
|
const docker = resolveDockerExe();
|
|
49
53
|
const spin = spinner();
|
|
50
54
|
spin.start(`Starting ${databaseEngine} container`);
|
|
51
|
-
const dockerAction = databaseEngine in userTables
|
|
55
|
+
const dockerAction = initializeSchema && databaseEngine in userTables
|
|
52
56
|
? () => initDockerSchema({
|
|
53
57
|
authOption,
|
|
54
58
|
databaseEngine,
|
|
@@ -1,4 +1,7 @@
|
|
|
1
1
|
import { availableDrizzleDialects } from '../../data';
|
|
2
|
+
/* A Turso database needs its auth token; a local libSQL `file:` URL has none,
|
|
3
|
+
so the token stays optional. */
|
|
4
|
+
const tursoClient = 'createClient({ authToken: env.DATABASE_AUTH_TOKEN, url: getEnv("DATABASE_URL") })';
|
|
2
5
|
const connectionMap = {
|
|
3
6
|
cockroachdb: {
|
|
4
7
|
none: { expr: 'new SQL(getEnv("DATABASE_URL"))' }
|
|
@@ -36,13 +39,13 @@ const connectionMap = {
|
|
|
36
39
|
},
|
|
37
40
|
sqlite: {
|
|
38
41
|
none: { expr: 'new Database("db/database.sqlite")' },
|
|
39
|
-
turso: { expr:
|
|
42
|
+
turso: { expr: tursoClient }
|
|
40
43
|
}
|
|
41
44
|
};
|
|
42
45
|
const remoteDrizzleInit = {
|
|
43
46
|
neon: 'neon(getEnv("DATABASE_URL"));',
|
|
44
47
|
planetscale: 'new Client({ url: getEnv("DATABASE_URL") })',
|
|
45
|
-
turso:
|
|
48
|
+
turso: tursoClient
|
|
46
49
|
};
|
|
47
50
|
const drizzleDialectSet = new Set([...availableDrizzleDialects]);
|
|
48
51
|
export const generateDBBlock = ({ databaseEngine, orm, databaseHost }) => {
|
|
@@ -67,6 +70,12 @@ export const generateDBBlock = ({ databaseEngine, orm, databaseHost }) => {
|
|
|
67
70
|
return `
|
|
68
71
|
const pool = createPool(getEnv("DATABASE_URL"))
|
|
69
72
|
const db = drizzle({ client: pool })
|
|
73
|
+
`;
|
|
74
|
+
}
|
|
75
|
+
if (databaseEngine === 'cockroachdb') {
|
|
76
|
+
return `
|
|
77
|
+
const pool = new Pool({ connectionString: getEnv("DATABASE_URL") })
|
|
78
|
+
const db = drizzle({ client: pool })
|
|
70
79
|
`;
|
|
71
80
|
}
|
|
72
81
|
if (databaseEngine === 'mssql' && hostKey === 'none') {
|
|
@@ -42,7 +42,10 @@ export const generateImportsBlock = ({ deps, flags, orm, authOption, databaseEng
|
|
|
42
42
|
const connectorImports = {
|
|
43
43
|
neon: [`import { neon } from '@neondatabase/serverless'`],
|
|
44
44
|
planetscale: [`import { Client } from '@planetscale/database'`],
|
|
45
|
-
turso: [
|
|
45
|
+
turso: [
|
|
46
|
+
`import { createClient } from '@libsql/client'`,
|
|
47
|
+
`import { env } from 'bun'`
|
|
48
|
+
]
|
|
46
49
|
};
|
|
47
50
|
const dialectImports = {
|
|
48
51
|
neon: [`import { drizzle } from 'drizzle-orm/neon-http'`],
|
|
@@ -77,13 +80,15 @@ export const generateImportsBlock = ({ deps, flags, orm, authOption, databaseEng
|
|
|
77
80
|
};
|
|
78
81
|
const ormDatabaseImports = {
|
|
79
82
|
drizzle: {
|
|
80
|
-
|
|
81
|
-
`import {
|
|
82
|
-
`import {
|
|
83
|
+
cockroachdb: [
|
|
84
|
+
`import { drizzle } from 'drizzle-orm/cockroach'`,
|
|
85
|
+
`import { Pool } from 'pg'`
|
|
83
86
|
],
|
|
87
|
+
/* drizzle-orm/mysql2 1.0 sets options on the pool's `config`, which
|
|
88
|
+
only mysql2's callback pool has; it wraps it in .promise() itself. */
|
|
84
89
|
mariadb: [
|
|
85
90
|
`import { drizzle } from 'drizzle-orm/mysql2'`,
|
|
86
|
-
`import { createPool } from 'mysql2
|
|
91
|
+
`import { createPool } from 'mysql2'`
|
|
87
92
|
],
|
|
88
93
|
mssql: [
|
|
89
94
|
`import { connect } from 'mssql'`,
|
|
@@ -92,7 +97,7 @@ export const generateImportsBlock = ({ deps, flags, orm, authOption, databaseEng
|
|
|
92
97
|
mysql: !isRemoteHost
|
|
93
98
|
? [
|
|
94
99
|
`import { drizzle } from 'drizzle-orm/mysql2'`,
|
|
95
|
-
`import { createPool } from 'mysql2
|
|
100
|
+
`import { createPool } from 'mysql2'`
|
|
96
101
|
]
|
|
97
102
|
: [],
|
|
98
103
|
postgresql: getPostgresqlOrmDatabaseImports(),
|
|
@@ -34,7 +34,8 @@ export const generateServerFile = ({ tailwind, authOption, plugins, buildDirecto
|
|
|
34
34
|
const useBlock = deps
|
|
35
35
|
.flatMap((dependency) => dependency.imports ?? [])
|
|
36
36
|
.filter((pluginImport) => pluginImport.isPlugin &&
|
|
37
|
-
pluginImport.packageName !== 'networking' &&
|
|
37
|
+
pluginImport.packageName !== 'networking' &&
|
|
38
|
+
pluginImport.packageName !== 'openapi')
|
|
38
39
|
.map((pluginImport) => {
|
|
39
40
|
if (pluginImport.packageName === 'auth') {
|
|
40
41
|
return 'authPlugin';
|
package/dist/index.js
CHANGED
|
@@ -14,7 +14,7 @@ if (help === true) {
|
|
|
14
14
|
exit(0);
|
|
15
15
|
}
|
|
16
16
|
const response = await prompt(argumentConfiguration);
|
|
17
|
-
const { dockerFreshInstall } = await scaffold({
|
|
17
|
+
const { databaseMigrationPending, dockerFreshInstall } = await scaffold({
|
|
18
18
|
envVariables,
|
|
19
19
|
latest,
|
|
20
20
|
packageManager,
|
|
@@ -27,6 +27,7 @@ const debugMessage = debug !== false
|
|
|
27
27
|
})
|
|
28
28
|
: '';
|
|
29
29
|
const outroMessage = getOutroMessage({
|
|
30
|
+
databaseMigrationPending,
|
|
30
31
|
installDependenciesNow: response.installDependenciesNow,
|
|
31
32
|
packageManager,
|
|
32
33
|
projectName: response.projectName
|
package/dist/messages.d.ts
CHANGED
|
@@ -4,8 +4,9 @@ type OutroMessageProps = {
|
|
|
4
4
|
projectName: string;
|
|
5
5
|
packageManager: string;
|
|
6
6
|
installDependenciesNow: boolean;
|
|
7
|
+
databaseMigrationPending: boolean;
|
|
7
8
|
};
|
|
8
|
-
export declare const getOutroMessage: ({ projectName, packageManager, installDependenciesNow }: OutroMessageProps) => string;
|
|
9
|
+
export declare const getOutroMessage: ({ databaseMigrationPending, projectName, packageManager, installDependenciesNow }: OutroMessageProps) => string;
|
|
9
10
|
type DebugMessageProps = {
|
|
10
11
|
response: CreateConfiguration;
|
|
11
12
|
packageManager: string;
|
package/dist/messages.js
CHANGED
|
@@ -46,9 +46,10 @@ Options:
|
|
|
46
46
|
${cyan('--vue')} Include a Vue frontend
|
|
47
47
|
${cyan('--vue-dir')} ${dim(cyan('<directory>'))} Specify the directory for and use the Vue frontend
|
|
48
48
|
`;
|
|
49
|
-
export const getOutroMessage = ({ projectName, packageManager, installDependenciesNow }) => `${green('Created successfully')}, you can now run:\n\n` +
|
|
49
|
+
export const getOutroMessage = ({ databaseMigrationPending, projectName, packageManager, installDependenciesNow }) => `${green('Created successfully')}, you can now run:\n\n` +
|
|
50
50
|
`${cyan('cd')} ${projectName}\n` +
|
|
51
51
|
`${installDependenciesNow ? '' : `${cyan(`${packageManager} install`)}\n`}` +
|
|
52
|
+
`${databaseMigrationPending ? `${cyan(`${packageManager} run db:migrate`)}\n` : ''}` +
|
|
52
53
|
`${cyan(`${packageManager} dev`)}`; // TODO: Some package managers need run
|
|
53
54
|
export const getDebugMessage = ({ response: { agentic, projectName, codeQualityTool, directoryConfig, useTailwind, tailwind, frontends, includeExamples, useHTMLScripts, frontendDirectories, buildDirectory, assetsDirectory, databaseEngine, databaseHost, databaseDirectory, orm, authOption, plugins, initializeGitNow, installDependenciesNow }, packageManager }) => {
|
|
54
55
|
const htmlScriptingValue = useHTMLScripts
|
|
@@ -6,7 +6,10 @@ export const getAuthOption = async () => {
|
|
|
6
6
|
message: 'Auth provider:',
|
|
7
7
|
options: [
|
|
8
8
|
{ label: 'None', value: 'none' },
|
|
9
|
-
{
|
|
9
|
+
{
|
|
10
|
+
label: cyan('Absolute Auth (Google; requires a database)'),
|
|
11
|
+
value: 'abs'
|
|
12
|
+
}
|
|
10
13
|
]
|
|
11
14
|
});
|
|
12
15
|
if (isCancel(authOption))
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare const getDatabaseEngine: () => Promise<"mariadb" | "mssql" | "mysql" | "postgresql" | "singlestore" | "sqlite" | "mongodb" | "
|
|
1
|
+
export declare const getDatabaseEngine: () => Promise<"cockroachdb" | "mariadb" | "mssql" | "mysql" | "postgresql" | "singlestore" | "sqlite" | "mongodb" | "gel" | undefined>;
|
package/dist/scaffold.d.ts
CHANGED
|
@@ -7,6 +7,7 @@ type ScaffoldProps = {
|
|
|
7
7
|
verifyLocalDatabase?: boolean;
|
|
8
8
|
};
|
|
9
9
|
export declare const scaffold: ({ response: { agentic, projectName, codeQualityTool, initializeGitNow, githubLink, githubRepoUrl, githubVisibility, databaseEngine, databaseHost, useHTMLScripts, useTailwind, databaseDirectory, absProviders, includeExamples, orm, frontends, plugins, authOption, buildDirectory, assetsDirectory, tailwind, installDependenciesNow, frontendDirectories }, latest, verifyLocalDatabase, envVariables, packageManager }: ScaffoldProps) => Promise<{
|
|
10
|
+
databaseMigrationPending: boolean;
|
|
10
11
|
dockerFreshInstall: boolean;
|
|
11
12
|
}>;
|
|
12
13
|
export {};
|
package/dist/scaffold.js
CHANGED
|
@@ -4,6 +4,7 @@ import { fileURLToPath } from 'url';
|
|
|
4
4
|
import { formatProject } from './commands/formatProject';
|
|
5
5
|
import { initializeGit } from './commands/initializeGit';
|
|
6
6
|
import { installDependencies } from './commands/installDependencies';
|
|
7
|
+
import { migrateDatabase } from './commands/migrateDatabase';
|
|
7
8
|
import { createPackageJson } from './generators/configurations/generatePackageJson';
|
|
8
9
|
import { initalizeRoot } from './generators/configurations/initializeRoot';
|
|
9
10
|
import { scaffoldConfigurationFiles } from './generators/configurations/scaffoldConfigurationFiles';
|
|
@@ -11,9 +12,15 @@ import { scaffoldDatabase } from './generators/db/scaffoldDatabase';
|
|
|
11
12
|
import { scaffoldAgentic } from './generators/project/scaffoldAgentic';
|
|
12
13
|
import { scaffoldBackend } from './generators/project/scaffoldBackend';
|
|
13
14
|
import { scaffoldFrontends } from './generators/project/scaffoldFrontends';
|
|
15
|
+
import { validateDatabaseSelection } from './utils/validateDatabaseSelection';
|
|
14
16
|
export const scaffold = async ({ response: { agentic, projectName, codeQualityTool, initializeGitNow, githubLink, githubRepoUrl, githubVisibility, databaseEngine, databaseHost, useHTMLScripts, useTailwind, databaseDirectory, absProviders, includeExamples, orm, frontends, plugins, authOption, buildDirectory, assetsDirectory, tailwind, installDependenciesNow, frontendDirectories }, latest, verifyLocalDatabase = true, envVariables, packageManager }) => {
|
|
15
|
-
|
|
16
|
-
|
|
17
|
+
const { errors: databaseErrors } = validateDatabaseSelection({
|
|
18
|
+
databaseEngine,
|
|
19
|
+
databaseHost,
|
|
20
|
+
orm
|
|
21
|
+
});
|
|
22
|
+
if (databaseErrors.length > 0)
|
|
23
|
+
throw new Error(databaseErrors.join('\n'));
|
|
17
24
|
if (orm === 'prisma')
|
|
18
25
|
throw new Error('Prisma scaffolding is not implemented. Choose Drizzle or no ORM.');
|
|
19
26
|
if (authOption === 'abs' && (!databaseEngine || databaseEngine === 'none'))
|
|
@@ -114,6 +121,14 @@ export const server = treaty<Api>(serverUrl)
|
|
|
114
121
|
if (installDependenciesNow) {
|
|
115
122
|
await installDependencies(packageManager, projectName);
|
|
116
123
|
}
|
|
124
|
+
const databaseMigrated = orm === 'drizzle' &&
|
|
125
|
+
installDependenciesNow &&
|
|
126
|
+
(await migrateDatabase({
|
|
127
|
+
databaseEngine,
|
|
128
|
+
databaseHost,
|
|
129
|
+
projectName,
|
|
130
|
+
verifyLocalDatabase
|
|
131
|
+
}));
|
|
117
132
|
await formatProject({
|
|
118
133
|
installDependenciesNow,
|
|
119
134
|
packageManager,
|
|
@@ -127,5 +142,8 @@ export const server = treaty<Api>(serverUrl)
|
|
|
127
142
|
projectName
|
|
128
143
|
});
|
|
129
144
|
}
|
|
130
|
-
return {
|
|
145
|
+
return {
|
|
146
|
+
databaseMigrationPending: orm === 'drizzle' && !databaseMigrated,
|
|
147
|
+
dockerFreshInstall
|
|
148
|
+
};
|
|
131
149
|
};
|
|
@@ -1,48 +1,87 @@
|
|
|
1
|
-
|
|
2
1
|
import { defineConfig } from 'eslint/config';
|
|
3
2
|
import absolute from 'eslint-plugin-absolute';
|
|
4
3
|
import reactHooks from 'eslint-plugin-react-hooks';
|
|
5
4
|
import tseslint from 'typescript-eslint';
|
|
6
5
|
|
|
7
6
|
export default defineConfig([
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
7
|
+
{
|
|
8
|
+
ignores: [
|
|
9
|
+
'node_modules/**',
|
|
10
|
+
'build/**',
|
|
11
|
+
'dist/**',
|
|
12
|
+
'.absolutejs/**',
|
|
13
|
+
'.data/**',
|
|
14
|
+
'**/.absolutejs-hmr-*',
|
|
15
|
+
'drizzle/**'
|
|
16
|
+
]
|
|
17
|
+
},
|
|
18
|
+
{
|
|
19
|
+
linterOptions: {
|
|
20
|
+
noInlineConfig: true,
|
|
21
|
+
reportUnusedDisableDirectives: 'error'
|
|
22
|
+
}
|
|
23
|
+
},
|
|
24
|
+
...tseslint.configs.recommended,
|
|
25
|
+
{
|
|
26
|
+
files: ['**/*.{ts,tsx,js,jsx,mjs}'],
|
|
27
|
+
plugins: { absolute },
|
|
28
|
+
rules: {
|
|
29
|
+
'@typescript-eslint/ban-ts-comment': [
|
|
30
|
+
'error',
|
|
31
|
+
{
|
|
32
|
+
'ts-check': true,
|
|
33
|
+
'ts-expect-error': true,
|
|
34
|
+
'ts-ignore': true,
|
|
35
|
+
'ts-nocheck': true
|
|
36
|
+
}
|
|
37
|
+
],
|
|
38
|
+
'absolute/button-icon-is-hidden': 'error',
|
|
39
|
+
'absolute/elysia-composition-boundaries': 'error',
|
|
40
|
+
'absolute/icon-button-has-accessible-name': 'error',
|
|
41
|
+
'absolute/loading-indicator-has-aria-busy': 'error',
|
|
42
|
+
'absolute/no-chained-type-assertions': 'error',
|
|
43
|
+
'absolute/no-nondeterministic-render': 'error',
|
|
44
|
+
'absolute/no-unsafe-schema-types': 'error',
|
|
45
|
+
'absolute/prefer-drizzle-query-builders': 'error',
|
|
46
|
+
'absolute/progressbar-has-state': 'error'
|
|
47
|
+
}
|
|
48
|
+
},
|
|
49
|
+
{
|
|
50
|
+
files: ['src/backend/**/*.{ts,tsx}'],
|
|
51
|
+
rules: { 'absolute/elysia-no-response-return': 'error' }
|
|
52
|
+
},
|
|
53
|
+
{
|
|
54
|
+
files: ['src/frontend/**/*.{ts,tsx,js,jsx}'],
|
|
55
|
+
rules: {
|
|
56
|
+
'absolute/eden-requires-react-query': 'error',
|
|
57
|
+
'no-restricted-syntax': [
|
|
58
|
+
'error',
|
|
59
|
+
{
|
|
60
|
+
message: 'Use a directly typed Eden subapp client.',
|
|
61
|
+
selector: "CallExpression[callee.name='fetch']"
|
|
62
|
+
},
|
|
63
|
+
{
|
|
64
|
+
message: 'Use a directly typed Eden subapp client.',
|
|
65
|
+
selector: "CallExpression[callee.property.name='fetch']"
|
|
66
|
+
}
|
|
67
|
+
]
|
|
68
|
+
}
|
|
69
|
+
},
|
|
70
|
+
{
|
|
71
|
+
files: ['**/*.{html,vue,svelte,gjs,gts}'],
|
|
72
|
+
plugins: { absolute },
|
|
73
|
+
processor: 'absolute/template-source'
|
|
74
|
+
},
|
|
75
|
+
{
|
|
76
|
+
// React Hooks rules do not apply to Angular's unrelated usePageContext API.
|
|
77
|
+
files: [
|
|
78
|
+
'src/frontend/**/*.{tsx,jsx}',
|
|
79
|
+
'src/frontend/**/hooks/**/*.{ts,js}'
|
|
80
|
+
],
|
|
81
|
+
plugins: { 'react-hooks': reactHooks },
|
|
82
|
+
rules: {
|
|
83
|
+
'react-hooks/exhaustive-deps': 'error',
|
|
84
|
+
'react-hooks/rules-of-hooks': 'error'
|
|
85
|
+
}
|
|
86
|
+
}
|
|
48
87
|
]);
|
package/dist/templates/db/migrations/cockroach-count-history/20260926210314_init/snapshot.json
ADDED
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": "1",
|
|
3
|
+
"dialect": "cockroach",
|
|
4
|
+
"id": "25a4568e-927c-4251-8f0c-145bd20ef6cf",
|
|
5
|
+
"prevIds": ["00000000-0000-0000-0000-000000000000"],
|
|
6
|
+
"ddl": [
|
|
7
|
+
{
|
|
8
|
+
"isRlsEnabled": false,
|
|
9
|
+
"name": "count_history",
|
|
10
|
+
"entityType": "tables",
|
|
11
|
+
"schema": "public"
|
|
12
|
+
},
|
|
13
|
+
{
|
|
14
|
+
"type": "int4",
|
|
15
|
+
"typeSchema": null,
|
|
16
|
+
"notNull": true,
|
|
17
|
+
"dimensions": 0,
|
|
18
|
+
"default": null,
|
|
19
|
+
"generated": null,
|
|
20
|
+
"identity": {
|
|
21
|
+
"type": "always",
|
|
22
|
+
"increment": "1",
|
|
23
|
+
"startWith": "1",
|
|
24
|
+
"minValue": "1",
|
|
25
|
+
"maxValue": "2147483647",
|
|
26
|
+
"cache": 1
|
|
27
|
+
},
|
|
28
|
+
"name": "uid",
|
|
29
|
+
"entityType": "columns",
|
|
30
|
+
"schema": "public",
|
|
31
|
+
"table": "count_history"
|
|
32
|
+
},
|
|
33
|
+
{
|
|
34
|
+
"type": "int4",
|
|
35
|
+
"typeSchema": null,
|
|
36
|
+
"notNull": true,
|
|
37
|
+
"dimensions": 0,
|
|
38
|
+
"default": null,
|
|
39
|
+
"generated": null,
|
|
40
|
+
"identity": null,
|
|
41
|
+
"name": "count",
|
|
42
|
+
"entityType": "columns",
|
|
43
|
+
"schema": "public",
|
|
44
|
+
"table": "count_history"
|
|
45
|
+
},
|
|
46
|
+
{
|
|
47
|
+
"type": "timestamp",
|
|
48
|
+
"typeSchema": null,
|
|
49
|
+
"notNull": true,
|
|
50
|
+
"dimensions": 0,
|
|
51
|
+
"default": "now()",
|
|
52
|
+
"generated": null,
|
|
53
|
+
"identity": null,
|
|
54
|
+
"name": "created_at",
|
|
55
|
+
"entityType": "columns",
|
|
56
|
+
"schema": "public",
|
|
57
|
+
"table": "count_history"
|
|
58
|
+
},
|
|
59
|
+
{
|
|
60
|
+
"columns": ["uid"],
|
|
61
|
+
"nameExplicit": false,
|
|
62
|
+
"name": "count_history_pkey",
|
|
63
|
+
"schema": "public",
|
|
64
|
+
"table": "count_history",
|
|
65
|
+
"entityType": "pks"
|
|
66
|
+
}
|
|
67
|
+
],
|
|
68
|
+
"renames": []
|
|
69
|
+
}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": "1",
|
|
3
|
+
"dialect": "cockroach",
|
|
4
|
+
"id": "b7fed725-7fff-4c26-8562-5dbb3a0e1a7a",
|
|
5
|
+
"prevIds": ["00000000-0000-0000-0000-000000000000"],
|
|
6
|
+
"ddl": [
|
|
7
|
+
{
|
|
8
|
+
"isRlsEnabled": false,
|
|
9
|
+
"name": "users",
|
|
10
|
+
"entityType": "tables",
|
|
11
|
+
"schema": "public"
|
|
12
|
+
},
|
|
13
|
+
{
|
|
14
|
+
"type": "varchar(255)",
|
|
15
|
+
"typeSchema": null,
|
|
16
|
+
"notNull": true,
|
|
17
|
+
"dimensions": 0,
|
|
18
|
+
"default": null,
|
|
19
|
+
"generated": null,
|
|
20
|
+
"identity": null,
|
|
21
|
+
"name": "auth_sub",
|
|
22
|
+
"entityType": "columns",
|
|
23
|
+
"schema": "public",
|
|
24
|
+
"table": "users"
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
"type": "timestamp",
|
|
28
|
+
"typeSchema": null,
|
|
29
|
+
"notNull": true,
|
|
30
|
+
"dimensions": 0,
|
|
31
|
+
"default": "now()",
|
|
32
|
+
"generated": null,
|
|
33
|
+
"identity": null,
|
|
34
|
+
"name": "created_at",
|
|
35
|
+
"entityType": "columns",
|
|
36
|
+
"schema": "public",
|
|
37
|
+
"table": "users"
|
|
38
|
+
},
|
|
39
|
+
{
|
|
40
|
+
"type": "jsonb",
|
|
41
|
+
"typeSchema": null,
|
|
42
|
+
"notNull": false,
|
|
43
|
+
"dimensions": 0,
|
|
44
|
+
"default": "'{}'",
|
|
45
|
+
"generated": null,
|
|
46
|
+
"identity": null,
|
|
47
|
+
"name": "metadata",
|
|
48
|
+
"entityType": "columns",
|
|
49
|
+
"schema": "public",
|
|
50
|
+
"table": "users"
|
|
51
|
+
},
|
|
52
|
+
{
|
|
53
|
+
"columns": ["auth_sub"],
|
|
54
|
+
"nameExplicit": false,
|
|
55
|
+
"name": "users_pkey",
|
|
56
|
+
"schema": "public",
|
|
57
|
+
"table": "users",
|
|
58
|
+
"entityType": "pks"
|
|
59
|
+
}
|
|
60
|
+
],
|
|
61
|
+
"renames": []
|
|
62
|
+
}
|