maxserver 0.0.15 → 0.0.17

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
@@ -11,58 +11,63 @@
11
11
  I am simplifying and improving things, that it will work for everyone plugn play.
12
12
 
13
13
 
14
- Ready node server setup based on **Fastify** to speedup api development.
14
+ Ready node server setup based on **Fastify** to speed up backend development.
15
+ maxserver stands for **maximized simplicity** and **minimum boilerplate**.
15
16
 
16
17
  - **Auto Routes**: auto imports and registers routes and schemas
17
18
  - **Auto Docs**: auto generates docs based on schemas
18
- - **Preconfigures JWT auth, Cores, Helmet**
19
+ - **Preconfigures essentials**: jwt auth, cors, helmet
19
20
  - **Auto Connect MongoDB** (optional)
20
21
  - **Dev server**
21
22
  <br><br>
22
23
 
23
- - Dependencies: original fastify packages + scalar/fastify-api-reference (doc generator)
24
- - The source is simple and short. Everyone shall be able to read, understand and modify if needed.
25
-
26
24
 
27
25
  ## Install
28
26
 
29
27
  ### Setup ready project
28
+ ```js
30
29
  npx maxserver [appname]
30
+ ```
31
31
 
32
- ### Install
32
+ ### Or install as packge
33
+ ```js
33
34
  npm install maxserver
35
+ ```
36
+ <br>
34
37
 
35
38
  ## Setup
36
39
  ```js
37
40
  import maxserver from "maxserver";
38
41
 
39
- const server = await maxserver();
40
- await server.listen();
42
+ const server = await maxserver({
43
+ port: 3000,
44
+ secret: "your_secret"
45
+ });
41
46
 
42
- console.log("Server running at ", server.getAddress());
47
+ await server.start();
43
48
  export default server;
44
-
45
49
  ```
46
- ---
50
+ <br>
47
51
 
48
52
  ## ⚙️ Configure
49
- Quick configure your server by passing options to the **maxserver()** or define them in your .env file.
50
- You can also pass any fastify options.
53
+ Configs can be passed to the init call to **maxserver()** or set in your .env file.
54
+ If you define options in env, use all upper case letters.
55
+ Any fastify options can be passed to maxserver() too.
56
+
51
57
 
52
58
  | Variable | Default | Description |
53
59
  | :--- | :--- | :--- |
54
- | `PORT` | `3000` | Server port |
55
- | `JWT_SECRET` | *-* | Enables JWT auth (private-by-default routes) |
56
- | `MONGODB_URI` | *-* | Enables MongoDB auto-connect + global `db` |
57
- | `DOCS` | `true` | Set `false` to disable docs UI at `/docs` |
58
- | `STATIC_DIR` | *(optional)* | Serve static files (example: `./public`) |
59
- | `CORS_ORIGIN` | `*` | Allowed CORS origins |
60
-
61
- ---
62
-
63
- ## 🗂️ Project Structure
60
+ | `port` | `3000` | Server port |
61
+ | `secret` | *-* | Secret used for jwt and cookies |
62
+ | `cors` | `*` | Allowed CORS origins, default all allowed |
63
+ | `docs` | `true` | Set `false` to disable auto generated docs` |
64
+ | `mongodb` | *-* | MongoDB URI, if set auto-connects db |
65
+ | `public` | `false` | Set `true` to expose the server publicly (binds to `0.0.0.0`) |
66
+ | `static` | *-* | If set, serves this directory statically |
67
+ <br><br>
64
68
 
65
- **1 route = 1 handler file + 1 schema file**
69
+ ## 🗂️ Project Structure
70
+ Our golden rule: **1 route = 1 handler file + 1 schema file**
66
71
 
67
72
  Example:
68
73
 
@@ -75,12 +80,11 @@ src/
75
80
  hello.schema.js
76
81
  ...
77
82
  ```
78
-
79
- ---
83
+ <br>
80
84
 
81
85
  ## 🛣️ Handlers
82
86
 
83
- ### 1) Define method + path
87
+ #### 1) Define method + path
84
88
  Start each route file with a comment to define the path.
