create-faas-app 8.0.0-beta.1 → 8.0.0-beta.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -1,164 +1,345 @@
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.0"};
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
- }
1
+ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
2
+ //#region \0rolldown/runtime.js
3
+ var __create = Object.create;
4
+ var __defProp = Object.defineProperty;
5
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
6
+ var __getOwnPropNames = Object.getOwnPropertyNames;
7
+ var __getProtoOf = Object.getPrototypeOf;
8
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
9
+ var __copyProps = (to, from, except, desc) => {
10
+ if (from && typeof from === "object" || typeof from === "function") {
11
+ for (var keys = __getOwnPropNames(from), i = 0, n = keys.length, key; i < n; i++) {
12
+ key = keys[i];
13
+ if (!__hasOwnProp.call(to, key) && key !== except) {
14
+ __defProp(to, key, {
15
+ get: ((k) => from[k]).bind(null, key),
16
+ enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
17
+ });
18
+ }
19
+ }
20
+ }
21
+ return to;
22
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:
23
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", {
24
+ value: mod,
25
+ enumerable: true
26
+ }) : target, mod));
27
+
28
+ //#endregion
29
+ let commander = require("commander");
30
+ let node_child_process = require("node:child_process");
31
+ let node_fs = require("node:fs");
32
+ let node_path = require("node:path");
33
+ let enquirer = require("enquirer");
34
+ enquirer = __toESM(enquirer);
35
+
36
+ //#region package.json
37
+ var version = "8.0.0-beta.9";
38
+
39
+ //#endregion
40
+ //#region src/action.ts
41
+ const prompt = enquirer.default.prompt;
42
+ const Validator = { name(input) {
43
+ const match = /^[a-z0-9-_]+$/i.test(input) ? true : "Must be a-z, 0-9 or -_";
44
+ if (match !== true) return match;
45
+ if ((0, node_fs.existsSync)(input)) return `${input} folder exists, please try another name`;
46
+ return true;
47
+ } };
48
+ function writeFile(path, content) {
49
+ (0, node_fs.mkdirSync)((0, node_path.dirname)(path), { recursive: true });
50
+ (0, node_fs.writeFileSync)(path, content);
51
+ }
52
+ function buildPackageJSON(name) {
53
+ return `${JSON.stringify({
54
+ name,
55
+ private: true,
56
+ type: "module",
57
+ version: "1.0.0",
58
+ scripts: {
59
+ dev: "vite",
60
+ build: "vite build",
61
+ start: "node server.ts",
62
+ check: "faas lint",
63
+ test: "vitest run",
64
+ "migrate:latest": "faas knex latest",
65
+ "migrate:rollback": "faas knex rollback",
66
+ "migrate:status": "faas knex status",
67
+ "migrate:current": "faas knex current",
68
+ "migrate:make": "faas knex make"
69
+ },
70
+ dependencies: {
71
+ "@faasjs/core": "*",
72
+ pg: "*",
73
+ react: "*",
74
+ "react-dom": "*"
75
+ },
76
+ devDependencies: {
77
+ "@electric-sql/pglite": "*",
78
+ "@faasjs/dev": "*",
79
+ "@types/node": "*",
80
+ "@types/react": "*",
81
+ "@types/react-dom": "*",
82
+ "@vitejs/plugin-react": "*",
83
+ jsdom: "*",
84
+ "knex-pglite": "*",
85
+ oxlint: "*",
86
+ typescript: "*",
87
+ vite: "*",
88
+ vitest: "*"
89
+ }
90
+ }, null, 2)}
91
+ `;
92
+ }
93
+ function scaffold(rootPath) {
94
+ writeFile((0, node_path.join)(rootPath, ".gitignore"), `node_modules/
95
+ dist/
96
+ coverage/
97
+ .pglite_dev/
98
+ `);
99
+ writeFile((0, node_path.join)(rootPath, "tsconfig.json"), `{
100
+ "compilerOptions": {
101
+ "target": "ES2022",
102
+ "module": "ESNext",
103
+ "moduleResolution": "Bundler",
104
+ "jsx": "react-jsx",
105
+ "strict": true,
106
+ "types": ["vitest/globals"]
107
+ },
108
+ "include": ["src", "vite.config.ts", "server.ts"]
109
+ }
110
+ `);
111
+ writeFile((0, node_path.join)(rootPath, "index.html"), `<!doctype html>
112
+ <html lang="en">
113
+ <head>
114
+ <meta charset="UTF-8" />
115
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
116
+ <title>FaasJS App</title>
117
+ </head>
118
+ <body>
119
+ <div id="root"></div>
120
+ <script type="module" src="/src/main.tsx"><\/script>
121
+ </body>
122
+ </html>
123
+ `);
124
+ writeFile((0, node_path.join)(rootPath, "vite.config.ts"), `import { viteFaasJsServer } from '@faasjs/dev'
125
+ import react from '@vitejs/plugin-react'
126
+ import { defineConfig } from 'vite'
127
+
128
+ export default defineConfig({
129
+ server: {
130
+ host: '0.0.0.0',
131
+ },
132
+ plugins: [react(), viteFaasJsServer()],
133
+ })
134
+ `);
135
+ writeFile((0, node_path.join)(rootPath, "server.ts"), `import { dirname, join } from 'node:path'
136
+ import { fileURLToPath } from 'node:url'
137
+ import { Server, staticHandler } from '@faasjs/core'
138
+
139
+ const __filename = fileURLToPath(import.meta.url)
140
+ const __dirname = dirname(__filename)
141
+
142
+ const publicHandler = staticHandler({
143
+ root: join(__dirname, 'public'),
144
+ notFound: false,
145
+ })
146
+
147
+ const distHandler = staticHandler({
148
+ root: join(__dirname, 'dist'),
149
+ notFound: 'index.html',
150
+ })
151
+
152
+ new Server(join(__dirname, 'src'), {
153
+ beforeHandle: async (req, res, ctx) => {
154
+ if (!req.url || req.method !== 'GET') return
155
+
156
+ await publicHandler(req, res, ctx)
157
+ await distHandler(req, res, ctx)
158
+ },
159
+ }).listen()
160
+ `);
161
+ writeFile((0, node_path.join)(rootPath, "src", "faas.yaml"), `defaults:
162
+ server:
163
+ root: .
164
+ base: /
39
165
  plugins:
166
+ http:
167
+ config:
168
+ cookie:
169
+ secure: false
170
+ session:
171
+ secret: secret
172
+ knex:
173
+ config:
174
+ client: pg
175
+ pool:
176
+ min: 0
177
+ max: 10
178
+ migrations:
179
+ directory: ./src/db/migrations
180
+ extension: ts
40
181
  development:
182
+ plugins:
183
+ knex:
184
+ config:
185
+ client: pglite
186
+ connection: ./.pglite_dev
41
187
  testing:
42
- staging:
188
+ plugins:
189
+ knex:
190
+ config:
191
+ client: pglite
43
192
  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": "*"
193
+ plugins:
194
+ knex:
195
+ config:
196
+ client: pg
197
+ `);
198
+ writeFile((0, node_path.join)(rootPath, "src", "db", "migrations", ".gitkeep"), "");
199
+ writeFile((0, node_path.join)(rootPath, "src", "main.tsx"), `import { createRoot } from 'react-dom/client'
200
+ import HomePage from './pages/home'
201
+
202
+ createRoot(document.getElementById('root') as HTMLElement).render(<HomePage />)
203
+ `);
204
+ writeFile((0, node_path.join)(rootPath, "src", "pages", "home", "index.tsx"), `import { useState } from 'react'
205
+
206
+ type ApiResponse = {
207
+ ok: boolean
208
+ data: string
209
+ error: null | {
210
+ code?: string
211
+ message: string
61
212
  }
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": "."
213
+ }
214
+
215
+ export default function HomePage() {
216
+ const [message, setMessage] = useState('Click button to call API')
217
+ const [loading, setLoading] = useState(false)
218
+
219
+ const fetchMessage = async () => {
220
+ setLoading(true)
221
+
222
+ try {
223
+ const data = await fetch('/home/api/hello', {
224
+ method: 'POST',
225
+ headers: {
226
+ 'Content-Type': 'application/json',
227
+ },
228
+ body: JSON.stringify({ name: 'world' }),
229
+ }).then(res => res.json() as Promise<ApiResponse>)
230
+
231
+ if (data.ok) setMessage(data.data)
232
+ else setMessage(data.error?.message || 'Unknown error')
233
+ } catch (error: any) {
234
+ setMessage(error?.message || 'Unknown error')
235
+ } finally {
236
+ setLoading(false)
237
+ }
74
238
  }
239
+
240
+ return (
241
+ <main style={{ margin: '5rem auto', maxWidth: 420, padding: 24 }}>
242
+ <h1>FaasJS Starter</h1>
243
+ <p>{message}</p>
244
+ <button type="button" onClick={fetchMessage} disabled={loading}>
245
+ {loading ? 'Loading...' : 'Call /home/api/hello'}
246
+ </button>
247
+ </main>
248
+ )
75
249
  }
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
250
+ `);
251
+ writeFile((0, node_path.join)(rootPath, "src", "pages", "home", "api", "hello.func.ts"), `import { defineApi, z } from '@faasjs/core'
252
+
253
+ const schema = z
254
+ .object({
255
+ name: z.string().optional(),
256
+ })
257
+ .required()
258
+
259
+ export const func = defineApi({
260
+ schema,
261
+ async handler({ params }) {
262
+ return {
263
+ ok: true,
264
+ data: \`Hello, \${params.name || 'FaasJS'}\`,
265
+ error: null,
266
+ }
95
267
  },
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
268
  })
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', () => {
269
+ `);
270
+ writeFile((0, node_path.join)(rootPath, "src", "pages", "home", "api", "__tests__", "hello.test.ts"), `import { test } from '@faasjs/dev'
271
+ import { func } from '../hello.func'
272
+
273
+ describe('home/api/hello', () => {
132
274
  it('should work', async () => {
133
275
  const testFunc = test(func)
134
276
 
135
- const { statusCode, data } = await testFunc.JSONhandler<string>({ name: 'world' })
277
+ const { statusCode, data } = await testFunc.JSONhandler({ name: 'world' })
136
278
 
137
279
  expect(statusCode).toEqual(200)
138
- expect(data).toEqual('Hello, world')
280
+ expect(data).toEqual({
281
+ ok: true,
282
+ data: 'Hello, world',
283
+ error: null,
284
+ })
139
285
  })
140
286
  })
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" });
287
+ `);
288
+ }
289
+ async function action(options = {}) {
290
+ const answers = Object.assign(options, {});
291
+ if (!options.name || Validator.name(options.name) !== true) answers.name = await prompt({
292
+ type: "input",
293
+ name: "value",
294
+ message: "Project name",
295
+ initial: "faasjs",
296
+ validate: Validator.name
297
+ }).then((res) => res.value);
298
+ if (!answers.name) return;
299
+ const runtime = process.versions.bun ? "bun" : "npm";
300
+ (0, node_fs.mkdirSync)(answers.name);
301
+ (0, node_fs.writeFileSync)((0, node_path.join)(answers.name, "package.json"), buildPackageJSON(answers.name));
302
+ scaffold(answers.name);
303
+ (0, node_child_process.execSync)(`cd ${answers.name} && ${runtime} install`, { stdio: "inherit" });
304
+ if (runtime === "bun") (0, node_child_process.execSync)(`cd ${answers.name} && bun test`, { stdio: "inherit" });
305
+ else (0, node_child_process.execSync)(`cd ${answers.name} && npm run test`, { stdio: "inherit" });
146
306
  }
