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.
Files changed (63) hide show
  1. package/dist/data.d.ts +1 -1
  2. package/dist/data.js +2 -2
  3. package/dist/generators/configurations/generatePackageJson.d.ts +2 -2
  4. package/dist/generators/configurations/generatePackageJson.js +12 -4
  5. package/dist/generators/configurations/initializeRoot.js +2 -2
  6. package/dist/generators/db/generateDatabaseTypes.d.ts +3 -3
  7. package/dist/generators/db/generateDatabaseTypes.js +12 -7
  8. package/dist/generators/db/generateDrizzleSchema.d.ts +3 -3
  9. package/dist/generators/db/generateDrizzleSchema.js +4 -6
  10. package/dist/generators/db/generateSqliteSchema.d.ts +2 -2
  11. package/dist/generators/db/generateSqliteSchema.js +1 -1
  12. package/dist/generators/db/handlerTemplates.d.ts +40 -20
  13. package/dist/generators/db/handlerTemplates.js +131 -91
  14. package/dist/generators/db/scaffoldDatabase.d.ts +2 -2
  15. package/dist/generators/db/scaffoldDatabase.js +6 -6
  16. package/dist/generators/db/scaffoldDocker.d.ts +3 -3
  17. package/dist/generators/db/scaffoldDocker.js +2 -2
  18. package/dist/generators/html/scaffoldHTML.js +2 -2
  19. package/dist/generators/project/collectDependencies.d.ts +2 -2
  20. package/dist/generators/project/collectDependencies.js +2 -2
  21. package/dist/generators/project/generateAbsoluteAuthConfig.d.ts +2 -0
  22. package/dist/generators/project/generateAbsoluteAuthConfig.js +128 -0
  23. package/dist/generators/project/generateDBBlock.js +17 -10
  24. package/dist/generators/project/generateImportsBlock.d.ts +2 -2
  25. package/dist/generators/project/generateImportsBlock.js +28 -23
  26. package/dist/generators/project/generateRoutesBlock.d.ts +3 -3
  27. package/dist/generators/project/generateRoutesBlock.js +57 -46
  28. package/dist/generators/project/generateServer.d.ts +2 -2
  29. package/dist/generators/project/generateServer.js +28 -12
  30. package/dist/generators/project/scaffoldBackend.d.ts +6 -0
  31. package/dist/generators/project/scaffoldBackend.js +23 -0
  32. package/dist/generators/project/scaffoldFrontends.d.ts +2 -2
  33. package/dist/generators/project/scaffoldFrontends.js +18 -3
  34. package/dist/generators/react/generateReactComponents.d.ts +5 -0
  35. package/dist/generators/react/generateReactComponents.js +126 -0
  36. package/dist/generators/react/scaffoldReact.d.ts +1 -1
  37. package/dist/generators/react/scaffoldReact.js +11 -2
  38. package/dist/index.js +1 -1
  39. package/dist/messages.d.ts +1 -1
  40. package/dist/messages.js +5 -4
  41. package/dist/prompt.js +4 -3
  42. package/dist/questions/authOption.d.ts +1 -0
  43. package/dist/questions/{authProvider.js → authOption.js} +5 -5
  44. package/dist/questions/databaseHost.js +12 -0
  45. package/dist/scaffold.d.ts +1 -1
  46. package/dist/scaffold.js +13 -9
  47. package/dist/templates/assets/svg/google-logo.svg +7 -0
  48. package/dist/templates/react/components/OAuthLink.tsx +39 -0
  49. package/dist/templates/react/components/ProfilePicture.tsx +56 -0
  50. package/dist/templates/styles/tailwind.css +1 -0
  51. package/dist/typeGuards.d.ts +2 -2
  52. package/dist/typeGuards.js +1 -1
  53. package/dist/types.d.ts +7 -2
  54. package/dist/utils/abort.js +1 -1
  55. package/dist/utils/parseCommandLineOptions.js +30 -9
  56. package/dist/utils/t3-utils.js +1 -1
  57. package/package.json +2 -1
  58. package/dist/generators/project/generateUseBlock.d.ts +0 -6
  59. package/dist/generators/project/generateUseBlock.js +0 -32
  60. package/dist/generators/react/generateReactPage.d.ts +0 -2
  61. package/dist/generators/react/generateReactPage.js +0 -23
  62. package/dist/questions/authProvider.d.ts +0 -1
  63. package/dist/templates/react/pages/ReactExample.tsx +0 -18
