create-harper 0.0.1 → 0.0.3
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/README.md +5 -0
- package/index.js +37 -214
- package/lib/constants/defaultTargetDir.js +1 -0
- package/lib/constants/frameworks.js +75 -0
- package/lib/constants/helpMessage.js +23 -0
- package/lib/constants/renameFiles.js +7 -0
- package/lib/constants/templates.js +6 -0
- package/lib/fs/applyAndWriteTemplateFile.js +9 -0
- package/lib/fs/copy.js +11 -0
- package/lib/fs/copyDir.js +12 -0
- package/lib/fs/crawlTemplateDir.js +18 -0
- package/lib/fs/emptyDir.js +14 -0
- package/lib/fs/formatTargetDir.js +3 -0
- package/lib/fs/isEmpty.js +6 -0
- package/lib/install.js +17 -0
- package/lib/pkg/getInstallCommand.js +6 -0
- package/lib/pkg/getRunCommand.js +12 -0
- package/lib/pkg/isValidPackageName.js +5 -0
- package/lib/pkg/pkgFromUserAgent.js +9 -0
- package/lib/pkg/toValidPackageName.js +9 -0
- package/lib/run.js +14 -0
- package/lib/start.js +15 -0
- package/lib/steps/getEnvVars.js +79 -0
- package/lib/steps/getImmediate.js +29 -0
- package/lib/steps/getPackageName.js +38 -0
- package/lib/steps/getProjectName.js +40 -0
- package/lib/steps/getTemplate.js +65 -0
- package/lib/steps/handleExistingDir.js +61 -0
- package/lib/steps/scaffoldProject.js +40 -0
- package/lib/steps/showOutro.js +30 -0
- package/package.json +20 -8
- package/template-barebones/README.md +7 -0
- package/template-barebones/_aiignore +1 -0
- package/template-barebones/_env +3 -0
- package/template-barebones/_env.example +3 -0
- package/template-barebones/_gitignore +147 -0
- package/template-barebones/config.yaml +7 -0
- package/template-barebones/graphql.config.yml +3 -0
- package/template-barebones/package.json +14 -0
- package/template-barebones/schema.graphql +1 -0
- package/template-react/README.md +45 -0
- package/template-react/_aiignore +1 -0
- package/template-react/_env +3 -0
- package/template-react/_env.example +3 -0
- package/template-react/_github/workflow/deploy.yaml +40 -0
- package/template-react/_gitignore +147 -0
- package/template-react/config.yaml +23 -0
- package/template-react/deploy-template/config.yaml +2 -0
- package/template-react/deploy-template/fastify/static.js +14 -0
- package/template-react/deploy-template/package.json +5 -0
- package/template-react/graphql.config.yml +3 -0
- package/template-react/index.html +13 -0
- package/template-react/package.json +25 -0
- package/template-react/public/react.svg +14 -0
- package/template-react/public/typescript.svg +16 -0
- package/template-react/public/vite.svg +42 -0
- package/template-react/resources.js +27 -0
- package/template-react/schema.graphql +5 -0
- package/template-react/src/App.jsx +34 -0
- package/template-react/src/main.jsx +13 -0
- package/template-react/src/style.css +96 -0
- package/template-react/src/vite-env.d.ts +9 -0
- package/template-react/vite.config.js +22 -0
- package/template-react-ts/README.md +45 -0
- package/template-react-ts/_aiignore +1 -0
- package/template-react-ts/_env +3 -0
- package/template-react-ts/_env.example +3 -0
- package/template-react-ts/_github/workflow/deploy.yaml +40 -0
- package/template-react-ts/_gitignore +147 -0
- package/template-react-ts/config.yaml +23 -0
- package/template-react-ts/deploy-template/config.yaml +2 -0
- package/template-react-ts/deploy-template/fastify/static.js +14 -0
- package/template-react-ts/deploy-template/package.json +5 -0
- package/template-react-ts/graphql.config.yml +3 -0
- package/template-react-ts/index.html +13 -0
- package/template-react-ts/package.json +29 -0
- package/template-react-ts/public/react.svg +14 -0
- package/template-react-ts/public/typescript.svg +16 -0
- package/template-react-ts/public/vite.svg +42 -0
- package/template-react-ts/resources.ts +52 -0
- package/template-react-ts/schema.graphql +5 -0
- package/template-react-ts/src/App.tsx +34 -0
- package/template-react-ts/src/main.tsx +13 -0
- package/template-react-ts/src/style.css +96 -0
- package/template-react-ts/src/vite-env.d.ts +9 -0
- package/template-react-ts/tsconfig.json +34 -0
- package/template-react-ts/vite.config.ts +22 -0
- package/template-studio/README.md +34 -0
- package/template-studio/_aiignore +1 -0
- package/template-studio/_gitignore +147 -0
- package/template-studio/config.yaml +24 -0
- package/template-studio/graphql.config.yml +3 -0
- package/template-studio/package.json +14 -0
- package/template-studio/resources.js +27 -0
- package/template-studio/schema.graphql +7 -0
- package/template-studio/web/index.html +28 -0
- package/template-studio/web/index.js +18 -0
- package/template-studio/web/styles.css +57 -0
- package/template-studio-ts/README.md +34 -0
- package/template-studio-ts/_aiignore +1 -0
- package/template-studio-ts/_gitignore +147 -0
- package/template-studio-ts/config.yaml +24 -0
- package/template-studio-ts/graphql.config.yml +3 -0
- package/template-studio-ts/package.json +14 -0
- package/template-studio-ts/resources.ts +52 -0
- package/template-studio-ts/schema.graphql +7 -0
- package/template-studio-ts/tsconfig.json +10 -0
- package/template-studio-ts/web/index.html +28 -0
- package/template-studio-ts/web/index.js +18 -0
- package/template-studio-ts/web/styles.css +57 -0
- package/template-vanilla/README.md +57 -0
- package/template-vanilla/_aiignore +1 -0
- package/template-vanilla/_env +3 -0
- package/template-vanilla/_env.example +3 -0
- package/template-vanilla/_gitignore +147 -0
- package/template-vanilla/config.yaml +24 -0
- package/template-vanilla/graphql.config.yml +3 -0
- package/template-vanilla/package.json +14 -0
- package/template-vanilla/resources.js +27 -0
- package/template-vanilla/schema.graphql +7 -0
- package/template-vanilla/web/index.html +28 -0
- package/template-vanilla/web/index.js +18 -0
- package/template-vanilla/web/styles.css +57 -0
- package/template-vanilla-ts/README.md +57 -0
- package/template-vanilla-ts/_aiignore +1 -0
- package/template-vanilla-ts/_env +3 -0
- package/template-vanilla-ts/_env.example +3 -0
- package/template-vanilla-ts/_gitignore +147 -0
- package/template-vanilla-ts/config.yaml +24 -0
- package/template-vanilla-ts/graphql.config.yml +3 -0
- package/template-vanilla-ts/package.json +14 -0
- package/template-vanilla-ts/resources.ts +52 -0
- package/template-vanilla-ts/schema.graphql +7 -0
- package/template-vanilla-ts/tsconfig.json +10 -0
- package/template-vanilla-ts/web/index.html +28 -0
- package/template-vanilla-ts/web/index.js +18 -0
- package/template-vanilla-ts/web/styles.css +57 -0
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import * as prompts from '@clack/prompts';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Step 5: Ask about immediate install and package manager
|
|
5
|
+
* @param {boolean | undefined} argImmediate
|
|
6
|
+
* @param {boolean} interactive
|
|
7
|
+
* @param {string} pkgManager
|
|
8
|
+
* @returns {Promise<{immediate: boolean, cancelled: boolean}>}
|
|
9
|
+
*/
|
|
10
|
+
export async function getImmediate(argImmediate, interactive, pkgManager) {
|
|
11
|
+
let immediate = argImmediate;
|
|
12
|
+
|
|
13
|
+
if (immediate === undefined) {
|
|
14
|
+
if (interactive) {
|
|
15
|
+
const immediateResult = await prompts.confirm({
|
|
16
|
+
message: `Install with ${pkgManager} and start now?`,
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
if (prompts.isCancel(immediateResult)) {
|
|
20
|
+
return { immediate: false, cancelled: true };
|
|
21
|
+
}
|
|
22
|
+
immediate = immediateResult;
|
|
23
|
+
} else {
|
|
24
|
+
immediate = false;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
return { immediate, cancelled: false };
|
|
29
|
+
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import * as prompts from '@clack/prompts';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import { isValidPackageName } from '../pkg/isValidPackageName.js';
|
|
4
|
+
import { toValidPackageName } from '../pkg/toValidPackageName.js';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Step 3: Get package name
|
|
8
|
+
* @param {string} targetDir
|
|
9
|
+
* @param {boolean} interactive
|
|
10
|
+
* @returns {Promise<{packageName: string, cancelled: boolean}>}
|
|
11
|
+
*/
|
|
12
|
+
export async function getPackageName(targetDir, interactive) {
|
|
13
|
+
let packageName = path.basename(path.resolve(targetDir));
|
|
14
|
+
|
|
15
|
+
if (!isValidPackageName(packageName)) {
|
|
16
|
+
if (interactive) {
|
|
17
|
+
const packageNameResult = await prompts.text({
|
|
18
|
+
message: 'Package name:',
|
|
19
|
+
defaultValue: toValidPackageName(packageName),
|
|
20
|
+
placeholder: toValidPackageName(packageName),
|
|
21
|
+
validate(dir) {
|
|
22
|
+
if (dir && !isValidPackageName(dir)) {
|
|
23
|
+
return 'Invalid package.json name';
|
|
24
|
+
}
|
|
25
|
+
},
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
if (prompts.isCancel(packageNameResult)) {
|
|
29
|
+
return { packageName: '', cancelled: true };
|
|
30
|
+
}
|
|
31
|
+
packageName = packageNameResult;
|
|
32
|
+
} else {
|
|
33
|
+
packageName = toValidPackageName(packageName);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
return { packageName, cancelled: false };
|
|
38
|
+
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import * as prompts from '@clack/prompts';
|
|
2
|
+
import { defaultTargetDir } from '../constants/defaultTargetDir.js';
|
|
3
|
+
import { formatTargetDir } from '../fs/formatTargetDir.js';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Step 1: Get project name and target directory
|
|
7
|
+
* @param {string | undefined} argTargetDir
|
|
8
|
+
* @param {boolean} interactive
|
|
9
|
+
* @returns {Promise<{projectName: string, targetDir: string, cancelled: boolean}>}
|
|
10
|
+
*/
|
|
11
|
+
export async function getProjectName(argTargetDir, interactive) {
|
|
12
|
+
let targetDir = argTargetDir;
|
|
13
|
+
let projectName = targetDir;
|
|
14
|
+
|
|
15
|
+
if (!targetDir) {
|
|
16
|
+
if (interactive) {
|
|
17
|
+
projectName = await prompts.text({
|
|
18
|
+
message: 'Project name:',
|
|
19
|
+
defaultValue: defaultTargetDir,
|
|
20
|
+
placeholder: defaultTargetDir,
|
|
21
|
+
validate: (value) => {
|
|
22
|
+
return !value || formatTargetDir(value).length > 0
|
|
23
|
+
? undefined
|
|
24
|
+
: 'Invalid project name';
|
|
25
|
+
},
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
if (prompts.isCancel(projectName)) {
|
|
29
|
+
return { projectName: '', targetDir: '', cancelled: true };
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
targetDir = formatTargetDir(projectName);
|
|
33
|
+
} else {
|
|
34
|
+
targetDir = defaultTargetDir;
|
|
35
|
+
projectName = targetDir;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
return { projectName, targetDir, cancelled: false };
|
|
40
|
+
}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import * as prompts from '@clack/prompts';
|
|
2
|
+
import { FRAMEWORKS } from '../constants/frameworks.js';
|
|
3
|
+
import { TEMPLATES } from '../constants/templates.js';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Step 4: Choose a framework and variant
|
|
7
|
+
* @param {string | undefined} argTemplate
|
|
8
|
+
* @param {boolean} interactive
|
|
9
|
+
* @returns {Promise<{template: string, cancelled: boolean}>}
|
|
10
|
+
*/
|
|
11
|
+
export async function getTemplate(argTemplate, interactive) {
|
|
12
|
+
let template = argTemplate;
|
|
13
|
+
let hasInvalidArgTemplate = false;
|
|
14
|
+
|
|
15
|
+
if (argTemplate && !TEMPLATES.includes(argTemplate)) {
|
|
16
|
+
template = undefined;
|
|
17
|
+
hasInvalidArgTemplate = true;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
if (!template) {
|
|
21
|
+
if (interactive) {
|
|
22
|
+
const framework = await prompts.select({
|
|
23
|
+
message: hasInvalidArgTemplate
|
|
24
|
+
? `"${argTemplate}" isn't a valid template. Please choose from below: `
|
|
25
|
+
: 'Select a framework:',
|
|
26
|
+
options: FRAMEWORKS
|
|
27
|
+
.filter(framework => !framework.hidden)
|
|
28
|
+
.map((framework) => {
|
|
29
|
+
const frameworkColor = framework.color;
|
|
30
|
+
return {
|
|
31
|
+
label: frameworkColor(framework.display),
|
|
32
|
+
value: framework,
|
|
33
|
+
};
|
|
34
|
+
}),
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
if (prompts.isCancel(framework)) {
|
|
38
|
+
return { template: '', cancelled: true };
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
const variant = framework.variants.length === 1
|
|
42
|
+
? framework.variants[0].name
|
|
43
|
+
: await prompts.select({
|
|
44
|
+
message: 'Select a variant:',
|
|
45
|
+
options: framework.variants.map((variant) => {
|
|
46
|
+
const variantColor = variant.color;
|
|
47
|
+
return {
|
|
48
|
+
label: variantColor(variant.display || variant.name),
|
|
49
|
+
value: variant.name,
|
|
50
|
+
};
|
|
51
|
+
}),
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
if (prompts.isCancel(variant)) {
|
|
55
|
+
return { template: '', cancelled: true };
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
template = variant;
|
|
59
|
+
} else {
|
|
60
|
+
template = 'vanilla-ts';
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
return { template, cancelled: false };
|
|
65
|
+
}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import * as prompts from '@clack/prompts';
|
|
2
|
+
import fs from 'node:fs';
|
|
3
|
+
import { emptyDir } from '../fs/emptyDir.js';
|
|
4
|
+
import { isEmpty } from '../fs/isEmpty.js';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Step 2: Handle directory if exist and not empty
|
|
8
|
+
* @param {string} targetDir
|
|
9
|
+
* @param {boolean | undefined} argOverwrite
|
|
10
|
+
* @param {boolean} interactive
|
|
11
|
+
* @returns {Promise<{cancelled: boolean}>}
|
|
12
|
+
*/
|
|
13
|
+
export async function handleExistingDir(targetDir, argOverwrite, interactive) {
|
|
14
|
+
if (fs.existsSync(targetDir) && !isEmpty(targetDir)) {
|
|
15
|
+
let overwrite = argOverwrite
|
|
16
|
+
? 'yes'
|
|
17
|
+
: undefined;
|
|
18
|
+
|
|
19
|
+
if (!overwrite) {
|
|
20
|
+
if (interactive) {
|
|
21
|
+
const res = await prompts.select({
|
|
22
|
+
message: (targetDir === '.'
|
|
23
|
+
? 'Current directory'
|
|
24
|
+
: `Target directory "${targetDir}"`)
|
|
25
|
+
+ ` is not empty. Please choose how to proceed:`,
|
|
26
|
+
options: [
|
|
27
|
+
{
|
|
28
|
+
label: 'Cancel operation',
|
|
29
|
+
value: 'no',
|
|
30
|
+
},
|
|
31
|
+
{
|
|
32
|
+
label: 'Remove existing files and continue',
|
|
33
|
+
value: 'yes',
|
|
34
|
+
},
|
|
35
|
+
{
|
|
36
|
+
label: 'Ignore files and continue',
|
|
37
|
+
value: 'ignore',
|
|
38
|
+
},
|
|
39
|
+
],
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
if (prompts.isCancel(res)) {
|
|
43
|
+
return { cancelled: true };
|
|
44
|
+
}
|
|
45
|
+
overwrite = res;
|
|
46
|
+
} else {
|
|
47
|
+
overwrite = 'no';
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
switch (overwrite) {
|
|
52
|
+
case 'yes':
|
|
53
|
+
emptyDir(targetDir);
|
|
54
|
+
break;
|
|
55
|
+
case 'no':
|
|
56
|
+
return { cancelled: true };
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
return { cancelled: false };
|
|
61
|
+
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import * as prompts from '@clack/prompts';
|
|
2
|
+
import fs from 'node:fs';
|
|
3
|
+
import path from 'node:path';
|
|
4
|
+
import { fileURLToPath } from 'node:url';
|
|
5
|
+
import { crawlTemplateDir } from '../fs/crawlTemplateDir.js';
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Step 6: Write out the contents based on all prior steps.
|
|
9
|
+
* @param {string} targetDir
|
|
10
|
+
* @param {string} projectName
|
|
11
|
+
* @param {string} packageName
|
|
12
|
+
* @param {string} template
|
|
13
|
+
* @param {{username: string, target: string, password?: string}} envVars
|
|
14
|
+
* @returns {string} The root directory of the project
|
|
15
|
+
*/
|
|
16
|
+
export function scaffoldProject(targetDir, projectName, packageName, template, envVars) {
|
|
17
|
+
const cwd = process.cwd();
|
|
18
|
+
const root = path.join(cwd, targetDir);
|
|
19
|
+
fs.mkdirSync(root, { recursive: true });
|
|
20
|
+
prompts.log.step(`Scaffolding project in ${root}...`);
|
|
21
|
+
|
|
22
|
+
const substitutions = {
|
|
23
|
+
'your-project-name-here': projectName,
|
|
24
|
+
'your-package-name-here': packageName,
|
|
25
|
+
'your-cluster-username-here': envVars.username,
|
|
26
|
+
'your-cluster-password-here': envVars.password,
|
|
27
|
+
'your-fabric.harper.fast-cluster-url-here': envVars.target,
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
const templateDir = path.resolve(
|
|
31
|
+
fileURLToPath(import.meta.url),
|
|
32
|
+
'..',
|
|
33
|
+
'..',
|
|
34
|
+
'..',
|
|
35
|
+
`template-${template}`,
|
|
36
|
+
);
|
|
37
|
+
crawlTemplateDir(root, templateDir, substitutions);
|
|
38
|
+
|
|
39
|
+
return root;
|
|
40
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import * as prompts from '@clack/prompts';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import { install } from '../install.js';
|
|
4
|
+
import { getInstallCommand } from '../pkg/getInstallCommand.js';
|
|
5
|
+
import { getRunCommand } from '../pkg/getRunCommand.js';
|
|
6
|
+
import { start } from '../start.js';
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Step 7: Log out the next steps.
|
|
10
|
+
* @param {string} root
|
|
11
|
+
* @param {string} pkgManager
|
|
12
|
+
* @param {boolean} immediate
|
|
13
|
+
*/
|
|
14
|
+
export function showOutro(root, pkgManager, immediate) {
|
|
15
|
+
if (immediate) {
|
|
16
|
+
install(root, pkgManager);
|
|
17
|
+
start(root, pkgManager);
|
|
18
|
+
} else {
|
|
19
|
+
let doneMessage = '';
|
|
20
|
+
const cwd = process.cwd();
|
|
21
|
+
const cdProjectName = path.relative(cwd, root);
|
|
22
|
+
doneMessage += `Done. Now run:\n`;
|
|
23
|
+
if (root !== cwd) {
|
|
24
|
+
doneMessage += `\n cd ${cdProjectName.includes(' ') ? `"${cdProjectName}"` : cdProjectName}`;
|
|
25
|
+
}
|
|
26
|
+
doneMessage += `\n ${getInstallCommand(pkgManager).join(' ')}`;
|
|
27
|
+
doneMessage += `\n ${getRunCommand(pkgManager, 'dev').join(' ')}`;
|
|
28
|
+
prompts.outro(doneMessage);
|
|
29
|
+
}
|
|
30
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "create-harper",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.3",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "HarperDB",
|
|
@@ -12,15 +12,26 @@
|
|
|
12
12
|
},
|
|
13
13
|
"files": [
|
|
14
14
|
"index.js",
|
|
15
|
-
"
|
|
15
|
+
"lib/",
|
|
16
|
+
"!lib/**/*.test.js",
|
|
17
|
+
"template-barebones/",
|
|
18
|
+
"template-react/",
|
|
19
|
+
"template-react-ts/",
|
|
20
|
+
"template-studio/",
|
|
21
|
+
"template-studio-ts/",
|
|
22
|
+
"template-vanilla/",
|
|
23
|
+
"template-vanilla-ts/"
|
|
16
24
|
],
|
|
17
25
|
"scripts": {
|
|
18
|
-
"
|
|
19
|
-
"
|
|
20
|
-
"format": "dprint check",
|
|
26
|
+
"commitlint": "commitlint --edit",
|
|
27
|
+
"format:check": "dprint check",
|
|
21
28
|
"format:fix": "dprint fmt",
|
|
22
29
|
"format:staged": "dprint check --staged",
|
|
23
|
-
"
|
|
30
|
+
"lint:check": "oxlint .",
|
|
31
|
+
"lint:fix": "oxlint . --fix",
|
|
32
|
+
"test": "vitest run",
|
|
33
|
+
"test:coverage": "vitest run --coverage",
|
|
34
|
+
"test:watch": "vitest"
|
|
24
35
|
},
|
|
25
36
|
"engines": {
|
|
26
37
|
"node": "^20.19.0 || >=22.12.0"
|
|
@@ -37,13 +48,14 @@
|
|
|
37
48
|
"@clack/prompts": "^1.0.0-alpha.9",
|
|
38
49
|
"@vercel/detect-agent": "^1.0.0",
|
|
39
50
|
"cross-spawn": "^7.0.6",
|
|
40
|
-
"lodash": "^4.17.21",
|
|
41
51
|
"mri": "^1.2.0",
|
|
42
52
|
"picocolors": "^1.1.1"
|
|
43
53
|
},
|
|
44
54
|
"devDependencies": {
|
|
55
|
+
"@commitlint/cli": "^20.0.0",
|
|
56
|
+
"@commitlint/config-conventional": "^20.0.0",
|
|
57
|
+
"@vitest/coverage-v8": "^4.0.17",
|
|
45
58
|
"dprint": "^0.51.1",
|
|
46
|
-
"harperdb": "^4.7.15",
|
|
47
59
|
"oxlint": "^1.38.0",
|
|
48
60
|
"vitest": "^4.0.17"
|
|
49
61
|
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
# your-project-name-here
|
|
2
|
+
|
|
3
|
+
This repository is intended for use alongside the Harper Learn ["Getting Started > Create Your First Application"](https://docs.harperdb.io/learn/getting-started/create-your-first-application) guide.
|
|
4
|
+
|
|
5
|
+
The `main` branch is the starting point for the guide.
|
|
6
|
+
|
|
7
|
+
The `completed` branch is the completed code example if you need to check your work.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
.env
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
.DS_Store
|
|
2
|
+
|
|
3
|
+
#
|
|
4
|
+
# https://raw.githubusercontent.com/github/gitignore/refs/heads/main/Node.gitignore
|
|
5
|
+
#
|
|
6
|
+
|
|
7
|
+
# Logs
|
|
8
|
+
logs
|
|
9
|
+
*.log
|
|
10
|
+
npm-debug.log*
|
|
11
|
+
yarn-debug.log*
|
|
12
|
+
yarn-error.log*
|
|
13
|
+
lerna-debug.log*
|
|
14
|
+
|
|
15
|
+
# Diagnostic reports (https://nodejs.org/api/report.html)
|
|
16
|
+
report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
|
|
17
|
+
|
|
18
|
+
# Runtime data
|
|
19
|
+
pids
|
|
20
|
+
*.pid
|
|
21
|
+
*.seed
|
|
22
|
+
*.pid.lock
|
|
23
|
+
|
|
24
|
+
# Directory for instrumented libs generated by jscoverage/JSCover
|
|
25
|
+
lib-cov
|
|
26
|
+
|
|
27
|
+
# Coverage directory used by tools like istanbul
|
|
28
|
+
coverage
|
|
29
|
+
*.lcov
|
|
30
|
+
|
|
31
|
+
# nyc test coverage
|
|
32
|
+
.nyc_output
|
|
33
|
+
|
|
34
|
+
# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
|
|
35
|
+
.grunt
|
|
36
|
+
|
|
37
|
+
# Bower dependency directory (https://bower.io/)
|
|
38
|
+
bower_components
|
|
39
|
+
|
|
40
|
+
# node-waf configuration
|
|
41
|
+
.lock-wscript
|
|
42
|
+
|
|
43
|
+
# Compiled binary addons (https://nodejs.org/api/addons.html)
|
|
44
|
+
build/Release
|
|
45
|
+
|
|
46
|
+
# Dependency directories
|
|
47
|
+
node_modules/
|
|
48
|
+
jspm_packages/
|
|
49
|
+
|
|
50
|
+
# Snowpack dependency directory (https://snowpack.dev/)
|
|
51
|
+
web_modules/
|
|
52
|
+
|
|
53
|
+
# TypeScript cache
|
|
54
|
+
*.tsbuildinfo
|
|
55
|
+
|
|
56
|
+
# Optional npm cache directory
|
|
57
|
+
.npm
|
|
58
|
+
|
|
59
|
+
# Optional eslint cache
|
|
60
|
+
.eslintcache
|
|
61
|
+
|
|
62
|
+
# Optional stylelint cache
|
|
63
|
+
.stylelintcache
|
|
64
|
+
|
|
65
|
+
# Optional REPL history
|
|
66
|
+
.node_repl_history
|
|
67
|
+
|
|
68
|
+
# Output of 'npm pack'
|
|
69
|
+
*.tgz
|
|
70
|
+
|
|
71
|
+
# Yarn Integrity file
|
|
72
|
+
.yarn-integrity
|
|
73
|
+
|
|
74
|
+
# dotenv environment variable files
|
|
75
|
+
.env
|
|
76
|
+
.env.*
|
|
77
|
+
!.env.example
|
|
78
|
+
|
|
79
|
+
# parcel-bundler cache (https://parceljs.org/)
|
|
80
|
+
.cache
|
|
81
|
+
.parcel-cache
|
|
82
|
+
|
|
83
|
+
# Next.js build output
|
|
84
|
+
.next
|
|
85
|
+
out
|
|
86
|
+
|
|
87
|
+
# Nuxt.js build / generate output
|
|
88
|
+
.nuxt
|
|
89
|
+
dist
|
|
90
|
+
.output
|
|
91
|
+
|
|
92
|
+
# Gatsby files
|
|
93
|
+
.cache/
|
|
94
|
+
# Comment in the public line in if your project uses Gatsby and not Next.js
|
|
95
|
+
# https://nextjs.org/blog/next-9-1#public-directory-support
|
|
96
|
+
# public
|
|
97
|
+
|
|
98
|
+
# vuepress build output
|
|
99
|
+
.vuepress/dist
|
|
100
|
+
|
|
101
|
+
# vuepress v2.x temp and cache directory
|
|
102
|
+
.temp
|
|
103
|
+
.cache
|
|
104
|
+
|
|
105
|
+
# Sveltekit cache directory
|
|
106
|
+
.svelte-kit/
|
|
107
|
+
|
|
108
|
+
# vitepress build output
|
|
109
|
+
**/.vitepress/dist
|
|
110
|
+
|
|
111
|
+
# vitepress cache directory
|
|
112
|
+
**/.vitepress/cache
|
|
113
|
+
|
|
114
|
+
# Docusaurus cache and generated files
|
|
115
|
+
.docusaurus
|
|
116
|
+
|
|
117
|
+
# Serverless directories
|
|
118
|
+
.serverless/
|
|
119
|
+
|
|
120
|
+
# FuseBox cache
|
|
121
|
+
.fusebox/
|
|
122
|
+
|
|
123
|
+
# DynamoDB Local files
|
|
124
|
+
.dynamodb/
|
|
125
|
+
|
|
126
|
+
# Firebase cache directory
|
|
127
|
+
.firebase/
|
|
128
|
+
|
|
129
|
+
# TernJS port file
|
|
130
|
+
.tern-port
|
|
131
|
+
|
|
132
|
+
# Stores VSCode versions used for testing VSCode extensions
|
|
133
|
+
.vscode-test
|
|
134
|
+
|
|
135
|
+
# yarn v3
|
|
136
|
+
.pnp.*
|
|
137
|
+
.yarn/*
|
|
138
|
+
!.yarn/patches
|
|
139
|
+
!.yarn/plugins
|
|
140
|
+
!.yarn/releases
|
|
141
|
+
!.yarn/sdks
|
|
142
|
+
!.yarn/versions
|
|
143
|
+
|
|
144
|
+
# Vite files
|
|
145
|
+
vite.config.js.timestamp-*
|
|
146
|
+
vite.config.ts.timestamp-*
|
|
147
|
+
.vite/
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
# yaml-language-server: $schema=./node_modules/harperdb/config-app.schema.json
|
|
2
|
+
|
|
3
|
+
# This is the configuration file for the application.
|
|
4
|
+
# It specifies built-in Harper components that will load the specified feature and files.
|
|
5
|
+
# For more information, see https://docs.harperdb.io/docs/reference/components/built-in-extensions
|
|
6
|
+
|
|
7
|
+
# Follow along with https://github.com/HarperFast/create-your-first-application to learn more!
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "your-package-name-here",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Your new Harper app",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"scripts": {
|
|
7
|
+
"start": "harperdb run .",
|
|
8
|
+
"dev": "harperdb dev .",
|
|
9
|
+
"deploy": "npx -y dotenv-cli -- harperdb deploy . restart=rolling replicated=true"
|
|
10
|
+
},
|
|
11
|
+
"devDependencies": {
|
|
12
|
+
"harperdb": "^4.7.15"
|
|
13
|
+
}
|
|
14
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
## Table Schemas
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
# your-project-name-here
|
|
2
|
+
|
|
3
|
+
## Installation
|
|
4
|
+
|
|
5
|
+
To get started, make sure you have [installed Harper](https://docs.harperdb.io/docs/deployments/install-harper), which can be done quickly:
|
|
6
|
+
|
|
7
|
+
```sh
|
|
8
|
+
npm install -g harperdb
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Development
|
|
12
|
+
|
|
13
|
+
Then you can start your app:
|
|
14
|
+
|
|
15
|
+
```sh
|
|
16
|
+
npm run dev
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
Navigate to [http://localhost:9926](http://localhost:9926) in a browser and view the functional web application.
|
|
20
|
+
|
|
21
|
+
For more information about getting started with HarperDB and building applications, see our [getting started guide](https://docs.harperdb.io/docs).
|
|
22
|
+
|
|
23
|
+
For more information on Harper Components, see the [Components documentation](https://docs.harperdb.io/docs/reference/components).
|
|
24
|
+
|
|
25
|
+
Take a look at the [default configuration](./config.yaml), which specifies how files are handled in your application.
|
|
26
|
+
|
|
27
|
+
The [schema.graphql](./schema.graphql) is the table schema definition. This is the main starting point for defining your database schema, specifying which tables you want and what attributes/fields they should have.
|
|
28
|
+
|
|
29
|
+
The [resources.js](resources.ts) provides a template for defining JavaScript resource classes, for customized application logic in your endpoints.
|
|
30
|
+
|
|
31
|
+
## Deployment
|
|
32
|
+
|
|
33
|
+
When you are ready, head to [https://fabric.harper.fast/](https://fabric.harper.fast/), log in to your account, and create a cluster.
|
|
34
|
+
|
|
35
|
+
Set up your .env file with your secure cluster credentials. Don't commit this file to source control!
|
|
36
|
+
|
|
37
|
+
```sh
|
|
38
|
+
npm run login
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
Then you can deploy your app to your cluster:
|
|
42
|
+
|
|
43
|
+
```sh
|
|
44
|
+
npm run deploy
|
|
45
|
+
```
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
.env
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
name: Deploy to Harper Fabric
|
|
2
|
+
on:
|
|
3
|
+
workflow_dispatch:
|
|
4
|
+
# push:
|
|
5
|
+
# branches:
|
|
6
|
+
# - main
|
|
7
|
+
|
|
8
|
+
concurrency:
|
|
9
|
+
group: main
|
|
10
|
+
cancel-in-progress: false
|
|
11
|
+
|
|
12
|
+
jobs:
|
|
13
|
+
deploy:
|
|
14
|
+
runs-on: ubuntu-latest
|
|
15
|
+
steps:
|
|
16
|
+
- name: Checkout code
|
|
17
|
+
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
|
|
18
|
+
with:
|
|
19
|
+
fetch-depth: 0
|
|
20
|
+
fetch-tags: true
|
|
21
|
+
- name: Set up Node.js
|
|
22
|
+
uses: actions/setup-node@395ad3262231945c25e8478fd5baf05154b1d79f # v6.1.0
|
|
23
|
+
with:
|
|
24
|
+
cache: 'npm'
|
|
25
|
+
node-version-file: '.nvmrc'
|
|
26
|
+
- name: Install dependencies
|
|
27
|
+
run: npm ci
|
|
28
|
+
- name: Run unit tests
|
|
29
|
+
run: npm test
|
|
30
|
+
- name: Run lint
|
|
31
|
+
run: npm run lint
|
|
32
|
+
- name: Build
|
|
33
|
+
run: npm run build
|
|
34
|
+
- name: Deploy
|
|
35
|
+
run: |
|
|
36
|
+
mkdir deploy
|
|
37
|
+
mv web deploy/
|
|
38
|
+
cp -R deploy-template/* deploy/
|
|
39
|
+
cd deploy
|
|
40
|
+
CLI_TARGET_USERNAME=${{ secrets.CLI_TARGET_USERNAME }} CLI_TARGET_PASSWORD='${{ secrets.CLI_TARGET_PASSWORD }}' harperdb deploy_component project='${{ secrets.CLI_DEPLOY_TARGET_NAME }}' target='${{ secrets.CLI_DEPLOY_TARGET_URL }}' restart=false replicated=true
|