147
307
  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);
308
+ program.description("Create a new faas app").on("--help", () => console.log("Examples:\nnpx create-faas-app")).option("--name <name>", "Project name").action(action);
149
309
  }
150
310
 
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);
311
+ //#endregion
312
+ //#region src/index.ts
313
+ /**
314
+ * [![License: MIT](https://img.shields.io/npm/l/create-faas-app.svg)](https://github.com/faasjs/faasjs/blob/main/packages/create-faas-app/LICENSE)
315
+ * [![NPM Version](https://img.shields.io/npm/v/create-faas-app.svg)](https://www.npmjs.com/package/create-faas-app)
316
+ *
317
+ * Quick way to create a FaasJS project.
318
+ *
319
+ * ## Usage
320
+ *
321
+ * ```bash
322
+ * # use npm
323
+ * npx create-faas-app --name faasjs
324
+ *
325
+ * # use bun
326
+ * bunx create-faas-app --name faasjs
327
+ * ```
328
+ *
329
+ * @packageDocumentation
330
+ */
331
+ const commander$1 = new commander.Command();
332
+ commander$1.storeOptionsAsProperties(false).allowUnknownOption(true).version(version).name("create-faas-app").exitOverride();
333
+ action_default(commander$1);
155
334
  async function main(argv) {
156
- try {
157
- await commander.parseAsync(argv);
158
- } catch (error) {
159
- console.error(error);
160
- }
161
- return commander;
335
+ try {
336
+ await commander$1.parseAsync(argv);
337
+ } catch (error) {
338
+ if (typeof error === "object" && error !== null && "code" in error && error.code === "commander.helpDisplayed") return commander$1;
339
+ console.error(error);
340
+ }
341
+ return commander$1;
162
342
  }
