@appinit/cli 1.1.0 → 1.3.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/LICENSE +68 -0
- package/README.md +27 -95
- package/dist/index.d.ts +371 -2
- package/dist/index.js +3795 -24
- package/dist/templates/backend-express/.appinit-generate/project/.appinit/project.json +6 -0
- package/dist/templates/backend-express/.appinit-generate/project/.appinit/template.json +6 -0
- package/dist/templates/backend-express/.appinit-generate/project/.env.example +4 -0
- package/dist/templates/backend-express/.appinit-generate/project/.husky/pre-commit +1 -0
- package/dist/templates/backend-express/.appinit-generate/project/.prettierignore +3 -0
- package/dist/templates/backend-express/.appinit-generate/project/.prettierrc +28 -0
- package/dist/templates/backend-express/.appinit-generate/project/.vscode/settings.json +6 -0
- package/dist/templates/backend-express/.appinit-generate/project/Dockerfile +14 -0
- package/dist/templates/backend-express/.appinit-generate/project/README.md +26 -0
- package/dist/templates/backend-express/.appinit-generate/project/eslint.config.js +76 -0
- package/dist/templates/backend-express/.appinit-generate/project/nodemon.json +8 -0
- package/dist/templates/backend-express/.appinit-generate/project/package.json +69 -0
- package/dist/templates/backend-express/.appinit-generate/project/src/__tests__/health.test.ts +19 -0
- package/dist/templates/backend-express/.appinit-generate/project/src/__tests__/validation.test.ts +36 -0
- package/dist/templates/backend-express/.appinit-generate/project/src/app.ts +72 -0
- package/dist/templates/backend-express/.appinit-generate/project/src/config/defaults.ts +5 -0
- package/dist/templates/backend-express/.appinit-generate/project/src/config/dev.ts +3 -0
- package/dist/templates/backend-express/.appinit-generate/project/src/config/env.ts +62 -0
- package/dist/templates/backend-express/.appinit-generate/project/src/config/prod.ts +3 -0
- package/dist/templates/backend-express/.appinit-generate/project/src/config/test.ts +3 -0
- package/dist/templates/backend-express/.appinit-generate/project/src/errors/app-error.ts +20 -0
- package/dist/templates/backend-express/.appinit-generate/project/src/errors/not-found.ts +16 -0
- package/dist/templates/backend-express/.appinit-generate/project/src/middleware/error-handler.ts +73 -0
- package/dist/templates/backend-express/.appinit-generate/project/src/middleware/http-logger.ts +5 -0
- package/dist/templates/backend-express/.appinit-generate/project/src/middleware/validate.ts +17 -0
- package/dist/templates/backend-express/.appinit-generate/project/src/routes/health.ts +13 -0
- package/dist/templates/backend-express/.appinit-generate/project/src/routes/users.ts +12 -0
- package/dist/templates/backend-express/.appinit-generate/project/src/schema/create-user.schema.ts +8 -0
- package/dist/templates/backend-express/.appinit-generate/project/src/server.ts +54 -0
- package/dist/templates/backend-express/.appinit-generate/project/src/utils/logger.ts +21 -0
- package/dist/templates/backend-express/.appinit-generate/project/tsconfig.json +30 -0
- package/dist/templates/backend-express/.appinit-generate/project/vitest.config.ts +15 -0
- package/dist/templates/backend-express/.appinit-preview/project/.appinit/project.json +6 -0
- package/dist/templates/backend-express/.appinit-preview/project/.appinit/template.json +6 -0
- package/dist/templates/backend-express/.appinit-preview/project/.env.example +4 -0
- package/dist/templates/backend-express/.appinit-preview/project/.husky/pre-commit +1 -0
- package/dist/templates/backend-express/.appinit-preview/project/.prettierignore +3 -0
- package/dist/templates/backend-express/.appinit-preview/project/.prettierrc +28 -0
- package/dist/templates/backend-express/.appinit-preview/project/.vscode/settings.json +6 -0
- package/dist/templates/backend-express/.appinit-preview/project/Dockerfile +14 -0
- package/dist/templates/backend-express/.appinit-preview/project/README.md +26 -0
- package/dist/templates/backend-express/.appinit-preview/project/eslint.config.js +76 -0
- package/dist/templates/backend-express/.appinit-preview/project/nodemon.json +8 -0
- package/dist/templates/backend-express/.appinit-preview/project/package.json +69 -0
- package/dist/templates/backend-express/.appinit-preview/project/src/__tests__/health.test.ts +19 -0
- package/dist/templates/backend-express/.appinit-preview/project/src/__tests__/validation.test.ts +36 -0
- package/dist/templates/backend-express/.appinit-preview/project/src/app.ts +72 -0
- package/dist/templates/backend-express/.appinit-preview/project/src/config/defaults.ts +5 -0
- package/dist/templates/backend-express/.appinit-preview/project/src/config/dev.ts +3 -0
- package/dist/templates/backend-express/.appinit-preview/project/src/config/env.ts +62 -0
- package/dist/templates/backend-express/.appinit-preview/project/src/config/prod.ts +3 -0
- package/dist/templates/backend-express/.appinit-preview/project/src/config/test.ts +3 -0
- package/dist/templates/backend-express/.appinit-preview/project/src/errors/app-error.ts +20 -0
- package/dist/templates/backend-express/.appinit-preview/project/src/errors/not-found.ts +16 -0
- package/dist/templates/backend-express/.appinit-preview/project/src/middleware/error-handler.ts +73 -0
- package/dist/templates/backend-express/.appinit-preview/project/src/middleware/http-logger.ts +5 -0
- package/dist/templates/backend-express/.appinit-preview/project/src/middleware/validate.ts +17 -0
- package/dist/templates/backend-express/.appinit-preview/project/src/routes/health.ts +13 -0
- package/dist/templates/backend-express/.appinit-preview/project/src/routes/users.ts +12 -0
- package/dist/templates/backend-express/.appinit-preview/project/src/schema/create-user.schema.ts +8 -0
- package/dist/templates/backend-express/.appinit-preview/project/src/server.ts +54 -0
- package/dist/templates/backend-express/.appinit-preview/project/src/utils/logger.ts +21 -0
- package/dist/templates/backend-express/.appinit-preview/project/tsconfig.json +30 -0
- package/dist/templates/backend-express/.appinit-preview/project/vitest.config.ts +15 -0
- package/dist/templates/backend-express/README.md +107 -0
- package/dist/templates/backend-express/appinit.template.json +25 -0
- package/dist/templates/backend-express/docs/README.md +11 -0
- package/dist/templates/backend-express/package.json +5 -0
- package/dist/templates/backend-express/template/.env.example +4 -0
- package/dist/templates/backend-express/template/.husky/pre-commit +1 -0
- package/dist/templates/backend-express/template/.prettierignore +3 -0
- package/dist/templates/backend-express/template/.prettierrc +28 -0
- package/dist/templates/backend-express/template/.vscode/settings.json +6 -0
- package/dist/templates/backend-express/template/Dockerfile +14 -0
- package/dist/templates/backend-express/template/README.md__tmpl +26 -0
- package/dist/templates/backend-express/template/eslint.config.js +76 -0
- package/dist/templates/backend-express/template/nodemon.json +8 -0
- package/dist/templates/backend-express/template/package.json__tmpl +69 -0
- package/dist/templates/backend-express/template/src/__tests__/health.test.ts +19 -0
- package/dist/templates/backend-express/template/src/__tests__/validation.test.ts +36 -0
- package/dist/templates/backend-express/template/src/app.ts +72 -0
- package/dist/templates/backend-express/template/src/config/defaults.ts +5 -0
- package/dist/templates/backend-express/template/src/config/dev.ts +3 -0
- package/dist/templates/backend-express/template/src/config/env.ts +62 -0
- package/dist/templates/backend-express/template/src/config/prod.ts +3 -0
- package/dist/templates/backend-express/template/src/config/test.ts +3 -0
- package/dist/templates/backend-express/template/src/errors/app-error.ts +20 -0
- package/dist/templates/backend-express/template/src/errors/not-found.ts +16 -0
- package/dist/templates/backend-express/template/src/middleware/error-handler.ts +73 -0
- package/dist/templates/backend-express/template/src/middleware/http-logger.ts +5 -0
- package/dist/templates/backend-express/template/src/middleware/validate.ts +17 -0
- package/dist/templates/backend-express/template/src/routes/health.ts +13 -0
- package/dist/templates/backend-express/template/src/routes/users.ts +12 -0
- package/dist/templates/backend-express/template/src/schema/create-user.schema.ts +8 -0
- package/dist/templates/backend-express/template/src/server.ts +54 -0
- package/dist/templates/backend-express/template/src/utils/logger.ts +21 -0
- package/dist/templates/backend-express/template/tsconfig.json +30 -0
- package/dist/templates/backend-express/template/vitest.config.ts +15 -0
- package/dist/templates/backend-express/template.config.ts +36 -0
- package/dist/templates/backend-express/variables/defaults.json +7 -0
- package/dist/templates/backend-express/variables/defaults.ts +4 -0
- package/dist/templates/backend-express/variables/schema.json +22 -0
- package/dist/templates/backend-express/variables/schema.ts +11 -0
- package/dist/templates/backend-express/variables/transform.ts +6 -0
- package/dist/templates/backend-fastify/.appinit-generate/project/.appinit/project.json +6 -0
- package/dist/templates/backend-fastify/.appinit-generate/project/.appinit/template.json +6 -0
- package/dist/templates/backend-fastify/.appinit-generate/project/README.md +26 -0
- package/dist/templates/backend-fastify/.appinit-generate/project/nodemon.json +8 -0
- package/dist/templates/backend-fastify/.appinit-generate/project/package-lock.json +3245 -0
- package/dist/templates/backend-fastify/.appinit-generate/project/package.json +24 -0
- package/dist/templates/backend-fastify/.appinit-generate/project/src/app.ts +13 -0
- package/dist/templates/backend-fastify/.appinit-generate/project/src/server.ts +15 -0
- package/dist/templates/backend-fastify/.appinit-generate/project/tsconfig.json +30 -0
- package/dist/templates/backend-fastify/README.md +27 -0
- package/dist/templates/backend-fastify/appinit.template.json +25 -0
- package/dist/templates/backend-fastify/docs/README.md +12 -0
- package/dist/templates/backend-fastify/package.json +5 -0
- package/dist/templates/backend-fastify/template/README.md__tmpl +26 -0
- package/dist/templates/backend-fastify/template/nodemon.json +8 -0
- package/dist/templates/backend-fastify/template/package.json__tmpl +24 -0
- package/dist/templates/backend-fastify/template/src/app.ts +13 -0
- package/dist/templates/backend-fastify/template/src/server.ts +15 -0
- package/dist/templates/backend-fastify/template/tsconfig.json +30 -0
- package/dist/templates/backend-fastify/template.config.ts +32 -0
- package/dist/templates/backend-fastify/variables/defaults.json +4 -0
- package/dist/templates/backend-fastify/variables/defaults.ts +3 -0
- package/dist/templates/backend-fastify/variables/schema.json +7 -0
- package/dist/templates/backend-fastify/variables/schema.ts +1 -0
- package/dist/templates/backend-fastify/variables/transform.ts +3 -0
- package/dist/templates/frontend-nextjs/.appinit-generate/project/.appinit/project.json +6 -0
- package/dist/templates/frontend-nextjs/.appinit-generate/project/.appinit/template.json +6 -0
- package/dist/templates/frontend-nextjs/.appinit-generate/project/README.md +33 -0
- package/dist/templates/frontend-nextjs/.appinit-generate/project/app/favicon.ico +0 -0
- package/dist/templates/frontend-nextjs/.appinit-generate/project/app/globals.css +42 -0
- package/dist/templates/frontend-nextjs/.appinit-generate/project/app/layout.tsx +33 -0
- package/dist/templates/frontend-nextjs/.appinit-generate/project/app/page.module.css +141 -0
- package/dist/templates/frontend-nextjs/.appinit-generate/project/app/page.tsx +67 -0
- package/dist/templates/frontend-nextjs/.appinit-generate/project/next-env.d.ts +6 -0
- package/dist/templates/frontend-nextjs/.appinit-generate/project/next.config.ts +8 -0
- package/dist/templates/frontend-nextjs/.appinit-generate/project/package.json +25 -0
- package/dist/templates/frontend-nextjs/.appinit-generate/project/public/file.svg +1 -0
- package/dist/templates/frontend-nextjs/.appinit-generate/project/public/globe.svg +1 -0
- package/dist/templates/frontend-nextjs/.appinit-generate/project/public/next.svg +1 -0
- package/dist/templates/frontend-nextjs/.appinit-generate/project/public/vercel.svg +1 -0
- package/dist/templates/frontend-nextjs/.appinit-generate/project/public/window.svg +1 -0
- package/dist/templates/frontend-nextjs/.appinit-generate/project/tsconfig.json +34 -0
- package/dist/templates/frontend-nextjs/.appinit-preview/project/.appinit/project.json +6 -0
- package/dist/templates/frontend-nextjs/.appinit-preview/project/.appinit/template.json +6 -0
- package/dist/templates/frontend-nextjs/.appinit-preview/project/README.md +33 -0
- package/dist/templates/frontend-nextjs/.appinit-preview/project/app/favicon.ico +0 -0
- package/dist/templates/frontend-nextjs/.appinit-preview/project/app/globals.css +42 -0
- package/dist/templates/frontend-nextjs/.appinit-preview/project/app/layout.tsx +33 -0
- package/dist/templates/frontend-nextjs/.appinit-preview/project/app/page.module.css +141 -0
- package/dist/templates/frontend-nextjs/.appinit-preview/project/app/page.tsx +67 -0
- package/dist/templates/frontend-nextjs/.appinit-preview/project/next-env.d.ts +6 -0
- package/dist/templates/frontend-nextjs/.appinit-preview/project/next.config.ts +8 -0
- package/dist/templates/frontend-nextjs/.appinit-preview/project/package.json +25 -0
- package/dist/templates/frontend-nextjs/.appinit-preview/project/public/file.svg +1 -0
- package/dist/templates/frontend-nextjs/.appinit-preview/project/public/globe.svg +1 -0
- package/dist/templates/frontend-nextjs/.appinit-preview/project/public/next.svg +1 -0
- package/dist/templates/frontend-nextjs/.appinit-preview/project/public/vercel.svg +1 -0
- package/dist/templates/frontend-nextjs/.appinit-preview/project/public/window.svg +1 -0
- package/dist/templates/frontend-nextjs/.appinit-preview/project/tsconfig.json +34 -0
- package/dist/templates/frontend-nextjs/README.md +27 -0
- package/dist/templates/frontend-nextjs/appinit.template.json +25 -0
- package/dist/templates/frontend-nextjs/docs/README.md +12 -0
- package/dist/templates/frontend-nextjs/package.json +5 -0
- package/dist/templates/frontend-nextjs/template/README.md__tmpl +33 -0
- package/dist/templates/frontend-nextjs/template/app/favicon.ico +0 -0
- package/dist/templates/frontend-nextjs/template/app/globals.css +42 -0
- package/dist/templates/frontend-nextjs/template/app/layout.tsx +33 -0
- package/dist/templates/frontend-nextjs/template/app/page.module.css +141 -0
- package/dist/templates/frontend-nextjs/template/app/page.tsx +67 -0
- package/dist/templates/frontend-nextjs/template/next-env.d.ts +6 -0
- package/dist/templates/frontend-nextjs/template/next.config.ts +8 -0
- package/dist/templates/frontend-nextjs/template/package.json__tmpl +25 -0
- package/dist/templates/frontend-nextjs/template/public/file.svg +1 -0
- package/dist/templates/frontend-nextjs/template/public/globe.svg +1 -0
- package/dist/templates/frontend-nextjs/template/public/next.svg +1 -0
- package/dist/templates/frontend-nextjs/template/public/vercel.svg +1 -0
- package/dist/templates/frontend-nextjs/template/public/window.svg +1 -0
- package/dist/templates/frontend-nextjs/template/tsconfig.json +34 -0
- package/dist/templates/frontend-nextjs/template.config.ts +28 -0
- package/dist/templates/frontend-nextjs/variables/defaults.json +6 -0
- package/dist/templates/frontend-nextjs/variables/defaults.ts +4 -0
- package/dist/templates/frontend-nextjs/variables/schema.json +22 -0
- package/dist/templates/frontend-nextjs/variables/schema.ts +7 -0
- package/dist/templates/frontend-nextjs/variables/transform.ts +3 -0
- package/dist/templates/frontend-react/.appinit-generate/project/.appinit/project.json +6 -0
- package/dist/templates/frontend-react/.appinit-generate/project/.appinit/template.json +6 -0
- package/dist/templates/frontend-react/.appinit-generate/project/README.md +14 -0
- package/dist/templates/frontend-react/.appinit-generate/project/index.html +12 -0
- package/dist/templates/frontend-react/.appinit-generate/project/package.json +26 -0
- package/dist/templates/frontend-react/.appinit-generate/project/public/vite.svg +30 -0
- package/dist/templates/frontend-react/.appinit-generate/project/src/App.tsx +16 -0
- package/dist/templates/frontend-react/.appinit-generate/project/src/assets/react.svg +1 -0
- package/dist/templates/frontend-react/.appinit-generate/project/src/index.css +9 -0
- package/dist/templates/frontend-react/.appinit-generate/project/src/main.tsx +10 -0
- package/dist/templates/frontend-react/.appinit-generate/project/tsconfig.app.json +31 -0
- package/dist/templates/frontend-react/.appinit-generate/project/tsconfig.json +7 -0
- package/dist/templates/frontend-react/.appinit-generate/project/tsconfig.node.json +26 -0
- package/dist/templates/frontend-react/.appinit-generate/project/vite.config.ts +16 -0
- package/dist/templates/frontend-react/appinit.template.json +26 -0
- package/dist/templates/frontend-react/docs/README.md +12 -0
- package/dist/templates/frontend-react/hooks/afterRender.ts +3 -0
- package/dist/templates/frontend-react/hooks/afterWrite.ts +3 -0
- package/dist/templates/frontend-react/hooks/beforeRender.ts +3 -0
- package/dist/templates/frontend-react/hooks/beforeWrite.ts +3 -0
- package/dist/templates/frontend-react/package.json +16 -0
- package/dist/templates/frontend-react/template/.env.example__tmpl +1 -0
- package/dist/templates/frontend-react/template/README.md__tmpl +14 -0
- package/dist/templates/frontend-react/template/_gitignore +41 -0
- package/dist/templates/frontend-react/template/index.html__tmpl +12 -0
- package/dist/templates/frontend-react/template/package.json__tmpl +26 -0
- package/dist/templates/frontend-react/template/public/vite.svg +30 -0
- package/dist/templates/frontend-react/template/src/App.tsx__tmpl +16 -0
- package/dist/templates/frontend-react/template/src/assets/react.svg +1 -0
- package/dist/templates/frontend-react/template/src/index.css__tmpl +9 -0
- package/dist/templates/frontend-react/template/src/main.tsx__tmpl +10 -0
- package/dist/templates/frontend-react/template/tsconfig.app.json__tmpl +31 -0
- package/dist/templates/frontend-react/template/tsconfig.json__tmpl +7 -0
- package/dist/templates/frontend-react/template/tsconfig.node.json__tmpl +26 -0
- package/dist/templates/frontend-react/template/vite.config.ts__tmpl +16 -0
- package/dist/templates/frontend-react/template.config.ts +26 -0
- package/dist/templates/frontend-react/template.meta.json +10 -0
- package/dist/templates/frontend-react/variables/defaults.json +6 -0
- package/dist/templates/frontend-react/variables/defaults.ts +6 -0
- package/dist/templates/frontend-react/variables/schema.json +15 -0
- package/dist/templates/frontend-react/variables/schema.ts +17 -0
- package/dist/templates/frontend-react/variables/transform.ts +10 -0
- package/dist/templates/frontend-vue/README.md +27 -0
- package/dist/templates/frontend-vue/appinit.template.json +25 -0
- package/dist/templates/frontend-vue/docs/README.md +12 -0
- package/dist/templates/frontend-vue/package.json +5 -0
- package/dist/templates/frontend-vue/template/README.md__tmpl +31 -0
- package/dist/templates/frontend-vue/template/index.html +13 -0
- package/dist/templates/frontend-vue/template/package.json__tmpl +25 -0
- package/dist/templates/frontend-vue/template/public/vite.svg +1 -0
- package/dist/templates/frontend-vue/template/src/App.vue +30 -0
- package/dist/templates/frontend-vue/template/src/assets/vue.svg +1 -0
- package/dist/templates/frontend-vue/template/src/components/HelloWorld.vue +42 -0
- package/dist/templates/frontend-vue/template/src/main.ts +6 -0
- package/dist/templates/frontend-vue/template/src/style.css +79 -0
- package/dist/templates/frontend-vue/template/tsconfig.app.json +16 -0
- package/dist/templates/frontend-vue/template/tsconfig.json +7 -0
- package/dist/templates/frontend-vue/template/tsconfig.node.json +26 -0
- package/dist/templates/frontend-vue/template/vite.config.ts +7 -0
- package/dist/templates/frontend-vue/template.config.ts +32 -0
- package/dist/templates/frontend-vue/variables/defaults.json +6 -0
- package/dist/templates/frontend-vue/variables/defaults.ts +3 -0
- package/dist/templates/frontend-vue/variables/schema.json +22 -0
- package/dist/templates/frontend-vue/variables/schema.ts +1 -0
- package/dist/templates/frontend-vue/variables/transform.ts +3 -0
- package/package.json +40 -29
- package/bin/appinit.js +0 -15
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { app } from "./app";
|
|
2
|
+
import { logger } from "./utils/logger";
|
|
3
|
+
|
|
4
|
+
// Assuming the Pino logger from before
|
|
5
|
+
|
|
6
|
+
const PORT = process.env.PORT || 3001;
|
|
7
|
+
|
|
8
|
+
const server = app.listen(PORT, () => {
|
|
9
|
+
logger.info(`🚀 Server version 1.0.0 started`);
|
|
10
|
+
logger.info(`📡 Listening on http://localhost:${PORT}`);
|
|
11
|
+
logger.info(`🌍 Environment: ${process.env.NODE_ENV || "development"}`);
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* GRACEFUL SHUTDOWN LOGIC
|
|
16
|
+
* Ensures the server closes existing connections before exiting.
|
|
17
|
+
*/
|
|
18
|
+
const shutdown = (signal: string) => {
|
|
19
|
+
logger.info(`${signal} received. Starting graceful shutdown...`);
|
|
20
|
+
|
|
21
|
+
server.close(() => {
|
|
22
|
+
logger.info("⛔ HTTP server closed.");
|
|
23
|
+
|
|
24
|
+
// Close database connections here (e.g., prisma.$disconnect() or mongoose.connection.close())
|
|
25
|
+
|
|
26
|
+
process.exit(0);
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
// Force close after 10 seconds if graceful shutdown fails
|
|
30
|
+
setTimeout(() => {
|
|
31
|
+
logger.error(
|
|
32
|
+
"Could not close connections in time, forcefully shutting down",
|
|
33
|
+
);
|
|
34
|
+
process.exit(1);
|
|
35
|
+
}, 10000);
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
// Listen for termination signals
|
|
39
|
+
process.on("SIGTERM", () => shutdown("SIGTERM"));
|
|
40
|
+
process.on("SIGINT", () => shutdown("SIGINT"));
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* UNHANDLED REJECTION/EXCEPTION CATCHING
|
|
44
|
+
* Prevents the process from crashing silently.
|
|
45
|
+
*/
|
|
46
|
+
process.on("unhandledRejection", (reason, promise) => {
|
|
47
|
+
logger.fatal({ promise, reason }, "Unhandled Rejection at Promise");
|
|
48
|
+
throw reason; // Let uncaughtException handle it
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
process.on("uncaughtException", (error) => {
|
|
52
|
+
logger.fatal(error, "Uncaught Exception thrown");
|
|
53
|
+
process.exit(1);
|
|
54
|
+
});
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import pino from "pino";
|
|
2
|
+
|
|
3
|
+
import { env } from "../config/env.js";
|
|
4
|
+
|
|
5
|
+
const isProduction = process.env.NODE_ENV === "production";
|
|
6
|
+
|
|
7
|
+
export const logger = pino({
|
|
8
|
+
level: env.logLevel,
|
|
9
|
+
// Redact sensitive data from logs for security
|
|
10
|
+
redact: ["req.headers.authorization", "password", "confirmPassword"],
|
|
11
|
+
transport: isProduction
|
|
12
|
+
? undefined // In production, output raw JSON for Datadog/ELK
|
|
13
|
+
: {
|
|
14
|
+
target: "pino-pretty",
|
|
15
|
+
options: {
|
|
16
|
+
colorize: true,
|
|
17
|
+
translateTime: "SYS:standard",
|
|
18
|
+
ignore: "pid,hostname",
|
|
19
|
+
},
|
|
20
|
+
},
|
|
21
|
+
});
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
/* Language & runtime */
|
|
4
|
+
"target": "ES2022",
|
|
5
|
+
"module": "ESNext",
|
|
6
|
+
"moduleResolution": "node",
|
|
7
|
+
|
|
8
|
+
/* Project structure */
|
|
9
|
+
"rootDir": "src",
|
|
10
|
+
"outDir": "dist",
|
|
11
|
+
|
|
12
|
+
/* Interop & correctness */
|
|
13
|
+
"esModuleInterop": true,
|
|
14
|
+
"allowSyntheticDefaultImports": true,
|
|
15
|
+
|
|
16
|
+
/* Safety */
|
|
17
|
+
"strict": true,
|
|
18
|
+
"forceConsistentCasingInFileNames": true,
|
|
19
|
+
"skipLibCheck": true,
|
|
20
|
+
"noEmitOnError": true,
|
|
21
|
+
|
|
22
|
+
/* DX & production debugging */
|
|
23
|
+
"sourceMap": true,
|
|
24
|
+
|
|
25
|
+
/* Node environment */
|
|
26
|
+
"types": ["node", "vitest/globals"]
|
|
27
|
+
},
|
|
28
|
+
"include": ["src"],
|
|
29
|
+
"exclude": ["node_modules", "dist", "__tests__"]
|
|
30
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { defineConfig } from "vitest/config";
|
|
2
|
+
|
|
3
|
+
export default defineConfig({
|
|
4
|
+
test: {
|
|
5
|
+
environment: "node",
|
|
6
|
+
globals: true,
|
|
7
|
+
clearMocks: true,
|
|
8
|
+
restoreMocks: true,
|
|
9
|
+
coverage: {
|
|
10
|
+
provider: "v8",
|
|
11
|
+
reporter: ["text", "html"],
|
|
12
|
+
exclude: ["dist", "node_modules"],
|
|
13
|
+
},
|
|
14
|
+
},
|
|
15
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
npx lint-staged
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
{
|
|
2
|
+
"arrowParens": "always",
|
|
3
|
+
"bracketSameLine": false,
|
|
4
|
+
"objectWrap": "preserve",
|
|
5
|
+
"bracketSpacing": true,
|
|
6
|
+
"semi": true,
|
|
7
|
+
"experimentalOperatorPosition": "end",
|
|
8
|
+
"experimentalTernaries": false,
|
|
9
|
+
"singleQuote": false,
|
|
10
|
+
"jsxSingleQuote": false,
|
|
11
|
+
"quoteProps": "as-needed",
|
|
12
|
+
"trailingComma": "all",
|
|
13
|
+
"singleAttributePerLine": false,
|
|
14
|
+
"htmlWhitespaceSensitivity": "css",
|
|
15
|
+
"vueIndentScriptAndStyle": false,
|
|
16
|
+
"proseWrap": "preserve",
|
|
17
|
+
"endOfLine": "lf",
|
|
18
|
+
"insertPragma": false,
|
|
19
|
+
"printWidth": 80,
|
|
20
|
+
"requirePragma": false,
|
|
21
|
+
"tabWidth": 2,
|
|
22
|
+
"useTabs": false,
|
|
23
|
+
"embeddedLanguageFormatting": "auto",
|
|
24
|
+
"importOrder": ["^@core/(.*)$", "^@server/(.*)$", "^@ui/(.*)$", "^[./]"],
|
|
25
|
+
"importOrderSeparation": true,
|
|
26
|
+
"importOrderSortSpecifiers": true,
|
|
27
|
+
"plugins": ["@trivago/prettier-plugin-sort-imports"]
|
|
28
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
FROM node:20-alpine AS builder
|
|
2
|
+
WORKDIR /app
|
|
3
|
+
COPY package*.json ./
|
|
4
|
+
RUN npm ci
|
|
5
|
+
COPY . .
|
|
6
|
+
RUN npm run build
|
|
7
|
+
|
|
8
|
+
FROM node:20-alpine
|
|
9
|
+
WORKDIR /app
|
|
10
|
+
ENV NODE_ENV=production
|
|
11
|
+
COPY --from=builder /app/dist ./dist
|
|
12
|
+
COPY --from=builder /app/node_modules ./node_modules
|
|
13
|
+
EXPOSE 3001
|
|
14
|
+
CMD ["node", "dist/server.js"]
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# ⚛️ backend-express
|
|
2
|
+
|
|
3
|
+
This project was generated using **AppInit 1.0**.
|
|
4
|
+
|
|
5
|
+
## 🚀 Quick Start
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
pnpm install
|
|
9
|
+
pnpm dev
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
## 🛠️ Stack Configuration
|
|
13
|
+
|
|
14
|
+
- **Framework**: React 18+ (Vite)
|
|
15
|
+
- **Engine Used**:
|
|
16
|
+
- **Generated At**:
|
|
17
|
+
|
|
18
|
+
## 📂 Project Structure
|
|
19
|
+
|
|
20
|
+
- `src/`: Your React components and logic.
|
|
21
|
+
- `public/`: Static assets (images, icons).
|
|
22
|
+
- `tailwind.config.js`: Styling configuration.
|
|
23
|
+
|
|
24
|
+
---
|
|
25
|
+
|
|
26
|
+
_Built with speed using the AppInit Scaffolding Engine._
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import js from "@eslint/js";
|
|
2
|
+
import tsPlugin from "@typescript-eslint/eslint-plugin";
|
|
3
|
+
import tsParser from "@typescript-eslint/parser";
|
|
4
|
+
import prettier from "eslint-config-prettier";
|
|
5
|
+
|
|
6
|
+
export default [
|
|
7
|
+
// ─────────────────────────────────────────────
|
|
8
|
+
// Global ignores (ESLint v9 way)
|
|
9
|
+
// ─────────────────────────────────────────────
|
|
10
|
+
{
|
|
11
|
+
ignores: ["dist/**", "node_modules/**", "coverage/**"],
|
|
12
|
+
},
|
|
13
|
+
|
|
14
|
+
// ─────────────────────────────────────────────
|
|
15
|
+
// Base JS rules
|
|
16
|
+
// ─────────────────────────────────────────────
|
|
17
|
+
js.configs.recommended,
|
|
18
|
+
|
|
19
|
+
// ─────────────────────────────────────────────
|
|
20
|
+
// TypeScript (Node backend)
|
|
21
|
+
// ─────────────────────────────────────────────
|
|
22
|
+
{
|
|
23
|
+
files: ["src/**/*.ts"],
|
|
24
|
+
languageOptions: {
|
|
25
|
+
parser: tsParser,
|
|
26
|
+
parserOptions: {
|
|
27
|
+
project: "./tsconfig.json",
|
|
28
|
+
sourceType: "module",
|
|
29
|
+
},
|
|
30
|
+
globals: {
|
|
31
|
+
process: "readonly",
|
|
32
|
+
console: "readonly",
|
|
33
|
+
setTimeout: "readonly",
|
|
34
|
+
clearTimeout: "readonly",
|
|
35
|
+
},
|
|
36
|
+
},
|
|
37
|
+
plugins: {
|
|
38
|
+
"@typescript-eslint": tsPlugin,
|
|
39
|
+
},
|
|
40
|
+
rules: {
|
|
41
|
+
/* Disable base JS rules */
|
|
42
|
+
"no-undef": "off",
|
|
43
|
+
"no-unused-vars": "off",
|
|
44
|
+
|
|
45
|
+
/* TypeScript correctness */
|
|
46
|
+
"@typescript-eslint/no-unused-vars": [
|
|
47
|
+
"warn",
|
|
48
|
+
{ argsIgnorePattern: "^_" },
|
|
49
|
+
],
|
|
50
|
+
"@typescript-eslint/no-floating-promises": "error",
|
|
51
|
+
"@typescript-eslint/no-misused-promises": "error",
|
|
52
|
+
|
|
53
|
+
/* Production discipline */
|
|
54
|
+
"no-console": "error",
|
|
55
|
+
"no-debugger": "error",
|
|
56
|
+
|
|
57
|
+
/* Reality */
|
|
58
|
+
"@typescript-eslint/no-explicit-any": "off",
|
|
59
|
+
},
|
|
60
|
+
},
|
|
61
|
+
|
|
62
|
+
// ─────────────────────────────────────────────
|
|
63
|
+
// Allow console ONLY in env bootstrap
|
|
64
|
+
// ─────────────────────────────────────────────
|
|
65
|
+
{
|
|
66
|
+
files: ["src/config/env.ts"],
|
|
67
|
+
rules: {
|
|
68
|
+
"no-console": "off",
|
|
69
|
+
},
|
|
70
|
+
},
|
|
71
|
+
|
|
72
|
+
// ─────────────────────────────────────────────
|
|
73
|
+
// Disable formatting rules (Prettier owns formatting)
|
|
74
|
+
// ─────────────────────────────────────────────
|
|
75
|
+
prettier,
|
|
76
|
+
];
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "my-express-app",
|
|
3
|
+
"description": "%%description | default:'Backend API built with AppInit'%%",
|
|
4
|
+
"author": "",
|
|
5
|
+
"license": "",
|
|
6
|
+
"version": "0.0.0",
|
|
7
|
+
"private": true,
|
|
8
|
+
"type": "module",
|
|
9
|
+
"scripts": {
|
|
10
|
+
"dev": "nodemon",
|
|
11
|
+
"clean": "rimraf dist",
|
|
12
|
+
"build": "npm run clean && tsc",
|
|
13
|
+
"start": "node dist/server.js",
|
|
14
|
+
"format": "prettier --write .",
|
|
15
|
+
"format:check": "prettier --check .",
|
|
16
|
+
"typecheck": "tsc --noEmit",
|
|
17
|
+
"lint": "eslint .",
|
|
18
|
+
"lint:fix": "eslint . --fix",
|
|
19
|
+
"test": "vitest",
|
|
20
|
+
"test:run": "vitest run",
|
|
21
|
+
"test:watch": "vitest watch",
|
|
22
|
+
"test:coverage": "vitest run --coverage",
|
|
23
|
+
"prepare": "husky"
|
|
24
|
+
},
|
|
25
|
+
"lint-staged": {
|
|
26
|
+
"**/*": "prettier --write --ignore-unknown"
|
|
27
|
+
},
|
|
28
|
+
"main": "index.js",
|
|
29
|
+
"keywords": [],
|
|
30
|
+
"dependencies": {
|
|
31
|
+
"compression": "^1.8.1",
|
|
32
|
+
"cors": "^2.8.5",
|
|
33
|
+
"dotenv": "^17.2.3",
|
|
34
|
+
"express": "^5.2.1",
|
|
35
|
+
"helmet": "^8.1.0",
|
|
36
|
+
"http-errors": "^2.0.1",
|
|
37
|
+
"pino": "^10.1.0",
|
|
38
|
+
"pino-http": "^11.0.0",
|
|
39
|
+
"uuid": "^13.0.0",
|
|
40
|
+
"zod": "^4.2.1"
|
|
41
|
+
},
|
|
42
|
+
"devDependencies": {
|
|
43
|
+
"@trivago/prettier-plugin-sort-imports": "^6.0.0",
|
|
44
|
+
"@types/compression": "^1.8.1",
|
|
45
|
+
"@types/cors": "^2.8.19",
|
|
46
|
+
"@types/express": "^5.0.6",
|
|
47
|
+
"@types/morgan": "^1.9.10",
|
|
48
|
+
"@types/node": "^25.0.2",
|
|
49
|
+
"@types/supertest": "^6.0.3",
|
|
50
|
+
"@typescript-eslint/eslint-plugin": "^8.50.0",
|
|
51
|
+
"@typescript-eslint/parser": "^8.50.0",
|
|
52
|
+
"eslint": "^9.39.2",
|
|
53
|
+
"eslint-config-prettier": "^10.1.8",
|
|
54
|
+
"husky": "^9.1.7",
|
|
55
|
+
"lint-staged": "^16.2.7",
|
|
56
|
+
"morgan": "^1.10.1",
|
|
57
|
+
"nodemon": "^3.1.11",
|
|
58
|
+
"pino-pretty": "^13.1.3",
|
|
59
|
+
"prettier": "3.7.4",
|
|
60
|
+
"rimraf": "^6.1.2",
|
|
61
|
+
"supertest": "^7.1.4",
|
|
62
|
+
"tsx": "^4.21.0",
|
|
63
|
+
"typescript": "^5.9.3",
|
|
64
|
+
"vitest": "^4.0.16"
|
|
65
|
+
},
|
|
66
|
+
"engines": {
|
|
67
|
+
"node": ">=18"
|
|
68
|
+
}
|
|
69
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import request from "supertest";
|
|
2
|
+
|
|
3
|
+
import { app } from "../app.js";
|
|
4
|
+
|
|
5
|
+
describe("Health endpoints", () => {
|
|
6
|
+
it("GET /health should return ok", async () => {
|
|
7
|
+
const res = await request(app).get("/api/health");
|
|
8
|
+
|
|
9
|
+
expect(res.status).toBe(200);
|
|
10
|
+
expect(res.body).toEqual({ status: "ok" });
|
|
11
|
+
});
|
|
12
|
+
|
|
13
|
+
it("GET /ready should return ready", async () => {
|
|
14
|
+
const res = await request(app).get("/api/health/ready");
|
|
15
|
+
|
|
16
|
+
expect(res.status).toBe(200);
|
|
17
|
+
expect(res.body).toEqual({ ready: true });
|
|
18
|
+
});
|
|
19
|
+
});
|
package/dist/templates/backend-express/.appinit-preview/project/src/__tests__/validation.test.ts
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import request from "supertest";
|
|
2
|
+
|
|
3
|
+
import { app } from "../app.js";
|
|
4
|
+
|
|
5
|
+
describe("Zod validation errors", () => {
|
|
6
|
+
it("returns 400 with field errors", async () => {
|
|
7
|
+
const res = await request(app)
|
|
8
|
+
.post("/api/users")
|
|
9
|
+
.send({ email: "invalid", password: "123" });
|
|
10
|
+
|
|
11
|
+
expect(res.status).toBe(400);
|
|
12
|
+
expect(res.body).toEqual({
|
|
13
|
+
error: {
|
|
14
|
+
code: "VALIDATION_ERROR",
|
|
15
|
+
message: "Invalid request",
|
|
16
|
+
fields: {
|
|
17
|
+
"body.email": ["Invalid email address"],
|
|
18
|
+
"body.password": [
|
|
19
|
+
"Too small: expected string to have >=8 characters",
|
|
20
|
+
],
|
|
21
|
+
},
|
|
22
|
+
},
|
|
23
|
+
});
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
it("returns 201 with register", async () => {
|
|
27
|
+
const res = await request(app)
|
|
28
|
+
.post("/api/users")
|
|
29
|
+
.send({ email: "abc@gmail.com", password: "12345678" });
|
|
30
|
+
|
|
31
|
+
expect(res.status).toBe(201);
|
|
32
|
+
expect(res.body).toEqual({
|
|
33
|
+
ok: true,
|
|
34
|
+
});
|
|
35
|
+
});
|
|
36
|
+
});
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import compression from "compression";
|
|
2
|
+
import cors from "cors";
|
|
3
|
+
import express, { Express } from "express";
|
|
4
|
+
import type { Request, Response } from "express";
|
|
5
|
+
import helmet from "helmet";
|
|
6
|
+
import morgan from "morgan";
|
|
7
|
+
import path from "path";
|
|
8
|
+
import { fileURLToPath } from "url";
|
|
9
|
+
|
|
10
|
+
import { env } from "./config/env";
|
|
11
|
+
import { notFoundHandler } from "./errors/not-found";
|
|
12
|
+
import { errorHandler } from "./middleware/error-handler";
|
|
13
|
+
import { httpLogger } from "./middleware/http-logger";
|
|
14
|
+
import { healthRouter } from "./routes/health";
|
|
15
|
+
import { userRouter } from "./routes/users";
|
|
16
|
+
|
|
17
|
+
// Define __dirname for ESM
|
|
18
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
19
|
+
const __dirname = path.dirname(__filename);
|
|
20
|
+
|
|
21
|
+
const app: Express = express();
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* 1. SECURITY MIDDLEWARE
|
|
25
|
+
*/
|
|
26
|
+
app.use(helmet());
|
|
27
|
+
app.use(cors({ origin: env.corsOrigin }));
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* 2. PERFORMANCE MIDDLEWARE
|
|
31
|
+
*/
|
|
32
|
+
app.use(compression());
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* 3. REQUEST PARSING
|
|
36
|
+
*/
|
|
37
|
+
app.use(express.json({ limit: "10kb" }));
|
|
38
|
+
app.use(express.urlencoded({ extended: true, limit: "10kb" }));
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* 4. LOGGING & STATIC FILES
|
|
42
|
+
*/
|
|
43
|
+
app.use(httpLogger);
|
|
44
|
+
if (process.env.NODE_ENV !== "production") {
|
|
45
|
+
app.use(morgan("dev"));
|
|
46
|
+
} else {
|
|
47
|
+
app.use(morgan("combined"));
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
// Fixed static path for ESM
|
|
51
|
+
app.use(express.static(path.join(__dirname, "../public")));
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* 5. SETTINGS
|
|
55
|
+
*/
|
|
56
|
+
app.disable("x-powered-by");
|
|
57
|
+
|
|
58
|
+
// route
|
|
59
|
+
app.get("/", (_req: Request, res: Response) => {
|
|
60
|
+
res.status(200).json({
|
|
61
|
+
version: "1.0.0",
|
|
62
|
+
});
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
app.use("/api/health", healthRouter);
|
|
66
|
+
app.use("/api/users", userRouter);
|
|
67
|
+
/* 404 */
|
|
68
|
+
app.use(notFoundHandler);
|
|
69
|
+
|
|
70
|
+
/* error handler (LAST) */
|
|
71
|
+
app.use(errorHandler);
|
|
72
|
+
export { app };
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
|
|
3
|
+
import { defaults } from "./defaults";
|
|
4
|
+
import { developmentConfig } from "./dev";
|
|
5
|
+
import { productionConfig } from "./prod";
|
|
6
|
+
import { testConfig } from "./test";
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Load dotenv ONLY outside production
|
|
10
|
+
*/
|
|
11
|
+
if (process.env.NODE_ENV !== "production") {
|
|
12
|
+
await import("dotenv/config");
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Raw env schema (what the platform provides)
|
|
17
|
+
*/
|
|
18
|
+
const rawEnvSchema = z.object({
|
|
19
|
+
NODE_ENV: z
|
|
20
|
+
.enum(["development", "test", "production"])
|
|
21
|
+
.default("development"),
|
|
22
|
+
PORT: z.coerce.number().int().positive().optional(),
|
|
23
|
+
LOG_LEVEL: z
|
|
24
|
+
.enum(["fatal", "error", "warn", "info", "debug", "trace"])
|
|
25
|
+
.optional(),
|
|
26
|
+
CORS_ORIGIN: z.string().optional(),
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Validate process.env
|
|
31
|
+
*/
|
|
32
|
+
const parsed = rawEnvSchema.safeParse(process.env);
|
|
33
|
+
|
|
34
|
+
if (!parsed.success) {
|
|
35
|
+
console.error("❌ Invalid environment variables");
|
|
36
|
+
console.error(parsed.error.format());
|
|
37
|
+
process.exit(1);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
const nodeEnv = parsed.data.NODE_ENV;
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Select environment config
|
|
44
|
+
*/
|
|
45
|
+
const envConfigMap = {
|
|
46
|
+
development: developmentConfig,
|
|
47
|
+
test: testConfig,
|
|
48
|
+
production: productionConfig,
|
|
49
|
+
} as const;
|
|
50
|
+
|
|
51
|
+
const envOverrides = envConfigMap[nodeEnv];
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Final resolved config (single export)
|
|
55
|
+
*/
|
|
56
|
+
export const env = {
|
|
57
|
+
nodeEnv,
|
|
58
|
+
|
|
59
|
+
port: parsed.data.PORT ?? defaults.port,
|
|
60
|
+
logLevel: parsed.data.LOG_LEVEL ?? envOverrides.logLevel ?? defaults.logLevel,
|
|
61
|
+
corsOrigin: parsed.data.CORS_ORIGIN ?? defaults.corsOrigin,
|
|
62
|
+
} as const;
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
export class AppError extends Error {
|
|
2
|
+
public readonly statusCode: number;
|
|
3
|
+
public readonly code: string;
|
|
4
|
+
public readonly isOperational: boolean;
|
|
5
|
+
|
|
6
|
+
constructor(
|
|
7
|
+
message: string,
|
|
8
|
+
options: {
|
|
9
|
+
statusCode?: number;
|
|
10
|
+
code?: string;
|
|
11
|
+
isOperational?: boolean;
|
|
12
|
+
} = {},
|
|
13
|
+
) {
|
|
14
|
+
super(message);
|
|
15
|
+
|
|
16
|
+
this.statusCode = options.statusCode ?? 500;
|
|
17
|
+
this.code = options.code ?? "INTERNAL_SERVER_ERROR";
|
|
18
|
+
this.isOperational = options.isOperational ?? true;
|
|
19
|
+
}
|
|
20
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { NextFunction, Request, Response } from "express";
|
|
2
|
+
|
|
3
|
+
import { AppError } from "../errors/app-error.js";
|
|
4
|
+
|
|
5
|
+
export function notFoundHandler(
|
|
6
|
+
_req: Request,
|
|
7
|
+
_res: Response,
|
|
8
|
+
next: NextFunction,
|
|
9
|
+
) {
|
|
10
|
+
next(
|
|
11
|
+
new AppError("Route not found", {
|
|
12
|
+
statusCode: 404,
|
|
13
|
+
code: "NOT_FOUND",
|
|
14
|
+
}),
|
|
15
|
+
);
|
|
16
|
+
}
|