@@ -1,36 +1,14 @@
1
- const buildSqlAuthTemplate = ({ importLines, dbType, queries }) => `
2
- import { isValidProviderOption, providers, extractPropFromIdentity } from 'citra'
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 createUser = async ({ authProvider, db, userIdentity }: UserHandlerProps) => {
23
- const providerConfiguration = providers[authProvider]
5
+ export const getUser = async (db: DatabaseType, authSub: string) => {
6
+ ${queries.selectUser}
7
+ };
24
8
 
25
- const subject = extractPropFromIdentity(
26
- userIdentity,
27
- providerConfiguration.subject,
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.insert(schema.users).values({ auth_sub: authSub, metadata: userIdentity }).returning()
48
- if (!newUser) throw new Error('Failed to create user')
49
- return newUser`,
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.select().from(schema.users).where(eq(schema.users.auth_sub, authSub)).execute()
53
- return user`
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 postgresNeonQueryOperations = {
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 uid = \${insertId}
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.uid, uid));
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: `import { SQL } from 'bun'`,
325
+ importLines: ``,
293
326
  queries: postgresSqlQueryOperations
294
327
  },
295
328
  'gel:drizzle:local': {
296
329
  dbType: 'GelJsDatabase<SchemaType>',
297
- importLines: `
298
- import { eq } from 'drizzle-orm'
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: `import { Client } from 'gel'`,
337
+ importLines: ``,
307
338
  queries: gelClientQueryOperations
308
339
  },
309
340
  'mariadb:drizzle:local': {
310
341
  dbType: 'MySql2Database<SchemaType>',
311
- importLines: `
312
- import { eq } from 'drizzle-orm'
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: `import { SQL } from 'bun'`,
348
+ importLines: ``,
320
349
  queries: mysqlSqlQueryOperations
321
350
  },
322
351
  'mongodb:native:local': {
323
352
  dbType: 'Db',
324
- importLines: `import { Db } from 'mongodb'`,
353
+ importLines: ``,
325
354
  queries: mongodbQueryOperations
326
355
  },
327
356
  'mssql:sql:local': {
328
357
  dbType: 'ConnectionPool',
329
- importLines: `import { ConnectionPool } from 'mssql'`,
358
+ importLines: ``,
330
359
  queries: mssqlSqlQueryOperations
331
360
  },
332
361
  'mysql:drizzle:local': {
333
362
  dbType: 'MySql2Database<SchemaType>',
334
- importLines: `
335
- import { eq } from 'drizzle-orm'
336
- import { MySql2Database } from 'drizzle-orm/mysql2'
337
- import { schema, type SchemaType } from '../../../db/schema'`,
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: `import { SQL } from 'bun'`,
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 { eq } from 'drizzle-orm'
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 { eq } from 'drizzle-orm'
357
- import { NeonDatabase } from 'drizzle-orm/neon-serverless'
358
- import { schema, type SchemaType } from '../../../db/schema'`,
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: `import { SQL } from 'bun'`,
403
+ importLines: ``,
364
404
  queries: postgresSqlQueryOperations
365
405
  },
366
406
  'postgresql:sql:neon': {
367
407
  dbType: 'Pool',
368
- importLines: `import { Pool } from '@neondatabase/serverless'`,
369
- queries: postgresNeonQueryOperations
408
+ importLines: ``,
409
+ queries: postgresQueryOperations
370
410
  },