163
343
 
164
- exports.main = main;
344
+ //#endregion
345
+ exports.main = main;
package/dist/index.d.ts CHANGED
@@ -1,24 +1,6 @@
1
- import { Command } from 'commander';
2
-
3
- /**
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)
6
- *
7
- * Quick way to create a FaasJS project.
8
- *
9
- * ## Usage
10
- *
11
- * ```bash
12
- * # use npm
13
- * npx create-faas-app --name faasjs
14
- *
15
- * # use bun
16
- * bunx create-faas-app --name faasjs
17
- * ```
18
- *
19
- * @packageDocumentation
20
- */
1
+ import { Command } from "commander";
21
2
 
3
+ //#region src/index.d.ts
22
4
  declare function main(argv: string[]): Promise<Command>;
23
-
24
- export { main };
5
+ //#endregion
6
+ export { main };
package/dist/index.mjs CHANGED
@@ -1,162 +1,316 @@
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.0"};
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:
1
+ import { Command } from "commander";
2
+ import { execSync } from "node:child_process";
3
+ import { existsSync, mkdirSync, writeFileSync } from "node:fs";
4
+ import { dirname, join } from "node:path";
5
+ import enquirer from "enquirer";
6
+
7
+ //#region package.json
8
+ var version = "8.0.0-beta.9";
9
+
10
+ //#endregion
11
+ //#region src/action.ts
12
+ const prompt = enquirer.prompt;
13
+ const Validator = { 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)) return `${input} folder exists, please try another name`;
17
+ return true;
18
+ } };
19
+ function writeFile(path, content) {
20
+ mkdirSync(dirname(path), { recursive: true });
21
+ writeFileSync(path, content);
22
+ }
23
+ function buildPackageJSON(name) {
24
+ return `${JSON.stringify({
25
+ name,
26
+ private: true,
27
+ type: "module",
28
+ version: "1.0.0",
29
+ scripts: {
30
+ dev: "vite",
31
+ build: "vite build",
32
+ start: "node server.ts",
33
+ check: "faas lint",
34
+ test: "vitest run",
35
+ "migrate:latest": "faas knex latest",
36
+ "migrate:rollback": "faas knex rollback",
37
+ "migrate:status": "faas knex status",
38
+ "migrate:current": "faas knex current",
39
+ "migrate:make": "faas knex make"
40
+ },
41
+ dependencies: {
42
+ "@faasjs/core": "*",
43
+ pg: "*",
44
+ react: "*",
45
+ "react-dom": "*"
46
+ },
47
+ devDependencies: {
48
+ "@electric-sql/pglite": "*",
49
+ "@faasjs/dev": "*",
50
+ "@types/node": "*",
51
+ "@types/react": "*",
52
+ "@types/react-dom": "*",
53
+ "@vitejs/plugin-react": "*",
54
+ jsdom: "*",
55
+ "knex-pglite": "*",
56
+ oxlint: "*",
57
+ typescript: "*",
58
+ vite: "*",
59
+ vitest: "*"
60
+ }
61
+ }, null, 2)}
62
+ `;
63
+ }
64
+ function scaffold(rootPath) {
65
+ writeFile(join(rootPath, ".gitignore"), `node_modules/
66
+ dist/
67
+ coverage/
68
+ .pglite_dev/
69
+ `);
70
+ writeFile(join(rootPath, "tsconfig.json"), `{
71
+ "compilerOptions": {
72
+ "target": "ES2022",
73
+ "module": "ESNext",
74
+ "moduleResolution": "Bundler",
75
+ "jsx": "react-jsx",
76
+ "strict": true,
77
+ "types": ["vitest/globals"]
78
+ },
79
+ "include": ["src", "vite.config.ts", "server.ts"]
80
+ }
81
+ `);
82
+ writeFile(join(rootPath, "index.html"), `<!doctype html>
83
+ <html lang="en">
84
+ <head>
85
+ <meta charset="UTF-8" />
86
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
87
+ <title>FaasJS App</title>
88
+ </head>
89
+ <body>
90
+ <div id="root"></div>
91
+ <script type="module" src="/src/main.tsx"><\/script>
92
+ </body>
93
+ </html>
94
+ `);
95
+ writeFile(join(rootPath, "vite.config.ts"), `import { viteFaasJsServer } from '@faasjs/dev'
96
+ import react from '@vitejs/plugin-react'
97
+ import { defineConfig } from 'vite'
98
+
99
+ export default defineConfig({
100
+ server: {
101
+ host: '0.0.0.0',
102
+ },
103
+ plugins: [react(), viteFaasJsServer()],
104
+ })
105
+ `);
106
+ writeFile(join(rootPath, "server.ts"), `import { dirname, join } from 'node:path'
107
+ import { fileURLToPath } from 'node:url'
108
+ import { Server, staticHandler } from '@faasjs/core'
109
+
110
+ const __filename = fileURLToPath(import.meta.url)
111
+ const __dirname = dirname(__filename)
112
+
113
+ const publicHandler = staticHandler({
114
+ root: join(__dirname, 'public'),
115
+ notFound: false,
116
+ })
117
+
118
+ const distHandler = staticHandler({
119
+ root: join(__dirname, 'dist'),
120
+ notFound: 'index.html',
121
+ })
122
+
123
+ new Server(join(__dirname, 'src'), {
124
+ beforeHandle: async (req, res, ctx) => {
125
+ if (!req.url || req.method !== 'GET') return
126
+
127
+ await publicHandler(req, res, ctx)
128
+ await distHandler(req, res, ctx)
129
+ },
130
+ }).listen()
131
+ `);
132
+ writeFile(join(rootPath, "src", "faas.yaml"), `defaults:
133
+ server:
134
+ root: .
135
+ base: /
37
136
  plugins:
137
+ http:
138
+ config:
139
+ cookie:
140
+ secure: false
141
+ session:
142
+ secret: secret
143
+ knex:
144
+ config:
145
+ client: pg
146
+ pool:
147
+ min: 0
148
+ max: 10
149
+ migrations:
150
+ directory: ./src/db/migrations
151
+ extension: ts
38
152
  development:
153
+ plugins:
154
+ knex:
155
+ config:
156
+ client: pglite
157
+ connection: ./.pglite_dev
39
158
  testing:
40
- staging:
159
+ plugins:
160
+ knex:
161
+ config:
162
+ client: pglite
41
163
  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": "*"
164
+ plugins:
165
+ knex:
166
+ config:
167
+ client: pg
168
+ `);
169
+ writeFile(join(rootPath, "src", "db", "migrations", ".gitkeep"), "");
170
+ writeFile(join(rootPath, "src", "main.tsx"), `import { createRoot } from 'react-dom/client'
171
+ import HomePage from './pages/home'
172
+
173
+ createRoot(document.getElementById('root') as HTMLElement).render(<HomePage />)
174
+ `);
175
+ writeFile(join(rootPath, "src", "pages", "home", "index.tsx"), `import { useState } from 'react'
176
+
177
+ type ApiResponse = {
178
+ ok: boolean
179
+ data: string
180
+ error: null | {
181
+ code?: string
182
+ message: string
59
183
  }
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": "."
184
+ }
185
+
186
+ export default function HomePage() {
187
+ const [message, setMessage] = useState('Click button to call API')
188
+ const [loading, setLoading] = useState(false)
189
+
190
+ const fetchMessage = async () => {
191
+ setLoading(true)
192
+
193
+ try {
194
+ const data = await fetch('/home/api/hello', {
195
+ method: 'POST',
196
+ headers: {
197
+ 'Content-Type': 'application/json',
198
+ },
199
+ body: JSON.stringify({ name: 'world' }),
200
+ }).then(res => res.json() as Promise<ApiResponse>)
201
+
202
+ if (data.ok) setMessage(data.data)
203
+ else setMessage(data.error?.message || 'Unknown error')
204
+ } catch (error: any) {
205
+ setMessage(error?.message || 'Unknown error')
206
+ } finally {
207
+ setLoading(false)
208
+ }
72
209
  }
210
+
211
+ return (
212
+ <main style={{ margin: '5rem auto', maxWidth: 420, padding: 24 }}>
213
+ <h1>FaasJS Starter</h1>
214
+ <p>{message}</p>
215
+ <button type="button" onClick={fetchMessage} disabled={loading}>
216
+ {loading ? 'Loading...' : 'Call /home/api/hello'}
217
+ </button>
218
+ </main>
219
+ )
73
220
  }
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
221
+ `);
222
+ writeFile(join(rootPath, "src", "pages", "home", "api", "hello.func.ts"), `import { defineApi, z } from '@faasjs/core'
223
+
224
+ const schema = z
225
+ .object({
226
+ name: z.string().optional(),
227
+ })
228
+ .required()
229
+
230
+ export const func = defineApi({
231
+ schema,
232
+ async handler({ params }) {
233
+ return {
234
+ ok: true,
235
+ data: \`Hello, \${params.name || 'FaasJS'}\`,
236
+ error: null,
237
+ }
93
238
  },
94
- "editor.wordWrap": "on",
95
- "files.insertFinalNewline": true,
96
- "files.trimFinalNewlines": true,
97
- "files.trimTrailingWhitespace": true
98
- }
99
- `
100
- );
101
- writeFileSync(
102
- join(answers.name, ".vscode", "extensions.json"),
103
- `{
104
- "recommendations": [
105
- "faasjs.faasjs-snippets"
106
- ]
107
- }
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
239
  })
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', () => {
240
+ `);
241
+ writeFile(join(rootPath, "src", "pages", "home", "api", "__tests__", "hello.test.ts"), `import { test } from '@faasjs/dev'
242
+ import { func } from '../hello.func'
243
+
244
+ describe('home/api/hello', () => {
130
245
  it('should work', async () => {
131
246
  const testFunc = test(func)
132
247
 
133
- const { statusCode, data } = await testFunc.JSONhandler<string>({ name: 'world' })
248
+ const { statusCode, data } = await testFunc.JSONhandler({ name: 'world' })
134
249
 
135
250
  expect(statusCode).toEqual(200)
136
- expect(data).toEqual('Hello, world')
251
+ expect(data).toEqual({
252
+ ok: true,
253
+ data: 'Hello, world',
254
+ error: null,
255
+ })
137
256
  })
138
257
  })
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" });
258
+ `);
259
+ }
260
+ async function action(options = {}) {
261
+ const answers = Object.assign(options, {});
262
+ if (!options.name || Validator.name(options.name) !== true) answers.name = await prompt({
263
+ type: "input",
264
+ name: "value",
265
+ message: "Project name",
266
+ initial: "faasjs",
267
+ validate: Validator.name
268
+ }).then((res) => res.value);
269
+ if (!answers.name) return;
270
+ const runtime = process.versions.bun ? "bun" : "npm";
271
+ mkdirSync(answers.name);
272
+ writeFileSync(join(answers.name, "package.json"), buildPackageJSON(answers.name));
273
+ scaffold(answers.name);
274
+ execSync(`cd ${answers.name} && ${runtime} install`, { stdio: "inherit" });
275
+ if (runtime === "bun") execSync(`cd ${answers.name} && bun test`, { stdio: "inherit" });
276
+ else execSync(`cd ${answers.name} && npm run test`, { stdio: "inherit" });
144
277
  }