85
89
  That comment is what the route loader uses to auto-register the route.
86
90
 
@@ -88,13 +92,9 @@ That comment is what the route loader uses to auto-register the route.
88
92
  // GET /teams/:id
89
93
  ```
90
94
 
95
+ #### 2) Export default handler
91
96
 
92
97
 
93
- ### 2) Default export handler
94
-
95
-
96
- ### Example
97
-
98
98
  ```js
99
99
  // GET /teams/:id
100
100
 
@@ -106,89 +106,90 @@ export default async function (req, res) {
106
106
  }
107
107
  ```
108
108
 
109
- ---
109
+ If you don't want to autoregister some routes, then simply don't add that magic comment 😃
110
110
 
111
- ## 🧾 Define Schemas
112
- Create a sibling file ending in **`.schema.js`**.
113
- The schema is offcourse a jsonschema.
114
- This file will be auto registered.
115
111
 
116
- Schemas:
117
- - validate inputs
118
- - generate OpenAPI docs
119
- - control route options for example (public/private)
112
+ <br>
113
+ <br>
114
+
115
+
116
+ ## 🧾 Schemas
117
+ Create a sibling file ending with **`.schema.js`**, so it will be auto registered.
118
+ For example: **hello.js** and **hello.schema.js**
119
+
120
+ Besides the basic validation fields we can set fields like summary and description,
121
+ which will appear in the docs. Mostly you don't need to write schemas yourself, chat gpt and gemini do it excelently.
120
122
 
121
123
 
122
- **`Important - use default export`**
123
124
  ```js
