create-absolutejs 0.3.12 → 0.3.13

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.
@@ -85,6 +85,11 @@ export const createPackageJson = ({ projectName, authProvider, plugins, database
85
85
  scripts['predev'] = 'bun db:up';
86
86
  scripts['postdev'] = 'bun db:down';
87
87
  }
88
+ if (databaseEngine === 'sqlite' &&
89
+ (!databaseHost || databaseHost === 'none')) {
90
+ scripts['db:sqlite'] = 'sqlite3 db/database.sqlite';
91
+ scripts['db:init'] = 'sqlite3 db/database.sqlite < db/init.sql';
92
+ }
88
93
  const packageJson = {
89
94
  dependencies,
90
95
  devDependencies,
@@ -0,0 +1,2 @@
1
+ import { AuthProvider } from '../../types';
2
+ export declare const generateSqliteSchema: (authProvider: AuthProvider) => "CREATE TABLE IF NOT EXISTS users (\n auth_sub TEXT PRIMARY KEY,\n created_at INTEGER NOT NULL DEFAULT ((julianday('now') - 2440587.5) * 86400000),\n metadata TEXT DEFAULT '{}'\n);" | "CREATE TABLE IF NOT EXISTS count_history (\n uid INTEGER PRIMARY KEY AUTOINCREMENT,\n count INTEGER NOT NULL,\n created_at INTEGER NOT NULL DEFAULT ((julianday('now') - 2440587.5) * 86400000)\n);";
@@ -0,0 +1,11 @@
1
+ export const generateSqliteSchema = (authProvider) => authProvider && authProvider !== 'none'
2
+ ? `CREATE TABLE IF NOT EXISTS users (
3
+ auth_sub TEXT PRIMARY KEY,
4
+ created_at INTEGER NOT NULL DEFAULT ((julianday('now') - 2440587.5) * 86400000),
5
+ metadata TEXT DEFAULT '{}'
6
+ );`
7
+ : `CREATE TABLE IF NOT EXISTS count_history (
8
+ uid INTEGER PRIMARY KEY AUTOINCREMENT,
9
+ count INTEGER NOT NULL,
10
+ created_at INTEGER NOT NULL DEFAULT ((julianday('now') - 2440587.5) * 86400000)
11
+ );`;
@@ -1,11 +1,14 @@
1
1
  import { copyFileSync, mkdirSync, writeFileSync } from 'fs';
2
2
  import { join } from 'path';
3
+ import { $ } from 'bun';
3
4
  import { dim, yellow } from 'picocolors';
4
5
  import { isDrizzleDialect } from '../../typeGuards';
5
6
  import { checkDockerInstalled } from '../../utils/checkDockerInstalled';
7
+ import { checkSqliteInstalled } from '../../utils/checkSqliteInstalled';
6
8
  import { createDrizzleConfig } from '../configurations/generateDrizzleConfig';
7
9
  import { generateDBHandlers } from './generateDBHandlers';
8
10
  import { generateDrizzleSchema } from './generateDrizzleSchema';
11
+ import { generateSqliteSchema } from './generateSqliteSchema';
9
12
  export const scaffoldDatabase = async ({ projectName, databaseEngine, databaseHost, databaseDirectory, backendDirectory, templatesDirectory, authProvider, orm }) => {
10
13
  const projectDatabaseDirectory = join(projectName, databaseDirectory);
11
14
  const handlerDirectory = join(backendDirectory, 'handlers');
@@ -22,10 +25,13 @@ export const scaffoldDatabase = async ({ projectName, databaseEngine, databaseHo
22
25
  usesAuth
23
26
  });
24
27
  writeFileSync(join(handlerDirectory, handlerFileName), dbHandlers, 'utf-8');
25
- if (databaseEngine === 'postgresql' &&
26
- (databaseHost === undefined || databaseHost === 'none')) {
27
- await checkDockerInstalled();
28
- copyFileSync(join(templatesDirectory, 'db', 'docker-compose.db.yml'), join(projectDatabaseDirectory, 'docker-compose.db.yml'));
28
+ if (databaseEngine === 'sqlite') {
29
+ void ((orm === undefined || orm === 'none') &&
30
+ (await checkSqliteInstalled()));
31
+ const sqliteSchema = generateSqliteSchema(authProvider);
32
+ const sqliteSchemaFilePath = join(projectDatabaseDirectory, 'schema.sql');
33
+ writeFileSync(sqliteSchemaFilePath, sqliteSchema);
34
+ await $ `sqlite3 ${databaseDirectory}/database.sqlite ".read ${join(databaseDirectory, 'schema.sql')}"`.cwd(projectName);
29
35
  }
30
36
  if (orm === 'drizzle') {
31
37
  if (!isDrizzleDialect(databaseEngine)) {
@@ -43,5 +49,10 @@ export const scaffoldDatabase = async ({ projectName, databaseEngine, databaseHo
43
49
  }
44
50
  if (orm === 'prisma') {
45
51
  console.warn(`${dim('│')}\n${yellow('▲')} Prisma support is not implemented yet`);
52
+ return;
53
+ }
54
+ if (databaseEngine === 'postgresql') {
55
+ await checkDockerInstalled();
56
+ copyFileSync(join(templatesDirectory, 'db', 'docker-compose.db.yml'), join(projectDatabaseDirectory, 'docker-compose.db.yml'));
46
57
  }
47
58
  };
@@ -29,13 +29,13 @@ const db = neon(getEnv("DATABASE_URL"))
29
29
  (!databaseHost || databaseHost === 'none');
30
30
  if (isLocalSqlite && orm === 'drizzle') {
31
31
  return `
32
- const sql = new Database("database.sqlite")
32
+ const sql = new Database("db/database.sqlite")
33
33
  const db = drizzle(sql, { schema })
34
34
  `;
35
35
  }
36
36
  if (isLocalSqlite) {
37
37
  return `
38
- const db = new Database("database.sqlite")
38
+ const db = new Database("db/database.sqlite")
39
39
  `;
40
40
  }
41
41
  const isTursoSqlite = databaseEngine === 'sqlite' && databaseHost === 'turso';
@@ -0,0 +1 @@
1
+ export declare const checkSqliteInstalled: () => Promise<void>;
@@ -0,0 +1,133 @@
1
+ import os from 'os';
2
+ import { env, platform } from 'process';
3
+ import { confirm, spinner } from '@clack/prompts';
4
+ import { $ } from 'bun';
5
+ import { dim, yellow } from 'picocolors';
6
+ const SQLITE_URL = 'https://sqlite.org/download.html';
7
+ const isWSL = () => env.WSL_DISTRO_NAME !== undefined || /microsoft/i.test(os.release());
8
+ let hostEnv;
9
+ if (platform === 'win32') {
10
+ hostEnv = 'windows';
11
+ }
12
+ else if (isWSL()) {
13
+ hostEnv = 'wsl';
14
+ }
15
+ else {
16
+ hostEnv = 'linux';
17
+ }
18
+ const commandExists = async (cmd) => (platform === 'win32'
19
+ ? await $ `where ${cmd}`.quiet().nothrow()
20
+ : await $ `command -v ${cmd}`.quiet().nothrow()).exitCode === 0;
21
+ const ensureSudo = async () => {
22
+ if ((await $ `sudo -n true`.nothrow()).exitCode !== 0) {
23
+ console.log(`${dim('│')}\n${yellow('▲')} sudo password required`);
24
+ await $ `sudo -v`;
25
+ }
26
+ };
27
+ const hasSqlite = async () => (await $ `sqlite3 --version`.quiet().nothrow()).exitCode === 0;
28
+ const aptInstallSqlite = async () => {
29
+ await ensureSudo();
30
+ const spin = spinner();
31
+ spin.start('Installing sqlite3 with apt');
32
+ await $ `sudo DEBIAN_FRONTEND=noninteractive apt-get update`.quiet();
33
+ const res = await $ `sudo DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends sqlite3`
34
+ .quiet()
35
+ .nothrow();
36
+ spin.stop(res.exitCode === 0 ? 'sqlite3 installed' : 'apt install failed');
37
+ return res.exitCode === 0;
38
+ };
39
+ const dnfInstallSqlite = async () => {
40
+ const spin = spinner();
41
+ spin.start('Installing sqlite3 with dnf');
42
+ const res = await $ `sudo dnf install -y sqlite`.quiet().nothrow();
43
+ spin.stop(res.exitCode === 0 ? 'sqlite3 installed' : 'dnf install failed');
44
+ return res.exitCode === 0;
45
+ };
46
+ const pacmanInstallSqlite = async () => {
47
+ const spin = spinner();
48
+ spin.start('Installing sqlite3 with pacman');
49
+ const res = await $ `sudo pacman -S --noconfirm sqlite`.quiet().nothrow();
50
+ spin.stop(res.exitCode === 0 ? 'sqlite3 installed' : 'pacman install failed');
51
+ return res.exitCode === 0;
52
+ };
53
+ const apkInstallSqlite = async () => {
54
+ const spin = spinner();
55
+ spin.start('Installing sqlite3 with apk');
56
+ const res = await $ `sudo apk add sqlite`.quiet().nothrow();
57
+ spin.stop(res.exitCode === 0 ? 'sqlite3 installed' : 'apk install failed');
58
+ return res.exitCode === 0;
59
+ };
60
+ const installWindowsSqlite = async () => {
61
+ if (await commandExists('winget')) {
62
+ const spin = spinner();
63
+ spin.start('Installing sqlite3 with winget');
64
+ const res = await $ `winget install -e --id SQLite.SQLite`
65
+ .quiet()
66
+ .nothrow();
67
+ spin.stop(res.exitCode === 0 ? 'sqlite3 installed' : 'winget install failed');
68
+ return res.exitCode === 0;
69
+ }
70
+ if (await commandExists('choco')) {
71
+ const spin = spinner();
72
+ spin.start('Installing sqlite3 with Chocolatey');
73
+ const res = await $ `choco install sqlite -y`.quiet().nothrow();
74
+ spin.stop(res.exitCode === 0
75
+ ? 'sqlite3 installed'
76
+ : 'Chocolatey install failed');
77
+ return res.exitCode === 0;
78
+ }
79
+ console.log(`Automatic Windows install failed. Get sqlite3 from ${SQLITE_URL}`);
80
+ return false;
81
+ };
82
+ const installWSLSqlite = async () => {
83
+ if (await hasSqlite())
84
+ return true;
85
+ if (await aptInstallSqlite())
86
+ return true;
87
+ return false;
88
+ };
89
+ const installLinuxSqlite = async () => {
90
+ if (await commandExists('apt-get')) {
91
+ if (await aptInstallSqlite())
92
+ return true;
93
+ }
94
+ if (await commandExists('dnf')) {
95
+ if (await dnfInstallSqlite())
96
+ return true;
97
+ }
98
+ if (await commandExists('pacman')) {
99
+ if (await pacmanInstallSqlite())
100
+ return true;
101
+ }
102
+ if (await commandExists('apk')) {
103
+ if (await apkInstallSqlite())
104
+ return true;
105
+ }
106
+ console.log(`Automatic Linux install failed. See ${SQLITE_URL}`);
107
+ return false;
108
+ };
109
+ export const checkSqliteInstalled = async () => {
110
+ if (await hasSqlite())
111
+ return;
112
+ const proceed = await confirm({
113
+ initialValue: true,
114
+ message: 'sqlite3 CLI is required for local SQLite databases. Install now?'
115
+ });
116
+ if (!proceed)
117
+ return;
118
+ switch (hostEnv) {
119
+ case 'windows':
120
+ if (await installWindowsSqlite())
121
+ return;
122
+ break;
123
+ case 'wsl':
124
+ if (await installWSLSqlite())
125
+ return;
126
+ break;
127
+ case 'linux':
128
+ if (await installLinuxSqlite())
129
+ return;
130
+ break;
131
+ }
132
+ console.log(`Couldn't install sqlite3 automatically. Download it from ${SQLITE_URL}`);
133
+ };
package/package.json CHANGED
@@ -47,5 +47,5 @@
47
47
  "typecheck": "bun run tsc --noEmit"
48
48
  },
49
49
  "type": "module",
50
- "version": "0.3.12"
50
+ "version": "0.3.13"
51
51
  }