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 CHANGED
@@ -1,20 +1,5 @@
1
1
  # create-faas-app
2
2
 
3
- [![License: MIT](https://img.shields.io/npm/l/create-faas-app.svg)](https://github.com/faasjs/faasjs/blob/main/packages/create-faas-app/LICENSE)
4
- [![NPM Version](https://img.shields.io/npm/v/create-faas-app.svg)](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 'commander';
1
+ import { Command } from "commander";
2
2
 
3
+ //#region src/index.d.ts
3
4
  /**
4
- * [![License: MIT](https://img.shields.io/npm/l/create-faas-app.svg)](https://github.com/faasjs/faasjs/blob/main/packages/create-faas-app/LICENSE)
5
- * [![NPM Version](https://img.shields.io/npm/v/create-faas-app.svg)](https://www.npmjs.com/package/create-faas-app)
5
+ * Run the `create-faas-app` CLI with a provided argv array.
6
6
  *
7
- * Quick way to create a FaasJS project.
7
+ * @param argv - CLI arguments forwarded to Commander.
8
+ * @returns Commander program instance after parsing.
8
9
  *
9
- * ## Usage
10
+ * @example
11
+ * ```ts
12
+ * import { main } from 'create-faas-app'
10
13
  *
11
- * ```bash
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 'commander';
2
- import { execSync } from 'child_process';
3
- import { mkdirSync, writeFileSync, existsSync } from 'fs';
4
- import { join } from 'path';
5
- import { prompt } from 'enquirer';
6
-
7
- // src/index.ts
8
-
9
- // package.json
10
- var package_default = {
11
- version: "v8.0.0-beta.1"};
12
- var Validator = {
13
- name(input) {
14
- const match = /^[a-z0-9-_]+$/i.test(input) ? true : "Must be a-z, 0-9 or -_";
15
- if (match !== true) return match;
16
- if (existsSync(input))
17
- return `${input} folder exists, please try another name`;
18
- return true;
19
- }
20
- };
21
- async function action(options = {}) {
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
- writeFileSync(
77
- join(answers.name, ".gitignore"),
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
- execSync(`cd ${answers.name} && ${runtime} install`, { stdio: "inherit" });
111
- writeFileSync(
112
- join(answers.name, "index.func.ts"),
113
- `import { useFunc } from '@faasjs/func'
114
- import { useHttp } from '@faasjs/http'
115
-
116
- export const func = useFunc(() => {
117
- const http = useHttp<{ name: string }>()
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 action_default(program) {
146
- program.description("Create a new faas app").on("--help", () => console.log("Examples:\nnpx create-faas-app")).option("--name <name>", "Project name").action(action);
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
- // src/index.ts
150
- var commander = new Command();
151
- commander.storeOptionsAsProperties(false).allowUnknownOption(true).version(package_default.version).name("create-faas-app").exitOverride();
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
+ * [![License: MIT](https://img.shields.io/npm/l/create-faas-app.svg)](https://github.com/faasjs/faasjs/blob/main/packages/create-faas-app/LICENSE)
76
+ * [![NPM Version](https://img.shields.io/npm/v/create-faas-app.svg)](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
- try {
155
- await commander.parseAsync(argv);
156
- } catch (error) {
157
- console.error(error);
158
- }
159
- return commander;
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
@@ -2,4 +2,4 @@
2
2
 
3
3
  import { main } from './dist/index.mjs'
4
4
 
5
- main(process.argv)
5
+ await main(process.argv)
package/package.json CHANGED
@@ -1,38 +1,35 @@
1
1
  {
2
2
  "name": "create-faas-app",
3
- "version": "v8.0.0-beta.2",
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
- "scripts": {
30
- "build": "tsup-node src/index.ts --config ../../tsup.config.ts"
15
+ "bin": {
16
+ "create-faas-app": "index.mjs"
31
17
  },
32
18
  "files": [
33
19
  "dist",
34
- "index.js"
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,3 @@
1
+ node_modules/
2
+ dist/
3
+ coverage/
@@ -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,11 @@
1
+ defaults:
2
+ server:
3
+ root: .
4
+ base: /
5
+ plugins:
6
+ http:
7
+ config:
8
+ cookie:
9
+ secure: false
10
+ session:
11
+ secret: secret
@@ -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,12 @@
1
+ import { defineApi, z } from '@faasjs/core'
2
+
3
+ export const func = defineApi({
4
+ schema: z.object({
5
+ name: z.string().min(1).optional(),
6
+ }),
7
+ async handler({ params }) {
8
+ return {
9
+ message: `Hello, ${params.name || 'FaasJS'}!`,
10
+ }
11
+ },
12
+ })
@@ -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,4 @@
1
+ {
2
+ "extends": "@faasjs/types/tsconfig/build.json",
3
+ "include": ["src", "vite.config.ts", "server.ts"]
4
+ }
@@ -0,0 +1,6 @@
1
+ import { viteConfig } from '@faasjs/dev'
2
+ import { defineConfig } from 'vite-plus'
3
+
4
+ export default defineConfig({
5
+ ...viteConfig,
6
+ })
@@ -0,0 +1,3 @@
1
+ node_modules/
2
+ dist/
3
+ coverage/
@@ -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,11 @@
1
+ defaults:
2
+ server:
3
+ root: .
4
+ base: /
5
+ plugins:
6
+ http:
7
+ config:
8
+ cookie:
9
+ secure: false
10
+ session:
11
+ secret: secret
@@ -0,0 +1,5 @@
1
+ import { createRoot } from 'react-dom/client'
2
+
3
+ import HomePage from './pages/home'
4
+
5
+ createRoot(document.getElementById('root') as HTMLElement).render(<HomePage />)
@@ -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,12 @@
1
+ import { defineApi, z } from '@faasjs/core'
2
+
3
+ export const func = defineApi({
4
+ schema: z.object({
5
+ name: z.string().min(1).optional(),
6
+ }),
7
+ async handler({ params }) {
8
+ return {
9
+ message: `Hello, ${params.name || 'FaasJS'}!`,
10
+ }
11
+ },
12
+ })
@@ -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
+ }
@@ -0,0 +1,8 @@
1
+ import { FaasReactClient } from '@faasjs/react'
2
+
3
+ const client = FaasReactClient({
4
+ baseUrl: '/',
5
+ })
6
+
7
+ export const faas = client.faas
8
+ export const useFaas = client.useFaas
@@ -0,0 +1,4 @@
1
+ {
2
+ "extends": "@faasjs/types/tsconfig/build.json",
3
+ "include": ["src", "vite.config.ts", "server.ts"]
4
+ }
@@ -0,0 +1,6 @@
1
+ import { viteConfig } from '@faasjs/dev'
2
+ import { defineConfig } from 'vite-plus'
3
+
4
+ export default defineConfig({
5
+ ...viteConfig,
6
+ })
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;