dappbooster 3.1.5 → 3.3.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/app.d.ts +6 -1
- package/dist/app.js +55 -15
- package/dist/cli.js +84 -20
- package/dist/components/Multiselect/MultiSelect.d.ts +2 -1
- package/dist/components/Multiselect/MultiSelect.js +12 -7
- package/dist/components/steps/CloneRepo/CloneRepo.d.ts +2 -0
- package/dist/components/steps/CloneRepo/CloneRepo.js +8 -5
- package/dist/components/steps/Confirmation.d.ts +8 -0
- package/dist/components/steps/Confirmation.js +26 -0
- package/dist/components/steps/FileCleanup.d.ts +2 -0
- package/dist/components/steps/FileCleanup.js +11 -6
- package/dist/components/steps/Install/Install.d.ts +2 -0
- package/dist/components/steps/Install/Install.js +10 -8
- package/dist/components/steps/InstallationMode.d.ts +2 -0
- package/dist/components/steps/InstallationMode.js +12 -15
- package/dist/components/steps/OptionalPackages.d.ts +2 -0
- package/dist/components/steps/OptionalPackages.js +34 -11
- package/dist/components/steps/PostInstall.d.ts +2 -0
- package/dist/components/steps/PostInstall.js +13 -6
- package/dist/components/steps/ProjectName.d.ts +0 -7
- package/dist/components/steps/ProjectName.js +43 -17
- package/dist/components/steps/StackSelection.d.ts +8 -0
- package/dist/components/steps/StackSelection.js +21 -0
- package/dist/constants/config.d.ts +32 -4
- package/dist/constants/config.js +156 -44
- package/dist/info.d.ts +4 -1
- package/dist/info.js +37 -11
- package/dist/nonInteractive.d.ts +1 -0
- package/dist/nonInteractive.js +40 -17
- package/dist/operations/cleanupFiles.d.ts +2 -2
- package/dist/operations/cleanupFiles.js +169 -19
- package/dist/operations/cloneRepo.d.ts +2 -1
- package/dist/operations/cloneRepo.js +35 -11
- package/dist/operations/createEnvFile.d.ts +2 -1
- package/dist/operations/createEnvFile.js +9 -2
- package/dist/operations/installGuard.d.ts +8 -0
- package/dist/operations/installGuard.js +35 -0
- package/dist/operations/installPackages.d.ts +2 -2
- package/dist/operations/installPackages.js +14 -6
- package/dist/types/types.d.ts +1 -1
- package/dist/utils/utils.d.ts +9 -3
- package/dist/utils/utils.js +78 -6
- package/package.json +2 -9
- package/readme.md +143 -77
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import type { FC } from 'react';
|
|
2
|
+
import { type Stack } from '../../constants/config.js';
|
|
2
3
|
import type { InstallationType, MultiSelectItem } from '../../types/types.js';
|
|
3
4
|
interface Props {
|
|
5
|
+
stack: Stack;
|
|
4
6
|
installationConfig: {
|
|
5
7
|
installationType: InstallationType | undefined;
|
|
6
8
|
selectedFeatures?: Array<MultiSelectItem>;
|
|
@@ -2,14 +2,21 @@ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-run
|
|
|
2
2
|
import figures from 'figures';
|
|
3
3
|
import { Box, Text } from 'ink';
|
|
4
4
|
import Link from 'ink-link';
|
|
5
|
-
import {
|
|
5
|
+
import { getStackConfig } from '../../constants/config.js';
|
|
6
|
+
import { isFeatureSelected, resolveModeFeatures } from '../../utils/utils.js';
|
|
6
7
|
import Divider from '../Divider.js';
|
|
7
8
|
const SubgraphWarningMessage = () => (_jsxs(Box, { flexDirection: 'column', rowGap: 1, children: [_jsx(Box, { alignItems: 'center', borderColor: 'yellow', borderStyle: 'bold', flexDirection: 'column', justifyContent: 'center', padding: 1, children: _jsxs(Text, { color: 'yellow', children: [figures.warning, figures.warning, " ", _jsx(Text, { bold: true, children: "WARNING:" }), " You ", _jsx(Text, { bold: true, children: "MUST" }), " finish the subgraph's configuration manually ", figures.warning, figures.warning] }) }), _jsx(Text, { color: 'whiteBright', children: "Follow these steps:" }), _jsxs(Box, { flexDirection: 'column', children: [_jsxs(Text, { children: ["1- Provide your own API key for ", _jsx(Text, { color: 'gray', children: "PUBLIC_SUBGRAPHS_API_KEY" }), " in", ' ', _jsx(Text, { color: 'gray', children: ".env.local" }), " You can get one", ' ', _jsx(Link, { url: "https://thegraph.com/studio/apikeys", children: "here" })] }), _jsxs(Text, { children: ["2- After the API key is correctly configured, run", ' ', _jsx(Text, { color: 'gray', children: "pnpm subgraph-codegen" }), " in your console from the project's folder"] })] }), _jsxs(Text, { children: ["More configuration info in", ' ', _jsx(Link, { url: 'https://docs.dappbooster.dev/introduction/getting-started', children: "the docs" }), "."] }), _jsxs(Text, { color: 'yellow', bold: true, children: [figures.info, " Only after you have followed the previous steps you may proceed."] })] }));
|
|
8
|
-
const
|
|
9
|
-
const
|
|
9
|
+
const EvmPostInstallMessage = ({ projectName }) => (_jsxs(Box, { flexDirection: 'column', rowGap: 1, paddingBottom: 2, children: [_jsx(Text, { color: 'whiteBright', children: "To start development on your project:" }), _jsxs(Box, { flexDirection: 'column', children: [_jsxs(Text, { children: ["1- Move into the project's folder with ", _jsxs(Text, { color: 'gray', children: ["cd ", projectName] })] }), _jsxs(Text, { children: ["2- Start the development server with ", _jsx(Text, { color: 'gray', children: "pnpm dev" })] })] }), _jsx(Text, { color: 'whiteBright', children: "More info:" }), _jsxs(Box, { flexDirection: 'column', children: [_jsxs(Text, { children: ["- Check out ", _jsx(Text, { color: 'gray', children: ".env.local" }), " for more configurations."] }), _jsxs(Text, { children: ["- Read ", _jsx(Link, { url: "https://docs.dappbooster.dev", children: "the docs" }), " to know more about", ' ', _jsx(Text, { color: 'gray', children: "dAppBooster" }), "!"] }), _jsxs(Text, { children: ["- Report issues with this installer", ' ', _jsx(Link, { url: "https://github.com/BootNodeDev/dAppBoosterInstallScript/issues", children: "here" })] })] })] }));
|
|
10
|
+
const CantonPostInstallMessage = ({ projectName, features }) => {
|
|
11
|
+
const carpinchoEnabled = isFeatureSelected('carpincho', features);
|
|
12
|
+
return (_jsxs(Box, { flexDirection: 'column', rowGap: 1, paddingBottom: 2, children: [_jsx(Text, { color: 'whiteBright', children: "To start the Canton stack:" }), _jsxs(Box, { flexDirection: 'column', children: [_jsxs(Text, { children: ["1- Move into the project's folder with ", _jsxs(Text, { color: 'gray', children: ["cd ", projectName] })] }), _jsxs(Text, { children: ["2- Configure canton-barebones: ", _jsx(Text, { color: 'gray', children: "canton-barebones/.env" }), " was created from the example \u2014 review it."] }), _jsxs(Text, { children: ["3- Start the local Canton stack with ", _jsx(Text, { color: 'gray', children: "npm run canton:up" })] }), _jsxs(Text, { children: ["4- In a separate terminal, run the dapp frontend:", ' ', _jsx(Text, { color: 'gray', children: "npm run app:dev" })] })] }), carpinchoEnabled && (_jsx(Box, { alignItems: 'center', borderColor: 'yellow', borderStyle: 'bold', flexDirection: 'column', justifyContent: 'center', padding: 1, children: _jsxs(Text, { color: 'yellow', children: [figures.info, " ", _jsx(Text, { bold: true, children: "Carpincho Wallet" }), ": build it with", ' ', _jsx(Text, { color: 'gray', children: "npm run carpincho:build:extension" }), " and load", ' ', _jsx(Text, { color: 'gray', children: "carpincho-wallet/dist-extension" }), " as an unpacked browser extension ", figures.info] }) })), _jsx(Text, { children: "See the Canton stack README inside the project for full instructions." })] }));
|
|
13
|
+
};
|
|
14
|
+
const PostInstall = ({ stack, installationConfig, projectName }) => {
|
|
10
15
|
const { selectedFeatures, installationType } = installationConfig;
|
|
11
|
-
const
|
|
12
|
-
const
|
|
13
|
-
|
|
16
|
+
const selectedNames = selectedFeatures?.map((f) => f.value) ?? [];
|
|
17
|
+
const features = resolveModeFeatures(stack, installationType ?? 'full', selectedNames);
|
|
18
|
+
const stackLabel = getStackConfig(stack).label;
|
|
19
|
+
return (_jsxs(_Fragment, { children: [_jsx(Divider, { title: `Post-install instructions — ${stackLabel}` }), _jsxs(Box, { flexDirection: 'column', rowGap: 2, children: [stack === 'evm' &&
|
|
20
|
+
(isFeatureSelected('subgraph', features) || installationType === 'full') && (_jsx(SubgraphWarningMessage, {})), stack === 'evm' && _jsx(EvmPostInstallMessage, { projectName: projectName }), stack === 'canton' && (_jsx(CantonPostInstallMessage, { projectName: projectName, features: features }))] })] }));
|
|
14
21
|
};
|
|
15
22
|
export default PostInstall;
|
|
@@ -2,13 +2,6 @@ import { type FC } from 'react';
|
|
|
2
2
|
interface Props {
|
|
3
3
|
onCompletion: () => void;
|
|
4
4
|
onSubmit: (value: string) => void;
|
|
5
|
-
projectName: string;
|
|
6
5
|
}
|
|
7
|
-
/**
|
|
8
|
-
* Component to ask for the project name.
|
|
9
|
-
* @param projectName
|
|
10
|
-
* @param onSubmit
|
|
11
|
-
* @param onCompletion
|
|
12
|
-
*/
|
|
13
6
|
declare const ProjectName: FC<Props>;
|
|
14
7
|
export default ProjectName;
|
|
@@ -1,26 +1,52 @@
|
|
|
1
1
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
-
import { useCallback, useMemo } from 'react';
|
|
3
|
-
import { isValidName } from '../../utils/utils.js';
|
|
2
|
+
import { useCallback, useMemo, useState } from 'react';
|
|
3
|
+
import { isValidName, projectDirectoryExists } from '../../utils/utils.js';
|
|
4
4
|
import Ask from '../Ask.js';
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
const
|
|
5
|
+
const initialValidation = {
|
|
6
|
+
status: 'idle',
|
|
7
|
+
value: '',
|
|
8
|
+
error: '',
|
|
9
|
+
};
|
|
10
|
+
const ProjectName = ({ onSubmit, onCompletion }) => {
|
|
11
|
+
const [validation, setValidation] = useState(initialValidation);
|
|
12
12
|
const validateName = useCallback((name) => {
|
|
13
|
-
if (name.length
|
|
14
|
-
return
|
|
15
|
-
|
|
13
|
+
if (name.length === 0) {
|
|
14
|
+
return {
|
|
15
|
+
status: 'idle',
|
|
16
|
+
value: '',
|
|
17
|
+
error: '',
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
if (!isValidName(name)) {
|
|
21
|
+
return {
|
|
22
|
+
status: 'invalid',
|
|
23
|
+
value: name,
|
|
24
|
+
error: 'Not a valid name!',
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
if (projectDirectoryExists(name)) {
|
|
28
|
+
return {
|
|
29
|
+
status: 'invalid',
|
|
30
|
+
value: name,
|
|
31
|
+
error: `A directory named "${name}" already exists. Choose another name.`,
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
return {
|
|
35
|
+
status: 'valid',
|
|
36
|
+
value: name,
|
|
37
|
+
error: '',
|
|
38
|
+
};
|
|
16
39
|
}, []);
|
|
17
|
-
const errorMessage = useMemo(() =>
|
|
40
|
+
const errorMessage = useMemo(() => (validation.status === 'invalid' ? validation.error : ''), [validation.error, validation.status]);
|
|
41
|
+
const confirmedName = useMemo(() => (validation.status === 'valid' ? validation.value : undefined), [validation.status, validation.value]);
|
|
18
42
|
const handleSubmit = useCallback((name) => {
|
|
19
|
-
|
|
20
|
-
|
|
43
|
+
const nextValidation = validateName(name);
|
|
44
|
+
setValidation(nextValidation);
|
|
45
|
+
if (nextValidation.status === 'valid') {
|
|
46
|
+
onSubmit(nextValidation.value);
|
|
21
47
|
onCompletion();
|
|
22
48
|
}
|
|
23
|
-
}, [onSubmit, onCompletion]);
|
|
24
|
-
return (_jsx(Ask, { answer:
|
|
49
|
+
}, [onSubmit, onCompletion, validateName]);
|
|
50
|
+
return (_jsx(Ask, { answer: confirmedName, errorMessage: errorMessage, onSubmit: handleSubmit, question: 'Project name', tip: 'Letters (a-z, A-Z), numbers (0-9), and underscores (_) are allowed.' }));
|
|
25
51
|
};
|
|
26
52
|
export default ProjectName;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
|
+
import figures from 'figures';
|
|
3
|
+
import { Text } from 'ink';
|
|
4
|
+
import SelectInput from 'ink-select-input';
|
|
5
|
+
import { useState } from 'react';
|
|
6
|
+
import { stackDefinitions, stackNames } from '../../constants/config.js';
|
|
7
|
+
import Divider from '../Divider.js';
|
|
8
|
+
const stackItems = stackNames.map((name) => ({
|
|
9
|
+
label: `${stackDefinitions[name].label} — ${stackDefinitions[name].description}`,
|
|
10
|
+
value: name,
|
|
11
|
+
}));
|
|
12
|
+
const StackSelection = ({ onCompletion, onSelect }) => {
|
|
13
|
+
const [selectedStack, setSelectedStack] = useState();
|
|
14
|
+
const handleSelect = (item) => {
|
|
15
|
+
onSelect(item.value);
|
|
16
|
+
setSelectedStack(item.value);
|
|
17
|
+
onCompletion();
|
|
18
|
+
};
|
|
19
|
+
return (_jsxs(_Fragment, { children: [_jsx(Divider, { title: 'Select stack' }), selectedStack ? (_jsxs(Text, { children: ["Stack:", ' ', _jsx(Text, { bold: true, color: 'green', children: stackDefinitions[selectedStack].label })] })) : (_jsxs(_Fragment, { children: [_jsx(Text, { color: 'whiteBright', children: "Which stack do you want to scaffold?" }), _jsx(SelectInput, { indicatorComponent: ({ isSelected }) => (_jsx(Text, { color: "green", children: isSelected ? `${figures.pointer} ` : ' ' })), itemComponent: ({ label, isSelected }) => (_jsx(Text, { color: isSelected ? 'green' : 'white', bold: isSelected, children: label })), items: stackItems, onSelect: handleSelect })] }))] }));
|
|
20
|
+
};
|
|
21
|
+
export default StackSelection;
|
|
@@ -1,11 +1,39 @@
|
|
|
1
|
-
|
|
2
|
-
export type
|
|
1
|
+
import type { InstallationType } from '../types/types.js';
|
|
2
|
+
export type Stack = 'evm' | 'canton';
|
|
3
|
+
export type RefType = 'tag-latest' | 'branch';
|
|
4
|
+
export type PackageManager = 'pnpm' | 'npm';
|
|
5
|
+
export type FeatureName = string;
|
|
3
6
|
export type FeatureDefinition = {
|
|
4
7
|
description: string;
|
|
5
8
|
label: string;
|
|
6
9
|
packages: string[];
|
|
7
10
|
default: boolean;
|
|
8
11
|
postInstall?: string[];
|
|
12
|
+
paths?: string[];
|
|
13
|
+
requires?: FeatureName[];
|
|
9
14
|
};
|
|
10
|
-
export
|
|
11
|
-
|
|
15
|
+
export type EnvFile = {
|
|
16
|
+
from: string;
|
|
17
|
+
to: string;
|
|
18
|
+
ifFeature?: FeatureName;
|
|
19
|
+
};
|
|
20
|
+
export type StackConfig = {
|
|
21
|
+
label: string;
|
|
22
|
+
description: string;
|
|
23
|
+
repoUrl: string;
|
|
24
|
+
refType: RefType;
|
|
25
|
+
ref?: string;
|
|
26
|
+
packageManager: PackageManager;
|
|
27
|
+
removeAfterClone: string[];
|
|
28
|
+
postInstall?: string[];
|
|
29
|
+
envFiles: EnvFile[];
|
|
30
|
+
features: Record<FeatureName, FeatureDefinition>;
|
|
31
|
+
};
|
|
32
|
+
export declare const stackDefinitions: Record<Stack, StackConfig>;
|
|
33
|
+
export declare const stackNames: Stack[];
|
|
34
|
+
export declare function getStackConfig(stack: Stack): StackConfig;
|
|
35
|
+
export declare function getFeatureNames(stack: Stack): FeatureName[];
|
|
36
|
+
export declare function isFeatureNameValid(stack: Stack, name: string): boolean;
|
|
37
|
+
export declare function isStackName(name: string): name is Stack;
|
|
38
|
+
export declare function getDefaultFeatureNames(stack: Stack): FeatureName[];
|
|
39
|
+
export declare function getInstallationModes(stack: Stack): InstallationType[];
|
package/dist/constants/config.js
CHANGED
|
@@ -1,50 +1,162 @@
|
|
|
1
|
-
|
|
2
|
-
export const
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
1
|
+
import process from 'node:process';
|
|
2
|
+
export const stackDefinitions = {
|
|
3
|
+
evm: {
|
|
4
|
+
label: 'EVM',
|
|
5
|
+
description: 'dAppBooster for EVM chains (Ethereum, Polygon, Base, …)',
|
|
6
|
+
repoUrl: 'https://github.com/BootNodeDev/dAppBooster.git',
|
|
7
|
+
refType: 'tag-latest',
|
|
8
|
+
packageManager: 'pnpm',
|
|
9
|
+
removeAfterClone: [],
|
|
10
|
+
envFiles: [{ from: '.env.example', to: '.env.local' }],
|
|
11
|
+
features: {
|
|
12
|
+
demo: {
|
|
13
|
+
description: 'Component demos and example pages',
|
|
14
|
+
label: 'Component Demos',
|
|
15
|
+
packages: [],
|
|
16
|
+
default: true,
|
|
17
|
+
},
|
|
18
|
+
subgraph: {
|
|
19
|
+
description: 'TheGraph subgraph integration',
|
|
20
|
+
label: 'Subgraph support',
|
|
21
|
+
packages: [
|
|
22
|
+
'@bootnodedev/db-subgraph',
|
|
23
|
+
'graphql',
|
|
24
|
+
'graphql-request',
|
|
25
|
+
'@graphql-codegen/cli',
|
|
26
|
+
'@graphql-typed-document-node/core',
|
|
27
|
+
],
|
|
28
|
+
default: true,
|
|
29
|
+
postInstall: [
|
|
30
|
+
'Provide your own API key for PUBLIC_SUBGRAPHS_API_KEY in .env.local',
|
|
31
|
+
'Run pnpm subgraph-codegen from the project folder',
|
|
32
|
+
],
|
|
33
|
+
},
|
|
34
|
+
typedoc: {
|
|
35
|
+
description: 'TypeDoc API documentation generation',
|
|
36
|
+
label: 'Typedoc documentation support',
|
|
37
|
+
packages: [
|
|
38
|
+
'typedoc',
|
|
39
|
+
'typedoc-github-theme',
|
|
40
|
+
'typedoc-plugin-inline-sources',
|
|
41
|
+
'typedoc-plugin-missing-exports',
|
|
42
|
+
'typedoc-plugin-rename-defaults',
|
|
43
|
+
],
|
|
44
|
+
default: true,
|
|
45
|
+
},
|
|
46
|
+
vocs: {
|
|
47
|
+
description: 'Vocs documentation site',
|
|
48
|
+
label: 'Vocs documentation support',
|
|
49
|
+
packages: ['vocs'],
|
|
50
|
+
default: true,
|
|
51
|
+
},
|
|
52
|
+
husky: {
|
|
53
|
+
description: 'Git hooks with Husky, lint-staged, and commitlint',
|
|
54
|
+
label: 'Husky Git hooks support',
|
|
55
|
+
packages: ['husky', 'lint-staged', '@commitlint/cli', '@commitlint/config-conventional'],
|
|
56
|
+
default: true,
|
|
57
|
+
},
|
|
58
|
+
},
|
|
8
59
|
},
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
'@graphql-typed-document-node/core',
|
|
18
|
-
],
|
|
19
|
-
default: true,
|
|
60
|
+
canton: {
|
|
61
|
+
label: 'Canton',
|
|
62
|
+
description: 'dAppBooster for Canton (Daml ledger, Carpincho wallet, off-chain services)',
|
|
63
|
+
repoUrl: 'https://github.com/BootNodeDev/cn-dappbooster.git',
|
|
64
|
+
refType: 'branch',
|
|
65
|
+
ref: 'main',
|
|
66
|
+
packageManager: 'npm',
|
|
67
|
+
removeAfterClone: [],
|
|
20
68
|
postInstall: [
|
|
21
|
-
'
|
|
22
|
-
'Run
|
|
69
|
+
'Review canton-barebones/.env (created from the example)',
|
|
70
|
+
'Run npm run canton:up to start the local Canton stack',
|
|
71
|
+
'Run npm run app:dev to start the dapp frontend',
|
|
23
72
|
],
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
'typedoc-plugin-missing-exports',
|
|
33
|
-
'typedoc-plugin-rename-defaults',
|
|
73
|
+
envFiles: [
|
|
74
|
+
{ from: 'canton-barebones/.env.example', to: 'canton-barebones/.env' },
|
|
75
|
+
{ from: 'dapp/frontend/.env.local.example', to: 'dapp/frontend/.env.local' },
|
|
76
|
+
{
|
|
77
|
+
from: 'carpincho-wallet/.env.local.example',
|
|
78
|
+
to: 'carpincho-wallet/.env.local',
|
|
79
|
+
ifFeature: 'carpincho',
|
|
80
|
+
},
|
|
34
81
|
],
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
82
|
+
features: {
|
|
83
|
+
github: {
|
|
84
|
+
description: 'GitHub issue/PR templates and workflows (.github)',
|
|
85
|
+
label: 'GitHub templates & workflows',
|
|
86
|
+
packages: [],
|
|
87
|
+
default: false,
|
|
88
|
+
paths: ['.github'],
|
|
89
|
+
},
|
|
90
|
+
precommit: {
|
|
91
|
+
description: 'Pre-commit hooks (Husky, lint-staged, commitlint)',
|
|
92
|
+
label: 'Pre-commit hooks',
|
|
93
|
+
packages: [],
|
|
94
|
+
default: false,
|
|
95
|
+
paths: ['.husky', '.lintstagedrc.mjs', 'commitlint.config.js'],
|
|
96
|
+
},
|
|
97
|
+
carpincho: {
|
|
98
|
+
description: 'Carpincho browser-extension wallet (frontend + build tooling)',
|
|
99
|
+
label: 'Carpincho wallet',
|
|
100
|
+
packages: [],
|
|
101
|
+
default: true,
|
|
102
|
+
paths: ['carpincho-wallet'],
|
|
103
|
+
postInstall: [
|
|
104
|
+
'Build the Carpincho extension with npm run carpincho:build:extension',
|
|
105
|
+
'Load carpincho-wallet/dist-extension as an unpacked browser extension',
|
|
106
|
+
],
|
|
107
|
+
},
|
|
108
|
+
llm: {
|
|
109
|
+
description: 'LLM and agent artifacts (.claude, AGENTS.md, CLAUDE.md, architecture.md, …)',
|
|
110
|
+
label: 'LLM & agent artifacts',
|
|
111
|
+
packages: [],
|
|
112
|
+
default: true,
|
|
113
|
+
paths: [
|
|
114
|
+
'.claude',
|
|
115
|
+
'AGENTS.md',
|
|
116
|
+
'CLAUDE.md',
|
|
117
|
+
'architecture.md',
|
|
118
|
+
'.llm',
|
|
119
|
+
'.llms',
|
|
120
|
+
'llm',
|
|
121
|
+
'llms',
|
|
122
|
+
'llms.txt',
|
|
123
|
+
'docs/llm',
|
|
124
|
+
'docs/llms',
|
|
125
|
+
],
|
|
126
|
+
},
|
|
127
|
+
},
|
|
48
128
|
},
|
|
49
129
|
};
|
|
50
|
-
export const
|
|
130
|
+
export const stackNames = Object.keys(stackDefinitions);
|
|
131
|
+
function envOverride(stack, suffix) {
|
|
132
|
+
const key = `DAPPBOOSTER_${stack.toUpperCase()}_${suffix}`;
|
|
133
|
+
const value = process.env[key];
|
|
134
|
+
return value && value.length > 0 ? value : undefined;
|
|
135
|
+
}
|
|
136
|
+
export function getStackConfig(stack) {
|
|
137
|
+
const base = stackDefinitions[stack];
|
|
138
|
+
const repoUrl = envOverride(stack, 'REPO_URL') ?? base.repoUrl;
|
|
139
|
+
const ref = envOverride(stack, 'REF') ?? base.ref;
|
|
140
|
+
return { ...base, repoUrl, ref };
|
|
141
|
+
}
|
|
142
|
+
export function getFeatureNames(stack) {
|
|
143
|
+
return Object.keys(stackDefinitions[stack].features);
|
|
144
|
+
}
|
|
145
|
+
export function isFeatureNameValid(stack, name) {
|
|
146
|
+
return name in stackDefinitions[stack].features;
|
|
147
|
+
}
|
|
148
|
+
export function isStackName(name) {
|
|
149
|
+
return stackNames.includes(name);
|
|
150
|
+
}
|
|
151
|
+
export function getDefaultFeatureNames(stack) {
|
|
152
|
+
return Object.entries(stackDefinitions[stack].features)
|
|
153
|
+
.filter(([, definition]) => definition.default)
|
|
154
|
+
.map(([name]) => name);
|
|
155
|
+
}
|
|
156
|
+
// Available installation modes per stack. `default` (keep only default:true features) is offered
|
|
157
|
+
// only when the stack has at least one opt-out (default:false) feature; otherwise it would be
|
|
158
|
+
// identical to `full`. Today that means Canton only (EVM's features are all default:true).
|
|
159
|
+
export function getInstallationModes(stack) {
|
|
160
|
+
const hasOptOutFeature = getDefaultFeatureNames(stack).length < getFeatureNames(stack).length;
|
|
161
|
+
return hasOptOutFeature ? ['default', 'full', 'custom'] : ['full', 'custom'];
|
|
162
|
+
}
|
package/dist/info.d.ts
CHANGED
package/dist/info.js
CHANGED
|
@@ -1,17 +1,43 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
const
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
1
|
+
import { stackDefinitions, stackNames } from './constants/config.js';
|
|
2
|
+
function buildStackInfo(stack) {
|
|
3
|
+
const config = stackDefinitions[stack];
|
|
4
|
+
return {
|
|
5
|
+
label: config.label,
|
|
6
|
+
description: config.description,
|
|
7
|
+
packageManager: config.packageManager,
|
|
8
|
+
features: Object.fromEntries(Object.entries(config.features).map(([name, def]) => [
|
|
9
|
+
name,
|
|
10
|
+
{
|
|
11
|
+
description: def.description,
|
|
12
|
+
default: def.default,
|
|
13
|
+
...(def.postInstall ? { postInstall: def.postInstall } : {}),
|
|
14
|
+
...(def.requires ? { requires: def.requires } : {}),
|
|
15
|
+
},
|
|
16
|
+
])),
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
export class InvalidStackFilterError extends Error {
|
|
20
|
+
constructor(filter) {
|
|
21
|
+
super(`Unknown stack '${filter}'. Valid stacks: ${stackNames.join(', ')}`);
|
|
22
|
+
this.name = 'InvalidStackFilterError';
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
export function getInfoOutput(stackFilter) {
|
|
26
|
+
if (stackFilter !== undefined && !stackNames.includes(stackFilter)) {
|
|
27
|
+
throw new InvalidStackFilterError(stackFilter);
|
|
28
|
+
}
|
|
29
|
+
const stacks = {};
|
|
30
|
+
for (const name of stackNames) {
|
|
31
|
+
if (stackFilter !== undefined && stackFilter !== name) {
|
|
32
|
+
continue;
|
|
33
|
+
}
|
|
34
|
+
stacks[name] = buildStackInfo(name);
|
|
35
|
+
}
|
|
11
36
|
return JSON.stringify({
|
|
12
|
-
|
|
37
|
+
stacks,
|
|
13
38
|
modes: {
|
|
14
39
|
full: 'Install all features',
|
|
40
|
+
default: 'Install the recommended set (Canton only; for EVM this equals full)',
|
|
15
41
|
custom: 'Choose features individually',
|
|
16
42
|
},
|
|
17
43
|
}, null, 2);
|
package/dist/nonInteractive.d.ts
CHANGED
package/dist/nonInteractive.js
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import process from 'node:process';
|
|
2
|
-
import {
|
|
2
|
+
import { getFeatureNames, isFeatureNameValid, isStackName, stackNames, } from './constants/config.js';
|
|
3
3
|
import { cleanupFiles, cloneRepo, createEnvFile, installPackages } from './operations/index.js';
|
|
4
|
-
import {
|
|
4
|
+
import { beginInstall, completeInstall } from './operations/installGuard.js';
|
|
5
|
+
import { getPostInstallMessages, getProjectFolder, isValidName, projectDirectoryExists, resolveModeFeatures, } from './utils/utils.js';
|
|
5
6
|
function fail(error) {
|
|
6
7
|
const result = { success: false, error };
|
|
7
8
|
console.log(JSON.stringify(result, null, 2));
|
|
@@ -25,6 +26,11 @@ function parseFeatures(featuresFlag) {
|
|
|
25
26
|
});
|
|
26
27
|
}
|
|
27
28
|
function validate(flags) {
|
|
29
|
+
const stackFlag = flags.stack ?? 'evm';
|
|
30
|
+
if (!isStackName(stackFlag)) {
|
|
31
|
+
fail(`Invalid stack: '${stackFlag}'. Valid stacks: ${stackNames.join(', ')}`);
|
|
32
|
+
}
|
|
33
|
+
const stack = stackFlag;
|
|
28
34
|
if (!flags.name) {
|
|
29
35
|
fail('Missing required flag: --name');
|
|
30
36
|
}
|
|
@@ -34,15 +40,22 @@ function validate(flags) {
|
|
|
34
40
|
if (!isValidName(flags.name)) {
|
|
35
41
|
fail('Invalid project name: only letters, numbers, and underscores are allowed');
|
|
36
42
|
}
|
|
37
|
-
if (flags.mode !== 'full' && flags.mode !== 'custom') {
|
|
38
|
-
fail("Invalid mode: must be 'full' or 'custom'");
|
|
43
|
+
if (flags.mode !== 'full' && flags.mode !== 'default' && flags.mode !== 'custom') {
|
|
44
|
+
fail("Invalid mode: must be 'full', 'default', or 'custom'");
|
|
45
|
+
}
|
|
46
|
+
if (flags.mode === 'default' && stack === 'evm') {
|
|
47
|
+
fail("Invalid mode: 'default' is only available for the canton stack");
|
|
39
48
|
}
|
|
40
|
-
|
|
41
|
-
if (flags.mode === 'full') {
|
|
49
|
+
if (flags.mode === 'full' || flags.mode === 'default') {
|
|
42
50
|
if (projectDirectoryExists(flags.name)) {
|
|
43
51
|
fail(`Project directory '${flags.name}' already exists`);
|
|
44
52
|
}
|
|
45
|
-
return {
|
|
53
|
+
return {
|
|
54
|
+
stack,
|
|
55
|
+
name: flags.name,
|
|
56
|
+
mode: flags.mode,
|
|
57
|
+
features: resolveModeFeatures(stack, flags.mode),
|
|
58
|
+
};
|
|
46
59
|
}
|
|
47
60
|
if (!flags.features) {
|
|
48
61
|
fail('--mode custom requires --features. Use --info to see available features.');
|
|
@@ -51,30 +64,40 @@ function validate(flags) {
|
|
|
51
64
|
if (features.length === 0) {
|
|
52
65
|
fail('--features value is empty. Use --info to see available features.');
|
|
53
66
|
}
|
|
54
|
-
const invalidFeatures = features.filter((f) => !
|
|
67
|
+
const invalidFeatures = features.filter((f) => !isFeatureNameValid(stack, f));
|
|
55
68
|
if (invalidFeatures.length > 0) {
|
|
56
|
-
|
|
69
|
+
const validNames = getFeatureNames(stack).join(', ');
|
|
70
|
+
fail(`Unknown features for stack '${stack}': ${invalidFeatures.join(', ')}. Valid features: ${validNames}`);
|
|
57
71
|
}
|
|
58
72
|
if (projectDirectoryExists(flags.name)) {
|
|
59
73
|
fail(`Project directory '${flags.name}' already exists`);
|
|
60
74
|
}
|
|
61
|
-
return {
|
|
75
|
+
return {
|
|
76
|
+
stack,
|
|
77
|
+
name: flags.name,
|
|
78
|
+
mode: flags.mode,
|
|
79
|
+
features: resolveModeFeatures(stack, 'custom', features),
|
|
80
|
+
};
|
|
62
81
|
}
|
|
63
82
|
export async function runNonInteractive(flags) {
|
|
64
|
-
const { name, mode, features } = validate(flags);
|
|
83
|
+
const { stack, name, mode, features } = validate(flags);
|
|
84
|
+
const projectFolder = getProjectFolder(name);
|
|
65
85
|
try {
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
await
|
|
69
|
-
await
|
|
70
|
-
await
|
|
86
|
+
// From here on a project directory exists on disk; an interrupt removes the partial scaffold.
|
|
87
|
+
beginInstall(projectFolder);
|
|
88
|
+
await cloneRepo(stack, name);
|
|
89
|
+
await createEnvFile(stack, projectFolder, features);
|
|
90
|
+
await installPackages(stack, projectFolder, mode, features);
|
|
91
|
+
await cleanupFiles(stack, projectFolder, mode, features);
|
|
92
|
+
completeInstall();
|
|
71
93
|
const result = {
|
|
72
94
|
success: true,
|
|
95
|
+
stack,
|
|
73
96
|
projectName: name,
|
|
74
97
|
mode,
|
|
75
98
|
features,
|
|
76
99
|
path: projectFolder,
|
|
77
|
-
postInstall: getPostInstallMessages(mode, features),
|
|
100
|
+
postInstall: getPostInstallMessages(stack, mode, features),
|
|
78
101
|
};
|
|
79
102
|
console.log(JSON.stringify(result, null, 2));
|
|
80
103
|
}
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import type
|
|
1
|
+
import { type FeatureName, type Stack } from '../constants/config.js';
|
|
2
2
|
import type { InstallationType } from '../types/types.js';
|
|
3
|
-
export declare function cleanupFiles(projectFolder: string, mode: InstallationType, features?: FeatureName[], onProgress?: (step: string) => void): Promise<void>;
|
|
3
|
+
export declare function cleanupFiles(stack: Stack, projectFolder: string, mode: InstallationType, features?: FeatureName[], onProgress?: (step: string) => void): Promise<void>;
|