145
278
  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);
279
+ program.description("Create a new faas app").on("--help", () => console.log("Examples:\nnpx create-faas-app")).option("--name <name>", "Project name").action(action);
147
280
  }
148
281
 
149
- // src/index.ts
150
- var commander = new Command();
151
- commander.storeOptionsAsProperties(false).allowUnknownOption(true).version(package_default.version).name("create-faas-app").exitOverride();
282
+ //#endregion
283
+ //#region src/index.ts
284
+ /**
285
+ * [![License: MIT](https://img.shields.io/npm/l/create-faas-app.svg)](https://github.com/faasjs/faasjs/blob/main/packages/create-faas-app/LICENSE)
286
+ * [![NPM Version](https://img.shields.io/npm/v/create-faas-app.svg)](https://www.npmjs.com/package/create-faas-app)
287
+ *
288
+ * Quick way to create a FaasJS project.
289
+ *
290
+ * ## Usage
291
+ *
292
+ * ```bash
293
+ * # use npm
294
+ * npx create-faas-app --name faasjs
295
+ *
296
+ * # use bun
297
+ * bunx create-faas-app --name faasjs
298
+ * ```
299
+ *
300
+ * @packageDocumentation
301
+ */
302
+ const commander = new Command();
303
+ commander.storeOptionsAsProperties(false).allowUnknownOption(true).version(version).name("create-faas-app").exitOverride();
152
304
  action_default(commander);
