create-absolutejs 0.5.0 → 0.6.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/dist/data.d.ts +1 -1
- package/dist/data.js +2 -2
- package/dist/generators/configurations/generatePackageJson.d.ts +2 -2
- package/dist/generators/configurations/generatePackageJson.js +12 -4
- package/dist/generators/configurations/initializeRoot.js +2 -2
- package/dist/generators/db/generateDatabaseTypes.d.ts +3 -3
- package/dist/generators/db/generateDatabaseTypes.js +12 -7
- package/dist/generators/db/generateDrizzleSchema.d.ts +3 -3
- package/dist/generators/db/generateDrizzleSchema.js +4 -6
- package/dist/generators/db/generateSqliteSchema.d.ts +2 -2
- package/dist/generators/db/generateSqliteSchema.js +1 -1
- package/dist/generators/db/handlerTemplates.d.ts +40 -20
- package/dist/generators/db/handlerTemplates.js +131 -91
- package/dist/generators/db/scaffoldDatabase.d.ts +2 -2
- package/dist/generators/db/scaffoldDatabase.js +6 -6
- package/dist/generators/db/scaffoldDocker.d.ts +3 -3
- package/dist/generators/db/scaffoldDocker.js +2 -2
- package/dist/generators/html/scaffoldHTML.js +2 -2
- package/dist/generators/project/collectDependencies.d.ts +2 -2
- package/dist/generators/project/collectDependencies.js +2 -2
- package/dist/generators/project/generateAbsoluteAuthConfig.d.ts +2 -0
- package/dist/generators/project/generateAbsoluteAuthConfig.js +128 -0
- package/dist/generators/project/generateDBBlock.js +17 -10
- package/dist/generators/project/generateImportsBlock.d.ts +2 -2
- package/dist/generators/project/generateImportsBlock.js +28 -23
- package/dist/generators/project/generateRoutesBlock.d.ts +3 -3
- package/dist/generators/project/generateRoutesBlock.js +57 -46
- package/dist/generators/project/generateServer.d.ts +2 -2
- package/dist/generators/project/generateServer.js +28 -12
- package/dist/generators/project/scaffoldBackend.d.ts +6 -0
- package/dist/generators/project/scaffoldBackend.js +23 -0
- package/dist/generators/project/scaffoldFrontends.d.ts +2 -2
- package/dist/generators/project/scaffoldFrontends.js +18 -3
- package/dist/generators/react/generateReactComponents.d.ts +5 -0
- package/dist/generators/react/generateReactComponents.js +126 -0
- package/dist/generators/react/scaffoldReact.d.ts +1 -1
- package/dist/generators/react/scaffoldReact.js +11 -2
- package/dist/index.js +1 -1
- package/dist/messages.d.ts +1 -1
- package/dist/messages.js +5 -4
- package/dist/prompt.js +4 -3
- package/dist/questions/authOption.d.ts +1 -0
- package/dist/questions/{authProvider.js → authOption.js} +5 -5
- package/dist/questions/databaseHost.js +12 -0
- package/dist/scaffold.d.ts +1 -1
- package/dist/scaffold.js +13 -9
- package/dist/templates/assets/svg/google-logo.svg +7 -0
- package/dist/templates/react/components/OAuthLink.tsx +39 -0
- package/dist/templates/react/components/ProfilePicture.tsx +56 -0
- package/dist/templates/styles/tailwind.css +1 -0
- package/dist/typeGuards.d.ts +2 -2
- package/dist/typeGuards.js +1 -1
- package/dist/types.d.ts +7 -2
- package/dist/utils/abort.js +1 -1
- package/dist/utils/parseCommandLineOptions.js +30 -9
- package/dist/utils/t3-utils.js +1 -1
- package/package.json +2 -1
- package/dist/generators/project/generateUseBlock.d.ts +0 -6
- package/dist/generators/project/generateUseBlock.js +0 -32
- package/dist/generators/react/generateReactPage.d.ts +0 -2
- package/dist/generators/react/generateReactPage.js +0 -23
- package/dist/questions/authProvider.d.ts +0 -1
- package/dist/templates/react/pages/ReactExample.tsx +0 -18
|
@@ -1,36 +1,14 @@
|
|
|
1
|
-
const buildSqlAuthTemplate = ({ importLines,
|
|
2
|
-
import {
|
|
1
|
+
const buildSqlAuthTemplate = ({ importLines, queries }) => `
|
|
2
|
+
import { DatabaseType, NewUser } from '../../types/databaseTypes';
|
|
3
3
|
${importLines}
|
|
4
|
-
type UserHandlerProps = {
|
|
5
|
-
authProvider: string
|
|
6
|
-
db: ${dbType}
|
|
7
|
-
userIdentity: Record<string, unknown>
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
export const getUser = async ({ authProvider, db, userIdentity }: UserHandlerProps) => {
|
|
11
|
-
const providerConfiguration = providers[authProvider]
|
|
12
|
-
|
|
13
|
-
const subject = extractPropFromIdentity(
|
|
14
|
-
userIdentity,
|
|
15
|
-
providerConfiguration.subject,
|
|
16
|
-
providerConfiguration.subjectType
|
|
17
|
-
)
|
|
18
|
-
const authSub = \`\${authProvider.toUpperCase()}|\${subject}\`;
|
|
19
|
-
${queries.selectUser}
|
|
20
|
-
}
|
|
21
4
|
|
|
22
|
-
export const
|
|
23
|
-
|
|
5
|
+
export const getUser = async (db: DatabaseType, authSub: string) => {
|
|
6
|
+
${queries.selectUser}
|
|
7
|
+
};
|
|
24
8
|
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
providerConfiguration.subjectType
|
|
29
|
-
)
|
|
30
|
-
const authSub = \`\${authProvider.toUpperCase()}|\${subject}\`;
|
|
31
|
-
${queries.insertUser}
|
|
32
|
-
}
|
|
33
|
-
`;
|
|
9
|
+
export const createUser = async (db: DatabaseType, newUserData: NewUser) => {
|
|
10
|
+
${queries.insertUser}
|
|
11
|
+
}`;
|
|
34
12
|
const buildSqlCountTemplate = ({ importLines, dbType, queries }) => `
|
|
35
13
|
${importLines}
|
|
36
14
|
export const getCountHistory = async (db: ${dbType}, uid: number) => {
|
|
@@ -44,13 +22,21 @@ export const createCountHistory = async (db: ${dbType}, count: number) => {
|
|
|
44
22
|
const drizzleQueryOperations = {
|
|
45
23
|
insertHistory: `const [newHistory] = await db.insert(schema.countHistory).values({ count }).returning()
|
|
46
24
|
return newHistory`,
|
|
47
|
-
insertUser: `const [newUser] = await db
|
|
48
|
-
|
|
49
|
-
|
|
25
|
+
insertUser: `const [newUser] = await db
|
|
26
|
+
.insert(schema.users)
|
|
27
|
+
.values(newUserData)
|
|
28
|
+
.returning();
|
|
29
|
+
if (!newUser) throw new Error('Failed to create user');
|
|
30
|
+
return newUser;
|
|
31
|
+
`,
|
|
50
32
|
selectHistory: `const [history] = await db.select().from(schema.countHistory).where(eq(schema.countHistory.uid, uid)).execute()
|
|
51
33
|
return history`,
|
|
52
|
-
selectUser: `const [user] = await db
|
|
53
|
-
|
|
34
|
+
selectUser: `const [user] = await db
|
|
35
|
+
.select()
|
|
36
|
+
.from(schema.users)
|
|
37
|
+
.where(eq(schema.users.auth_sub, authSub))
|
|
38
|
+
.execute();
|
|
39
|
+
return user;`
|
|
54
40
|
};
|
|
55
41
|
const libsqlQueryOperations = {
|
|
56
42
|
insertHistory: `const { rows } = await db.execute({ sql: 'INSERT INTO count_history (count) VALUES (?) RETURNING *', args: [count] })
|
|
@@ -81,7 +67,7 @@ const bunSqliteQueryOperations = {
|
|
|
81
67
|
const [user] = statement.all(authSub)
|
|
82
68
|
return user ?? null`
|
|
83
69
|
};
|
|
84
|
-
const
|
|
70
|
+
const postgresQueryOperations = {
|
|
85
71
|
insertHistory: `const { rows } = await db.query(
|
|
86
72
|
'INSERT INTO count_history (count) VALUES ($1) RETURNING *',
|
|
87
73
|
[count]
|
|
@@ -220,12 +206,10 @@ const mysqlSqlQueryOperations = {
|
|
|
220
206
|
VALUES (\${authSub}, \${JSON.stringify(userIdentity)})
|
|
221
207
|
\`;
|
|
222
208
|
|
|
223
|
-
const insertId = result.lastInsertRowid;
|
|
224
|
-
|
|
225
209
|
const [row] = await db\`
|
|
226
210
|
SELECT *
|
|
227
211
|
FROM users
|
|
228
|
-
WHERE
|
|
212
|
+
WHERE auth_sub = \${authSub}
|
|
229
213
|
LIMIT 1
|
|
230
214
|
\`;
|
|
231
215
|
|
|
@@ -270,141 +254,197 @@ const mysqlDrizzleQueryOperations = {
|
|
|
270
254
|
return newHistory;`,
|
|
271
255
|
insertUser: `const [row] = await db
|
|
272
256
|
.insert(schema.users)
|
|
273
|
-
.values({ auth_sub: authSub, metadata: userIdentity })
|
|
274
|
-
.$returningId();
|
|
275
|
-
|
|
276
|
-
if (!row) throw new Error('insert failed: no uid returned');
|
|
277
|
-
const { uid } = row;
|
|
257
|
+
.values({ auth_sub: authSub, metadata: userIdentity });
|
|
278
258
|
|
|
279
259
|
const [newUser] = await db
|
|
280
260
|
.select()
|
|
281
261
|
.from(schema.users)
|
|
282
|
-
.where(eq(schema.users.
|
|
262
|
+
.where(eq(schema.users.auth_sub, authSub));
|
|
283
263
|
|
|
284
264
|
if (!newUser) throw new Error('Failed to create user');
|
|
285
265
|
return newUser;`,
|
|
286
266
|
selectHistory: drizzleQueryOperations.selectHistory,
|
|
287
267
|
selectUser: drizzleQueryOperations.selectUser
|
|
288
268
|
};
|
|
269
|
+
const mysqlPlanetScaleQueryOperations = {
|
|
270
|
+
insertHistory: `
|
|
271
|
+
const result = await db.execute(
|
|
272
|
+
\`INSERT INTO count_history (count) VALUES (?)\`,
|
|
273
|
+
[count]
|
|
274
|
+
);
|
|
275
|
+
|
|
276
|
+
const insertId = result.insertId;
|
|
277
|
+
if (!insertId) throw new Error("Could not insert count history");
|
|
278
|
+
|
|
279
|
+
const { rows } = await db.execute(
|
|
280
|
+
\`SELECT * FROM count_history WHERE uid = ? LIMIT 1\`,
|
|
281
|
+
[insertId]
|
|
282
|
+
);
|
|
283
|
+
|
|
284
|
+
const row = rows[0] ?? null;
|
|
285
|
+
if (!row) throw new Error("Could not retrieve the newly-inserted history");
|
|
286
|
+
|
|
287
|
+
return row;
|
|
288
|
+
`,
|
|
289
|
+
insertUser: `
|
|
290
|
+
const result = await db.execute(
|
|
291
|
+
\`INSERT INTO users (auth_sub, metadata) VALUES (?, ?)\`,
|
|
292
|
+
[authSub, JSON.stringify(userIdentity)]
|
|
293
|
+
);
|
|
294
|
+
|
|
295
|
+
const { rows } = await db.execute(
|
|
296
|
+
\`SELECT * FROM users WHERE auth_sub = ? LIMIT 1\`,
|
|
297
|
+
[authSub]
|
|
298
|
+
);
|
|
299
|
+
|
|
300
|
+
const row = rows[0] ?? null;
|
|
301
|
+
if (!row) throw new Error("Failed to create user");
|
|
302
|
+
|
|
303
|
+
return row;
|
|
304
|
+
`,
|
|
305
|
+
selectHistory: `
|
|
306
|
+
const { rows } = await db.execute(
|
|
307
|
+
\`SELECT * FROM count_history WHERE uid = ? LIMIT 1\`,
|
|
308
|
+
[uid]
|
|
309
|
+
);
|
|
310
|
+
|
|
311
|
+
return rows[0] ?? null;
|
|
312
|
+
`,
|
|
313
|
+
selectUser: `
|
|
314
|
+
const { rows } = await db.execute(
|
|
315
|
+
\`SELECT * FROM users WHERE auth_sub = ? LIMIT 1\`,
|
|
316
|
+
[authSub]
|
|
317
|
+
);
|
|
318
|
+
|
|
319
|
+
return rows[0] ?? null;
|
|
320
|
+
`
|
|
321
|
+
};
|
|
289
322
|
const driverConfigurations = {
|
|
290
323
|
'cockroachdb:sql:local': {
|
|
291
324
|
dbType: 'SQL',
|
|
292
|
-
importLines:
|
|
325
|
+
importLines: ``,
|
|
293
326
|
queries: postgresSqlQueryOperations
|
|
294
327
|
},
|
|
295
328
|
'gel:drizzle:local': {
|
|
296
329
|
dbType: 'GelJsDatabase<SchemaType>',
|
|
297
|
-
importLines: `
|
|
298
|
-
import {
|
|
299
|
-
import { GelJsDatabase } from 'drizzle-orm/gel'
|
|
300
|
-
import { schema, type SchemaType } from '../../../db/schema'
|
|
330
|
+
importLines: `import { eq } from 'drizzle-orm'
|
|
331
|
+
import { schema } from '../../../db/schema'
|
|
301
332
|
`,
|
|
302
333
|
queries: drizzleQueryOperations
|
|
303
334
|
},
|
|
304
335
|
'gel:sql:local': {
|
|
305
336
|
dbType: 'Client',
|
|
306
|
-
importLines:
|
|
337
|
+
importLines: ``,
|
|
307
338
|
queries: gelClientQueryOperations
|
|
308
339
|
},
|
|
309
340
|
'mariadb:drizzle:local': {
|
|
310
341
|
dbType: 'MySql2Database<SchemaType>',
|
|
311
|
-
importLines: `
|
|
312
|
-
import {
|
|
313
|
-
import { MySql2Database } from 'drizzle-orm/mysql2'
|
|
314
|
-
import { schema, type SchemaType } from '../../../db/schema'`,
|
|
342
|
+
importLines: `import { eq } from 'drizzle-orm'
|
|
343
|
+
import { schema } from '../../../db/schema'`,
|
|
315
344
|
queries: mysqlDrizzleQueryOperations
|
|
316
345
|
},
|
|
317
346
|
'mariadb:sql:local': {
|
|
318
347
|
dbType: 'SQL',
|
|
319
|
-
importLines:
|
|
348
|
+
importLines: ``,
|
|
320
349
|
queries: mysqlSqlQueryOperations
|
|
321
350
|
},
|
|
322
351
|
'mongodb:native:local': {
|
|
323
352
|
dbType: 'Db',
|
|
324
|
-
importLines:
|
|
353
|
+
importLines: ``,
|
|
325
354
|
queries: mongodbQueryOperations
|
|
326
355
|
},
|
|
327
356
|
'mssql:sql:local': {
|
|
328
357
|
dbType: 'ConnectionPool',
|
|
329
|
-
importLines:
|
|
358
|
+
importLines: ``,
|
|
330
359
|
queries: mssqlSqlQueryOperations
|
|
331
360
|
},
|
|
332
361
|
'mysql:drizzle:local': {
|
|
333
362
|
dbType: 'MySql2Database<SchemaType>',
|
|
334
|
-
importLines: `
|
|
335
|
-
import {
|
|
336
|
-
|
|
337
|
-
|
|
363
|
+
importLines: `import { eq } from 'drizzle-orm'
|
|
364
|
+
import { schema } from '../../../db/schema'`,
|
|
365
|
+
queries: mysqlDrizzleQueryOperations
|
|
366
|
+
},
|
|
367
|
+
'mysql:drizzle:planetscale': {
|
|
368
|
+
dbType: 'PlanetScaleDatabase<SchemaType>',
|
|
369
|
+
importLines: `import { eq } from 'drizzle-orm'
|
|
370
|
+
import { schema } from '../../../db/schema'`,
|
|
338
371
|
queries: mysqlDrizzleQueryOperations
|
|
339
372
|
},
|
|
340
373
|
'mysql:sql:local': {
|
|
341
374
|
dbType: 'SQL',
|
|
342
|
-
importLines:
|
|
375
|
+
importLines: ``,
|
|
343
376
|
queries: mysqlSqlQueryOperations
|
|
344
377
|
},
|
|
378
|
+
'mysql:sql:planetscale': {
|
|
379
|
+
dbType: 'Client',
|
|
380
|
+
importLines: ``,
|
|
381
|
+
queries: mysqlPlanetScaleQueryOperations
|
|
382
|
+
},
|
|
345
383
|
'postgresql:drizzle:local': {
|
|
346
384
|
dbType: 'BunSQLDatabase<SchemaType>',
|
|
347
|
-
importLines: `
|
|
348
|
-
import {
|
|
349
|
-
import { BunSQLDatabase } from 'drizzle-orm/bun-sql'
|
|
350
|
-
import { schema, type SchemaType } from '../../../db/schema'`,
|
|
385
|
+
importLines: `import { eq } from 'drizzle-orm'
|
|
386
|
+
import { schema } from '../../../db/schema'`,
|
|
351
387
|
queries: drizzleQueryOperations
|
|
352
388
|
},
|
|
353
389
|
'postgresql:drizzle:neon': {
|
|
354
390
|
dbType: 'NeonDatabase<SchemaType>',
|
|
355
|
-
importLines: `
|
|
356
|
-
import {
|
|
357
|
-
|
|
358
|
-
|
|
391
|
+
importLines: `import { eq } from 'drizzle-orm'
|
|
392
|
+
import { schema } from '../../../db/schema'`,
|
|
393
|
+
queries: drizzleQueryOperations
|
|
394
|
+
},
|
|
395
|
+
'postgresql:drizzle:planetscale': {
|
|
396
|
+
dbType: 'NodePgDatabase<SchemaType>',
|
|
397
|
+
importLines: `import { eq } from 'drizzle-orm'
|
|
398
|
+
import { schema } from '../../../db/schema'`,
|
|
359
399
|
queries: drizzleQueryOperations
|
|
360
400
|
},
|
|
361
401
|
'postgresql:sql:local': {
|
|
362
402
|
dbType: 'SQL',
|
|
363
|
-
importLines:
|
|
403
|
+
importLines: ``,
|
|
364
404
|
queries: postgresSqlQueryOperations
|
|
365
405
|
},
|
|
366
406
|
'postgresql:sql:neon': {
|
|
367
407
|
dbType: 'Pool',
|
|
368
|
-
importLines:
|
|
369
|
-
queries:
|
|
408
|
+
importLines: ``,
|
|
409
|
+
queries: postgresQueryOperations
|
|
370
410
|
},
|
|
371
|
-
'
|
|
411
|
+
'postgresql:sql:planetscale': {
|
|
372
412
|
dbType: 'Pool',
|
|
373
|
-
importLines:
|
|
374
|
-
queries:
|
|
413
|
+
importLines: ``,
|
|
414
|
+
queries: postgresQueryOperations
|
|
375
415
|
},
|
|
376
416
|
'singlestore:drizzle:local': {
|
|
377
417
|
dbType: 'SingleStoreDriverDatabase<SchemaType>',
|
|
378
|
-
importLines: `
|
|
379
|
-
import {
|
|
380
|
-
import { SingleStoreDriverDatabase } from 'drizzle-orm/singlestore'
|
|
381
|
-
import { schema, type SchemaType } from '../../../db/schema'`,
|
|
418
|
+
importLines: `import { eq } from 'drizzle-orm'
|
|
419
|
+
import { schema } from '../../../db/schema'`,
|
|
382
420
|
queries: mysqlDrizzleQueryOperations
|
|
383
421
|
},
|
|
422
|
+
'singlestore:sql:local': {
|
|
423
|
+
dbType: 'Pool',
|
|
424
|
+
importLines: `import { RowDataPacket } from 'mysql2/promise'
|
|
425
|
+
`,
|
|
426
|
+
queries: singlestoreSqlQueryOperations
|
|
427
|
+
},
|
|
384
428
|
'sqlite:drizzle:local': {
|
|
385
429
|
dbType: 'BunSQLiteDatabase<SchemaType>',
|
|
386
|
-
importLines: `
|
|
387
|
-
import {
|
|
388
|
-
import { BunSQLiteDatabase } from 'drizzle-orm/bun-sqlite'
|
|
389
|
-
import { schema, type SchemaType } from '../../../db/schema'`,
|
|
430
|
+
importLines: `import { eq } from 'drizzle-orm'
|
|
431
|
+
import { schema } from '../../../db/schema'`,
|
|
390
432
|
queries: drizzleQueryOperations
|
|
391
433
|
},
|
|
392
434
|
'sqlite:drizzle:turso': {
|
|
393
435
|
dbType: 'LibSQLDatabase<SchemaType>',
|
|
394
|
-
importLines: `
|
|
395
|
-
import {
|
|
396
|
-
import { LibSQLDatabase } from 'drizzle-orm/libsql'
|
|
397
|
-
import { schema, type SchemaType } from '../../../db/schema'`,
|
|
436
|
+
importLines: `import { eq } from 'drizzle-orm'
|
|
437
|
+
import { schema } from '../../../db/schema'`,
|
|
398
438
|
queries: drizzleQueryOperations
|
|
399
439
|
},
|
|
400
440
|
'sqlite:sql:local': {
|
|
401
441
|
dbType: 'Database',
|
|
402
|
-
importLines:
|
|
442
|
+
importLines: ``,
|
|
403
443
|
queries: bunSqliteQueryOperations
|
|
404
444
|
},
|
|
405
445
|
'sqlite:sql:turso': {
|
|
406
446
|
dbType: 'Client',
|
|
407
|
-
importLines:
|
|
447
|
+
importLines: ``,
|
|
408
448
|
queries: libsqlQueryOperations
|
|
409
449
|
}
|
|
410
450
|
};
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import type { CreateConfiguration } from '../../types';
|
|
2
|
-
type ScaffoldDatabaseProps = Pick<CreateConfiguration, 'projectName' | 'databaseHost' | 'orm' | 'databaseDirectory' | '
|
|
2
|
+
type ScaffoldDatabaseProps = Pick<CreateConfiguration, 'projectName' | 'databaseHost' | 'orm' | 'databaseDirectory' | 'authOption' | 'databaseEngine'> & {
|
|
3
3
|
databaseDirectory: string;
|
|
4
4
|
backendDirectory: string;
|
|
5
5
|
typesDirectory: string;
|
|
6
6
|
};
|
|
7
|
-
export declare const scaffoldDatabase: ({ projectName, databaseEngine, databaseHost, databaseDirectory, backendDirectory,
|
|
7
|
+
export declare const scaffoldDatabase: ({ projectName, databaseEngine, databaseHost, databaseDirectory, backendDirectory, authOption, orm, typesDirectory }: ScaffoldDatabaseProps) => Promise<void>;
|
|
8
8
|
export {};
|
|
@@ -10,12 +10,12 @@ import { generateDrizzleSchema } from './generateDrizzleSchema';
|
|
|
10
10
|
import { generateDBHandlers } from './generateHandlers';
|
|
11
11
|
import { generateSqliteSchema } from './generateSqliteSchema';
|
|
12
12
|
import { scaffoldDocker } from './scaffoldDocker';
|
|
13
|
-
export const scaffoldDatabase = async ({ projectName, databaseEngine, databaseHost, databaseDirectory, backendDirectory,
|
|
13
|
+
export const scaffoldDatabase = async ({ projectName, databaseEngine, databaseHost, databaseDirectory, backendDirectory, authOption, orm, typesDirectory }) => {
|
|
14
14
|
const projectDatabaseDirectory = join(projectName, databaseDirectory);
|
|
15
15
|
const handlerDirectory = join(backendDirectory, 'handlers');
|
|
16
16
|
mkdirSync(projectDatabaseDirectory, { recursive: true });
|
|
17
17
|
mkdirSync(handlerDirectory, { recursive: true });
|
|
18
|
-
const usesAuth =
|
|
18
|
+
const usesAuth = authOption !== undefined && authOption !== 'none';
|
|
19
19
|
const handlerFileName = usesAuth
|
|
20
20
|
? 'userHandlers.ts'
|
|
21
21
|
: 'countHistoryHandlers.ts';
|
|
@@ -29,7 +29,7 @@ export const scaffoldDatabase = async ({ projectName, databaseEngine, databaseHo
|
|
|
29
29
|
if (databaseEngine === 'sqlite') {
|
|
30
30
|
void ((orm === undefined || orm === 'none') &&
|
|
31
31
|
(await checkSqliteInstalled()));
|
|
32
|
-
const sqliteSchema = generateSqliteSchema(
|
|
32
|
+
const sqliteSchema = generateSqliteSchema(authOption);
|
|
33
33
|
writeFileSync(join(projectDatabaseDirectory, 'schema.sql'), sqliteSchema);
|
|
34
34
|
await $ `sqlite3 ${databaseDirectory}/database.sqlite ".read ${join(databaseDirectory, 'schema.sql')}"`.cwd(projectName);
|
|
35
35
|
}
|
|
@@ -38,7 +38,7 @@ export const scaffoldDatabase = async ({ projectName, databaseEngine, databaseHo
|
|
|
38
38
|
databaseEngine !== undefined &&
|
|
39
39
|
databaseEngine !== 'none') {
|
|
40
40
|
await scaffoldDocker({
|
|
41
|
-
|
|
41
|
+
authOption,
|
|
42
42
|
databaseEngine,
|
|
43
43
|
projectDatabaseDirectory,
|
|
44
44
|
projectName
|
|
@@ -49,13 +49,13 @@ export const scaffoldDatabase = async ({ projectName, databaseEngine, databaseHo
|
|
|
49
49
|
throw new Error('Internal type error: Expected a Drizzle dialect');
|
|
50
50
|
}
|
|
51
51
|
const drizzleSchema = generateDrizzleSchema({
|
|
52
|
-
|
|
52
|
+
authOption,
|
|
53
53
|
databaseEngine
|
|
54
54
|
});
|
|
55
55
|
writeFileSync(join(projectDatabaseDirectory, 'schema.ts'), drizzleSchema);
|
|
56
56
|
createDrizzleConfig({ databaseDirectory, databaseEngine, projectName });
|
|
57
57
|
const drizzleTypes = generateDatabaseTypes({
|
|
58
|
-
|
|
58
|
+
authOption,
|
|
59
59
|
databaseEngine,
|
|
60
60
|
databaseHost
|
|
61
61
|
});
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { AuthOption, DatabaseEngine } from '../../types';
|
|
2
2
|
type ScaffoldDockerProps = {
|
|
3
3
|
databaseEngine: DatabaseEngine;
|
|
4
4
|
projectDatabaseDirectory: string;
|
|
5
|
-
|
|
5
|
+
authOption: AuthOption;
|
|
6
6
|
projectName: string;
|
|
7
7
|
};
|
|
8
|
-
export declare const scaffoldDocker: ({ databaseEngine, projectDatabaseDirectory, projectName,
|
|
8
|
+
export declare const scaffoldDocker: ({ databaseEngine, projectDatabaseDirectory, projectName, authOption }: ScaffoldDockerProps) => Promise<void>;
|
|
9
9
|
export {};
|
|
@@ -4,7 +4,7 @@ import { $ } from 'bun';
|
|
|
4
4
|
import { checkDockerInstalled } from '../../utils/checkDockerInstalled';
|
|
5
5
|
import { countHistoryTables, initTemplates, userTables } from './dockerInitTemplates';
|
|
6
6
|
import { generateDockerContainer } from './generateDockerContainer';
|
|
7
|
-
export const scaffoldDocker = async ({ databaseEngine, projectDatabaseDirectory, projectName,
|
|
7
|
+
export const scaffoldDocker = async ({ databaseEngine, projectDatabaseDirectory, projectName, authOption }) => {
|
|
8
8
|
if (databaseEngine === undefined ||
|
|
9
9
|
databaseEngine === 'none' ||
|
|
10
10
|
databaseEngine === 'sqlite') {
|
|
@@ -17,7 +17,7 @@ export const scaffoldDocker = async ({ databaseEngine, projectDatabaseDirectory,
|
|
|
17
17
|
}
|
|
18
18
|
else {
|
|
19
19
|
const { wait, cli } = initTemplates[databaseEngine];
|
|
20
|
-
const usesAuth =
|
|
20
|
+
const usesAuth = authOption !== undefined && authOption !== 'none';
|
|
21
21
|
const dbCommand = usesAuth
|
|
22
22
|
? userTables[databaseEngine]
|
|
23
23
|
: countHistoryTables[databaseEngine];
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { copyFileSync, cpSync, mkdirSync, writeFileSync } from '
|
|
2
|
-
import { join } from '
|
|
1
|
+
import { copyFileSync, cpSync, mkdirSync, writeFileSync } from 'fs';
|
|
2
|
+
import { join } from 'path';
|
|
3
3
|
import { generateMarkupCSS } from '../project/generateMarkupCSS';
|
|
4
4
|
import { generateHTMLPage } from './generateHTMLPage';
|
|
5
5
|
export const scaffoldHTML = ({ isSingleFrontend, targetDirectory, frontends, useHTMLScripts, templatesDirectory, projectAssetsDirectory }) => {
|
|
@@ -2,8 +2,8 @@ import type { CreateConfiguration } from '../../types';
|
|
|
2
2
|
import type { FrameworkFlags } from './computeFlags';
|
|
3
3
|
type CollectDependenciesProps = {
|
|
4
4
|
plugins: string[];
|
|
5
|
-
|
|
5
|
+
authOption: CreateConfiguration['authOption'];
|
|
6
6
|
flags: FrameworkFlags;
|
|
7
7
|
};
|
|
8
|
-
export declare const collectDependencies: ({ plugins,
|
|
8
|
+
export declare const collectDependencies: ({ plugins, authOption, flags }: CollectDependenciesProps) => import("../../types").AvailableDependency[];
|
|
9
9
|
export {};
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { defaultDependencies, defaultPlugins, absoluteAuthPlugin, scopedStatePlugin, availablePlugins } from '../../data';
|
|
2
|
-
export const collectDependencies = ({ plugins,
|
|
2
|
+
export const collectDependencies = ({ plugins, authOption, flags }) => {
|
|
3
3
|
const customSelections = availablePlugins.filter((plugin) => plugins.includes(plugin.value));
|
|
4
|
-
const authPlugins =
|
|
4
|
+
const authPlugins = authOption === 'abs' ? [absoluteAuthPlugin] : [];
|
|
5
5
|
const htmxPlugins = flags.requiresHtmx ? [scopedStatePlugin] : [];
|
|
6
6
|
const allDeps = [
|
|
7
7
|
...defaultDependencies,
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
const defaultProviderConfigurations = {
|
|
2
|
+
google: {
|
|
3
|
+
credentials: {
|
|
4
|
+
clientId: "getEnv('GOOGLE_CLIENT_ID')",
|
|
5
|
+
clientSecret: "getEnv('GOOGLE_CLIENT_SECRET')"
|
|
6
|
+
},
|
|
7
|
+
scope: [
|
|
8
|
+
'openid',
|
|
9
|
+
'https://www.googleapis.com/auth/userinfo.profile',
|
|
10
|
+
'https://www.googleapis.com/auth/userinfo.email'
|
|
11
|
+
],
|
|
12
|
+
searchParams: [['access_type', 'offline']]
|
|
13
|
+
}
|
|
14
|
+
};
|
|
15
|
+
export const generateAbsoluteAuthConfig = (absProviders) => {
|
|
16
|
+
const providerConfigs = (absProviders ?? [])
|
|
17
|
+
.map((provider) => {
|
|
18
|
+
const config = defaultProviderConfigurations[provider];
|
|
19
|
+
if (!config) {
|
|
20
|
+
console.warn(`No default OAuth2 configuration has been defined for provider "${provider}". ` +
|
|
21
|
+
`Please add a default entry to ` +
|
|
22
|
+
'`defaultProviderConfigurations` or configure this provider manually in `src/backend/utils/absoluteAuthConfig.ts`.');
|
|
23
|
+
return null;
|
|
24
|
+
}
|
|
25
|
+
const credentialsLines = [
|
|
26
|
+
...Object.entries(config.credentials).map(([key, value]) => ` ${key}: ${value}`),
|
|
27
|
+
` redirectUri: getEnv('OAUTH2_CALLBACK_URI')`
|
|
28
|
+
].join(',\n');
|
|
29
|
+
const scopePart = config.scope
|
|
30
|
+
? `,
|
|
31
|
+
scope: ${JSON.stringify(config.scope)}`
|
|
32
|
+
: '';
|
|
33
|
+
const searchParamsPart = config.searchParams && config.searchParams.length > 0
|
|
34
|
+
? `,
|
|
35
|
+
searchParams: ${JSON.stringify(config.searchParams)}`
|
|
36
|
+
: '';
|
|
37
|
+
return ` ${provider}: {
|
|
38
|
+
credentials: {
|
|
39
|
+
${credentialsLines}
|
|
40
|
+
}${scopePart}${searchParamsPart}
|
|
41
|
+
}`;
|
|
42
|
+
})
|
|
43
|
+
.filter((entry) => entry !== null)
|
|
44
|
+
.join(',\n');
|
|
45
|
+
return `import { getEnv } from '@absolutejs/absolute';
|
|
46
|
+
import {
|
|
47
|
+
AbsoluteAuthProps,
|
|
48
|
+
extractPropFromIdentity,
|
|
49
|
+
instantiateUserSession,
|
|
50
|
+
providers
|
|
51
|
+
} from '@absolutejs/auth';
|
|
52
|
+
import { DatabaseType, User } from '../../types/databaseTypes';
|
|
53
|
+
import { createUser, getUser } from '../handlers/userHandlers';
|
|
54
|
+
|
|
55
|
+
export const absoluteAuthConfig = (
|
|
56
|
+
db: DatabaseType
|
|
57
|
+
): AbsoluteAuthProps<User> => ({
|
|
58
|
+
providersConfiguration: {
|
|
59
|
+
${providerConfigs}
|
|
60
|
+
},
|
|
61
|
+
onCallbackSuccess: async ({
|
|
62
|
+
authProvider,
|
|
63
|
+
providerInstance,
|
|
64
|
+
tokenResponse,
|
|
65
|
+
unregisteredSession,
|
|
66
|
+
cookie: { user_session_id },
|
|
67
|
+
status,
|
|
68
|
+
session
|
|
69
|
+
}) =>
|
|
70
|
+
instantiateUserSession({
|
|
71
|
+
authProvider,
|
|
72
|
+
providerInstance,
|
|
73
|
+
session,
|
|
74
|
+
tokenResponse,
|
|
75
|
+
unregisteredSession,
|
|
76
|
+
user_session_id,
|
|
77
|
+
getUser: async (userIdentity) => {
|
|
78
|
+
const provider = authProvider.toUpperCase();
|
|
79
|
+
const providerConfiguration = providers[authProvider];
|
|
80
|
+
|
|
81
|
+
const subject = extractPropFromIdentity(
|
|
82
|
+
userIdentity,
|
|
83
|
+
providerConfiguration.subject,
|
|
84
|
+
providerConfiguration.subjectType
|
|
85
|
+
);
|
|
86
|
+
const authSub = \`\${provider}|\${subject}\`;
|
|
87
|
+
|
|
88
|
+
try {
|
|
89
|
+
const user = await getUser(db, authSub);
|
|
90
|
+
|
|
91
|
+
return user;
|
|
92
|
+
} catch (error) {
|
|
93
|
+
console.error('Error fetching user:', error);
|
|
94
|
+
return status(
|
|
95
|
+
'Internal Server Error',
|
|
96
|
+
'Could not fetch user data.'
|
|
97
|
+
);
|
|
98
|
+
}
|
|
99
|
+
},
|
|
100
|
+
onNewUser: async (userIdentity) => {
|
|
101
|
+
const provider = authProvider.toUpperCase();
|
|
102
|
+
const providerConfiguration = providers[authProvider];
|
|
103
|
+
|
|
104
|
+
const subject = extractPropFromIdentity(
|
|
105
|
+
userIdentity,
|
|
106
|
+
providerConfiguration.subject,
|
|
107
|
+
providerConfiguration.subjectType
|
|
108
|
+
);
|
|
109
|
+
const authSub = \`\${provider}|\${subject}\`;
|
|
110
|
+
|
|
111
|
+
try {
|
|
112
|
+
const newUser = await createUser(db, {
|
|
113
|
+
auth_sub: authSub,
|
|
114
|
+
metadata: userIdentity
|
|
115
|
+
});
|
|
116
|
+
return newUser;
|
|
117
|
+
} catch (error) {
|
|
118
|
+
console.error('Error creating user:', error);
|
|
119
|
+
return status(
|
|
120
|
+
'Internal Server Error',
|
|
121
|
+
'Could not create new user.'
|
|
122
|
+
);
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
})
|
|
126
|
+
});
|
|
127
|
+
`;
|
|
128
|
+
};
|
|
@@ -17,13 +17,16 @@ const connectionMap = {
|
|
|
17
17
|
},
|
|
18
18
|
mysql: {
|
|
19
19
|
none: { expr: 'new SQL(getEnv("DATABASE_URL"))' },
|
|
20
|
-
planetscale: { expr: '
|
|
20
|
+
planetscale: { expr: 'new Client({ url: getEnv("DATABASE_URL") })' }
|
|
21
21
|
},
|
|
22
22
|
postgresql: {
|
|
23
23
|
neon: {
|
|
24
|
-
expr: '
|
|
24
|
+
expr: 'neon(getEnv("DATABASE_URL"));'
|
|
25
25
|
},
|
|
26
|
-
none: { expr: 'new SQL(getEnv("DATABASE_URL"))' }
|
|
26
|
+
none: { expr: 'new SQL(getEnv("DATABASE_URL"))' },
|
|
27
|
+
planetscale: {
|
|
28
|
+
expr: 'new Pool({ connectionString: getEnv("DATABASE_URL") })'
|
|
29
|
+
}
|
|
27
30
|
},
|
|
28
31
|
singlestore: {
|
|
29
32
|
none: { expr: 'createPool(getEnv("DATABASE_URL"))' }
|
|
@@ -34,8 +37,8 @@ const connectionMap = {
|
|
|
34
37
|
}
|
|
35
38
|
};
|
|
36
39
|
const remoteDrizzleInit = {
|
|
37
|
-
neon: '
|
|
38
|
-
planetscale: '
|
|
40
|
+
neon: 'neon(getEnv("DATABASE_URL"));',
|
|
41
|
+
planetscale: 'new Client({ url: getEnv("DATABASE_URL") })',
|
|
39
42
|
turso: 'createClient({ url: getEnv("DATABASE_URL") })'
|
|
40
43
|
};
|
|
41
44
|
const drizzleDialectSet = new Set([...availableDrizzleDialects]);
|
|
@@ -56,13 +59,17 @@ export const generateDBBlock = ({ databaseEngine, orm, databaseHost }) => {
|
|
|
56
59
|
const expr = engineGroup[hostKey]?.expr ?? remoteDrizzleInit[hostKey];
|
|
57
60
|
if (!expr)
|
|
58
61
|
return '';
|
|
59
|
-
if (databaseEngine === 'mysql' || databaseEngine === 'mariadb')
|
|
60
|
-
|
|
61
|
-
? 'planetscale'
|
|
62
|
-
: 'default';
|
|
62
|
+
if ((databaseEngine === 'mysql' || databaseEngine === 'mariadb') &&
|
|
63
|
+
databaseHost !== 'planetscale') {
|
|
63
64
|
return `
|
|
64
65
|
const pool = createPool(getEnv("DATABASE_URL"))
|
|
65
|
-
const db = drizzle(pool, { schema, mode: '
|
|
66
|
+
const db = drizzle(pool, { schema, mode: 'default' })
|
|
67
|
+
`;
|
|
68
|
+
}
|
|
69
|
+
if (databaseEngine === 'postgresql' && databaseHost === 'neon') {
|
|
70
|
+
return `
|
|
71
|
+
const sql = neon(getEnv('DATABASE_URL'));
|
|
72
|
+
const db = drizzle(sql, { schema });
|
|
66
73
|
`;
|
|
67
74
|
}
|
|
68
75
|
return `
|
|
@@ -5,10 +5,10 @@ type GenerateImportsBlockProps = {
|
|
|
5
5
|
deps: AvailableDependency[];
|
|
6
6
|
flags: FrameworkFlags;
|
|
7
7
|
orm: CreateConfiguration['orm'];
|
|
8
|
-
|
|
8
|
+
authOption: CreateConfiguration['authOption'];
|
|
9
9
|
databaseEngine: CreateConfiguration['databaseEngine'];
|
|
10
10
|
databaseHost: CreateConfiguration['databaseHost'];
|
|
11
11
|
frontendDirectories: CreateConfiguration['frontendDirectories'];
|
|
12
12
|
};
|
|
13
|
-
export declare const generateImportsBlock: ({ backendDirectory, deps, flags, orm,
|
|
13
|
+
export declare const generateImportsBlock: ({ backendDirectory, deps, flags, orm, authOption, databaseEngine, databaseHost, frontendDirectories }: GenerateImportsBlockProps) => string;
|
|
14
14
|
export {};
|