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
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
import { cpSync, mkdirSync } from '
|
|
2
|
-
import { join } from '
|
|
1
|
+
import { cpSync, mkdirSync } from 'fs';
|
|
2
|
+
import { join } from 'path';
|
|
3
3
|
import { scaffoldHTML } from '../html/scaffoldHTML';
|
|
4
4
|
import { scaffoldHTMX } from '../htmx/scaffoldHTMX';
|
|
5
5
|
import { scaffoldReact } from '../react/scaffoldReact';
|
|
6
6
|
import { scaffoldSvelte } from '../svelte/scaffoldSvelte';
|
|
7
7
|
import { scaffoldVue } from '../vue/scaffoldVue';
|
|
8
|
-
export const scaffoldFrontends = ({ frontendDirectory, templatesDirectory, projectAssetsDirectory, useHTMLScripts, frontendDirectories, frontends }) => {
|
|
8
|
+
export const scaffoldFrontends = ({ frontendDirectory, assetsDirectory, absProviders, authOption, templatesDirectory, projectAssetsDirectory, useHTMLScripts, frontendDirectories, frontends }) => {
|
|
9
9
|
const stylesTargetDirectory = join(frontendDirectory, 'styles');
|
|
10
10
|
cpSync(join(templatesDirectory, 'styles'), stylesTargetDirectory, {
|
|
11
11
|
recursive: true
|
|
@@ -25,6 +25,9 @@ export const scaffoldFrontends = ({ frontendDirectory, templatesDirectory, proje
|
|
|
25
25
|
switch (frontendName) {
|
|
26
26
|
case 'react':
|
|
27
27
|
scaffoldReact({
|
|
28
|
+
absProviders,
|
|
29
|
+
assetsDirectory,
|
|
30
|
+
authOption,
|
|
28
31
|
frontends,
|
|
29
32
|
isSingleFrontend,
|
|
30
33
|
projectAssetsDirectory,
|
|
@@ -34,6 +37,9 @@ export const scaffoldFrontends = ({ frontendDirectory, templatesDirectory, proje
|
|
|
34
37
|
break;
|
|
35
38
|
case 'svelte':
|
|
36
39
|
scaffoldSvelte({
|
|
40
|
+
absProviders,
|
|
41
|
+
assetsDirectory,
|
|
42
|
+
authOption,
|
|
37
43
|
frontends,
|
|
38
44
|
isSingleFrontend,
|
|
39
45
|
projectAssetsDirectory,
|
|
@@ -43,6 +49,9 @@ export const scaffoldFrontends = ({ frontendDirectory, templatesDirectory, proje
|
|
|
43
49
|
break;
|
|
44
50
|
case 'vue':
|
|
45
51
|
scaffoldVue({
|
|
52
|
+
absProviders,
|
|
53
|
+
assetsDirectory,
|
|
54
|
+
authOption,
|
|
46
55
|
frontends,
|
|
47
56
|
projectAssetsDirectory,
|
|
48
57
|
targetDirectory,
|
|
@@ -54,6 +63,9 @@ export const scaffoldFrontends = ({ frontendDirectory, templatesDirectory, proje
|
|
|
54
63
|
break;
|
|
55
64
|
case 'html':
|
|
56
65
|
scaffoldHTML({
|
|
66
|
+
absProviders,
|
|
67
|
+
assetsDirectory,
|
|
68
|
+
authOption,
|
|
57
69
|
frontends,
|
|
58
70
|
isSingleFrontend,
|
|
59
71
|
projectAssetsDirectory,
|
|
@@ -64,6 +76,9 @@ export const scaffoldFrontends = ({ frontendDirectory, templatesDirectory, proje
|
|
|
64
76
|
break;
|
|
65
77
|
case 'htmx':
|
|
66
78
|
scaffoldHTMX({
|
|
79
|
+
absProviders,
|
|
80
|
+
assetsDirectory,
|
|
81
|
+
authOption,
|
|
67
82
|
frontends,
|
|
68
83
|
isSingleFrontend,
|
|
69
84
|
projectAssetsDirectory,
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import { ProviderOption } from '@absolutejs/auth';
|
|
2
|
+
import { AuthOption, Frontend } from '../../types';
|
|
3
|
+
export declare const generateDropdownComponent: (frontends: Frontend[]) => string;
|
|
4
|
+
export declare const generateSignInComponent: (absProviders: ProviderOption[] | undefined) => string;
|
|
5
|
+
export declare const generateReactExamplePage: (authOption: AuthOption) => string;
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
import { formatNavLink } from '../../utils/formatNavLink';
|
|
2
|
+
export const generateDropdownComponent = (frontends) => {
|
|
3
|
+
const navLinks = frontends.map(formatNavLink).join('\n\t\t\t');
|
|
4
|
+
return `import { useState } from 'react';
|
|
5
|
+
|
|
6
|
+
export const Dropdown = () => {
|
|
7
|
+
const [isOpen, setIsOpen] = useState(false);
|
|
8
|
+
|
|
9
|
+
return (
|
|
10
|
+
<details
|
|
11
|
+
onPointerEnter={() => setIsOpen(true)}
|
|
12
|
+
onPointerLeave={() => setIsOpen(false)}
|
|
13
|
+
open={isOpen}
|
|
14
|
+
>
|
|
15
|
+
<summary>Pages</summary>
|
|
16
|
+
<nav>
|
|
17
|
+
${navLinks}
|
|
18
|
+
</nav>
|
|
19
|
+
</details>
|
|
20
|
+
);
|
|
21
|
+
};
|
|
22
|
+
`;
|
|
23
|
+
};
|
|
24
|
+
export const generateSignInComponent = (absProviders) => `import { useState } from 'react';
|
|
25
|
+
import { OAuthLink } from './OAuthLink';
|
|
26
|
+
|
|
27
|
+
export const SignIn = () => {
|
|
28
|
+
const [isOpen, setIsOpen] = useState(false);
|
|
29
|
+
|
|
30
|
+
return (
|
|
31
|
+
<details
|
|
32
|
+
onPointerEnter={() => setIsOpen(true)}
|
|
33
|
+
onPointerLeave={() => setIsOpen(false)}
|
|
34
|
+
open={isOpen}
|
|
35
|
+
>
|
|
36
|
+
<summary>Sign In</summary>
|
|
37
|
+
<nav>
|
|
38
|
+
${absProviders && absProviders.length > 0
|
|
39
|
+
? absProviders
|
|
40
|
+
.map((provider) => {
|
|
41
|
+
const logoUrl = `/assets/svg/google-logo.svg`;
|
|
42
|
+
const name = provider.charAt(0).toUpperCase() +
|
|
43
|
+
provider.slice(1).toLowerCase();
|
|
44
|
+
return `<OAuthLink provider="${provider}" logoUrl="${logoUrl}" name="${name}" mode="in" />`;
|
|
45
|
+
})
|
|
46
|
+
.join('\n\t\t\t')
|
|
47
|
+
: `<p>No OAuth providers configured</p>`}
|
|
48
|
+
</nav>
|
|
49
|
+
</details>
|
|
50
|
+
);
|
|
51
|
+
}
|
|
52
|
+
`;
|
|
53
|
+
export const generateReactExamplePage = (authOption) => {
|
|
54
|
+
const useBlockReturn = authOption === 'abs';
|
|
55
|
+
const propsType = `
|
|
56
|
+
type ReactExampleProps = {
|
|
57
|
+
initialCount: number;
|
|
58
|
+
cssPath: string;
|
|
59
|
+
${authOption === 'abs' ? 'user: User | null;\n\tproviderConfiguration: ProviderConfiguration | undefined;' : ''}
|
|
60
|
+
};
|
|
61
|
+
`;
|
|
62
|
+
const fnSignature = authOption === 'abs'
|
|
63
|
+
? `export const ReactExample = ({ initialCount, cssPath, user, providerConfiguration }: ReactExampleProps) => {`
|
|
64
|
+
: `export const ReactExample = ({ initialCount, cssPath }: ReactExampleProps) => (`;
|
|
65
|
+
const extractProps = ` const userImage =
|
|
66
|
+
user?.metadata && providerConfiguration?.picture
|
|
67
|
+
? extractPropFromIdentity(
|
|
68
|
+
user.metadata,
|
|
69
|
+
providerConfiguration.picture,
|
|
70
|
+
'string'
|
|
71
|
+
)
|
|
72
|
+
: undefined;
|
|
73
|
+
|
|
74
|
+
const givenName =
|
|
75
|
+
user?.metadata && providerConfiguration?.givenName
|
|
76
|
+
? extractPropFromIdentity(
|
|
77
|
+
user.metadata,
|
|
78
|
+
providerConfiguration.givenName,
|
|
79
|
+
'string'
|
|
80
|
+
)
|
|
81
|
+
: undefined;
|
|
82
|
+
|
|
83
|
+
const familyName =
|
|
84
|
+
user?.metadata && providerConfiguration?.familyName
|
|
85
|
+
? extractPropFromIdentity(
|
|
86
|
+
user.metadata,
|
|
87
|
+
providerConfiguration.familyName,
|
|
88
|
+
'string'
|
|
89
|
+
)
|
|
90
|
+
: undefined;`;
|
|
91
|
+
const userButtonsBlock = authOption === 'abs'
|
|
92
|
+
? `{user ? <ProfilePicture userImage={userImage} givenName={givenName} familyName={familyName} /> : <SignIn />}`
|
|
93
|
+
: ``;
|
|
94
|
+
const rightGroup = authOption === 'abs'
|
|
95
|
+
? `<div style={{ display: 'flex', alignItems: 'center', gap: '1rem' }}>
|
|
96
|
+
<Dropdown />
|
|
97
|
+
${userButtonsBlock}
|
|
98
|
+
</div>`
|
|
99
|
+
: `<Dropdown />`;
|
|
100
|
+
const closing = authOption === 'abs' ? `};` : `);`;
|
|
101
|
+
return `
|
|
102
|
+
${authOption === 'abs' ? `import { User } from '../../../types/databaseTypes';\nimport { extractPropFromIdentity, ProviderConfiguration } from '@absolutejs/auth';` : ''}
|
|
103
|
+
import { App } from '../components/App';
|
|
104
|
+
import { Dropdown } from '../components/Dropdown';
|
|
105
|
+
import { Head } from '../components/Head';
|
|
106
|
+
${authOption === 'abs' ? `import { ProfilePicture } from '../components/ProfilePicture';\nimport { SignIn } from '../components/SignIn';` : ''}
|
|
107
|
+
|
|
108
|
+
${propsType}
|
|
109
|
+
|
|
110
|
+
${fnSignature}
|
|
111
|
+
${authOption === 'abs' ? extractProps : ''}
|
|
112
|
+
${useBlockReturn ? 'return (' : ''}
|
|
113
|
+
<html>
|
|
114
|
+
<Head cssPath={cssPath} />
|
|
115
|
+
<body>
|
|
116
|
+
<header>
|
|
117
|
+
<a href="/">AbsoluteJS</a>
|
|
118
|
+
${rightGroup}
|
|
119
|
+
</header>
|
|
120
|
+
<App initialCount={initialCount} />
|
|
121
|
+
</body>
|
|
122
|
+
</html>
|
|
123
|
+
${useBlockReturn ? ');' : ''}
|
|
124
|
+
${closing}
|
|
125
|
+
`;
|
|
126
|
+
};
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
import { ScaffoldFrontendProps } from '../../types';
|
|
2
|
-
export declare const scaffoldReact: ({ isSingleFrontend, targetDirectory, templatesDirectory, frontends, projectAssetsDirectory }: ScaffoldFrontendProps) => void;
|
|
2
|
+
export declare const scaffoldReact: ({ isSingleFrontend, authOption, targetDirectory, templatesDirectory, frontends, assetsDirectory, projectAssetsDirectory, absProviders }: ScaffoldFrontendProps) => void;
|
|
@@ -1,14 +1,23 @@
|
|
|
1
1
|
import { copyFileSync, cpSync, mkdirSync, writeFileSync } from 'fs';
|
|
2
2
|
import { join } from 'path';
|
|
3
3
|
import { generateMarkupCSS } from '../project/generateMarkupCSS';
|
|
4
|
-
import { generateDropdownComponent } from './
|
|
5
|
-
export const scaffoldReact = ({ isSingleFrontend, targetDirectory, templatesDirectory, frontends, projectAssetsDirectory }) => {
|
|
4
|
+
import { generateDropdownComponent, generateReactExamplePage, generateSignInComponent } from './generateReactComponents';
|
|
5
|
+
export const scaffoldReact = ({ isSingleFrontend, authOption, targetDirectory, templatesDirectory, frontends, assetsDirectory, projectAssetsDirectory, absProviders }) => {
|
|
6
|
+
mkdirSync(join(projectAssetsDirectory, 'svg'), { recursive: true });
|
|
6
7
|
copyFileSync(join(templatesDirectory, 'assets', 'svg', 'react.svg'), join(projectAssetsDirectory, 'svg', 'react.svg'));
|
|
8
|
+
copyFileSync(join(templatesDirectory, 'assets', 'svg', 'google-logo.svg'), join(projectAssetsDirectory, 'svg', 'google-logo.svg'));
|
|
7
9
|
cpSync(join(templatesDirectory, 'react'), targetDirectory, {
|
|
8
10
|
recursive: true
|
|
9
11
|
});
|
|
10
12
|
const dropdownComponent = generateDropdownComponent(frontends);
|
|
11
13
|
writeFileSync(join(targetDirectory, 'components', 'Dropdown.tsx'), dropdownComponent, 'utf-8');
|
|
14
|
+
if (authOption === 'abs') {
|
|
15
|
+
const signInComponent = generateSignInComponent(absProviders);
|
|
16
|
+
writeFileSync(join(targetDirectory, 'components', 'SignIn.tsx'), signInComponent, 'utf-8');
|
|
17
|
+
}
|
|
18
|
+
const pageComponent = generateReactExamplePage(authOption);
|
|
19
|
+
mkdirSync(join(targetDirectory, 'pages'), { recursive: true });
|
|
20
|
+
writeFileSync(join(targetDirectory, 'pages', 'ReactExample.tsx'), pageComponent, 'utf-8');
|
|
12
21
|
const cssOutputDir = join(targetDirectory, 'styles');
|
|
13
22
|
mkdirSync(cssOutputDir, { recursive: true });
|
|
14
23
|
const cssOutputFile = join(cssOutputDir, 'react-example.css');
|
package/dist/index.js
CHANGED
package/dist/messages.d.ts
CHANGED
|
@@ -10,5 +10,5 @@ type DebugMessageProps = {
|
|
|
10
10
|
response: CreateConfiguration;
|
|
11
11
|
packageManager: string;
|
|
12
12
|
};
|
|
13
|
-
export declare const getDebugMessage: ({ response: { projectName, codeQualityTool, directoryConfig, useTailwind, tailwind, frontends, useHTMLScripts, frontendDirectories, buildDirectory, assetsDirectory, databaseEngine, databaseHost, databaseDirectory, orm,
|
|
13
|
+
export declare const getDebugMessage: ({ response: { projectName, codeQualityTool, directoryConfig, useTailwind, tailwind, frontends, useHTMLScripts, frontendDirectories, buildDirectory, assetsDirectory, databaseEngine, databaseHost, databaseDirectory, orm, authOption, plugins, initializeGitNow, installDependenciesNow }, packageManager }: DebugMessageProps) => string;
|
|
14
14
|
export {};
|
package/dist/messages.js
CHANGED
|
@@ -11,10 +11,11 @@ Options:
|
|
|
11
11
|
${cyan('--help, -h')} Show this help message and exit
|
|
12
12
|
${cyan('--debug, -d')} Display a summary of the project configuration after creation
|
|
13
13
|
|
|
14
|
+
${cyan('--abs-provider')} A provider for Absolute-Auth (eg. 'google', 'github', 'discord') the full list is available at https://absolutejs.com/documentation/absolute-auth
|
|
14
15
|
${cyan('--angular')} Include an Angular frontend
|
|
15
16
|
${cyan('--angular-dir')} ${dim(cyan('<directory>'))} Specify the directory for and use the Angular frontend
|
|
16
17
|
${cyan('--assets')} ${dim(cyan('<directory>'))} Directory name for your static assets
|
|
17
|
-
${cyan('--auth')} ${dim(cyan('<plugin>'))} Pre-configured auth plugin (currently only "
|
|
18
|
+
${cyan('--auth')} ${dim(cyan('<plugin>'))} Pre-configured auth plugin (currently only "abs") or 'none'
|
|
18
19
|
${cyan('--biome')} Use Biome for code quality and formatting
|
|
19
20
|
${cyan('--build')} ${dim(cyan('<directory>'))} Output directory for build artifacts
|
|
20
21
|
${cyan('--db')} ${dim(cyan('<engine>'))} Database engine (postgresql | mysql | sqlite | mongodb | mariadb | gel | singlestore | cockroachdb | mssql) or 'none'
|
|
@@ -47,7 +48,7 @@ export const getOutroMessage = ({ projectName, packageManager, installDependenci
|
|
|
47
48
|
`${cyan('cd')} ${projectName}\n` +
|
|
48
49
|
`${installDependenciesNow ? '' : `${cyan(`${packageManager} install`)}\n`}` +
|
|
49
50
|
`${cyan(`${packageManager} dev`)}`; // TODO: Some package managers need run
|
|
50
|
-
export const getDebugMessage = ({ response: { projectName, codeQualityTool, directoryConfig, useTailwind, tailwind, frontends, useHTMLScripts, frontendDirectories, buildDirectory, assetsDirectory, databaseEngine, databaseHost, databaseDirectory, orm,
|
|
51
|
+
export const getDebugMessage = ({ response: { projectName, codeQualityTool, directoryConfig, useTailwind, tailwind, frontends, useHTMLScripts, frontendDirectories, buildDirectory, assetsDirectory, databaseEngine, databaseHost, databaseDirectory, orm, authOption, plugins, initializeGitNow, installDependenciesNow }, packageManager }) => {
|
|
51
52
|
const htmlScriptingValue = useHTMLScripts
|
|
52
53
|
? blueBright('TypeScript')
|
|
53
54
|
: dim('None');
|
|
@@ -73,7 +74,7 @@ export const getDebugMessage = ({ response: { projectName, codeQualityTool, dire
|
|
|
73
74
|
['Database Host', databaseHost && databaseHost !== 'none' ? databaseHost : dim('None')],
|
|
74
75
|
['Database Directory', databaseDirectory ?? dim('None')],
|
|
75
76
|
['ORM', orm ?? dim('None')],
|
|
76
|
-
['Auth Provider',
|
|
77
|
+
['Auth Provider', authOption && authOption !== 'none' ? authOption : dim('None')],
|
|
77
78
|
['Plugins', plugins.length && !plugins.includes('none') ? plugins.join(', ') : dim('None')],
|
|
78
79
|
['Initialize Git', initializeGitNow ? green('Yes') : red('No')],
|
|
79
80
|
['Install Dependencies', installDependenciesNow ? green('Yes') : red('No')],
|
package/dist/prompt.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { getAuthOption } from './questions/authOption';
|
|
2
2
|
import { getCodeQualityTool } from './questions/codeQualityTool';
|
|
3
3
|
import { getConfigurationType } from './questions/configurationType';
|
|
4
4
|
import { getDatabaseEngine } from './questions/databaseEngine';
|
|
@@ -51,7 +51,7 @@ export const prompt = async (argumentConfiguration) => {
|
|
|
51
51
|
if (argumentConfiguration.frontendDirectories !== undefined)
|
|
52
52
|
directoryConfig = 'custom';
|
|
53
53
|
// 12. Auth provider
|
|
54
|
-
const
|
|
54
|
+
const authOption = argumentConfiguration.authOption ?? (await getAuthOption());
|
|
55
55
|
// 13. Additional plugins
|
|
56
56
|
const plugins = argumentConfiguration.plugins?.filter((plugin) => plugin !== undefined) ?? (await getPlugins());
|
|
57
57
|
// 14. Initialize Git repository
|
|
@@ -60,8 +60,9 @@ export const prompt = async (argumentConfiguration) => {
|
|
|
60
60
|
const installDependenciesNow = argumentConfiguration.installDependenciesNow ??
|
|
61
61
|
(await getInstallDependencies());
|
|
62
62
|
const values = {
|
|
63
|
+
absProviders: argumentConfiguration.absProviders?.filter((provider) => provider !== undefined),
|
|
63
64
|
assetsDirectory,
|
|
64
|
-
|
|
65
|
+
authOption,
|
|
65
66
|
buildDirectory,
|
|
66
67
|
codeQualityTool,
|
|
67
68
|
databaseDirectory,
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const getAuthOption: () => Promise<"abs" | undefined>;
|
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
import { select, isCancel } from '@clack/prompts';
|
|
2
2
|
import { cyan } from 'picocolors';
|
|
3
3
|
import { abort } from '../utils/abort';
|
|
4
|
-
export const
|
|
5
|
-
const
|
|
4
|
+
export const getAuthOption = async () => {
|
|
5
|
+
const authOption = await select({
|
|
6
6
|
message: 'Auth provider:',
|
|
7
7
|
options: [
|
|
8
8
|
{ label: 'None', value: 'none' },
|
|
9
|
-
{ label: cyan('Absolute Auth'), value: '
|
|
9
|
+
{ label: cyan('Absolute Auth'), value: 'abs' }
|
|
10
10
|
]
|
|
11
11
|
});
|
|
12
|
-
if (isCancel(
|
|
12
|
+
if (isCancel(authOption))
|
|
13
13
|
abort();
|
|
14
|
-
return
|
|
14
|
+
return authOption === 'none' ? undefined : authOption;
|
|
15
15
|
};
|
package/dist/scaffold.d.ts
CHANGED
|
@@ -5,5 +5,5 @@ type ScaffoldProps = {
|
|
|
5
5
|
latest: boolean;
|
|
6
6
|
envVariables: string[] | undefined;
|
|
7
7
|
};
|
|
8
|
-
export declare const scaffold: ({ response: { projectName, codeQualityTool, initializeGitNow, databaseEngine, databaseHost, useHTMLScripts, useTailwind, databaseDirectory, orm, frontends, plugins,
|
|
8
|
+
export declare const scaffold: ({ response: { projectName, codeQualityTool, initializeGitNow, databaseEngine, databaseHost, useHTMLScripts, useTailwind, databaseDirectory, absProviders, orm, frontends, plugins, authOption, buildDirectory, assetsDirectory, tailwind, installDependenciesNow, frontendDirectories }, latest, envVariables, packageManager }: ScaffoldProps) => Promise<void>;
|
|
9
9
|
export {};
|
package/dist/scaffold.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { copyFileSync } from '
|
|
2
|
-
import { join, dirname } from '
|
|
3
|
-
import { fileURLToPath } from '
|
|
1
|
+
import { copyFileSync } from 'fs';
|
|
2
|
+
import { join, dirname } from 'path';
|
|
3
|
+
import { fileURLToPath } from 'url';
|
|
4
4
|
import { formatProject } from './commands/formatProject';
|
|
5
5
|
import { initializeGit } from './commands/initializeGit';
|
|
6
6
|
import { installDependencies } from './commands/installDependencies';
|
|
@@ -8,9 +8,9 @@ import { createPackageJson } from './generators/configurations/generatePackageJs
|
|
|
8
8
|
import { initalizeRoot } from './generators/configurations/initializeRoot';
|
|
9
9
|
import { scaffoldConfigurationFiles } from './generators/configurations/scaffoldConfigurationFiles';
|
|
10
10
|
import { scaffoldDatabase } from './generators/db/scaffoldDatabase';
|
|
11
|
-
import {
|
|
11
|
+
import { scaffoldBackend } from './generators/project/scaffoldBackend';
|
|
12
12
|
import { scaffoldFrontends } from './generators/project/scaffoldFrontends';
|
|
13
|
-
export const scaffold = async ({ response: { projectName, codeQualityTool, initializeGitNow, databaseEngine, databaseHost, useHTMLScripts, useTailwind, databaseDirectory, orm, frontends, plugins,
|
|
13
|
+
export const scaffold = async ({ response: { projectName, codeQualityTool, initializeGitNow, databaseEngine, databaseHost, useHTMLScripts, useTailwind, databaseDirectory, absProviders, orm, frontends, plugins, authOption, buildDirectory, assetsDirectory, tailwind, installDependenciesNow, frontendDirectories }, latest, envVariables, packageManager }) => {
|
|
14
14
|
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
15
15
|
const templatesDirectory = join(__dirname, '/templates');
|
|
16
16
|
const { frontendDirectory, backendDirectory, projectAssetsDirectory, typesDirectory } = initalizeRoot(projectName, templatesDirectory);
|
|
@@ -27,7 +27,7 @@ export const scaffold = async ({ response: { projectName, codeQualityTool, initi
|
|
|
27
27
|
templatesDirectory
|
|
28
28
|
});
|
|
29
29
|
createPackageJson({
|
|
30
|
-
|
|
30
|
+
authOption,
|
|
31
31
|
codeQualityTool,
|
|
32
32
|
databaseEngine,
|
|
33
33
|
databaseHost,
|
|
@@ -38,9 +38,10 @@ export const scaffold = async ({ response: { projectName, codeQualityTool, initi
|
|
|
38
38
|
projectName,
|
|
39
39
|
useTailwind
|
|
40
40
|
});
|
|
41
|
-
|
|
41
|
+
scaffoldBackend({
|
|
42
|
+
absProviders,
|
|
42
43
|
assetsDirectory,
|
|
43
|
-
|
|
44
|
+
authOption,
|
|
44
45
|
backendDirectory,
|
|
45
46
|
buildDirectory,
|
|
46
47
|
databaseEngine,
|
|
@@ -54,7 +55,7 @@ export const scaffold = async ({ response: { projectName, codeQualityTool, initi
|
|
|
54
55
|
databaseEngine !== 'none' &&
|
|
55
56
|
databaseEngine !== undefined &&
|
|
56
57
|
(await scaffoldDatabase({
|
|
57
|
-
|
|
58
|
+
authOption,
|
|
58
59
|
backendDirectory,
|
|
59
60
|
databaseDirectory,
|
|
60
61
|
databaseEngine,
|
|
@@ -64,6 +65,9 @@ export const scaffold = async ({ response: { projectName, codeQualityTool, initi
|
|
|
64
65
|
typesDirectory
|
|
65
66
|
})));
|
|
66
67
|
scaffoldFrontends({
|
|
68
|
+
absProviders,
|
|
69
|
+
assetsDirectory,
|
|
70
|
+
authOption,
|
|
67
71
|
frontendDirectories,
|
|
68
72
|
frontendDirectory,
|
|
69
73
|
frontends,
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 48 48">
|
|
2
|
+
<path fill="#EA4335" d="M24 9.5c3.54 0 6.71 1.22 9.21 3.6l6.85-6.85C35.9 2.38 30.47 0 24 0 14.62 0 6.51 5.38 2.56 13.22l7.98 6.19C12.43 13.72 17.74 9.5 24 9.5z" />
|
|
3
|
+
<path fill="#4285F4" d="M46.98 24.55c0-1.57-.15-3.09-.38-4.55H24v9.02h12.94c-.58 2.96-2.26 5.48-4.78 7.18l7.73 6c4.51-4.18 7.09-10.36 7.09-17.65z" />
|
|
4
|
+
<path fill="#FBBC05" d="M10.53 28.59c-.48-1.45-.76-2.99-.76-4.59s.27-3.14.76-4.59l-7.98-6.19C.92 16.46 0 20.12 0 24c0 3.88.92 7.54 2.56 10.78l7.97-6.19z" />
|
|
5
|
+
<path fill="#34A853" d="M24 48c6.48 0 11.93-2.13 15.89-5.81l-7.73-6c-2.15 1.45-4.92 2.3-8.16 2.3-6.26 0-11.57-4.22-13.47-9.91l-7.98 6.19C6.51 42.62 14.62 48 24 48z" />
|
|
6
|
+
<path fill="none" d="M0 0h48v48H0z" />
|
|
7
|
+
</svg>
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { ProviderOption } from 'citra';
|
|
2
|
+
|
|
3
|
+
type OAuthLinkProps = {
|
|
4
|
+
logoUrl: string;
|
|
5
|
+
name: string;
|
|
6
|
+
provider: Lowercase<ProviderOption> | undefined;
|
|
7
|
+
mode: 'in' | 'up';
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
export const OAuthLink = ({
|
|
11
|
+
provider,
|
|
12
|
+
logoUrl,
|
|
13
|
+
name,
|
|
14
|
+
mode
|
|
15
|
+
}: OAuthLinkProps) => {
|
|
16
|
+
const buttonText = `Sign ${mode} with ${name}`;
|
|
17
|
+
|
|
18
|
+
return (
|
|
19
|
+
<a
|
|
20
|
+
style={{
|
|
21
|
+
alignItems: 'center',
|
|
22
|
+
display: 'flex',
|
|
23
|
+
gap: '0.5rem'
|
|
24
|
+
}}
|
|
25
|
+
href={provider ? `/oauth2/${provider}/authorization` : undefined}
|
|
26
|
+
>
|
|
27
|
+
{provider ? (
|
|
28
|
+
<img
|
|
29
|
+
style={{ height: '2rem', width: '2rem' }}
|
|
30
|
+
alt={`${name} logo`}
|
|
31
|
+
src={logoUrl}
|
|
32
|
+
/>
|
|
33
|
+
) : (
|
|
34
|
+
<p>Provider not configured</p>
|
|
35
|
+
)}
|
|
36
|
+
<span>{buttonText}</span>
|
|
37
|
+
</a>
|
|
38
|
+
);
|
|
39
|
+
};
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
type ProfilePictureProps = {
|
|
2
|
+
userImage: string | null | undefined;
|
|
3
|
+
givenName?: string;
|
|
4
|
+
familyName?: string;
|
|
5
|
+
color?: string;
|
|
6
|
+
width?: string;
|
|
7
|
+
height?: string;
|
|
8
|
+
fontSize?: string;
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
export const ProfilePicture = ({
|
|
12
|
+
userImage,
|
|
13
|
+
givenName = '',
|
|
14
|
+
familyName = '',
|
|
15
|
+
color = '#4285F4',
|
|
16
|
+
width = '2rem',
|
|
17
|
+
height = '2rem',
|
|
18
|
+
fontSize = '0.85rem'
|
|
19
|
+
}: ProfilePictureProps) => {
|
|
20
|
+
if (userImage) {
|
|
21
|
+
return (
|
|
22
|
+
<img
|
|
23
|
+
alt="Profile"
|
|
24
|
+
src={userImage}
|
|
25
|
+
style={{
|
|
26
|
+
borderRadius: '50%',
|
|
27
|
+
height,
|
|
28
|
+
objectFit: 'cover',
|
|
29
|
+
width
|
|
30
|
+
}}
|
|
31
|
+
/>
|
|
32
|
+
);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
const initials = `${givenName.charAt(0).toUpperCase()}${familyName.charAt(0).toUpperCase()}`;
|
|
36
|
+
|
|
37
|
+
return (
|
|
38
|
+
<div
|
|
39
|
+
style={{
|
|
40
|
+
alignItems: 'center',
|
|
41
|
+
backgroundColor: color,
|
|
42
|
+
borderRadius: '50%',
|
|
43
|
+
color: 'white',
|
|
44
|
+
display: 'flex',
|
|
45
|
+
fontSize,
|
|
46
|
+
fontWeight: 600,
|
|
47
|
+
height,
|
|
48
|
+
justifyContent: 'center',
|
|
49
|
+
userSelect: 'none',
|
|
50
|
+
width
|
|
51
|
+
}}
|
|
52
|
+
>
|
|
53
|
+
{initials}
|
|
54
|
+
</div>
|
|
55
|
+
);
|
|
56
|
+
};
|
package/dist/typeGuards.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
export declare const
|
|
1
|
+
import type { AuthOption, AvailableDrizzleDialect, CodeQualityTool, DatabaseEngine, DatabaseHost, Frontend, ORM } from './types';
|
|
2
|
+
export declare const isValidAuthOption: (value: string | undefined) => value is AuthOption;
|
|
3
3
|
export declare const isDirectoryConfig: (value: string) => value is "default" | "custom";
|
|
4
4
|
export declare const isDrizzleDialect: (value: string | undefined) => value is AvailableDrizzleDialect;
|
|
5
5
|
export declare const isPrismaDialect: (value: string | undefined) => value is string;
|
package/dist/typeGuards.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { availableDatabaseEngines, availableDatabaseHosts, availableDrizzleDialects, availablePrismaDialects, frontendLabels } from './data';
|
|
2
|
-
export const
|
|
2
|
+
export const isValidAuthOption = (value) => value === 'abs' || value === 'none' || value === undefined;
|
|
3
3
|
export const isDirectoryConfig = (value) => value === 'default' || value === 'custom';
|
|
4
4
|
export const isDrizzleDialect = (value) => availableDrizzleDialects.some((dialect) => dialect === value);
|
|
5
5
|
export const isPrismaDialect = (value) => availablePrismaDialects.some((dialect) => dialect === value);
|
package/dist/types.d.ts
CHANGED
|
@@ -1,5 +1,9 @@
|
|
|
1
|
+
import { ProviderOption } from '@absolutejs/auth';
|
|
1
2
|
import { availableAuthProviders, availableCodeQualityTools, availableDatabaseEngines, availableDatabaseHosts, availableDirectoryConfigurations, availableDrizzleDialects, availableFrontends, availableORMs, availablePrismaDialects } from './data';
|
|
2
3
|
export type ScaffoldFrontendProps = {
|
|
4
|
+
absProviders: ProviderOption[] | undefined;
|
|
5
|
+
assetsDirectory: string;
|
|
6
|
+
authOption: AuthOption;
|
|
3
7
|
targetDirectory: string;
|
|
4
8
|
templatesDirectory: string;
|
|
5
9
|
projectAssetsDirectory: string;
|
|
@@ -21,7 +25,7 @@ export type AvailableDependency = {
|
|
|
21
25
|
latestVersion: string;
|
|
22
26
|
};
|
|
23
27
|
export type PackageManager = 'npm' | 'pnpm' | 'yarn' | 'bun';
|
|
24
|
-
export type
|
|
28
|
+
export type AuthOption = (typeof availableAuthProviders)[number] | undefined;
|
|
25
29
|
export type AvailableDrizzleDialect = (typeof availableDrizzleDialects)[number];
|
|
26
30
|
export type AvailablePrismaDialect = (typeof availablePrismaDialects)[number];
|
|
27
31
|
export type DatabaseEngine = (typeof availableDatabaseEngines)[number] | undefined;
|
|
@@ -34,8 +38,9 @@ export type TailwindConfig = {
|
|
|
34
38
|
output: string;
|
|
35
39
|
} | undefined;
|
|
36
40
|
export type CreateConfiguration = {
|
|
41
|
+
absProviders: ProviderOption[] | undefined;
|
|
37
42
|
assetsDirectory: string;
|
|
38
|
-
|
|
43
|
+
authOption: AuthOption;
|
|
39
44
|
buildDirectory: string;
|
|
40
45
|
directoryConfig: DirectoryConfiguration;
|
|
41
46
|
databaseEngine: DatabaseEngine;
|
package/dist/utils/abort.js
CHANGED
|
@@ -1,14 +1,16 @@
|
|
|
1
|
-
import { argv, exit } from '
|
|
2
|
-
import { parseArgs } from '
|
|
1
|
+
import { argv, exit } from 'process';
|
|
2
|
+
import { parseArgs } from 'util';
|
|
3
|
+
import { isValidProviderOption, providers } from '@absolutejs/auth';
|
|
3
4
|
import { DEFAULT_ARG_LENGTH } from '../constants';
|
|
4
5
|
import { availableAuthProviders, availableDatabaseEngines, availableDatabaseHosts, availableDirectoryConfigurations, availableDrizzleDialects, availableORMs, availablePrismaDialects } from '../data';
|
|
5
|
-
import {
|
|
6
|
+
import { isValidAuthOption, isDatabaseEngine, isDatabaseHost, isDirectoryConfig, isDrizzleDialect, isORM, isPrismaDialect } from '../typeGuards';
|
|
6
7
|
export const parseCommandLineOptions = () => {
|
|
7
8
|
const { values, positionals } = parseArgs({
|
|
8
9
|
allowNegative: true,
|
|
9
10
|
allowPositionals: true,
|
|
10
11
|
args: argv.slice(DEFAULT_ARG_LENGTH),
|
|
11
12
|
options: {
|
|
13
|
+
'abs-provider': { multiple: true, type: 'string' },
|
|
12
14
|
angular: { type: 'boolean' },
|
|
13
15
|
'angular-dir': { type: 'string' },
|
|
14
16
|
assets: { type: 'string' },
|
|
@@ -47,15 +49,33 @@ export const parseCommandLineOptions = () => {
|
|
|
47
49
|
});
|
|
48
50
|
const errors = [];
|
|
49
51
|
const projectName = positionals[0] ?? (values.skip ? 'absolutejs-project' : undefined);
|
|
50
|
-
let
|
|
51
|
-
if (values.auth !== undefined && !
|
|
52
|
+
let authOption;
|
|
53
|
+
if (values.auth !== undefined && !isValidAuthOption(values.auth)) {
|
|
52
54
|
errors.push(`Invalid auth provider: "${values.auth}". Expected: [ ${availableAuthProviders.join(', ')} ]`);
|
|
53
55
|
}
|
|
54
56
|
else if (values.auth !== undefined) {
|
|
55
|
-
|
|
57
|
+
authOption = values.auth;
|
|
56
58
|
}
|
|
57
59
|
else if (values.skip) {
|
|
58
|
-
|
|
60
|
+
authOption = 'none';
|
|
61
|
+
}
|
|
62
|
+
const absProviders = [];
|
|
63
|
+
if (values['abs-provider'] !== undefined) {
|
|
64
|
+
if (authOption === undefined || authOption === 'none') {
|
|
65
|
+
authOption = 'abs';
|
|
66
|
+
}
|
|
67
|
+
else if (authOption !== 'abs') {
|
|
68
|
+
errors.push(`Invalid auth configuration: "--abs-provider" specified but auth provider is set to "${authOption}". "--abs-provider" can only be used with "abs" auth provider.`);
|
|
69
|
+
}
|
|
70
|
+
for (const provider of values['abs-provider']) {
|
|
71
|
+
if (!isValidProviderOption(provider)) {
|
|
72
|
+
errors.push(`Invalid Absolute-Auth provider: "${provider}". Expected: ${Object.keys(providers).join(', ')}`);
|
|
73
|
+
continue;
|
|
74
|
+
}
|
|
75
|
+
else {
|
|
76
|
+
absProviders.push(provider);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
59
79
|
}
|
|
60
80
|
let databaseEngine;
|
|
61
81
|
if (values.db !== undefined && !isDatabaseEngine(values.db)) {
|
|
@@ -216,8 +236,9 @@ export const parseCommandLineOptions = () => {
|
|
|
216
236
|
}
|
|
217
237
|
values.env = validEnv.length ? validEnv : undefined;
|
|
218
238
|
const argumentConfiguration = {
|
|
239
|
+
absProviders: absProviders.length ? absProviders : undefined,
|
|
219
240
|
assetsDirectory: values.assets,
|
|
220
|
-
|
|
241
|
+
authOption,
|
|
221
242
|
buildDirectory: values.build,
|
|
222
243
|
codeQualityTool,
|
|
223
244
|
databaseDirectory,
|
package/dist/utils/t3-utils.js
CHANGED