create-absolutejs 0.5.1 → 0.6.1

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 (61) 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 +6 -2
  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 +6 -6
  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 +27 -27
  13. package/dist/generators/db/handlerTemplates.js +59 -92
  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 +8 -2
  24. package/dist/generators/project/generateImportsBlock.d.ts +2 -2
  25. package/dist/generators/project/generateImportsBlock.js +8 -15
  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 +4 -3
  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/scaffold.d.ts +1 -1
  45. package/dist/scaffold.js +13 -9
  46. package/dist/templates/assets/svg/google-logo.svg +7 -0
  47. package/dist/templates/react/components/OAuthLink.tsx +39 -0
  48. package/dist/templates/react/components/ProfilePicture.tsx +56 -0
  49. package/dist/typeGuards.d.ts +2 -2
  50. package/dist/typeGuards.js +1 -1
  51. package/dist/types.d.ts +7 -2
  52. package/dist/utils/abort.js +1 -1
  53. package/dist/utils/parseCommandLineOptions.js +29 -8
  54. package/dist/utils/t3-utils.js +1 -1
  55. package/package.json +3 -2
  56. package/dist/generators/project/generateUseBlock.d.ts +0 -6
  57. package/dist/generators/project/generateUseBlock.js +0 -32
  58. package/dist/generators/react/generateReactPage.d.ts +0 -2
  59. package/dist/generators/react/generateReactPage.js +0 -23
  60. package/dist/questions/authProvider.d.ts +0 -1
  61. package/dist/templates/react/pages/ReactExample.tsx +0 -18
