create-harper 1.7.4 → 1.8.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/lib/constants/frameworks.js +20 -0
- package/lib/constants/helpMessage.js +2 -2
- package/package.json +6 -2
- package/template-react/README.md +6 -2
- package/template-react/_gitignore +1 -2
- package/template-react/config.yaml +16 -3
- package/template-react/package.json +9 -7
- package/template-react/src/App.jsx +1 -5
- package/template-react/vite.config.js +2 -2
- package/template-react-ssr/README.md +124 -0
- package/template-react-ssr/_aiignore +1 -0
- package/template-react-ssr/_env +1 -0
- package/template-react-ssr/_env.example +1 -0
- package/template-react-ssr/_github/workflow/deploy.yaml +33 -0
- package/template-react-ssr/_gitignore +148 -0
- package/template-react-ssr/_nvmrc +1 -0
- package/template-react-ssr/config.yaml +42 -0
- package/template-react-ssr/eslint.config.js +23 -0
- package/template-react-ssr/graphql.config.yml +3 -0
- package/template-react-ssr/index.html +13 -0
- package/template-react-ssr/package.json +32 -0
- package/template-react-ssr/public/react.svg +14 -0
- package/template-react-ssr/public/vite.svg +42 -0
- package/template-react-ssr/resources/README.md +11 -0
- package/template-react-ssr/schemas/README.md +11 -0
- package/template-react-ssr/schemas/jsdocTypes.js +5 -0
- package/template-react-ssr/src/App.jsx +31 -0
- package/template-react-ssr/src/counter.js +7 -0
- package/template-react-ssr/src/entry-client.jsx +13 -0
- package/template-react-ssr/src/entry-server.jsx +18 -0
- package/template-react-ssr/src/style.css +96 -0
- package/template-react-ssr/src/vite-env.d.ts +9 -0
- package/template-react-ssr/test/counter.test.js +15 -0
- package/template-react-ssr/vite.config.js +22 -0
- package/template-react-ts/README.md +6 -2
- package/template-react-ts/_gitignore +1 -2
- package/template-react-ts/config.yaml +16 -3
- package/template-react-ts/package.json +10 -8
- package/template-react-ts/vite.config.ts +2 -2
- package/template-react-ts-ssr/README.md +132 -0
- package/template-react-ts-ssr/_aiignore +1 -0
- package/template-react-ts-ssr/_env +1 -0
- package/template-react-ts-ssr/_env.example +1 -0
- package/template-react-ts-ssr/_github/workflow/deploy.yaml +33 -0
- package/template-react-ts-ssr/_gitignore +148 -0
- package/template-react-ts-ssr/_nvmrc +1 -0
- package/template-react-ts-ssr/config.yaml +43 -0
- package/template-react-ts-ssr/eslint.config.js +23 -0
- package/template-react-ts-ssr/graphql.config.yml +3 -0
- package/template-react-ts-ssr/index.html +13 -0
- package/template-react-ts-ssr/package.json +36 -0
- package/template-react-ts-ssr/public/react.svg +14 -0
- package/template-react-ts-ssr/public/vite.svg +42 -0
- package/template-react-ts-ssr/resources/README.md +11 -0
- package/template-react-ts-ssr/schemas/README.md +11 -0
- package/template-react-ts-ssr/schemas/globalTypes.d.ts +5 -0
- package/template-react-ts-ssr/schemas/types.ts +5 -0
- package/template-react-ts-ssr/src/App.tsx +35 -0
- package/template-react-ts-ssr/src/counter.ts +7 -0
- package/template-react-ts-ssr/src/entry-client.tsx +13 -0
- package/template-react-ts-ssr/src/entry-server.tsx +17 -0
- package/template-react-ts-ssr/src/style.css +96 -0
- package/template-react-ts-ssr/src/vite-env.d.ts +9 -0
- package/template-react-ts-ssr/test/counter.test.ts +15 -0
- package/template-react-ts-ssr/tsconfig.json +34 -0
- package/template-react-ts-ssr/vite.config.ts +22 -0
- package/template-vanilla/README.md +5 -1
- package/template-vanilla-ts/README.md +5 -1
- package/template-vue/README.md +6 -2
- package/template-vue/_gitignore +1 -2
- package/template-vue/config.yaml +16 -3
- package/template-vue/package.json +9 -7
- package/template-vue/src/App.vue +1 -9
- package/template-vue/vite.config.js +1 -1
- package/template-vue-ssr/README.md +124 -0
- package/template-vue-ssr/_aiignore +1 -0
- package/template-vue-ssr/_env +1 -0
- package/template-vue-ssr/_env.example +1 -0
- package/template-vue-ssr/_github/workflow/deploy.yaml +33 -0
- package/template-vue-ssr/_gitignore +148 -0
- package/template-vue-ssr/_nvmrc +1 -0
- package/template-vue-ssr/config.yaml +42 -0
- package/template-vue-ssr/eslint.config.js +23 -0
- package/template-vue-ssr/graphql.config.yml +3 -0
- package/template-vue-ssr/index.html +13 -0
- package/template-vue-ssr/package.json +31 -0
- package/template-vue-ssr/public/react.svg +14 -0
- package/template-vue-ssr/public/vite.svg +42 -0
- package/template-vue-ssr/public/vue.svg +9 -0
- package/template-vue-ssr/resources/README.md +11 -0
- package/template-vue-ssr/schemas/README.md +11 -0
- package/template-vue-ssr/schemas/jsdocTypes.js +5 -0
- package/template-vue-ssr/src/App.vue +35 -0
- package/template-vue-ssr/src/counter.js +7 -0
- package/template-vue-ssr/src/entry-client.js +7 -0
- package/template-vue-ssr/src/entry-server.js +14 -0
- package/template-vue-ssr/src/style.css +96 -0
- package/template-vue-ssr/test/counter.test.js +15 -0
- package/template-vue-ssr/vite.config.js +22 -0
- package/template-vue-ts/README.md +6 -2
- package/template-vue-ts/_gitignore +1 -2
- package/template-vue-ts/config.yaml +16 -3
- package/template-vue-ts/package.json +8 -6
- package/template-vue-ts/vite.config.ts +1 -1
- package/template-vue-ts-ssr/README.md +132 -0
- package/template-vue-ts-ssr/_aiignore +1 -0
- package/template-vue-ts-ssr/_env +1 -0
- package/template-vue-ts-ssr/_env.example +1 -0
- package/template-vue-ts-ssr/_github/workflow/deploy.yaml +33 -0
- package/template-vue-ts-ssr/_gitignore +148 -0
- package/template-vue-ts-ssr/_nvmrc +1 -0
- package/template-vue-ts-ssr/config.yaml +43 -0
- package/template-vue-ts-ssr/eslint.config.js +23 -0
- package/template-vue-ts-ssr/graphql.config.yml +3 -0
- package/template-vue-ts-ssr/index.html +13 -0
- package/template-vue-ts-ssr/package.json +34 -0
- package/template-vue-ts-ssr/public/react.svg +14 -0
- package/template-vue-ts-ssr/public/vite.svg +42 -0
- package/template-vue-ts-ssr/public/vue.svg +9 -0
- package/template-vue-ts-ssr/resources/README.md +11 -0
- package/template-vue-ts-ssr/schemas/README.md +11 -0
- package/template-vue-ts-ssr/schemas/globalTypes.d.ts +5 -0
- package/template-vue-ts-ssr/schemas/types.ts +5 -0
- package/template-vue-ts-ssr/src/App.vue +43 -0
- package/template-vue-ts-ssr/src/counter.ts +7 -0
- package/template-vue-ts-ssr/src/entry-client.ts +7 -0
- package/template-vue-ts-ssr/src/entry-server.ts +13 -0
- package/template-vue-ts-ssr/src/style.css +96 -0
- package/template-vue-ts-ssr/src/vite-env.d.ts +15 -0
- package/template-vue-ts-ssr/test/counter.test.ts +15 -0
- package/template-vue-ts-ssr/tsconfig.json +33 -0
- package/template-vue-ts-ssr/vite.config.ts +22 -0
- package/template-react/deploy-template/config.yaml +0 -10
- package/template-react/deploy-template/fastify/static.js +0 -14
- package/template-react/deploy-template/package.json +0 -5
- package/template-react-ts/deploy-template/config.yaml +0 -10
- package/template-react-ts/deploy-template/fastify/static.js +0 -14
- package/template-react-ts/deploy-template/package.json +0 -5
- package/template-vue/deploy-template/config.yaml +0 -10
- package/template-vue/deploy-template/fastify/static.js +0 -14
- package/template-vue/deploy-template/package.json +0 -5
- package/template-vue-ts/deploy-template/config.yaml +0 -10
- package/template-vue-ts/deploy-template/fastify/static.js +0 -14
- package/template-vue-ts/deploy-template/package.json +0 -5
- /package/{template-react → template-react-ts-ssr}/public/typescript.svg +0 -0
- /package/{template-vue → template-vue-ts-ssr}/public/typescript.svg +0 -0
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
<svg
|
|
2
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
3
|
+
aria-hidden="true"
|
|
4
|
+
role="img"
|
|
5
|
+
class="iconify iconify--logos"
|
|
6
|
+
width="31.88"
|
|
7
|
+
height="32"
|
|
8
|
+
preserveAspectRatio="xMidYMid meet"
|
|
9
|
+
viewBox="0 0 256 257"
|
|
10
|
+
>
|
|
11
|
+
<defs>
|
|
12
|
+
<linearGradient
|
|
13
|
+
id="IconifyId1813088fe1fbc01fb466"
|
|
14
|
+
x1="-.828%"
|
|
15
|
+
x2="57.636%"
|
|
16
|
+
y1="7.652%"
|
|
17
|
+
y2="78.411%"
|
|
18
|
+
>
|
|
19
|
+
<stop offset="0%" stop-color="#41D1FF"></stop>
|
|
20
|
+
<stop offset="100%" stop-color="#BD34FE"></stop>
|
|
21
|
+
</linearGradient>
|
|
22
|
+
<linearGradient
|
|
23
|
+
id="IconifyId1813088fe1fbc01fb467"
|
|
24
|
+
x1="43.376%"
|
|
25
|
+
x2="50.316%"
|
|
26
|
+
y1="2.242%"
|
|
27
|
+
y2="89.03%"
|
|
28
|
+
>
|
|
29
|
+
<stop offset="0%" stop-color="#FFEA83"></stop>
|
|
30
|
+
<stop offset="8.333%" stop-color="#FFDD35"></stop>
|
|
31
|
+
<stop offset="100%" stop-color="#FFA800"></stop>
|
|
32
|
+
</linearGradient>
|
|
33
|
+
</defs>
|
|
34
|
+
<path
|
|
35
|
+
fill="url(#IconifyId1813088fe1fbc01fb466)"
|
|
36
|
+
d="M255.153 37.938L134.897 252.976c-2.483 4.44-8.862 4.466-11.382.048L.875 37.958c-2.746-4.814 1.371-10.646 6.827-9.67l120.385 21.517a6.537 6.537 0 0 0 2.322-.004l117.867-21.483c5.438-.991 9.574 4.796 6.877 9.62Z"
|
|
37
|
+
></path>
|
|
38
|
+
<path
|
|
39
|
+
fill="url(#IconifyId1813088fe1fbc01fb467)"
|
|
40
|
+
d="M185.432.063L96.44 17.501a3.268 3.268 0 0 0-2.634 3.014l-5.474 92.456a3.268 3.268 0 0 0 3.997 3.378l24.777-5.718c2.318-.535 4.413 1.507 3.936 3.838l-7.361 36.047c-.495 2.426 1.782 4.5 4.151 3.78l15.304-4.649c2.372-.72 4.652 1.36 4.15 3.788l-11.698 56.621c-.732 3.542 3.979 5.473 5.943 2.437l1.313-2.028l72.516-144.72c1.215-2.423-.88-5.186-3.54-4.672l-25.505 4.922c-2.396.462-4.435-1.77-3.759-4.114l16.646-57.705c.677-2.35-1.37-4.583-3.769-4.113Z"
|
|
41
|
+
></path>
|
|
42
|
+
</svg>
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
# Resources
|
|
2
|
+
|
|
3
|
+
The [schemas you define in .GraphQL files](../.agents/skills/harper-best-practices/rules/adding-tables-with-schemas.md) will [automatically stand-up REST APIs](../.agents/skills/harper-best-practices/rules/automatic-apis.md).
|
|
4
|
+
|
|
5
|
+
But you can [extend your tables with custom logic](../.agents/skills/harper-best-practices/rules/extending-tables.md) and [create your own resources](../.agents/skills/harper-best-practices/rules/custom-resources.md) in this directory.
|
|
6
|
+
|
|
7
|
+
## Want to read more?
|
|
8
|
+
|
|
9
|
+
Check out the rest of the "skills" documentation!
|
|
10
|
+
|
|
11
|
+
[Harper Best Practices Skill](../.agents/skills/harper-best-practices/SKILL.md)
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
# Schemas
|
|
2
|
+
|
|
3
|
+
Your schemas are defined in `.graphql` files within this `schemas` directory. These files contain the structure and types for your database tables, allowing Harper to automatically generate REST APIs for CRUD operations.
|
|
4
|
+
|
|
5
|
+
Take a look at the [Adding Tables with Schemas](../.agents/skills/harper-best-practices/rules/adding-tables-with-schemas.md) to learn more!
|
|
6
|
+
|
|
7
|
+
## Want to read more?
|
|
8
|
+
|
|
9
|
+
Check out the rest of the "skills" documentation!
|
|
10
|
+
|
|
11
|
+
[Harper Best Practices Skill](../.agents/skills/harper-best-practices/SKILL.md)
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import reactLogo from '/react.svg';
|
|
2
|
+
import viteLogo from '/vite.svg';
|
|
3
|
+
import { useCallback, useState } from 'react';
|
|
4
|
+
import { increment } from './counter.js';
|
|
5
|
+
|
|
6
|
+
export function App() {
|
|
7
|
+
const [counter, setCounter] = useState(0);
|
|
8
|
+
const countUp = useCallback(() => {
|
|
9
|
+
setCounter(counter => increment(counter));
|
|
10
|
+
}, []);
|
|
11
|
+
|
|
12
|
+
return (
|
|
13
|
+
<>
|
|
14
|
+
<div>
|
|
15
|
+
<a href="https://vite.dev" target="_blank" rel="noopener noreferrer">
|
|
16
|
+
<img src={viteLogo} className="logo" alt="Vite logo" />
|
|
17
|
+
</a>
|
|
18
|
+
<a href="https://react.dev/" target="_blank" rel="noopener noreferrer">
|
|
19
|
+
<img src={reactLogo} className="logo react" alt="React logo" />
|
|
20
|
+
</a>
|
|
21
|
+
<h1>Vite + React</h1>
|
|
22
|
+
<p>Wow, look at this!</p>
|
|
23
|
+
<div className="card">
|
|
24
|
+
<button id="counter" type="button" onClick={countUp}>
|
|
25
|
+
count is {counter}
|
|
26
|
+
</button>
|
|
27
|
+
</div>
|
|
28
|
+
</div>
|
|
29
|
+
</>
|
|
30
|
+
);
|
|
31
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { App } from '@/App.jsx';
|
|
2
|
+
import { StrictMode } from 'react';
|
|
3
|
+
import { hydrateRoot } from 'react-dom/client';
|
|
4
|
+
|
|
5
|
+
import './style.css';
|
|
6
|
+
|
|
7
|
+
// Hydrate the server-rendered markup. (A client-only app would use `createRoot(...).render(...)`.)
|
|
8
|
+
hydrateRoot(
|
|
9
|
+
document.getElementById('app'),
|
|
10
|
+
<StrictMode>
|
|
11
|
+
<App />
|
|
12
|
+
</StrictMode>,
|
|
13
|
+
);
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { App } from '@/App.jsx';
|
|
2
|
+
import { StrictMode } from 'react';
|
|
3
|
+
import { renderToString } from 'react-dom/server';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Server render entry. The Vite Harper plugin calls this for HTML navigations and injects the
|
|
7
|
+
* returned markup into the `<!--ssr-outlet-->` placeholder in index.html.
|
|
8
|
+
*
|
|
9
|
+
* @param {string} _url The request URL — use it to drive routing/data loading per request.
|
|
10
|
+
* @returns {string}
|
|
11
|
+
*/
|
|
12
|
+
export function render(_url) {
|
|
13
|
+
return renderToString(
|
|
14
|
+
<StrictMode>
|
|
15
|
+
<App />
|
|
16
|
+
</StrictMode>,
|
|
17
|
+
);
|
|
18
|
+
}
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
:root {
|
|
2
|
+
font-family: system-ui, Avenir, Helvetica, Arial, sans-serif;
|
|
3
|
+
line-height: 1.5;
|
|
4
|
+
font-weight: 400;
|
|
5
|
+
|
|
6
|
+
color-scheme: light dark;
|
|
7
|
+
color: rgba(255, 255, 255, 0.87);
|
|
8
|
+
background-color: #242424;
|
|
9
|
+
|
|
10
|
+
font-synthesis: none;
|
|
11
|
+
text-rendering: optimizeLegibility;
|
|
12
|
+
-webkit-font-smoothing: antialiased;
|
|
13
|
+
-moz-osx-font-smoothing: grayscale;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
a {
|
|
17
|
+
font-weight: 500;
|
|
18
|
+
color: #646cff;
|
|
19
|
+
text-decoration: inherit;
|
|
20
|
+
}
|
|
21
|
+
a:hover {
|
|
22
|
+
color: #535bf2;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
body {
|
|
26
|
+
margin: 0;
|
|
27
|
+
display: flex;
|
|
28
|
+
place-items: center;
|
|
29
|
+
min-width: 320px;
|
|
30
|
+
min-height: 100vh;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
h1 {
|
|
34
|
+
font-size: 3.2em;
|
|
35
|
+
line-height: 1.1;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
#app {
|
|
39
|
+
max-width: 1280px;
|
|
40
|
+
margin: 0 auto;
|
|
41
|
+
padding: 2rem;
|
|
42
|
+
text-align: center;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
.logo {
|
|
46
|
+
height: 6em;
|
|
47
|
+
padding: 1.5em;
|
|
48
|
+
will-change: filter;
|
|
49
|
+
transition: filter 300ms;
|
|
50
|
+
}
|
|
51
|
+
.logo:hover {
|
|
52
|
+
filter: drop-shadow(0 0 2em #646cffaa);
|
|
53
|
+
}
|
|
54
|
+
.logo.vanilla:hover {
|
|
55
|
+
filter: drop-shadow(0 0 2em #3178c6aa);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
.card {
|
|
59
|
+
padding: 2em;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
.read-the-docs {
|
|
63
|
+
color: #888;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
button {
|
|
67
|
+
border-radius: 8px;
|
|
68
|
+
border: 1px solid transparent;
|
|
69
|
+
padding: 0.6em 1.2em;
|
|
70
|
+
font-size: 1em;
|
|
71
|
+
font-weight: 500;
|
|
72
|
+
font-family: inherit;
|
|
73
|
+
background-color: #1a1a1a;
|
|
74
|
+
cursor: pointer;
|
|
75
|
+
transition: border-color 0.25s;
|
|
76
|
+
}
|
|
77
|
+
button:hover {
|
|
78
|
+
border-color: #646cff;
|
|
79
|
+
}
|
|
80
|
+
button:focus,
|
|
81
|
+
button:focus-visible {
|
|
82
|
+
outline: 4px auto -webkit-focus-ring-color;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
@media (prefers-color-scheme: light) {
|
|
86
|
+
:root {
|
|
87
|
+
color: #213547;
|
|
88
|
+
background-color: #ffffff;
|
|
89
|
+
}
|
|
90
|
+
a:hover {
|
|
91
|
+
color: #747bff;
|
|
92
|
+
}
|
|
93
|
+
button {
|
|
94
|
+
background-color: #f9f9f9;
|
|
95
|
+
}
|
|
96
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import assert from 'node:assert/strict';
|
|
2
|
+
import { test } from 'node:test';
|
|
3
|
+
import { decrement, increment } from '../src/counter.js';
|
|
4
|
+
|
|
5
|
+
test('increment function', () => {
|
|
6
|
+
assert.strictEqual(increment(0), 1);
|
|
7
|
+
assert.strictEqual(increment(1), 2);
|
|
8
|
+
assert.strictEqual(increment(-1), 0);
|
|
9
|
+
});
|
|
10
|
+
|
|
11
|
+
test('decrement function', () => {
|
|
12
|
+
assert.strictEqual(decrement(0), -1);
|
|
13
|
+
assert.strictEqual(decrement(1), 0);
|
|
14
|
+
assert.strictEqual(decrement(-1), -2);
|
|
15
|
+
});
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import react from '@vitejs/plugin-react';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import { defineConfig } from 'vite';
|
|
4
|
+
|
|
5
|
+
// https://vite.dev/config/
|
|
6
|
+
export default defineConfig({
|
|
7
|
+
plugins: [
|
|
8
|
+
react(),
|
|
9
|
+
],
|
|
10
|
+
resolve: {
|
|
11
|
+
alias: {
|
|
12
|
+
'@': path.resolve(import.meta.dirname, './src'),
|
|
13
|
+
},
|
|
14
|
+
},
|
|
15
|
+
build: {
|
|
16
|
+
outDir: 'dist',
|
|
17
|
+
emptyOutDir: true,
|
|
18
|
+
rolldownOptions: {
|
|
19
|
+
external: ['**/*.test.*', '**/*.spec.*'],
|
|
20
|
+
},
|
|
21
|
+
},
|
|
22
|
+
});
|
|
@@ -89,7 +89,7 @@ These schemas are the heart of a great Harper app, specifying which tables you w
|
|
|
89
89
|
|
|
90
90
|
### View Your Website
|
|
91
91
|
|
|
92
|
-
Pop open [http://localhost:9926](http://localhost:9926) to view [
|
|
92
|
+
Pop open [http://localhost:9926](http://localhost:9926) to view [index.html](./index.html) in your browser.
|
|
93
93
|
|
|
94
94
|
### Use Your API
|
|
95
95
|
|
|
@@ -113,7 +113,11 @@ Take a look at the [default configuration](./config.yaml), which specifies how f
|
|
|
113
113
|
|
|
114
114
|
When you are ready, head to [https://fabric.harper.fast/](https://fabric.harper.fast/), log in to your account, and create a cluster.
|
|
115
115
|
|
|
116
|
-
Come back
|
|
116
|
+
Come back and log in your local CLI to your cluster:
|
|
117
|
+
|
|
118
|
+
```sh
|
|
119
|
+
harper login
|
|
120
|
+
```
|
|
117
121
|
|
|
118
122
|
Then you can deploy your app to your cluster:
|
|
119
123
|
|
|
@@ -25,6 +25,19 @@ jsResource:
|
|
|
25
25
|
globalTypes: 'schemas/globalTypes.d.ts'
|
|
26
26
|
schemaTypes: 'schemas/types.ts'
|
|
27
27
|
|
|
28
|
-
# Bootstraps Vite to build your frontend to HTML/JS/CSS
|
|
29
|
-
|
|
30
|
-
|
|
28
|
+
# Bootstraps Vite to build your frontend to HTML/JS/CSS.
|
|
29
|
+
# In production it builds your app (and recompiles when files in `files` change); the `static`
|
|
30
|
+
# component below serves the built output. Listed before `static` so its dev server wins in `harper dev`.
|
|
31
|
+
'@harperfast/vite':
|
|
32
|
+
package: '@harperfast/vite'
|
|
33
|
+
files: 'src/**/*'
|
|
34
|
+
output: 'dist'
|
|
35
|
+
|
|
36
|
+
# Serves the built frontend from Vite's output directory. `notFound` + `fallthrough: false` makes
|
|
37
|
+
# client-side routing work (unmatched routes return index.html); the REST routes above take precedence.
|
|
38
|
+
static:
|
|
39
|
+
files: 'dist/**'
|
|
40
|
+
notFound:
|
|
41
|
+
file: 'index.html'
|
|
42
|
+
statusCode: 200
|
|
43
|
+
fallthrough: false
|
|
@@ -13,22 +13,24 @@
|
|
|
13
13
|
"test": "node --test test/*.test.ts",
|
|
14
14
|
"test:watch": "node --watch --test test/*.test.ts",
|
|
15
15
|
"build": "vite build",
|
|
16
|
-
"deploy": "
|
|
16
|
+
"deploy": "harper deploy_component . restart=true replicated=true"
|
|
17
|
+
},
|
|
18
|
+
"dependencies": {
|
|
19
|
+
"@harperfast/schema-codegen": "^1.0.10",
|
|
20
|
+
"@harperfast/vite": "^1.1.0",
|
|
21
|
+
"@vitejs/plugin-react": "^6.0.1",
|
|
22
|
+
"react": "^19.2.4",
|
|
23
|
+
"react-dom": "^19.2.4",
|
|
24
|
+
"vite": "^8.0.0"
|
|
17
25
|
},
|
|
18
26
|
"devDependencies": {
|
|
19
27
|
"@eslint/js": "^10.0.1",
|
|
20
|
-
"@harperfast/schema-codegen": "^1.0.10",
|
|
21
|
-
"@harperfast/vite-plugin": "^0.2.1",
|
|
22
28
|
"@types/node": "^24.10.1",
|
|
23
29
|
"@types/react": "^19.2.10",
|
|
24
30
|
"@types/react-dom": "^19.2.3",
|
|
25
|
-
"@vitejs/plugin-react": "^6.0.1",
|
|
26
31
|
"eslint": "^10.0.2",
|
|
27
32
|
"globals": "^17.4.0",
|
|
28
33
|
"prettier": "^3.8.1",
|
|
29
|
-
"
|
|
30
|
-
"react-dom": "^19.2.4",
|
|
31
|
-
"typescript": "~6.0.0",
|
|
32
|
-
"vite": "^8.0.0"
|
|
34
|
+
"typescript": "~6.0.0"
|
|
33
35
|
}
|
|
34
36
|
}
|
|
@@ -9,11 +9,11 @@ export default defineConfig({
|
|
|
9
9
|
],
|
|
10
10
|
resolve: {
|
|
11
11
|
alias: {
|
|
12
|
-
'@': path.resolve(
|
|
12
|
+
'@': path.resolve(import.meta.dirname, './src'),
|
|
13
13
|
},
|
|
14
14
|
},
|
|
15
15
|
build: {
|
|
16
|
-
outDir: '
|
|
16
|
+
outDir: 'dist',
|
|
17
17
|
emptyOutDir: true,
|
|
18
18
|
rolldownOptions: {
|
|
19
19
|
external: ['**/*.test.*', '**/*.spec.*'],
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
# your-project-name-here
|
|
2
|
+
|
|
3
|
+
Your new app is now ready for development!
|
|
4
|
+
|
|
5
|
+
Here's what you should do next:
|
|
6
|
+
|
|
7
|
+
## Installation
|
|
8
|
+
|
|
9
|
+
To get started, make sure you have [installed Harper](https://docs.harperdb.io/docs/deployments/install-harper):
|
|
10
|
+
|
|
11
|
+
```sh
|
|
12
|
+
npm install -g harper
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
## Development
|
|
16
|
+
|
|
17
|
+
Then you can start your app:
|
|
18
|
+
|
|
19
|
+
```sh
|
|
20
|
+
npm run dev
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
TypeScript is supported at runtime in Node.js through [type stripping](https://nodejs.org/api/typescript.html#type-stripping). Full TypeScript language support can be enabled through integrating third party build steps to transpile your TypeScript into JavaScript.
|
|
24
|
+
|
|
25
|
+
### Define Your Schema
|
|
26
|
+
|
|
27
|
+
1. Create a new yourTableName.graphql file in the [schemas](./schemas) directory.
|
|
28
|
+
2. Craft your schema by hand.
|
|
29
|
+
3. Save your changes.
|
|
30
|
+
|
|
31
|
+
These schemas are the heart of a great Harper app, specifying which tables you want and what attributes/fields they should have. Any table you `@export` stands up [endpoints automatically](./.agents/skills/harper-best-practices/rules/automatic-apis.md).
|
|
32
|
+
|
|
33
|
+
### Add Custom Endpoints
|
|
34
|
+
|
|
35
|
+
1. Create a new greeting.ts file in the [resources](./resources) directory.
|
|
36
|
+
|
|
37
|
+
2. Customize your resource:
|
|
38
|
+
|
|
39
|
+
```typescript
|
|
40
|
+
import { type RecordObject, type RequestTargetOrId, Resource } from 'harper';
|
|
41
|
+
|
|
42
|
+
interface GreetingRecord {
|
|
43
|
+
greeting: string;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export class Greeting extends Resource<GreetingRecord> {
|
|
47
|
+
static loadAsInstance = false;
|
|
48
|
+
|
|
49
|
+
async post(
|
|
50
|
+
target: RequestTargetOrId,
|
|
51
|
+
newRecord: Partial<GreetingRecord & RecordObject>,
|
|
52
|
+
): Promise<GreetingRecord> {
|
|
53
|
+
// By default, only super users can access these endpoints.
|
|
54
|
+
return { greeting: 'Greetings, post!' };
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
async get(target?: RequestTargetOrId): Promise<GreetingRecord> {
|
|
58
|
+
// But if we want anyone to be able to access it, we can turn off the permission checks!
|
|
59
|
+
target.checkPermission = false;
|
|
60
|
+
return { greeting: 'Greetings, get! ' + process.version };
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
async put(
|
|
64
|
+
target: RequestTargetOrId,
|
|
65
|
+
record: GreetingRecord & RecordObject,
|
|
66
|
+
): Promise<GreetingRecord> {
|
|
67
|
+
target.checkPermission = false;
|
|
68
|
+
if (this.getCurrentUser()?.name?.includes('Coffee')) {
|
|
69
|
+
// You can add your own authorization guards, of course.
|
|
70
|
+
return new Response('Coffee? COFFEE?!', { status: 418 });
|
|
71
|
+
}
|
|
72
|
+
return { greeting: 'Sssssssssssssss!' };
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
async patch(
|
|
76
|
+
target: RequestTargetOrId,
|
|
77
|
+
record: Partial<GreetingRecord & RecordObject>,
|
|
78
|
+
): Promise<GreetingRecord> {
|
|
79
|
+
return { greeting: 'We can make this work!' };
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
async delete(target: RequestTargetOrId): Promise<boolean> {
|
|
83
|
+
return true;
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
3. Save your changes.
|
|
89
|
+
|
|
90
|
+
### View Your Website
|
|
91
|
+
|
|
92
|
+
Pop open [http://localhost:9926](http://localhost:9926) to view [index.html](./index.html) in your browser.
|
|
93
|
+
|
|
94
|
+
### Use Your API
|
|
95
|
+
|
|
96
|
+
Test your application works by querying the `/Greeting` endpoint:
|
|
97
|
+
|
|
98
|
+
```sh
|
|
99
|
+
curl http://localhost:9926/Greeting
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
You should see the following:
|
|
103
|
+
|
|
104
|
+
```json
|
|
105
|
+
{ "greeting": "Hello, world!" }
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
### Configure Your App
|
|
109
|
+
|
|
110
|
+
Take a look at the [default configuration](./config.yaml), which specifies how files are handled in your application.
|
|
111
|
+
|
|
112
|
+
## Deployment
|
|
113
|
+
|
|
114
|
+
When you are ready, head to [https://fabric.harper.fast/](https://fabric.harper.fast/), log in to your account, and create a cluster.
|
|
115
|
+
|
|
116
|
+
Come back and log in your local CLI to your cluster:
|
|
117
|
+
|
|
118
|
+
```sh
|
|
119
|
+
harper login
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
Then you can deploy your app to your cluster:
|
|
123
|
+
|
|
124
|
+
```sh
|
|
125
|
+
npm run deploy
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
## Keep Going!
|
|
129
|
+
|
|
130
|
+
For more information about getting started with Harper and building applications, see our [getting started guide](https://docs.harperdb.io/docs).
|
|
131
|
+
|
|
132
|
+
For more information on Harper Components, see the [Components documentation](https://docs.harperdb.io/docs/reference/components).
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
.env
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
CLI_TARGET='your-fabric.harper.fast-cluster-url-here'
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
CLI_TARGET='YOUR_FABRIC.HARPER.FAST_CLUSTER_URL_HERE'
|
|
@@ -0,0 +1,33 @@
|
|
|
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 & deploy
|
|
33
|
+
run: npm run deploy
|