create-faas-app 8.0.0-beta.2 → 8.0.0-beta.20
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 +0 -15
- package/dist/index.d.ts +11 -16
- package/dist/index.mjs +108 -152
- package/index.mjs +1 -1
- package/package.json +19 -22
- package/template/antd/gitignore +3 -0
- package/template/antd/index.html +12 -0
- package/template/antd/package.json +27 -0
- package/template/antd/server.ts +26 -0
- package/template/antd/src/faas.yaml +11 -0
- package/template/antd/src/main.tsx +25 -0
- package/template/antd/src/pages/home/api/__tests__/hello.test.ts +17 -0
- package/template/antd/src/pages/home/api/hello.func.ts +12 -0
- package/template/antd/src/pages/home/index.tsx +79 -0
- package/template/antd/tsconfig.json +4 -0
- package/template/antd/vite.config.ts +6 -0
- package/template/basic/gitignore +3 -0
- package/template/basic/index.html +12 -0
- package/template/basic/package.json +27 -0
- package/template/basic/server.ts +26 -0
- package/template/basic/src/faas.yaml +11 -0
- package/template/basic/src/main.tsx +5 -0
- package/template/basic/src/pages/home/api/__tests__/hello.test.ts +17 -0
- package/template/basic/src/pages/home/api/hello.func.ts +12 -0
- package/template/basic/src/pages/home/index.tsx +51 -0
- package/template/basic/src/react-client.ts +8 -0
- package/template/basic/tsconfig.json +4 -0
- package/template/basic/vite.config.ts +6 -0
- package/dist/index.cjs +0 -164
package/README.md
CHANGED
|
@@ -1,20 +1,5 @@
|
|
|
1
1
|
# create-faas-app
|
|
2
2
|
|
|
3
|
-
[](https://github.com/faasjs/faasjs/blob/main/packages/create-faas-app/LICENSE)
|
|
4
|
-
[](https://www.npmjs.com/package/create-faas-app)
|
|
5
|
-
|
|
6
|
-
Quick way to create a FaasJS project.
|
|
7
|
-
|
|
8
|
-
## Usage
|
|
9
|
-
|
|
10
|
-
```bash
|
|
11
|
-
# use npm
|
|
12
|
-
npx create-faas-app --name faasjs
|
|
13
|
-
|
|
14
|
-
# use bun
|
|
15
|
-
bunx create-faas-app --name faasjs
|
|
16
|
-
```
|
|
17
|
-
|
|
18
3
|
## Functions
|
|
19
4
|
|
|
20
5
|
- [main](functions/main.md)
|
package/dist/index.d.ts
CHANGED
|
@@ -1,24 +1,19 @@
|
|
|
1
|
-
import { Command } from
|
|
1
|
+
import { Command } from "commander";
|
|
2
2
|
|
|
3
|
+
//#region src/index.d.ts
|
|
3
4
|
/**
|
|
4
|
-
*
|
|
5
|
-
* [](https://www.npmjs.com/package/create-faas-app)
|
|
5
|
+
* Run the `create-faas-app` CLI with a provided argv array.
|
|
6
6
|
*
|
|
7
|
-
*
|
|
7
|
+
* @param argv - CLI arguments forwarded to Commander.
|
|
8
|
+
* @returns Commander program instance after parsing.
|
|
8
9
|
*
|
|
9
|
-
*
|
|
10
|
+
* @example
|
|
11
|
+
* ```ts
|
|
12
|
+
* import { main } from 'create-faas-app'
|
|
10
13
|
*
|
|
11
|
-
*
|
|
12
|
-
* # use npm
|
|
13
|
-
* npx create-faas-app --name faasjs
|
|
14
|
-
*
|
|
15
|
-
* # use bun
|
|
16
|
-
* bunx create-faas-app --name faasjs
|
|
14
|
+
* await main(['node', 'create-faas-app', '--help'])
|
|
17
15
|
* ```
|
|
18
|
-
*
|
|
19
|
-
* @packageDocumentation
|
|
20
16
|
*/
|
|
21
|
-
|
|
22
17
|
declare function main(argv: string[]): Promise<Command>;
|
|
23
|
-
|
|
24
|
-
export { main };
|
|
18
|
+
//#endregion
|
|
19
|
+
export { main };
|
package/dist/index.mjs
CHANGED
|
@@ -1,162 +1,118 @@
|
|
|
1
|
-
import { Command } from
|
|
2
|
-
import { execSync } from
|
|
3
|
-
import { mkdirSync,
|
|
4
|
-
import { join } from
|
|
5
|
-
import {
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
const answers = Object.assign(options, {});
|
|
23
|
-
if (!options.name || Validator.name(options.name) !== true)
|
|
24
|
-
answers.name = await prompt({
|
|
25
|
-
type: "input",
|
|
26
|
-
name: "value",
|
|
27
|
-
message: "Project name",
|
|
28
|
-
initial: "faasjs",
|
|
29
|
-
validate: Validator.name
|
|
30
|
-
}).then((res) => res.value);
|
|
31
|
-
if (!answers.name) return;
|
|
32
|
-
mkdirSync(answers.name);
|
|
33
|
-
const runtime = process.versions.bun ? "bun" : "npm";
|
|
34
|
-
writeFileSync(
|
|
35
|
-
join(answers.name, "faas.yaml"),
|
|
36
|
-
`defaults:
|
|
37
|
-
plugins:
|
|
38
|
-
development:
|
|
39
|
-
testing:
|
|
40
|
-
staging:
|
|
41
|
-
production:
|
|
42
|
-
`
|
|
43
|
-
);
|
|
44
|
-
writeFileSync(
|
|
45
|
-
join(answers.name, "package.json"),
|
|
46
|
-
`{
|
|
47
|
-
"name": "${answers.name}",
|
|
48
|
-
"version": "1.0.0",
|
|
49
|
-
"private": true,
|
|
50
|
-
"scripts": {
|
|
51
|
-
"serve": "faas server",
|
|
52
|
-
"test": "vitest run"
|
|
53
|
-
},
|
|
54
|
-
"dependencies": {
|
|
55
|
-
"faasjs": "*"
|
|
56
|
-
},
|
|
57
|
-
"devDependencies": {
|
|
58
|
-
"vitest": "*"
|
|
59
|
-
}
|
|
60
|
-
}`
|
|
61
|
-
);
|
|
62
|
-
writeFileSync(
|
|
63
|
-
join(answers.name, "tsconfig.json"),
|
|
64
|
-
`{
|
|
65
|
-
"compilerOptions": {
|
|
66
|
-
"downlevelIteration": true,
|
|
67
|
-
"esModuleInterop": true,
|
|
68
|
-
"target": "ES2019",
|
|
69
|
-
"module": "ESNext",
|
|
70
|
-
"moduleResolution": "node",
|
|
71
|
-
"baseUrl": "."
|
|
72
|
-
}
|
|
1
|
+
import { Command } from "commander";
|
|
2
|
+
import { execSync } from "node:child_process";
|
|
3
|
+
import { existsSync, mkdirSync, readFileSync, readdirSync, writeFileSync } from "node:fs";
|
|
4
|
+
import { dirname, join } from "node:path";
|
|
5
|
+
import { fileURLToPath } from "node:url";
|
|
6
|
+
import enquirer from "enquirer";
|
|
7
|
+
//#region package.json
|
|
8
|
+
var version = "8.0.0-beta.19";
|
|
9
|
+
//#endregion
|
|
10
|
+
//#region src/action.ts
|
|
11
|
+
const prompt = enquirer.prompt;
|
|
12
|
+
const validateName = (input) => Validator.name(input);
|
|
13
|
+
const templateRoot = join(dirname(fileURLToPath(import.meta.url)), "..", "template");
|
|
14
|
+
const Validator = { name(input) {
|
|
15
|
+
const match = /^[a-z0-9-_]+$/i.test(input) ? true : "Must be a-z, 0-9 or -_";
|
|
16
|
+
if (match !== true) return match;
|
|
17
|
+
if (existsSync(input)) return `${input} folder exists, please try another name`;
|
|
18
|
+
return true;
|
|
19
|
+
} };
|
|
20
|
+
function getTemplateNames() {
|
|
21
|
+
return readdirSync(templateRoot, { withFileTypes: true }).filter((entry) => entry.isDirectory()).map((entry) => entry.name).sort();
|
|
73
22
|
}
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
`node_modules/
|
|
79
|
-
tmp/
|
|
80
|
-
coverage/
|
|
81
|
-
*.tmp.js
|
|
82
|
-
`
|
|
83
|
-
);
|
|
84
|
-
mkdirSync(join(answers.name, ".vscode"));
|
|
85
|
-
writeFileSync(
|
|
86
|
-
join(answers.name, ".vscode", "settings.json"),
|
|
87
|
-
`{
|
|
88
|
-
"editor.detectIndentation": true,
|
|
89
|
-
"editor.insertSpaces": true,
|
|
90
|
-
"editor.tabSize": 2,
|
|
91
|
-
"editor.codeActionsOnSave": {
|
|
92
|
-
"source.fixAll": true
|
|
93
|
-
},
|
|
94
|
-
"editor.wordWrap": "on",
|
|
95
|
-
"files.insertFinalNewline": true,
|
|
96
|
-
"files.trimFinalNewlines": true,
|
|
97
|
-
"files.trimTrailingWhitespace": true
|
|
23
|
+
function resolveTemplateName(template = "basic") {
|
|
24
|
+
const templates = getTemplateNames();
|
|
25
|
+
if (templates.includes(template)) return template;
|
|
26
|
+
throw new Error(`Unknown template "${template}". Available templates: ${templates.join(", ")}`);
|
|
98
27
|
}
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
writeFileSync(
|
|
102
|
-
join(answers.name, ".vscode", "extensions.json"),
|
|
103
|
-
`{
|
|
104
|
-
"recommendations": [
|
|
105
|
-
"faasjs.faasjs-snippets"
|
|
106
|
-
]
|
|
28
|
+
function renderTemplate(content, replacements) {
|
|
29
|
+
return Object.entries(replacements).reduce((result, [key, value]) => result.replaceAll(`{{${key}}}`, value), content);
|
|
107
30
|
}
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
return async () => \`Hello, \${http.params.name}\`
|
|
120
|
-
})
|
|
121
|
-
`
|
|
122
|
-
);
|
|
123
|
-
mkdirSync(join(answers.name, "__tests__"));
|
|
124
|
-
writeFileSync(
|
|
125
|
-
join(answers.name, "__tests__", "index.test.ts"),
|
|
126
|
-
`import { test } from '@faasjs/test'
|
|
127
|
-
import { func } from '../index.func'
|
|
128
|
-
|
|
129
|
-
describe('hello', () => {
|
|
130
|
-
it('should work', async () => {
|
|
131
|
-
const testFunc = test(func)
|
|
132
|
-
|
|
133
|
-
const { statusCode, data } = await testFunc.JSONhandler<string>({ name: 'world' })
|
|
134
|
-
|
|
135
|
-
expect(statusCode).toEqual(200)
|
|
136
|
-
expect(data).toEqual('Hello, world')
|
|
137
|
-
})
|
|
138
|
-
})
|
|
139
|
-
`
|
|
140
|
-
);
|
|
141
|
-
if (runtime === "bun") {
|
|
142
|
-
execSync(`cd ${answers.name} && bun test`, { stdio: "inherit" });
|
|
143
|
-
} else execSync(`cd ${answers.name} && npm run test`, { stdio: "inherit" });
|
|
31
|
+
function copyTemplateDirectory(sourcePath, targetPath, replacements) {
|
|
32
|
+
mkdirSync(targetPath, { recursive: true });
|
|
33
|
+
for (const entry of readdirSync(sourcePath, { withFileTypes: true })) {
|
|
34
|
+
const nextSourcePath = join(sourcePath, entry.name);
|
|
35
|
+
const nextTargetPath = join(targetPath, entry.name === "gitignore" ? ".gitignore" : entry.name);
|
|
36
|
+
if (entry.isDirectory()) {
|
|
37
|
+
copyTemplateDirectory(nextSourcePath, nextTargetPath, replacements);
|
|
38
|
+
continue;
|
|
39
|
+
}
|
|
40
|
+
writeFileSync(nextTargetPath, renderTemplate(readFileSync(nextSourcePath, "utf8"), replacements));
|
|
41
|
+
}
|
|
144
42
|
}
|
|
145
|
-
function
|
|
146
|
-
|
|
43
|
+
function scaffold(rootPath, replacements, templateName) {
|
|
44
|
+
mkdirSync(rootPath);
|
|
45
|
+
copyTemplateDirectory(join(templateRoot, templateName), rootPath, replacements);
|
|
46
|
+
}
|
|
47
|
+
async function action(options = {}) {
|
|
48
|
+
const templateName = resolveTemplateName(options.template);
|
|
49
|
+
const answers = Object.assign(options, {});
|
|
50
|
+
if (!options.name || Validator.name(options.name) !== true) answers.name = await prompt({
|
|
51
|
+
type: "input",
|
|
52
|
+
name: "value",
|
|
53
|
+
message: "Project name",
|
|
54
|
+
initial: "faasjs",
|
|
55
|
+
validate: validateName
|
|
56
|
+
}).then((res) => res.value);
|
|
57
|
+
if (!answers.name) return;
|
|
58
|
+
const runtime = process.versions.bun ? "bun" : "npm";
|
|
59
|
+
scaffold(answers.name, { name: answers.name }, templateName);
|
|
60
|
+
execSync(`cd ${answers.name} && ${runtime} install`, { stdio: "inherit" });
|
|
61
|
+
if (runtime === "bun") execSync(`cd ${answers.name} && bun test`, { stdio: "inherit" });
|
|
62
|
+
else execSync(`cd ${answers.name} && npm run test`, { stdio: "inherit" });
|
|
147
63
|
}
|
|
64
|
+
function action_default(program) {
|
|
65
|
+
program.description("Create a new faas app").on("--help", () => console.log(`Examples:
|
|
66
|
+
npx create-faas-app --name faasjs
|
|
67
|
+
npx create-faas-app --name faasjs-admin --template antd
|
|
148
68
|
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
69
|
+
Templates:
|
|
70
|
+
${getTemplateNames().join(", ")}`)).option("--name <name>", "Project name").option("--template <template>", "Template name", "basic").action(action);
|
|
71
|
+
}
|
|
72
|
+
//#endregion
|
|
73
|
+
//#region src/index.ts
|
|
74
|
+
/**
|
|
75
|
+
* [](https://github.com/faasjs/faasjs/blob/main/packages/create-faas-app/LICENSE)
|
|
76
|
+
* [](https://www.npmjs.com/package/create-faas-app)
|
|
77
|
+
*
|
|
78
|
+
* Quick way to create a FaasJS project.
|
|
79
|
+
*
|
|
80
|
+
* ## Usage
|
|
81
|
+
*
|
|
82
|
+
* ```bash
|
|
83
|
+
* # use npm
|
|
84
|
+
* npx create-faas-app --name faasjs
|
|
85
|
+
* npx create-faas-app --name faasjs-admin --template antd
|
|
86
|
+
*
|
|
87
|
+
* # use bun
|
|
88
|
+
* bunx create-faas-app --name faasjs
|
|
89
|
+
* bunx create-faas-app --name faasjs-admin --template antd
|
|
90
|
+
* ```
|
|
91
|
+
*/
|
|
92
|
+
const commander = new Command();
|
|
93
|
+
commander.storeOptionsAsProperties(false).allowUnknownOption(true).version(version).name("create-faas-app").exitOverride();
|
|
152
94
|
action_default(commander);
|
|
95
|
+
/**
|
|
96
|
+
* Run the `create-faas-app` CLI with a provided argv array.
|
|
97
|
+
*
|
|
98
|
+
* @param argv - CLI arguments forwarded to Commander.
|
|
99
|
+
* @returns Commander program instance after parsing.
|
|
100
|
+
*
|
|
101
|
+
* @example
|
|
102
|
+
* ```ts
|
|
103
|
+
* import { main } from 'create-faas-app'
|
|
104
|
+
*
|
|
105
|
+
* await main(['node', 'create-faas-app', '--help'])
|
|
106
|
+
* ```
|
|
107
|
+
*/
|
|
153
108
|
async function main(argv) {
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
109
|
+
try {
|
|
110
|
+
await commander.parseAsync(argv);
|
|
111
|
+
} catch (error) {
|
|
112
|
+
if (typeof error === "object" && error !== null && "code" in error && error.code === "commander.helpDisplayed") return commander;
|
|
113
|
+
console.error(error);
|
|
114
|
+
}
|
|
115
|
+
return commander;
|
|
160
116
|
}
|
|
161
|
-
|
|
117
|
+
//#endregion
|
|
162
118
|
export { main };
|
package/index.mjs
CHANGED
package/package.json
CHANGED
|
@@ -1,38 +1,35 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "create-faas-app",
|
|
3
|
-
"version": "
|
|
4
|
-
"license": "MIT",
|
|
5
|
-
"type": "module",
|
|
6
|
-
"main": "dist/index.cjs",
|
|
7
|
-
"module": "dist/index.mjs",
|
|
8
|
-
"types": "dist/index.d.ts",
|
|
9
|
-
"bin": {
|
|
10
|
-
"create-faas-app": "index.mjs"
|
|
11
|
-
},
|
|
12
|
-
"exports": {
|
|
13
|
-
".": {
|
|
14
|
-
"types": "./dist/index.d.ts",
|
|
15
|
-
"import": "./dist/index.mjs",
|
|
16
|
-
"require": "./dist/index.cjs"
|
|
17
|
-
}
|
|
18
|
-
},
|
|
3
|
+
"version": "8.0.0-beta.20",
|
|
19
4
|
"homepage": "https://faasjs.com/doc/create-faas-app",
|
|
5
|
+
"bugs": {
|
|
6
|
+
"url": "https://github.com/faasjs/faasjs/issues"
|
|
7
|
+
},
|
|
8
|
+
"license": "MIT",
|
|
20
9
|
"repository": {
|
|
21
10
|
"type": "git",
|
|
22
11
|
"url": "git+https://github.com/faasjs/faasjs.git",
|
|
23
12
|
"directory": "packages/create-faas-app"
|
|
24
13
|
},
|
|
25
|
-
"bugs": {
|
|
26
|
-
"url": "https://github.com/faasjs/faasjs/issues"
|
|
27
|
-
},
|
|
28
14
|
"funding": "https://github.com/sponsors/faasjs",
|
|
29
|
-
"
|
|
30
|
-
"
|
|
15
|
+
"bin": {
|
|
16
|
+
"create-faas-app": "index.mjs"
|
|
31
17
|
},
|
|
32
18
|
"files": [
|
|
33
19
|
"dist",
|
|
34
|
-
"index.
|
|
20
|
+
"index.mjs",
|
|
21
|
+
"template"
|
|
35
22
|
],
|
|
23
|
+
"type": "module",
|
|
24
|
+
"main": "dist/index.mjs",
|
|
25
|
+
"module": "dist/index.mjs",
|
|
26
|
+
"types": "dist/index.d.ts",
|
|
27
|
+
"exports": {
|
|
28
|
+
".": {
|
|
29
|
+
"types": "./dist/index.d.ts",
|
|
30
|
+
"default": "./dist/index.mjs"
|
|
31
|
+
}
|
|
32
|
+
},
|
|
36
33
|
"dependencies": {
|
|
37
34
|
"commander": ">=14.0.0",
|
|
38
35
|
"enquirer": "*"
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
<!doctype html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8" />
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
6
|
+
<title>FaasJS Ant Design App</title>
|
|
7
|
+
</head>
|
|
8
|
+
<body>
|
|
9
|
+
<div id="root"></div>
|
|
10
|
+
<script type="module" src="/src/main.tsx"></script>
|
|
11
|
+
</body>
|
|
12
|
+
</html>
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "{{name}}",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"private": true,
|
|
5
|
+
"type": "module",
|
|
6
|
+
"scripts": {
|
|
7
|
+
"dev": "vp dev",
|
|
8
|
+
"build": "vp build",
|
|
9
|
+
"start": "node --import @faasjs/node-utils/register-hooks server.ts",
|
|
10
|
+
"test": "vp test"
|
|
11
|
+
},
|
|
12
|
+
"dependencies": {
|
|
13
|
+
"@faasjs/ant-design": "*",
|
|
14
|
+
"@faasjs/core": "*"
|
|
15
|
+
},
|
|
16
|
+
"devDependencies": {
|
|
17
|
+
"@faasjs/dev": "*"
|
|
18
|
+
},
|
|
19
|
+
"overrides": {
|
|
20
|
+
"vite": "npm:@voidzero-dev/vite-plus-core",
|
|
21
|
+
"vitest": "npm:@voidzero-dev/vite-plus-test"
|
|
22
|
+
},
|
|
23
|
+
"engines": {
|
|
24
|
+
"node": ">=24.0.0",
|
|
25
|
+
"npm": ">=11.0.0"
|
|
26
|
+
}
|
|
27
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { dirname, join } from 'node:path'
|
|
2
|
+
import { fileURLToPath } from 'node:url'
|
|
3
|
+
|
|
4
|
+
import { Server, staticHandler } from '@faasjs/core'
|
|
5
|
+
|
|
6
|
+
const __filename = fileURLToPath(import.meta.url)
|
|
7
|
+
const __dirname = dirname(__filename)
|
|
8
|
+
|
|
9
|
+
const publicHandler = staticHandler({
|
|
10
|
+
root: join(__dirname, 'public'),
|
|
11
|
+
notFound: false,
|
|
12
|
+
})
|
|
13
|
+
|
|
14
|
+
const distHandler = staticHandler({
|
|
15
|
+
root: join(__dirname, 'dist'),
|
|
16
|
+
notFound: 'index.html',
|
|
17
|
+
})
|
|
18
|
+
|
|
19
|
+
new Server(join(__dirname, 'src'), {
|
|
20
|
+
beforeHandle: async (req, res, ctx) => {
|
|
21
|
+
if (!req.url || req.method !== 'GET') return
|
|
22
|
+
|
|
23
|
+
await publicHandler(req, res, ctx)
|
|
24
|
+
await distHandler(req, res, ctx)
|
|
25
|
+
},
|
|
26
|
+
}).listen()
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { App } from '@faasjs/ant-design'
|
|
2
|
+
import { createRoot } from 'react-dom/client'
|
|
3
|
+
|
|
4
|
+
import HomePage from './pages/home'
|
|
5
|
+
|
|
6
|
+
createRoot(document.getElementById('root') as HTMLElement).render(
|
|
7
|
+
<App
|
|
8
|
+
browserRouterProps={false}
|
|
9
|
+
configProviderProps={{
|
|
10
|
+
theme: {
|
|
11
|
+
token: {
|
|
12
|
+
borderRadius: 16,
|
|
13
|
+
colorPrimary: '#1677ff',
|
|
14
|
+
},
|
|
15
|
+
},
|
|
16
|
+
}}
|
|
17
|
+
faasConfigProviderProps={{
|
|
18
|
+
faasClientOptions: {
|
|
19
|
+
baseUrl: '/',
|
|
20
|
+
},
|
|
21
|
+
}}
|
|
22
|
+
>
|
|
23
|
+
<HomePage />
|
|
24
|
+
</App>,
|
|
25
|
+
)
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { test } from '@faasjs/dev'
|
|
2
|
+
import { describe, it, expect } from 'vitest'
|
|
3
|
+
|
|
4
|
+
import { func } from '../hello.func'
|
|
5
|
+
|
|
6
|
+
describe('pages/home/api/hello', () => {
|
|
7
|
+
it('should work', async () => {
|
|
8
|
+
const wrapped = test(func)
|
|
9
|
+
|
|
10
|
+
const { statusCode, data } = await wrapped.JSONhandler({ name: 'world' })
|
|
11
|
+
|
|
12
|
+
expect(statusCode).toEqual(200)
|
|
13
|
+
expect(data).toEqual({
|
|
14
|
+
message: 'Hello, world!',
|
|
15
|
+
})
|
|
16
|
+
})
|
|
17
|
+
})
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import { faas, useApp } from '@faasjs/ant-design'
|
|
2
|
+
import { Button, Card, Input, Space, Typography } from 'antd'
|
|
3
|
+
import { useState } from 'react'
|
|
4
|
+
|
|
5
|
+
type HelloResponse = {
|
|
6
|
+
message?: string
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export default function HomePage() {
|
|
10
|
+
const app = useApp()
|
|
11
|
+
const [name, setName] = useState('FaasJS')
|
|
12
|
+
const [messageText, setMessageText] = useState('Click button to call API')
|
|
13
|
+
const [loading, setLoading] = useState(false)
|
|
14
|
+
|
|
15
|
+
const callApi = async () => {
|
|
16
|
+
setLoading(true)
|
|
17
|
+
|
|
18
|
+
try {
|
|
19
|
+
const response = await faas('/pages/home/api/hello', {
|
|
20
|
+
name: name.trim() || undefined,
|
|
21
|
+
})
|
|
22
|
+
const nextMessage = (response.data as HelloResponse | undefined)?.message || 'Empty response'
|
|
23
|
+
|
|
24
|
+
setMessageText(nextMessage)
|
|
25
|
+
app.message.success('API call succeeded')
|
|
26
|
+
} catch (error: unknown) {
|
|
27
|
+
const errorMessage = error instanceof Error ? error.message : 'Request failed'
|
|
28
|
+
|
|
29
|
+
setMessageText(errorMessage)
|
|
30
|
+
app.notification.error({
|
|
31
|
+
message: 'API call failed',
|
|
32
|
+
description: errorMessage,
|
|
33
|
+
})
|
|
34
|
+
} finally {
|
|
35
|
+
setLoading(false)
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
return (
|
|
40
|
+
<div
|
|
41
|
+
style={{
|
|
42
|
+
minHeight: '100vh',
|
|
43
|
+
display: 'grid',
|
|
44
|
+
placeItems: 'center',
|
|
45
|
+
padding: 24,
|
|
46
|
+
background: 'linear-gradient(135deg, #f5f7fa 0%, #e4ecfb 100%)',
|
|
47
|
+
}}
|
|
48
|
+
>
|
|
49
|
+
<Card
|
|
50
|
+
style={{
|
|
51
|
+
width: '100%',
|
|
52
|
+
maxWidth: 560,
|
|
53
|
+
boxShadow: '0 20px 45px rgba(15, 23, 42, 0.08)',
|
|
54
|
+
}}
|
|
55
|
+
>
|
|
56
|
+
<Space direction="vertical" size="large" style={{ width: '100%' }}>
|
|
57
|
+
<div>
|
|
58
|
+
<Typography.Title level={2}>FaasJS Ant Design App</Typography.Title>
|
|
59
|
+
<Typography.Paragraph type="secondary">
|
|
60
|
+
Call a FaasJS API through the Ant Design app shell.
|
|
61
|
+
</Typography.Paragraph>
|
|
62
|
+
</div>
|
|
63
|
+
|
|
64
|
+
<Input
|
|
65
|
+
value={name}
|
|
66
|
+
onChange={(event) => setName(event.target.value)}
|
|
67
|
+
placeholder="What should the API greet?"
|
|
68
|
+
/>
|
|
69
|
+
|
|
70
|
+
<Button type="primary" loading={loading} onClick={callApi}>
|
|
71
|
+
Call /pages/home/api/hello
|
|
72
|
+
</Button>
|
|
73
|
+
|
|
74
|
+
<Typography.Paragraph style={{ marginBottom: 0 }}>{messageText}</Typography.Paragraph>
|
|
75
|
+
</Space>
|
|
76
|
+
</Card>
|
|
77
|
+
</div>
|
|
78
|
+
)
|
|
79
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
<!doctype html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8" />
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
6
|
+
<title>FaasJS App</title>
|
|
7
|
+
</head>
|
|
8
|
+
<body>
|
|
9
|
+
<div id="root"></div>
|
|
10
|
+
<script type="module" src="/src/main.tsx"></script>
|
|
11
|
+
</body>
|
|
12
|
+
</html>
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "{{name}}",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"private": true,
|
|
5
|
+
"type": "module",
|
|
6
|
+
"scripts": {
|
|
7
|
+
"dev": "vp dev",
|
|
8
|
+
"build": "vp build",
|
|
9
|
+
"start": "node --import @faasjs/node-utils/register-hooks server.ts",
|
|
10
|
+
"test": "vp test"
|
|
11
|
+
},
|
|
12
|
+
"dependencies": {
|
|
13
|
+
"@faasjs/core": "*",
|
|
14
|
+
"@faasjs/react": "*"
|
|
15
|
+
},
|
|
16
|
+
"devDependencies": {
|
|
17
|
+
"@faasjs/dev": "*"
|
|
18
|
+
},
|
|
19
|
+
"overrides": {
|
|
20
|
+
"vite": "npm:@voidzero-dev/vite-plus-core",
|
|
21
|
+
"vitest": "npm:@voidzero-dev/vite-plus-test"
|
|
22
|
+
},
|
|
23
|
+
"engines": {
|
|
24
|
+
"node": ">=24.0.0",
|
|
25
|
+
"npm": ">=11.0.0"
|
|
26
|
+
}
|
|
27
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { dirname, join } from 'node:path'
|
|
2
|
+
import { fileURLToPath } from 'node:url'
|
|
3
|
+
|
|
4
|
+
import { Server, staticHandler } from '@faasjs/core'
|
|
5
|
+
|
|
6
|
+
const __filename = fileURLToPath(import.meta.url)
|
|
7
|
+
const __dirname = dirname(__filename)
|
|
8
|
+
|
|
9
|
+
const publicHandler = staticHandler({
|
|
10
|
+
root: join(__dirname, 'public'),
|
|
11
|
+
notFound: false,
|
|
12
|
+
})
|
|
13
|
+
|
|
14
|
+
const distHandler = staticHandler({
|
|
15
|
+
root: join(__dirname, 'dist'),
|
|
16
|
+
notFound: 'index.html',
|
|
17
|
+
})
|
|
18
|
+
|
|
19
|
+
new Server(join(__dirname, 'src'), {
|
|
20
|
+
beforeHandle: async (req, res, ctx) => {
|
|
21
|
+
if (!req.url || req.method !== 'GET') return
|
|
22
|
+
|
|
23
|
+
await publicHandler(req, res, ctx)
|
|
24
|
+
await distHandler(req, res, ctx)
|
|
25
|
+
},
|
|
26
|
+
}).listen()
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { test } from '@faasjs/dev'
|
|
2
|
+
import { describe, it, expect } from 'vitest'
|
|
3
|
+
|
|
4
|
+
import { func } from '../hello.func'
|
|
5
|
+
|
|
6
|
+
describe('pages/home/api/hello', () => {
|
|
7
|
+
it('should work', async () => {
|
|
8
|
+
const wrapped = test(func)
|
|
9
|
+
|
|
10
|
+
const { statusCode, data } = await wrapped.JSONhandler({ name: 'world' })
|
|
11
|
+
|
|
12
|
+
expect(statusCode).toEqual(200)
|
|
13
|
+
expect(data).toEqual({
|
|
14
|
+
message: 'Hello, world!',
|
|
15
|
+
})
|
|
16
|
+
})
|
|
17
|
+
})
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { useState } from 'react'
|
|
2
|
+
|
|
3
|
+
import { faas } from '../../react-client'
|
|
4
|
+
|
|
5
|
+
type HelloResponse = {
|
|
6
|
+
message?: string
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export default function HomePage() {
|
|
10
|
+
const [name, setName] = useState('FaasJS')
|
|
11
|
+
const [message, setMessage] = useState('Click button to call API')
|
|
12
|
+
const [loading, setLoading] = useState(false)
|
|
13
|
+
|
|
14
|
+
const callApi = async () => {
|
|
15
|
+
setLoading(true)
|
|
16
|
+
|
|
17
|
+
try {
|
|
18
|
+
const response = await faas('/pages/home/api/hello', {
|
|
19
|
+
name: name.trim() || undefined,
|
|
20
|
+
})
|
|
21
|
+
|
|
22
|
+
const data = response.data as HelloResponse | undefined
|
|
23
|
+
|
|
24
|
+
setMessage(data?.message || 'Empty response')
|
|
25
|
+
} catch (error: unknown) {
|
|
26
|
+
setMessage(error instanceof Error ? error.message : 'Request failed')
|
|
27
|
+
} finally {
|
|
28
|
+
setLoading(false)
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
return (
|
|
33
|
+
<main style={{ margin: '5rem auto', maxWidth: 420, padding: 24 }}>
|
|
34
|
+
<h1>FaasJS App</h1>
|
|
35
|
+
<p>{message}</p>
|
|
36
|
+
|
|
37
|
+
<label style={{ display: 'block', marginBottom: 12 }}>
|
|
38
|
+
Name:
|
|
39
|
+
<input
|
|
40
|
+
style={{ marginLeft: 8 }}
|
|
41
|
+
value={name}
|
|
42
|
+
onChange={(event) => setName(event.target.value)}
|
|
43
|
+
/>
|
|
44
|
+
</label>
|
|
45
|
+
|
|
46
|
+
<button type="button" onClick={callApi} disabled={loading}>
|
|
47
|
+
{loading ? 'Loading...' : 'Call /pages/home/api/hello'}
|
|
48
|
+
</button>
|
|
49
|
+
</main>
|
|
50
|
+
)
|
|
51
|
+
}
|
package/dist/index.cjs
DELETED
|
@@ -1,164 +0,0 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
|
-
var commander$1 = require('commander');
|
|
4
|
-
var child_process = require('child_process');
|
|
5
|
-
var fs = require('fs');
|
|
6
|
-
var path = require('path');
|
|
7
|
-
var enquirer = require('enquirer');
|
|
8
|
-
|
|
9
|
-
// src/index.ts
|
|
10
|
-
|
|
11
|
-
// package.json
|
|
12
|
-
var package_default = {
|
|
13
|
-
version: "v8.0.0-beta.1"};
|
|
14
|
-
var Validator = {
|
|
15
|
-
name(input) {
|
|
16
|
-
const match = /^[a-z0-9-_]+$/i.test(input) ? true : "Must be a-z, 0-9 or -_";
|
|
17
|
-
if (match !== true) return match;
|
|
18
|
-
if (fs.existsSync(input))
|
|
19
|
-
return `${input} folder exists, please try another name`;
|
|
20
|
-
return true;
|
|
21
|
-
}
|
|
22
|
-
};
|
|
23
|
-
async function action(options = {}) {
|
|
24
|
-
const answers = Object.assign(options, {});
|
|
25
|
-
if (!options.name || Validator.name(options.name) !== true)
|
|
26
|
-
answers.name = await enquirer.prompt({
|
|
27
|
-
type: "input",
|
|
28
|
-
name: "value",
|
|
29
|
-
message: "Project name",
|
|
30
|
-
initial: "faasjs",
|
|
31
|
-
validate: Validator.name
|
|
32
|
-
}).then((res) => res.value);
|
|
33
|
-
if (!answers.name) return;
|
|
34
|
-
fs.mkdirSync(answers.name);
|
|
35
|
-
const runtime = process.versions.bun ? "bun" : "npm";
|
|
36
|
-
fs.writeFileSync(
|
|
37
|
-
path.join(answers.name, "faas.yaml"),
|
|
38
|
-
`defaults:
|
|
39
|
-
plugins:
|
|
40
|
-
development:
|
|
41
|
-
testing:
|
|
42
|
-
staging:
|
|
43
|
-
production:
|
|
44
|
-
`
|
|
45
|
-
);
|
|
46
|
-
fs.writeFileSync(
|
|
47
|
-
path.join(answers.name, "package.json"),
|
|
48
|
-
`{
|
|
49
|
-
"name": "${answers.name}",
|
|
50
|
-
"version": "1.0.0",
|
|
51
|
-
"private": true,
|
|
52
|
-
"scripts": {
|
|
53
|
-
"serve": "faas server",
|
|
54
|
-
"test": "vitest run"
|
|
55
|
-
},
|
|
56
|
-
"dependencies": {
|
|
57
|
-
"faasjs": "*"
|
|
58
|
-
},
|
|
59
|
-
"devDependencies": {
|
|
60
|
-
"vitest": "*"
|
|
61
|
-
}
|
|
62
|
-
}`
|
|
63
|
-
);
|
|
64
|
-
fs.writeFileSync(
|
|
65
|
-
path.join(answers.name, "tsconfig.json"),
|
|
66
|
-
`{
|
|
67
|
-
"compilerOptions": {
|
|
68
|
-
"downlevelIteration": true,
|
|
69
|
-
"esModuleInterop": true,
|
|
70
|
-
"target": "ES2019",
|
|
71
|
-
"module": "ESNext",
|
|
72
|
-
"moduleResolution": "node",
|
|
73
|
-
"baseUrl": "."
|
|
74
|
-
}
|
|
75
|
-
}
|
|
76
|
-
`
|
|
77
|
-
);
|
|
78
|
-
fs.writeFileSync(
|
|
79
|
-
path.join(answers.name, ".gitignore"),
|
|
80
|
-
`node_modules/
|
|
81
|
-
tmp/
|
|
82
|
-
coverage/
|
|
83
|
-
*.tmp.js
|
|
84
|
-
`
|
|
85
|
-
);
|
|
86
|
-
fs.mkdirSync(path.join(answers.name, ".vscode"));
|
|
87
|
-
fs.writeFileSync(
|
|
88
|
-
path.join(answers.name, ".vscode", "settings.json"),
|
|
89
|
-
`{
|
|
90
|
-
"editor.detectIndentation": true,
|
|
91
|
-
"editor.insertSpaces": true,
|
|
92
|
-
"editor.tabSize": 2,
|
|
93
|
-
"editor.codeActionsOnSave": {
|
|
94
|
-
"source.fixAll": true
|
|
95
|
-
},
|
|
96
|
-
"editor.wordWrap": "on",
|
|
97
|
-
"files.insertFinalNewline": true,
|
|
98
|
-
"files.trimFinalNewlines": true,
|
|
99
|
-
"files.trimTrailingWhitespace": true
|
|
100
|
-
}
|
|
101
|
-
`
|
|
102
|
-
);
|
|
103
|
-
fs.writeFileSync(
|
|
104
|
-
path.join(answers.name, ".vscode", "extensions.json"),
|
|
105
|
-
`{
|
|
106
|
-
"recommendations": [
|
|
107
|
-
"faasjs.faasjs-snippets"
|
|
108
|
-
]
|
|
109
|
-
}
|
|
110
|
-
`
|
|
111
|
-
);
|
|
112
|
-
child_process.execSync(`cd ${answers.name} && ${runtime} install`, { stdio: "inherit" });
|
|
113
|
-
fs.writeFileSync(
|
|
114
|
-
path.join(answers.name, "index.func.ts"),
|
|
115
|
-
`import { useFunc } from '@faasjs/func'
|
|
116
|
-
import { useHttp } from '@faasjs/http'
|
|
117
|
-
|
|
118
|
-
export const func = useFunc(() => {
|
|
119
|
-
const http = useHttp<{ name: string }>()
|
|
120
|
-
|
|
121
|
-
return async () => \`Hello, \${http.params.name}\`
|
|
122
|
-
})
|
|
123
|
-
`
|
|
124
|
-
);
|
|
125
|
-
fs.mkdirSync(path.join(answers.name, "__tests__"));
|
|
126
|
-
fs.writeFileSync(
|
|
127
|
-
path.join(answers.name, "__tests__", "index.test.ts"),
|
|
128
|
-
`import { test } from '@faasjs/test'
|
|
129
|
-
import { func } from '../index.func'
|
|
130
|
-
|
|
131
|
-
describe('hello', () => {
|
|
132
|
-
it('should work', async () => {
|
|
133
|
-
const testFunc = test(func)
|
|
134
|
-
|
|
135
|
-
const { statusCode, data } = await testFunc.JSONhandler<string>({ name: 'world' })
|
|
136
|
-
|
|
137
|
-
expect(statusCode).toEqual(200)
|
|
138
|
-
expect(data).toEqual('Hello, world')
|
|
139
|
-
})
|
|
140
|
-
})
|
|
141
|
-
`
|
|
142
|
-
);
|
|
143
|
-
if (runtime === "bun") {
|
|
144
|
-
child_process.execSync(`cd ${answers.name} && bun test`, { stdio: "inherit" });
|
|
145
|
-
} else child_process.execSync(`cd ${answers.name} && npm run test`, { stdio: "inherit" });
|
|
146
|
-
}
|
|
147
|
-
function action_default(program) {
|
|
148
|
-
program.description("Create a new faas app").on("--help", () => console.log("Examples:\nnpx create-faas-app")).option("--name <name>", "Project name").action(action);
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
// src/index.ts
|
|
152
|
-
var commander = new commander$1.Command();
|
|
153
|
-
commander.storeOptionsAsProperties(false).allowUnknownOption(true).version(package_default.version).name("create-faas-app").exitOverride();
|
|
154
|
-
action_default(commander);
|
|
155
|
-
async function main(argv) {
|
|
156
|
-
try {
|
|
157
|
-
await commander.parseAsync(argv);
|
|
158
|
-
} catch (error) {
|
|
159
|
-
console.error(error);
|
|
160
|
-
}
|
|
161
|
-
return commander;
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
exports.main = main;
|