371
- 'singlestore:sql:local': {
411
+ 'postgresql:sql:planetscale': {
372
412
  dbType: 'Pool',
373
- importLines: `import { Pool, RowDataPacket } from 'mysql2/promise'`,
374
- queries: singlestoreSqlQueryOperations
413
+ importLines: ``,
414
+ queries: postgresQueryOperations
375
415
  },
376
416
  'singlestore:drizzle:local': {
377
417
  dbType: 'SingleStoreDriverDatabase<SchemaType>',
378
- importLines: `
379
- import { eq } from 'drizzle-orm'
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 { eq } from 'drizzle-orm'
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 { eq } from 'drizzle-orm'
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: `import { Database } from 'bun:sqlite'`,
442
+ importLines: ``,
403
443
  queries: bunSqliteQueryOperations
404
444
  },
405
445
  'sqlite:sql:turso': {
406
446
  dbType: 'Client',
407
- importLines: `import { Client } from '@libsql/client'`,
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' | 'authProvider' | 'databaseEngine'> & {
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, authProvider, orm, typesDirectory }: ScaffoldDatabaseProps) => Promise<void>;
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, authProvider, orm, typesDirectory }) => {
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 = authProvider !== undefined && authProvider !== 'none';
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(authProvider);
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
- authProvider,
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
- authProvider,
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
- authProvider,
58
+ authOption,
59
59
  databaseEngine,
60
60
  databaseHost
61
61
  });
@@ -1,9 +1,9 @@
1
- import { AuthProvider, DatabaseEngine } from '../../types';
1
+ import { AuthOption, DatabaseEngine } from '../../types';
2
2
  type ScaffoldDockerProps = {
3
3
  databaseEngine: DatabaseEngine;
4
4
  projectDatabaseDirectory: string;
5
- authProvider: AuthProvider;
5
+ authOption: AuthOption;
6
6
  projectName: string;
7
7
  };
8
- export declare const scaffoldDocker: ({ databaseEngine, projectDatabaseDirectory, projectName, authProvider }: ScaffoldDockerProps) => Promise<void>;
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, authProvider }) => {
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 = authProvider !== undefined && authProvider !== 'none';
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 'node:fs';
2
- import { join } from 'node:path';
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
- authProvider: CreateConfiguration['authProvider'];
5
+ authOption: CreateConfiguration['authOption'];
6
6
  flags: FrameworkFlags;
7
7
  };
8
- export declare const collectDependencies: ({ plugins, authProvider, flags }: CollectDependenciesProps) => import("../../types").AvailableDependency[];
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, authProvider, flags }) => {
2
+ export const collectDependencies = ({ plugins, authOption, flags }) => {
3
3
  const customSelections = availablePlugins.filter((plugin) => plugins.includes(plugin.value));
4
- const authPlugins = authProvider === 'absoluteAuth' ? [absoluteAuthPlugin] : [];
4
+ const authPlugins = authOption === 'abs' ? [absoluteAuthPlugin] : [];
5
5
  const htmxPlugins = flags.requiresHtmx ? [scopedStatePlugin] : [];
6
6
  const allDeps = [
7
7
  ...defaultDependencies,
@@ -0,0 +1,2 @@
1
+ import { ProviderOption } from '@absolutejs/auth';
2
+ export declare const generateAbsoluteAuthConfig: (absProviders: ProviderOption[] | undefined) => string;
@@ -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: 'connect({ url: getEnv("DATABASE_URL") })' }
20
+ planetscale: { expr: 'new Client({ url: getEnv("DATABASE_URL") })' }
21
21
  },
22
22
  postgresql: {
23
23
  neon: {
24
- expr: 'new Pool({ connectionString: getEnv("DATABASE_URL") })'
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: 'new Pool({ connectionString: getEnv("DATABASE_URL") })',
38
- planetscale: 'connect({ url: getEnv("DATABASE_URL") })',
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
- const mode = databaseHost === 'planetscale' && databaseEngine === 'mysql'
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: '${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
- authProvider: CreateConfiguration['authProvider'];
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, authProvider, databaseEngine, databaseHost, frontendDirectories }: GenerateImportsBlockProps) => string;
13
+ export declare const generateImportsBlock: ({ backendDirectory, deps, flags, orm, authOption, databaseEngine, databaseHost, frontendDirectories }: GenerateImportsBlockProps) => string;
14
14
  export {};