153
305
  async function main(argv) {
154
- try {
155
- await commander.parseAsync(argv);
156
- } catch (error) {
157
- console.error(error);
158
- }
159
- return commander;
306
+ try {
307
+ await commander.parseAsync(argv);
308
+ } catch (error) {
309
+ if (typeof error === "object" && error !== null && "code" in error && error.code === "commander.helpDisplayed") return commander;
310
+ console.error(error);
311
+ }
312
+ return commander;
160
313
  }
161
314
 
162
- export { main };
315
+ //#endregion
316
+ export { main };
package/package.json CHANGED
@@ -1,14 +1,28 @@
1
1
  {
2
2
  "name": "create-faas-app",
3
- "version": "v8.0.0-beta.1",
3
+ "version": "8.0.0-beta.10",
4
+ "homepage": "https://faasjs.com/doc/create-faas-app",
5
+ "bugs": {
6
+ "url": "https://github.com/faasjs/faasjs/issues"
7
+ },
4
8
  "license": "MIT",
9
+ "repository": {
10
+ "type": "git",
11
+ "url": "git+https://github.com/faasjs/faasjs.git",
12
+ "directory": "packages/create-faas-app"
13
+ },
14
+ "funding": "https://github.com/sponsors/faasjs",
15
+ "bin": {
16
+ "create-faas-app": "index.mjs"
17
+ },
18
+ "files": [
19
+ "dist",
20
+ "index.js"
21
+ ],
5
22
  "type": "module",
6
23
  "main": "dist/index.cjs",
7
24
  "module": "dist/index.mjs",
8
25
  "types": "dist/index.d.ts",
9
- "bin": {
10
- "create-faas-app": "index.mjs"
11
- },
12
26
  "exports": {
13
27
  ".": {
14
28
  "types": "./dist/index.d.ts",
@@ -16,23 +30,9 @@
16
30
  "require": "./dist/index.cjs"
17
31
  }
18
32
  },
19
- "homepage": "https://faasjs.com/doc/create-faas-app",
20
- "repository": {
21
- "type": "git",
22
- "url": "git+https://github.com/faasjs/faasjs.git",
23
- "directory": "packages/create-faas-app"
24
- },
25
- "bugs": {
26
- "url": "https://github.com/faasjs/faasjs/issues"
27
- },
28
- "funding": "https://github.com/sponsors/faasjs",
29
33
  "scripts": {
30
- "build": "tsup-node src/index.ts --config ../../tsup.config.ts"
34
+ "build": "tsdown src/index.ts --config ../../tsdown.config.ts"
31
35
  },
32
- "files": [
33
- "dist",
34
- "index.js"
35
- ],
36
36
  "dependencies": {
37
37
  "commander": ">=14.0.0",
38
38
  "enquirer": "*"