@@ -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
+ };
@@ -21,7 +21,7 @@ const connectionMap = {
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
26
  none: { expr: 'new SQL(getEnv("DATABASE_URL"))' },
27
27
  planetscale: {
@@ -37,7 +37,7 @@ const connectionMap = {
37
37
  }
38
38
  };
39
39
  const remoteDrizzleInit = {
40
- neon: 'new Pool({ connectionString: getEnv("DATABASE_URL") })',
40
+ neon: 'neon(getEnv("DATABASE_URL"));',
41
41
  planetscale: 'new Client({ url: getEnv("DATABASE_URL") })',
42
42
  turso: 'createClient({ url: getEnv("DATABASE_URL") })'
43
43
  };
@@ -64,6 +64,12 @@ export const generateDBBlock = ({ databaseEngine, orm, databaseHost }) => {
64
64
  return `
65
65
  const pool = createPool(getEnv("DATABASE_URL"))
66
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 });
67
73
  `;
68
74
  }
69
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 {};
@@ -1,7 +1,7 @@
1
1
  import { mkdirSync, writeFileSync } from 'fs';
2
2
  import { join } from 'path';
3
3
  import { isDrizzleDialect } from '../../typeGuards';
4
- export const generateImportsBlock = ({ backendDirectory, deps, flags, orm, authProvider, databaseEngine, databaseHost, frontendDirectories }) => {
4
+ export const generateImportsBlock = ({ backendDirectory, deps, flags, orm, authOption, databaseEngine, databaseHost, frontendDirectories }) => {
5
5
  const rawImports = [];
6
6
  const pushHandler = (cond, name) => cond &&
7
7
  rawImports.push(`import { ${name} } from '@absolutejs/absolute'`);
@@ -38,12 +38,12 @@ export const generateImportsBlock = ({ backendDirectory, deps, flags, orm, authP
38
38
  if (flags.requiresVue && !flags.requiresSvelte && vueDir !== undefined)
39
39
  rawImports.push(`import VueExample from '${buildExamplePath(vueDir, 'VueExample.vue')}'`);
40
40
  const connectorImports = {
41
- neon: [`import { Pool } from '@neondatabase/serverless'`],
41
+ neon: [`import { neon } from '@neondatabase/serverless'`],
42
42
  planetscale: [`import { Client } from '@planetscale/database'`],
43
43
  turso: [`import { createClient } from '@libsql/client'`]
44
44
  };
45
45
  const dialectImports = {
46
- neon: [`import { drizzle } from 'drizzle-orm/neon-serverless'`],
46
+ neon: [`import { drizzle } from 'drizzle-orm/neon-http'`],
47
47
  planetscale: [
48
48
  `import { drizzle } from 'drizzle-orm/planetscale-serverless'`
49
49
  ],
@@ -58,11 +58,8 @@ export const generateImportsBlock = ({ backendDirectory, deps, flags, orm, authP
58
58
  ...(databaseEngine === 'sqlite' && !isRemoteHost
59
59
  ? []
60
60
  : [`import { getEnv } from '@absolutejs/absolute'`]),
61
- ...(authProvider === 'absoluteAuth'
62
- ? [
63
- `import { schema } from '../../db/schema'`,
64
- `import { User } from '../types/databaseTypes'`
65
- ]
61
+ ...(authOption === 'abs'
62
+ ? [`import { schema } from '../../db/schema'`]
66
63
  : [`import { schema } from '../../db/schema'`])
67
64
  ]
68
65
  };
@@ -171,13 +168,9 @@ export const generateImportsBlock = ({ backendDirectory, deps, flags, orm, authP
171
168
  if (noOrm && hasDatabase && noOrmImports[databaseEngine]) {
172
169
  rawImports.push(...noOrmImports[databaseEngine]);
173
170
  }
174
- if (authProvider === 'absoluteAuth')
175
- rawImports.push(`import { absoluteAuth, instantiateUserSession } from '@absolutejs/auth'`, ...(hasDatabase
176
- ? [
177
- `import { createUser, getUser } from './handlers/userHandlers'`
178
- ]
179
- : []));
180
- if (hasDatabase && (authProvider === undefined || authProvider === 'none'))
171
+ if (authOption === 'abs')
172
+ rawImports.push(`import { absoluteAuthConfig } from './utils/absoluteAuthConfig'`, `import { t } from 'elysia'`, `import { authProviderOption, providers, userSessionIdTypebox, getStatus } from '@absolutejs/auth'`);
173
+ if (hasDatabase && (authOption === undefined || authOption === 'none'))
181
174
  rawImports.push(`import { getCountHistory, createCountHistory } from './handlers/countHistoryHandlers'`, `import { t } from 'elysia'`);
182
175
  if (flags.requiresVue && flags.requiresSvelte) {
183
176
  const utilsDir = join(backendDirectory, 'utils');
@@ -1,10 +1,10 @@
1
- import type { AuthProvider, FrontendDirectories } from '../../types';
1
+ import type { AuthOption, FrontendDirectories } from '../../types';
2
2
  import type { FrameworkFlags } from './computeFlags';
3
3
  type GenerateRoutesBlockProps = {
4
4
  flags: FrameworkFlags;
5
5
  frontendDirectories: FrontendDirectories;
6
- authProvider: AuthProvider;
6
+ authOption: AuthOption;
7
7
  buildDirectory: string;
8
8
  };
9
- export declare const generateRoutesBlock: ({ flags, frontendDirectories, authProvider, buildDirectory }: GenerateRoutesBlockProps) => string;
9
+ export declare const generateRoutesBlock: ({ flags, frontendDirectories, authOption, buildDirectory }: GenerateRoutesBlockProps) => string;
10
10
  export {};
@@ -1,73 +1,84 @@
1
1
  import { isFrontend } from '../../typeGuards';
2
- export const generateRoutesBlock = ({ flags, frontendDirectories, authProvider, buildDirectory }) => {
2
+ export const generateRoutesBlock = ({ flags, frontendDirectories, authOption, buildDirectory }) => {
3
3
  const routes = [];
4
+ const wrap = (handlerCall) => authOption === 'abs'
5
+ ? `async ({ cookie: { auth_provider, user_session_id }, store: { session }, status }) => {
6
+ const { user, error } = await getStatus(session, user_session_id);
7
+
8
+ if (error) {
9
+ return status(error.code, error.message);
10
+ }
11
+
12
+ const providerConfiguration =
13
+ auth_provider.value && providers[auth_provider.value];
14
+
15
+ return ${handlerCall};
16
+ }`
17
+ : `() => ${handlerCall}`;
4
18
  const createHandlerCall = (frontend, directory) => {
5
19
  const base = `${buildDirectory}${directory ? `/${directory}` : ''}/pages`;
6
20
  if (frontend === 'html')
7
21
  return `handleHTMLPageRequest(\`${base}/HTMLExample.html\`)`;
8
22
  if (frontend === 'htmx')
9
23
  return `handleHTMXPageRequest(\`${base}/HTMXExample.html\`)`;
10
- if (frontend === 'react')
24
+ if (frontend === 'react') {
25
+ const reactProps = authOption === 'abs'
26
+ ? `{ initialCount: 0, cssPath: asset(manifest, 'ReactExampleCSS'), user, providerConfiguration }`
27
+ : `{ initialCount: 0, cssPath: asset(manifest, 'ReactExampleCSS') }`;
11
28
  return `handleReactPageRequest(
12
- ReactExample,
13
- asset(manifest, 'ReactExampleIndex'),
14
- { initialCount: 0, cssPath: asset(manifest, 'ReactExampleCSS') }
15
- )`;
29
+ ReactExample,
30
+ asset(manifest, 'ReactExampleIndex'),
31
+ ${reactProps}
32
+ )`;
33
+ }
16
34
  if (frontend === 'svelte')
17
35
  return `handleSveltePageRequest(
18
- SvelteExample,
19
- asset(manifest, 'SvelteExample'),
20
- asset(manifest, 'SvelteExampleIndex'),
21
- { initialCount: 0, cssPath: asset(manifest, 'SvelteExampleCSS') }
22
- )`;
23
- if (frontend === 'vue')
24
- return flags.requiresSvelte
25
- ? `handleVuePageRequest(
26
- vueImports.VueExample,
27
- asset(manifest, 'VueExample'),
28
- asset(manifest, 'VueExampleIndex'),
29
- generateHeadElement({
30
- cssPath: asset(manifest, 'VueExampleCSS'),
31
- title: 'AbsoluteJS + Vue',
32
- description: 'A Vue.js example with AbsoluteJS'
33
- }),
34
- { initialCount: 0 }
35
- )`
36
- : `handleVuePageRequest(
37
- VueExample,
38
- asset(manifest, 'VueExample'),
39
- asset(manifest, 'VueExampleIndex'),
40
- generateHeadElement({
41
- cssPath: asset(manifest, 'VueExampleCSS'),
42
- title: 'AbsoluteJS + Vue',
43
- description: 'A Vue.js example with AbsoluteJS'
44
- }),
45
- { initialCount: 0 }
46
- )`;
36
+ SvelteExample,
37
+ asset(manifest, 'SvelteExample'),
38
+ asset(manifest, 'SvelteExampleIndex'),
39
+ { initialCount: 0, cssPath: asset(manifest, 'SvelteExampleCSS') }
40
+ )`;
41
+ if (frontend === 'vue') {
42
+ const vueComponent = flags.requiresSvelte
43
+ ? 'vueImports.VueExample'
44
+ : 'VueExample';
45
+ return `handleVuePageRequest(
46
+ ${vueComponent},
47
+ asset(manifest, 'VueExample'),
48
+ asset(manifest, 'VueExampleIndex'),
49
+ generateHeadElement({
50
+ cssPath: asset(manifest, 'VueExampleCSS'),
51
+ title: 'AbsoluteJS + Vue',
52
+ description: 'A Vue.js example with AbsoluteJS'
53
+ }),
54
+ { initialCount: 0 }
55
+ )`;
56
+ }
47
57
  return '';
48
58
  };
49
59
  Object.entries(frontendDirectories).forEach(([frontend, directory], entryIndex) => {
50
60
  if (!isFrontend(frontend))
51
61
  return;
52
62
  const handlerCall = createHandlerCall(frontend, directory);
53
- if (entryIndex === 0)
54
- routes.push(`.get('/', () => ${handlerCall})`);
63
+ if (!handlerCall)
64
+ return;
65
+ const handler = wrap(handlerCall);
66
+ if (entryIndex === 0) {
67
+ routes.push(`.get('/', ${handler})`);
68
+ }
55
69
  if (frontend === 'htmx') {
56
- routes.push(`.get('/htmx', () => ${handlerCall})`, `.post('/htmx/reset', ({ resetScopedStore }) => resetScopedStore())`, `.get('/htmx/count', ({ scopedStore }) => scopedStore.count)`, `.post('/htmx/increment', ({ scopedStore }) => ++scopedStore.count)`);
70
+ routes.push(`.get('/htmx', ${handler})`);
71
+ routes.push(`.post('/htmx/reset', ({ resetScopedStore }) => resetScopedStore())`, `.get('/htmx/count', ({ scopedStore }) => scopedStore.count)`, `.post('/htmx/increment', ({ scopedStore }) => ++scopedStore.count)`);
57
72
  }
58
73
  else {
59
- routes.push(`.get('/${frontend}', () => ${handlerCall})`);
74
+ routes.push(`.get('/${frontend}', ${handler})`);
60
75
  }
61
76
  });
62
- if (authProvider === undefined || authProvider === 'none') {
77
+ if (authOption === undefined || authOption === 'none') {
63
78
  routes.push(`.get('/count/:uid', ({ params: { uid } }) => getCountHistory(db, uid), {
64
- params: t.Object({
65
- uid: t.Number()
66
- })
79
+ params: t.Object({ uid: t.Number() })
67
80
  })`, `.post('/count', ({ body: { count } }) => createCountHistory(db, count), {
68
- body: t.Object({
69
- count: t.Number()
70
- })
81
+ body: t.Object({ count: t.Number() })
71
82
  })`);
72
83
  }
73
84
  return routes.join('\n ');
@@ -1,6 +1,6 @@
1
1
  import type { CreateConfiguration } from '../../types';
2
- type CreateServerFileProps = Pick<CreateConfiguration, 'tailwind' | 'authProvider' | 'databaseEngine' | 'plugins' | 'buildDirectory' | 'databaseHost' | 'orm' | 'assetsDirectory' | 'frontendDirectories'> & {
2
+ type CreateServerFileProps = Pick<CreateConfiguration, 'tailwind' | 'authOption' | 'databaseEngine' | 'plugins' | 'buildDirectory' | 'databaseHost' | 'orm' | 'assetsDirectory' | 'frontendDirectories'> & {
3
3
  backendDirectory: string;
4
4
  };
5
- export declare const generateServerFile: ({ tailwind, authProvider, plugins, buildDirectory, databaseEngine, databaseHost, orm, assetsDirectory, frontendDirectories, backendDirectory }: CreateServerFileProps) => void;
5
+ export declare const generateServerFile: ({ tailwind, authOption, plugins, buildDirectory, databaseEngine, databaseHost, orm, assetsDirectory, frontendDirectories, backendDirectory }: CreateServerFileProps) => void;
6
6
  export {};
@@ -1,4 +1,4 @@
1
- import { writeFileSync, mkdirSync } from 'fs';
1
+ import { writeFileSync } from 'fs';
2
2
  import { join } from 'path';
3
3
  import { collectDependencies } from './collectDependencies';
4
4
  import { computeFlags } from './computeFlags';
@@ -6,13 +6,12 @@ import { generateBuildBlock } from './generateBuildBlock';
6
6
  import { generateDBBlock } from './generateDBBlock';
7
7
  import { generateImportsBlock } from './generateImportsBlock';
8
8
  import { generateRoutesBlock } from './generateRoutesBlock';
9
- import { generateUseBlock } from './generateUseBlock';
10
- export const generateServerFile = ({ tailwind, authProvider, plugins, buildDirectory, databaseEngine, databaseHost, orm, assetsDirectory, frontendDirectories, backendDirectory }) => {
9
+ export const generateServerFile = ({ tailwind, authOption, plugins, buildDirectory, databaseEngine, databaseHost, orm, assetsDirectory, frontendDirectories, backendDirectory }) => {
11
10
  const serverFilePath = join(backendDirectory, 'server.ts');
12
11
  const flags = computeFlags(frontendDirectories);
13
- const deps = collectDependencies({ authProvider, flags, plugins });
12
+ const deps = collectDependencies({ authOption, flags, plugins });
14
13
  const importsBlock = generateImportsBlock({
15
- authProvider,
14
+ authOption,
16
15
  backendDirectory,
17
16
  databaseEngine,
18
17
  databaseHost,
@@ -31,13 +30,30 @@ export const generateServerFile = ({ tailwind, authProvider, plugins, buildDirec
31
30
  if (databaseEngine && databaseEngine !== 'none') {
32
31
  dbBlock = generateDBBlock({ databaseEngine, databaseHost, orm });
33
32
  }
34
- const useBlock = generateUseBlock({
35
- databaseEngine,
36
- deps,
37
- orm
38
- });
33
+ const useBlock = deps
34
+ .flatMap((dependency) => dependency.imports ?? [])
35
+ .filter((pluginImport) => pluginImport.isPlugin)
36
+ .map((pluginImport) => {
37
+ if (pluginImport.packageName === 'absoluteAuth') {
38
+ return `.use(absoluteAuth(absoluteAuthConfig(db)))`;
39
+ }
40
+ if (pluginImport.config === undefined) {
41
+ return `.use(${pluginImport.packageName})`;
42
+ }
43
+ if (pluginImport.config === null) {
44
+ return `.use(${pluginImport.packageName}())`;
45
+ }
46
+ return `.use(${pluginImport.packageName}(${JSON.stringify(pluginImport.config)}))`;
47
+ })
48
+ .join('\n');
49
+ const guardBlock = `.guard({
50
+ cookie: t.Cookie({
51
+ auth_provider: t.Optional(authProviderOption),
52
+ user_session_id: userSessionIdTypebox
53
+ })
54
+ })`;
39
55
  const routesBlock = generateRoutesBlock({
40
- authProvider,
56
+ authOption,
41
57
  buildDirectory,
42
58
  flags,
43
59
  frontendDirectories
@@ -48,12 +64,12 @@ ${manifestBlock}
48
64
  ${dbBlock}
49
65
  new Elysia()
50
66
  ${useBlock}
67
+ ${authOption === 'abs' ? guardBlock : ''}
51
68
  ${routesBlock}
52
69
  .on('error', err => {
53
70
  const { request } = err
54
71
  console.error(\`Server error on \${request.method} \${request.url}: \${err.message}\`)
55
72
  });
56
73
  `;
57
- mkdirSync(backendDirectory, { recursive: true });
58
74
  writeFileSync(serverFilePath, content);
59
75
  };
@@ -0,0 +1,6 @@
1
+ import { CreateConfiguration } from '../../types';
2
+ type ScaffoldBackendProps = Pick<CreateConfiguration, 'assetsDirectory' | 'absProviders' | 'authOption' | 'buildDirectory' | 'databaseEngine' | 'databaseHost' | 'frontendDirectories' | 'orm' | 'plugins' | 'tailwind'> & {
3
+ backendDirectory: string;
4
+ };
5
+ export declare const scaffoldBackend: ({ assetsDirectory, authOption, absProviders, backendDirectory, buildDirectory, databaseEngine, databaseHost, frontendDirectories, orm, plugins, tailwind }: ScaffoldBackendProps) => void;
6
+ export {};
@@ -0,0 +1,23 @@
1
+ import { mkdirSync, writeFileSync } from 'fs';
2
+ import { join } from 'path';
3
+ import { generateAbsoluteAuthConfig } from './generateAbsoluteAuthConfig';
4
+ import { generateServerFile } from './generateServer';
5
+ export const scaffoldBackend = ({ assetsDirectory, authOption, absProviders, backendDirectory, buildDirectory, databaseEngine, databaseHost, frontendDirectories, orm, plugins, tailwind }) => {
6
+ generateServerFile({
7
+ assetsDirectory,
8
+ authOption,
9
+ backendDirectory,
10
+ buildDirectory,
11
+ databaseEngine,
12
+ databaseHost,
13
+ frontendDirectories,
14
+ orm,
15
+ plugins,
16
+ tailwind
17
+ });
18
+ if (authOption === 'abs') {
19
+ mkdirSync(join(backendDirectory, 'utils'), { recursive: true });
20
+ const absoluteAuthConfig = generateAbsoluteAuthConfig(absProviders);
21
+ writeFileSync(join(backendDirectory, 'utils', 'absoluteAuthConfig.ts'), absoluteAuthConfig, 'utf-8');
22
+ }
23
+ };
@@ -1,8 +1,8 @@
1
1
  import type { CreateConfiguration } from '../../types';
2
- type ScaffoldFrontendsProps = Pick<CreateConfiguration, 'useHTMLScripts' | 'frontendDirectories' | 'frontends'> & {
2
+ type ScaffoldFrontendsProps = Pick<CreateConfiguration, 'useHTMLScripts' | 'frontendDirectories' | 'assetsDirectory' | 'frontends' | 'authOption' | 'absProviders'> & {
3
3
  frontendDirectory: string;
4
4
  templatesDirectory: string;
5
5
  projectAssetsDirectory: string;
6
6
  };
7
- export declare const scaffoldFrontends: ({ frontendDirectory, templatesDirectory, projectAssetsDirectory, useHTMLScripts, frontendDirectories, frontends }: ScaffoldFrontendsProps) => void;
7
+ export declare const scaffoldFrontends: ({ frontendDirectory, assetsDirectory, absProviders, authOption, templatesDirectory, projectAssetsDirectory, useHTMLScripts, frontendDirectories, frontends }: ScaffoldFrontendsProps) => void;
8
8
  export {};