124
125
  export default {
125
- tags: ["Teams"],
126
- summary: "Get team",
127
- description: "Returns a single team by identifier.",
128
126
 
129
- params: {
127
+ tags: ["Test"],
128
+ summary: "Post hello",
129
+ description: "Accepts a name and returns a greeting.",
130
+
131
+ body: {
130
132
  type: "object",
131
- required: ["id"],
133
+ required: ["name"],
132
134
  properties: {
133
- id: {
135
+ name: {
134
136
  type: "string",
135
- minLength: 24,
136
- example: "",
137
137
  },
138
138
  },
139
139
  },
140
140
 
141
- response: {
142
- 200: {
143
- type: "object",
144
- properties: {
145
- id: {
146
- type: "string",
147
- example: "507f1f77bcf86cd799439011",
148
- },
149
- name: { type: "string", example: "Team A" },
150
- },
151
- required: ["id", "name"],
152
- },
153
- },
141
+ ...
154
142
  };
155
143
  ```
156
144
 
157
- <br>
145
+ **`‼️ Important use export default`**
158
146
 
147
+ <br>
159
148
 
160
- ## 📚 API Docs
149
+ ## 🛠️ Route Options
150
+ Though we don't mostly register routes manually, we don't set route options on the register call.
151
+ If needed, you can wether register that route manually or just set them on the schema.
161
152
 
162
- - Open in your browser **`localhost:3000/docs`**
163
- - OpenAPI JSON: **`/openapi.json`**
153
+ ```js
154
+ // Inside schema
164
155
 
165
- <br>
156
+ export default {
157
+ routeOptions: {
158
+ config: {
159
+ preHandler: ...
160
+ },
161
+ },
162
+ ...
163
+ ```
166
164
 
167
165
 
166
+ <br>
168
167
 
168
+ ## 📚 API Docs
169
169
 
170
- ## 🔐 Authentication (JWT)
170
+ Open in your browser **`localhost:3000/docs`**
171
+ OpenAPI JSON: **`/openapi.json`**
171
172
 
172
- Enable auth by setting:
173
+ <br>
173
174
 
174
- - `JWT_SECRET`
175
175
 
176
- Behavior:
177
- - **Private by default**: routes require JWT (cookie or Bearer header)
178
- - Authenticated user identifier is available as **`req.userId`**
179
- - Make a route **public** by setting `config.public: true` in its schema
176
+ ## 🔐 Authentication
177
+ JWT header and cookie based auth is preconfigured.
178
+ To enable auth for a route set in it's schema **auth = true**
179
+ The authenticated user is available as **`req.userId`**
180
180
 
181
181
  ```js
182
+ // Inside schema
183
+
182
184
  export default {
183
- config: { public: true },
184
- // ...
185
+ auth: true
185
186
  };
186
187
  ```
187
188
 
188
189
  <br>
189
190
 
190
191
  ## 🍃 MongoDB
191
- Define in the env **`MONGODB_URI`** and it will auto-connect at server start and you get:
192
+ Set option **`MONGODB`** your mongodbURI and it will auto-connect at server start and you get:
192
193
 
193
194
  - global **`db`** (connected database handle)
194
195
  - global **`oid(string)`** (string → MongoDB `ObjectId`)
@@ -198,8 +199,19 @@ Define in the env **`MONGODB_URI`** and it will auto-connect at server start and
198
199
  | `db` | MongoDB database handle | Use it directly in handlers |
199
200
  | `oid(id)` | string → `ObjectId` | Avoid importing `ObjectId` everywhere |
200
201
 
202
+ ### Example
201
203
 
202
- ---
204
+ ```js
205
+ // Inside route handlers
206
+
207
+ export default async function (req, res) {
208
+
209
+ await db.feedback.insert(...)
210
+ }
211
+ ```
212
+
213
+
214
+ <br>
203
215
 
204
216
  ## 🧰 Error Handling
205
217
 
@@ -211,9 +223,13 @@ if (!user) throw createError(404, "User not found");
211
223
 
212
224
  Rule of thumb: make the message something you would want to see at 03:00 in logs.
213
225
 
214
- ---
226
+ <br>
215
227
 
228
+ ## About
229
+ - Dependencies: original fastify packages + scalar/fastify-api-reference
230
+ - The source is simple. Everyone can read, understand and modify if needed.
216
231
 
232
+ <br>
217
233
 
218
234
  ## 🛠️ Tips & Tools
219
235
 
@@ -230,5 +246,6 @@ In `.vscode/tasks.json`, enable the task with:
230
246
  "runOptions": { "runOn": "folderOpen" }
231
247
  ```
232
248
 
233
- ### 🤖 AI Assistants (Code Style)
234
- Copy **`RULES.md`** into your AI tool as system context, then ask it to generate routes + schemas.
249
+ ### 🤖 AI Assistants
250
+ Copy **`RULES.md`** into your AI tool as system context,
251
+ then ask it to generate routes + schemas.
package/bin/init.js CHANGED
@@ -15,17 +15,17 @@ function main() {
15
15
  }
16
16
 
17
17
  try {
18
- console.log(`🚀 Creating "${projectName}"...`);
18
+ console.log(`🚀 Setting up "${projectName}"...`);
19
19
  fs.cpSync(templateDir, targetDir, { recursive: true });
20
20
 
21
21
  fixDotfiles(targetDir);
22
22
  patchPackageJson(targetDir, projectName);
23
23
 
24
24
  process.chdir(targetDir);
25
- console.log("📦 Installing maxserver...");
25
+ console.log("📦 Installing maxserver");
26
26
  execSync("npm install maxserver@latest", { stdio: "inherit" });
27
27
 
28
- console.log("\n✅ Done! Your project is ready. 😊");
28
+ console.log(`\n✅ Install complete\n\ncd ${projectName}\nnpm run dev\n`);
29
29
  } catch (err) {
30
30
  console.error("❌ Init failed:", err.message);
31
31
  process.exit(1);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "maxserver",
3
- "version": "0.0.15",
3
+ "version": "0.0.17",
4
4
  "description": "Node server setup based fastify",
5
5
  "author": "Max Matinpalo",
6
6
  "type": "module",
package/src/getAddress.js CHANGED
@@ -1,29 +1,5 @@
1
1
  import os from "node:os";
2
2
 
3
- export function setupGetAddress(app) {
4
- app.decorate("getAddress", () => {
5
- const addr = app.server?.address();
6
- const protocol = app.initialConfig?.https ? "https" : "http";
7
-
8
- if (!addr) return null;
9
- if (typeof addr === "string") return addr;
10
-
11
- const isPublicBind = addr.address === "0.0.0.0" || addr.address === "::";
12
- const isLoopback = addr.address === "127.0.0.1" || addr.address === "::1";
13
-
14
- const envIp = String(process.env.PUBLIC_IP || "").trim() || null;
15
- const detectedIp = envIp || getLanIp();
16
-
17
- const ip = (isPublicBind && !isLoopback)
18
- ? (detectedIp || addr.address)
19
- : "localhost";
20
-
21
- const host = ip.includes(":") ? `[${ip}]` : ip;
22
-
23
- return `${protocol}://${host}:${addr.port}`;
24
- });
25
- }
26
-
27
3
  function getLanIp() {
28
4
  const nets = os.networkInterfaces();
29
5
 
@@ -35,3 +11,28 @@ function getLanIp() {
35
11
 
36
12
  return null;
37
13
  }
14
+
15
+
16
+ export function getAddress(app) {
17
+
18
+ const addr = app.server?.address();
19
+ const protocol = app.initialConfig?.https ? "https" : "http";
20
+
21
+ if (!addr) return null;
22
+ if (typeof addr === "string") return addr;
23
+
24
+ const isPublicBind = addr.address === "0.0.0.0" || addr.address === "::";
25
+ const isLoopback = addr.address === "127.0.0.1" || addr.address === "::1";
26
+
27
+ const envIp = String(process.env.PUBLIC_IP || "").trim() || null;
28
+ const detectedIp = envIp || getLanIp();
29
+
30
+ const ip = (isPublicBind && !isLoopback)
31
+ ? (detectedIp || addr.address)
32
+ : "localhost";
33
+
34
+ const host = ip.includes(":") ? `[${ip}]` : ip;
35
+
36
+ return `${protocol}://${host}:${addr.port}`;
37
+ }
38
+
package/src/index.js CHANGED
@@ -12,7 +12,7 @@ import {
12
12
  getHttpsOptions,
13
13
  } from "./setup.js";
14
14
 
15
- import { setupGetAddress } from "./getAddress.js";
15
+ import { getAddress } from "./getAddress.js";
16
16
 
17
17
 
18
18
  export default async function maxserver(config = {}) {
@@ -20,47 +20,53 @@ export default async function maxserver(config = {}) {
20
20
  const {
21
21
 
22
22
  // maxserver options
23
+ port = Number(process.env.PORT || 3000),
23
24
  secret = process.env.SECRET,
24
- cookieSecret = process.env.COOKIE_SECRET,
25
- mongodbUri = process.env.MONGODB_URI,
25
+ mongodb = process.env.MONGODB,
26
26
  docs = process.env.DOCS !== "false",
27
- staticDir = process.env.STATIC_DIR,
28
- corsOrigin = process.env.CORS_ORIGIN || "*",
27
+ cors = process.env.CORS || "*",
28
+ env = process.env.NODE_ENV || "development",
29
+ openapiInfo,
30
+ static: isStatic = process.env.STATIC,
31
+ public: isPublic = process.env.PUBLIC === "true",
29
32
 
30
33
  // everything else goes straight to Fastify
31
34
  ...fastifyOpts
32
35
 
33
36
  } = config;
34
37
 
35
- if (process.env.NODE_ENV == "development") {
36
- console.error("Please define secret in env !");
37
-
38
- }
39
-
40
- let maxserverConfig = {
41
- secret, mongodbUri, docs, staticDir, corsOrigin
38
+ const maxserverConfig = {
39
+ port, secret, mongodb, docs, cors,
40
+ static: isStatic,
41
+ public: isPublic
42
42
  };
43
43
 
44
- process.env.NODE_ENV;
45
-
46
-
47
-
48
44
 
49
- const app = Fastify({
45
+ let app;
46
+ try {
47
+ app = Fastify({
48
+ https: getHttpsOptions() || undefined,
49
+ trustProxy: true,
50
50
 
51
- https: getHttpsOptions() || undefined,
52
- trustProxy: true,
51
+ // Required to allow adding doc fields on schema
52
+ ajv: { customOptions: { strictSchema: false } },
53
+ ...fastifyOpts
54
+ });
55
+ } catch (err) {
56
+ console.error("❌ Fastify initialization failed:", err);
57
+ throw err;
58
+ }
53
59
 
54
- // To allow writing example value fields to schemas for doucumentation
55
- ajv: { customOptions: { strictSchema: false } },
56
- ...fastifyOpts,
57
- });
58
60
 
59
61
  app.decorate("maxserver", maxserverConfig);
60
62
 
63
+ app.decorate("start", async function () {
64
+ const port = this.maxserver.port ?? 3000;
65
+ const host = this.maxserver.public ? '0.0.0.0' : '127.0.0.1';
66
+ await this.listen({ port, host });
67
+ console.log('Server running at ', getAddress(this));
68
+ });
61
69
 
62
-
63
- setupGetAddress(app);
64
70
  await setupCookie(app);
65
71
  await setupHelmet(app);
66
72
  await setupCors(app);
@@ -70,13 +76,11 @@ export default async function maxserver(config = {}) {
70
76
  await setupDocs(app);
71
77
  await setupRoutes(app);
72
78
 
73
-
74
79
  global.createError = function (code, message) {
75
80
  const err = new Error(message);
76
81
  err.statusCode = code;
77
82
  return err;
78
83
  };
79
84
 
80
-
81
85
  return app;
82
86
  }
@@ -1,89 +1,91 @@
1
- // Scans src/** for files whose first line looks like:
2
- // POST /teams/create
3
- // Imports handler + schema and registers them with Fastify.
1
+ /**
2
+ * 🚀 AUTO-LOADER
3
+ * Scans src/ for files with "// METHOD /url" comments.
4
+ * Automatically registers them as Fastify routes.
5
+ */
4
6
 
5
7
  import fs from "fs";
6
8
  import path from "path";
9
+ import { pathToFileURL } from "url";
7
10
 
8
- const ROUTE_OPTION_KEYS = new Set([
9
- "config",
10
- "preHandler",
11
- "onRequest",
12
- "preValidation",
13
- "preSerialization",
14
- "errorHandler",
15
- "logLevel",
16
- "bodyLimit",
17
- "attachValidation",
18
- "exposeHeadRoute",
19
- "constraints",
20
- "timeout",
21
- "websocket",
22
- "prefixTrailingSlash",
23
- ]);
24
11
 
12
+ // Matches lines like: // GET /api/v1/users
13
+ const ROUTE_REGEX = /^\/\/\s*(GET|POST|PUT|PATCH|DELETE)\s+(.+)$/gm;
14
+
15
+
16
+ /**
17
+ * Recursively finds all .js files in a directory.
18
+ * Skips node_modules and dotfiles.
19
+ */
25
20
  function walk(dir, out = []) {
26
21
  if (!fs.existsSync(dir)) return out;
27
- const entries = fs.readdirSync(dir, { withFileTypes: true });
28
22
 
29
- for (const entry of entries) {
30
- if (entry.name === "node_modules") continue;
31
- if (entry.name.startsWith(".")) continue;
32
- const full = path.join(dir, entry.name);
23
+ for (const e of fs.readdirSync(dir, { withFileTypes: true })) {
24
+ if (e.name === "node_modules") continue;
25
+ if (e.name.startsWith(".")) continue;
33
26
 
34
- if (entry.isDirectory()) {
27
+ const full = path.join(dir, e.name);
28
+ if (e.isDirectory()) {
35
29
  walk(full, out);
36
- } else if (entry.name.endsWith(".js")) {
37
- out.push(full);
30
+ continue;
38
31
  }
32
+
33
+ if (!e.name.endsWith(".js")) continue;
34
+ out.push(full);
39
35
  }
36
+
40
37
  return out;
41
38
  }
42
39
 
43
- function getFirstLine(file) {
40
+
41
+ /**
42
+ * Extracts method and URL from the file's "magic comment".
43
+ * Enforces strict "One Route Per File" policy.
44
+ */
45
+ function getRoute(file) {
44
46
  const text = fs.readFileSync(file, "utf8");
45
- const lines = text.split("\n");
46
- const firstContent = lines.find((line) => line.trim().length > 0);
47
+ const matches = [...text.matchAll(ROUTE_REGEX)];
47
48
 
48
- return (firstContent || "").trim().replace(/^\uFEFF/, "");
49
- }
49
+ if (matches.length === 0) return null;
50
50
 
51
- const ROUTE_REGEX = /^\/\/\s*(GET|POST|PUT|PATCH|DELETE)\s+(.+)$/;
51
+ // Warn if user accidentally defines multiple routes in one file
52
+ if (matches.length > 1) {
53
+ console.warn(
54
+ `⚠️ Ignored "${file}": Found ${matches.length} route comments. ` +
55
+ `Only 1 allowed per file.`
56
+ );
57
+ return null;
58
+ }
52
59
 
53
- function parseRouteComment(file) {
54
- const line = getFirstLine(file);
55
- const m = line.match(ROUTE_REGEX);
56
- if (!m) return null;
60
+ const m = matches[0];
61
+ const method = m[1].toLowerCase();
62
+ // Normalize URL: Remove all leading slashes, then add exactly one
63
+ const url = "/" + m[2].trim().replace(/^\/+/, "");
57
64
 
58
- return { method: m[1].toLowerCase(), url: m[2] };
65
+ return { method, url };
59
66
  }
60
67
 
61
- function splitSchemaExport(raw) {
62
- const routeOptions = {};
63
- const schema = {};
64
-
65
- for (const [key, value] of Object.entries(raw || {})) {
66
- if (ROUTE_OPTION_KEYS.has(key)) {
67
- routeOptions[key] = value;
68
- continue;
69
- }
70
- schema[key] = value;
71
- }
72
68
 
73
- return { routeOptions, schema };
69
+ /**
70
+ * Safe dynamic import that handles Windows paths correctly.
71
+ */
72
+ async function importDefault(file) {
73
+ return (await import(pathToFileURL(file).href)).default;
74
74
  }
75
75
 
76
+
76
77
  export async function loadRoutes(fastify) {
77
- const ROOT = path.join(process.cwd(), "src");
78
- const files = walk(ROOT);
79
78
  const seen = new Map();
79
+ const root = path.join(process.cwd(), "src");
80
80
 
81
- for (const file of files) {
81
+ for (const file of walk(root)) {
82
+ // Skip schema files; they are loaded alongside their route file
82
83
  if (file.endsWith(".schema.js")) continue;
83
84
 
84
- const info = parseRouteComment(file);
85
+ const info = getRoute(file);
85
86
  if (!info) continue;
86
87
 
88
+ // 🛡️ Collision Detection: Ensure no two files claim the same route
87
89
  const key = info.method + " " + info.url;
88
90
  if (seen.has(key)) {
89
91
  throw new Error(
@@ -94,29 +96,35 @@ export async function loadRoutes(fastify) {
94
96
  }
95
97
  seen.set(key, file);
96
98
 
97
- const handlerMod = await import("file://" + file);
98
- const handler = handlerMod.default;
99
+ // Import the route handler
100
+ const handler = await importDefault(file);
101
+ if (typeof handler !== "function") {
102
+ throw new Error(
103
+ `Route "${key}" in "${file}" must export a default function.`
104
+ );
105
+ }
99
106
 
107
+ // 🤝 Schema Loading: Look for sibling .schema.js file
100
108
  const schemaFile = file.replace(/\.js$/, ".schema.js");
101
- let raw = null;
109
+ let raw = {};
102
110
 
103
111
  if (fs.existsSync(schemaFile)) {
104
- const schemaMod = await import("file://" + schemaFile);
105
- raw = schemaMod.default || {};
106
- } else {
107
- fastify.log.warn(
108
- `Route schema missing: ` +
109
- `${info.method.toUpperCase()} ${info.url}`
110
- );
111
- raw = {};
112
+ const loaded = await importDefault(schemaFile);
113
+ // 🛡️ Guard: Ensure export is a valid object before using it
114
+ if (loaded && typeof loaded === "object") raw = loaded;
112
115
  }
113
116
 
114
- const parts = splitSchemaExport(raw);
117
+ // Magic: Extract 'auth' and 'routeOptions' specifically
118
+ let { auth, routeOptions = {}, ...schema } = raw;
115
119
 
116
- fastify[info.method](
117
- info.url,
118
- { ...parts.routeOptions, schema: parts.schema },
119
- handler
120
- );
120
+ // Inject 'auth' into config if present (Syntactic Sugar)
121
+ if (auth !== undefined) {
122
+ routeOptions = {
123
+ ...routeOptions,
124
+ config: { ...(routeOptions.config || {}), auth: !!auth },
125
+ };
126
+ }
127
+
128
+ fastify[info.method](info.url, { ...routeOptions, schema }, handler);
121
129
  }
122
- }
130
+ }
package/src/setup.js CHANGED
@@ -27,18 +27,21 @@ export async function setupHelmet(app) {
27
27
  }
28
28
 
29
29
 
30
+
31
+
30
32
  export async function setupCors(app) {
31
33
  const isProd = process.env.NODE_ENV === "production";
32
- const origin = app.maxserver.corsOrigin ?? true;
34
+ const origin = app.maxserver.cors ?? "*";
33
35
 
34
- if (isProd && origin === true) {
35
- app.log.warn("CORS origin not set, allowing all origins");
36
+ if (isProd && origin === "*") {
37
+ app.log.warn("CORS: allowing all origins (*) in production");
36
38
  }
37
39
 
38
40
  await app.register(cors, { origin });
39
41
  }
40
42
 
41
43
 
44
+
42
45
  export function getHttpsOptions() {
43
46
  const { TLS_KEY, TLS_CERT } = process.env;
44
47
  if (!TLS_KEY || !TLS_CERT) return null;
@@ -91,7 +94,7 @@ export async function setupJwt(app) {
91
94
 
92
95
 
93
96
  export async function setupMongo(app) {
94
- const url = app.maxserver.mongodbUri;
97
+ const url = app.maxserver.mongodb;
95
98
  if (!url) return;
96
99
  await app.register(mongodb, { url });
97
100
 
@@ -139,7 +142,7 @@ export async function setupDocs(app) {
139
142
 
140
143
 
141
144
  export async function setupStatic(app) {
142
- const dir = app.maxserver.staticDir;
145
+ const dir = app.maxserver.static;
143
146
  if (!dir) return;
144
147
 
145
148
  await app.register(fastifyStatic, {
package/templates/env CHANGED
@@ -1,24 +1,8 @@
1
- # Environment
2
- NODE_ENV = development
3
-
4
- # Server
5
- PORT = 3000
6
-
7
- # CORS(prod only, ignored in dev)
8
- # CORS_ORIGIN = https://app.example.com
9
-
10
- # JWT;
11
- # JWT_SECRET = supersecretkey
12
1
 
13
- # MongoDB;
14
- # MONGODB_URI = mongodb://127.0.0.1:27017/testdb
15
-
16
- # Static files
17
- # STATIC_DIR =./ public
18
-
19
- # API Docs in production
20
- DOCS = 1
2
+ NODE_ENV = development
21
3
 
22
- # Optional HTTPS(direct TLS, no nginx)
23
- # TLS_KEY = /etc/ssl / private / server.key
24
- # TLS_CERT = /etc/ssl / certs / server.crt;
4
+ # PORT
5
+ # CORS
6
+ # SECRET
7
+ # MONGODB
8
+ # STATIC
@@ -1,10 +1,9 @@
1
1
  import maxserver from "maxserver";
2
2
 
3
- const server = await maxserver();
4
-
5
- await server.listen({
6
- port: Number(process.env.PORT || 3000),
3
+ const server = await maxserver({
4
+ port: 3000,
5
+ secret: "your_secret"
7
6
  });
8
7
 
9
- console.log("Server running at ", server.getAddress());
8
+ await server.start();
10
9
  export default server;