maxserver 0.0.18 → 0.1.1

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
@@ -64,6 +64,7 @@ Any fastify options can be passed to maxserver() too.
64
64
  | `mongodb` | *-* | MongoDB URI, if set auto-connects db |
65
65
  | `public` | `false` | Set `true` to expose the server publicly (binds to `0.0.0.0`) |
66
66
  | `static` | *-* | If set, serves this directory statically |
67
+ | `routesDir` | *src* | Directory to auto collect routes |
67
68
  ---
68
69
 
69
70
  <br>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "maxserver",
3
- "version": "0.0.18",
3
+ "version": "0.1.1",
4
4
  "description": "Node server setup based fastify",
5
5
  "author": "Max Matinpalo",
6
6
  "type": "module",
package/src/getAddress.js CHANGED
@@ -1,5 +1,13 @@
1
1
  import os from "node:os";
2
2
 
3
+
4
+ /**
5
+ * When listening on all interfaces (0.0.0.0), Node returns "0.0.0.0".
6
+ * This is a setting, not a valid URL for other devices.
7
+ * So we try hunt down the actual LAN IP to print the real address on which server can be accessed
8
+ */
9
+
10
+
3
11
  function getLanIp() {
4
12
  const nets = os.networkInterfaces();
5
13
 
package/src/index.js CHANGED
@@ -6,13 +6,13 @@ import {
6
6
  setupJwt,
7
7
  setupMongo,
8
8
  setupStatic,
9
- setupRoutes,
10
9
  setupDocs,
11
10
  setupCookie,
12
- getHttpsOptions,
13
11
  } from "./setup.js";
14
12
 
13
+
15
14
  import { getAddress } from "./getAddress.js";
15
+ import { setupRoutes } from "./setupRoutes.js";
16
16
 
17
17
 
18
18
  export default async function maxserver(config = {}) {
@@ -26,6 +26,7 @@ export default async function maxserver(config = {}) {
26
26
  docs = process.env.DOCS !== "false",
27
27
  cors = process.env.CORS || "*",
28
28
  env = process.env.NODE_ENV || "development",
29
+ routesDir = process.env.ROUTESDIR || "src",
29
30
  openapiInfo,
30
31
  static: isStatic = process.env.STATIC,
31
32
  public: isPublic = process.env.PUBLIC === "true",
@@ -36,18 +37,19 @@ export default async function maxserver(config = {}) {
36
37
  } = config;
37
38
 
38
39
  const maxserverConfig = {
39
- port, secret, mongodb, docs, cors,
40
+ port, secret, mongodb, docs, cors, env, openapiInfo, src,
40
41
  static: isStatic,
41
42
  public: isPublic
42
43
  };
43
44
 
45
+ if (!secret)
46
+ throw new Error("secret is must have");
47
+
44
48
 
45
49
  let app;
46
50
  try {
47
51
  app = Fastify({
48
- https: getHttpsOptions() || undefined,
49
52
  trustProxy: true,
50
-
51
53
  // Required to allow adding doc fields on schema
52
54
  ajv: { customOptions: { strictSchema: false } },
53
55
  ...fastifyOpts
package/src/setup.js CHANGED
@@ -10,12 +10,6 @@ import helmet from "@fastify/helmet";
10
10
  import swagger from "@fastify/swagger";
11
11
  import apiReference from "@scalar/fastify-api-reference";
12
12
 
13
- import { loadRoutes } from "./routeLoader.js";
14
-
15
- export async function setupRoutes(app) {
16
- await loadRoutes(app);
17
- }
18
-
19
13
 
20
14
  export async function setupHelmet(app) {
21
15
  await app.register(helmet, {
@@ -27,50 +21,41 @@ export async function setupHelmet(app) {
27
21
  }
28
22
 
29
23
 
30
-
31
-
32
24
  export async function setupCors(app) {
33
- const isProd = process.env.NODE_ENV === "production";
25
+ const isProd = app.maxserver.env === "production";
34
26
  const origin = app.maxserver.cors ?? "*";
35
-
36
27
  if (isProd && origin === "*") {
37
28
  app.log.warn("CORS: allowing all origins (*) in production");
38
29
  }
39
-
40
30
  await app.register(cors, { origin });
41
31
  }
42
32
 
43
33
 
44
-
45
- export function getHttpsOptions() {
46
- const { TLS_KEY, TLS_CERT } = process.env;
47
- if (!TLS_KEY || !TLS_CERT) return null;
48
-
49
- try {
50
- return {
51
- key: fs.readFileSync(TLS_KEY),
52
- cert: fs.readFileSync(TLS_CERT),
53
- };
54
- } catch (err) {
55
- throw new Error(`TLS read failed: ${err.message || err}`);
56
- }
34
+ export async function setupCookie(app) {
35
+ await app.register(cookie, {
36
+ secret: app.maxserver.secret,
37
+ hook: "onRequest"
38
+ });
57
39
  }
58
40
 
59
41
 
60
42
 
61
43
 
62
- export async function setupCookie(app) {
63
- await app.register(cookie, {
64
- secret: app.maxserver.secret || "supersecret",
65
- hook: "onRequest"
66
- });
44
+ export async function setupMongo(app) {
45
+ const url = app.maxserver.mongodb;
46
+ if (!url) return;
47
+ await app.register(mongodb, { url });
48
+
49
+ const { ObjectId, db } = app.mongo;
50
+ global.oid = id => new ObjectId(id);
51
+ global.db = db;
67
52
  }
68
53
 
69
54
 
70
- export async function setupJwt(app) {
71
55
 
56
+ export async function setupJwt(app) {
72
57
  await app.register(jwt, {
73
- secret: app.maxserver.secret || "supersecret",
58
+ secret: app.maxserver.secret,
74
59
  cookie: { cookieName: "token" }
75
60
  });
76
61
 
@@ -79,9 +64,7 @@ export async function setupJwt(app) {
79
64
  // Let preflight requests pass
80
65
  if (req.method === "OPTIONS") return;
81
66
 
82
- const auth =
83
- req.routeOptions?.config?.auth ??
84
- req.routeOptions?.schema?.auth;
67
+ const auth = req.routeOptions?.config?.auth;
85
68
 
86
69
  if (!auth) return;
87
70
 
@@ -93,15 +76,6 @@ export async function setupJwt(app) {
93
76
  }
94
77
 
95
78
 
96
- export async function setupMongo(app) {
97
- const url = app.maxserver.mongodb;
98
- if (!url) return;
99
- await app.register(mongodb, { url });
100
-
101
- const { ObjectId, db } = app.mongo;
102
- global.oid = id => new ObjectId(id ? String(id) : undefined);
103
- global.db = db;
104
- }
105
79
 
106
80
 
107
81
  export async function setupDocs(app) {
@@ -128,11 +102,11 @@ export async function setupDocs(app) {
128
102
 
129
103
  app.get("/openapi.json", {}, () => app.swagger());
130
104
 
131
- if (app.maxserver.docs != false)
105
+ if (app.maxserver.docs !== false)
132
106
  await app.register(apiReference, { routePrefix: "/docs", openapi: true });
133
107
 
134
108
  app.addHook("onRoute", (route) => {
135
- const auth = route.config?.auth ?? route.schema?.auth;
109
+ const auth = route.config?.auth;
136
110
  if (!auth) return;
137
111
  route.schema ||= {};
138
112
  route.schema.security ||= [{ bearerAuth: [] }, { cookieAuth: [] }];
@@ -145,9 +119,19 @@ export async function setupStatic(app) {
145
119
  const dir = app.maxserver.static;
146
120
  if (!dir) return;
147
121
 
148
- await app.register(fastifyStatic, {
149
- root: path.resolve(dir),
150
- prefix: "/static/",
151
- });
122
+ if (typeof dir !== "string") {
123
+ console.error("❌ maxserver.static must be a string path");
124
+ return;
125
+ }
126
+
127
+ const abs = path.resolve(dir);
128
+ if (!fs.existsSync(abs)) {
129
+ console.error(`❌ maxserver.static not found: ${abs}`);
130
+ return;
131
+ }
132
+
133
+ await app.register(fastifyStatic, { root: abs });
152
134
  }
153
135
 
136
+
137
+
@@ -74,9 +74,9 @@ async function importDefault(file) {
74
74
  }
75
75
 
76
76
 
77
- export async function loadRoutes(fastify) {
77
+ export async function setupRoutes(app) {
78
78
  const seen = new Map();
79
- const root = path.join(process.cwd(), "src");
79
+ const root = path.resolve(app.maxserver.routesDir || "src");
80
80
 
81
81
  for (const file of walk(root)) {
82
82
  // Skip schema files; they are loaded alongside their route file
@@ -125,6 +125,6 @@ export async function loadRoutes(fastify) {
125
125
  };
126
126
  }
127
127
 
128
- fastify[info.method](info.url, { ...routeOptions, schema }, handler);
128
+ app[info.method](info.url, { ...routeOptions, schema }, handler);
129
129
  }
130
130
  }