create-absolutejs 0.5.1 → 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 +6 -2
- package/dist/generators/configurations/initializeRoot.js +2 -2
- package/dist/generators/db/generateDatabaseTypes.d.ts +3 -3
- package/dist/generators/db/generateDatabaseTypes.js +6 -6
- 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 +27 -27
- package/dist/generators/db/handlerTemplates.js +59 -92
- 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 +8 -2
- package/dist/generators/project/generateImportsBlock.d.ts +2 -2
- package/dist/generators/project/generateImportsBlock.js +8 -15
- 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 +4 -3
- 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/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/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 +29 -8
- 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
|
@@ -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
|
+
};
|
|
@@ -21,7 +21,7 @@ const connectionMap = {
|
|
|
21
21
|
},
|
|
22
22
|
postgresql: {
|
|
23
23
|
neon: {
|
|
24
|
-
expr: '
|
|
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: '
|
|
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
|
-
|
|
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 {};
|
|
@@ -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,
|
|
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 {
|
|
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-
|
|
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
|
-
...(
|
|
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 (
|
|
175
|
-
rawImports.push(`import {
|
|
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 {
|
|
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
|
-
|
|
6
|
+
authOption: AuthOption;
|
|
7
7
|
buildDirectory: string;
|
|
8
8
|
};
|
|
9
|
-
export declare const generateRoutesBlock: ({ flags, frontendDirectories,
|
|
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,
|
|
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
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
29
|
+
ReactExample,
|
|
30
|
+
asset(manifest, 'ReactExampleIndex'),
|
|
31
|
+
${reactProps}
|
|
32
|
+
)`;
|
|
33
|
+
}
|
|
16
34
|
if (frontend === 'svelte')
|
|
17
35
|
return `handleSveltePageRequest(
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
if (frontend === 'vue')
|
|
24
|
-
|
|
25
|
-
?
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
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 (
|
|
54
|
-
|
|
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',
|
|
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}',
|
|
74
|
+
routes.push(`.get('/${frontend}', ${handler})`);
|
|
60
75
|
}
|
|
61
76
|
});
|
|
62
|
-
if (
|
|
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' | '
|
|
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,
|
|
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
|
|
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
|
-
|
|
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({
|
|
12
|
+
const deps = collectDependencies({ authOption, flags, plugins });
|
|
14
13
|
const importsBlock = generateImportsBlock({
|
|
15
|
-
|
|
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 =
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
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
|
-
|
|
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 {};
|