@catmint/adapter-node 0.0.0-prealpha.3 → 0.0.0-prealpha.5

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.d.ts CHANGED
@@ -7,6 +7,13 @@ export interface NodeAdapterOptions {
7
7
  port?: number;
8
8
  /** Host to bind to (default: '0.0.0.0') */
9
9
  host?: string;
10
+ /**
11
+ * Maximum allowed request body size in bytes.
12
+ * Applies to server function RPC calls and API endpoints.
13
+ *
14
+ * @default 1_048_576 (1 MB)
15
+ */
16
+ maxBodySize?: number;
10
17
  }
11
18
  /**
12
19
  * Create a Node.js adapter for Catmint.
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,cAAc,EAA+B,MAAM,gBAAgB,CAAC;AAIlF;;GAEG;AACH,MAAM,WAAW,kBAAkB;IACjC,wCAAwC;IACxC,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,2CAA2C;IAC3C,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED;;;;;;;;;;;;;;;GAeG;AACH,MAAM,CAAC,OAAO,UAAU,WAAW,CACjC,OAAO,CAAC,EAAE,kBAAkB,GAC3B,cAAc,CA0BhB"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EACV,cAAc,EAGf,MAAM,gBAAgB,CAAC;AAIxB;;GAEG;AACH,MAAM,WAAW,kBAAkB;IACjC,wCAAwC;IACxC,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,2CAA2C;IAC3C,IAAI,CAAC,EAAE,MAAM,CAAC;IACd;;;;;OAKG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED;;;;;;;;;;;;;;;GAeG;AACH,MAAM,CAAC,OAAO,UAAU,WAAW,CACjC,OAAO,CAAC,EAAE,kBAAkB,GAC3B,cAAc,CAgChB"}
package/dist/index.js CHANGED
@@ -19,12 +19,18 @@ import { generateServerEntry } from "./server-template.js";
19
19
  export default function nodeAdapter(options) {
20
20
  const port = options?.port ?? 6468;
21
21
  const host = options?.host ?? "0.0.0.0";
22
+ const maxBodySize = options?.maxBodySize ?? 1_048_576;
22
23
  return {
23
24
  name: "@catmint/adapter-node",
24
25
  async adapt(context) {
25
26
  context.log("@catmint/adapter-node: Generating standalone Node.js server...");
26
27
  const manifest = context.manifest;
27
- const entryContent = generateServerEntry(manifest, { port, host });
28
+ const entryContent = generateServerEntry(manifest, {
29
+ port,
30
+ host,
31
+ maxBodySize,
32
+ headerPreset: manifest.config.security.headerPreset,
33
+ });
28
34
  // Write to dist/server/index.js (separate from the SSR bundle at dist/ssr/)
29
35
  // so `catmint start` can still load the SSR entry for its built-in server.
30
36
  await context.writeFile("server/index.js", entryContent);
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,4DAA4D;AAI5D,OAAO,EAAE,mBAAmB,EAAE,MAAM,sBAAsB,CAAC;AAY3D;;;;;;;;;;;;;;;GAeG;AACH,MAAM,CAAC,OAAO,UAAU,WAAW,CACjC,OAA4B;IAE5B,MAAM,IAAI,GAAG,OAAO,EAAE,IAAI,IAAI,IAAI,CAAC;IACnC,MAAM,IAAI,GAAG,OAAO,EAAE,IAAI,IAAI,SAAS,CAAC;IAExC,OAAO;QACL,IAAI,EAAE,uBAAuB;QAC7B,KAAK,CAAC,KAAK,CAAC,OAAuB;YACjC,OAAO,CAAC,GAAG,CACT,gEAAgE,CACjE,CAAC;YAEF,MAAM,QAAQ,GAAG,OAAO,CAAC,QAAuB,CAAC;YACjD,MAAM,YAAY,GAAG,mBAAmB,CAAC,QAAQ,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC;YAEnE,4EAA4E;YAC5E,2EAA2E;YAC3E,MAAM,OAAO,CAAC,SAAS,CAAC,iBAAiB,EAAE,YAAY,CAAC,CAAC;YAEzD,OAAO,CAAC,GAAG,CACT,oEAAoE,CACrE,CAAC;YACF,OAAO,CAAC,GAAG,CACT,iFAAiF,IAAI,IAAI,IAAI,GAAG,CACjG,CAAC;QACJ,CAAC;KACF,CAAC;AACJ,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,4DAA4D;AAQ5D,OAAO,EAAE,mBAAmB,EAAE,MAAM,sBAAsB,CAAC;AAmB3D;;;;;;;;;;;;;;;GAeG;AACH,MAAM,CAAC,OAAO,UAAU,WAAW,CACjC,OAA4B;IAE5B,MAAM,IAAI,GAAG,OAAO,EAAE,IAAI,IAAI,IAAI,CAAC;IACnC,MAAM,IAAI,GAAG,OAAO,EAAE,IAAI,IAAI,SAAS,CAAC;IACxC,MAAM,WAAW,GAAG,OAAO,EAAE,WAAW,IAAI,SAAS,CAAC;IAEtD,OAAO;QACL,IAAI,EAAE,uBAAuB;QAC7B,KAAK,CAAC,KAAK,CAAC,OAAuB;YACjC,OAAO,CAAC,GAAG,CACT,gEAAgE,CACjE,CAAC;YAEF,MAAM,QAAQ,GAAG,OAAO,CAAC,QAAuB,CAAC;YACjD,MAAM,YAAY,GAAG,mBAAmB,CAAC,QAAQ,EAAE;gBACjD,IAAI;gBACJ,IAAI;gBACJ,WAAW;gBACX,YAAY,EAAE,QAAQ,CAAC,MAAM,CAAC,QAAQ,CAAC,YAAY;aACpD,CAAC,CAAC;YAEH,4EAA4E;YAC5E,2EAA2E;YAC3E,MAAM,OAAO,CAAC,SAAS,CAAC,iBAAiB,EAAE,YAAY,CAAC,CAAC;YAEzD,OAAO,CAAC,GAAG,CACT,oEAAoE,CACrE,CAAC;YACF,OAAO,CAAC,GAAG,CACT,iFAAiF,IAAI,IAAI,IAAI,GAAG,CACjG,CAAC;QACJ,CAAC;KACF,CAAC;AACJ,CAAC"}
@@ -2,6 +2,8 @@ import type { AppManifest } from "catmint/config";
2
2
  interface ServerOptions {
3
3
  port: number;
4
4
  host: string;
5
+ maxBodySize: number;
6
+ headerPreset: "baseline" | "none";
5
7
  }
6
8
  /**
7
9
  * Generate the content of the standalone Node.js server entry point.
@@ -1 +1 @@
1
- {"version":3,"file":"server-template.d.ts","sourceRoot":"","sources":["../src/server-template.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAElD,UAAU,aAAa;IACrB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;CACd;AAED;;;;;;;;;GASG;AACH,wBAAgB,mBAAmB,CACjC,SAAS,EAAE,WAAW,EACtB,OAAO,EAAE,aAAa,GACrB,MAAM,CAoWR"}
1
+ {"version":3,"file":"server-template.d.ts","sourceRoot":"","sources":["../src/server-template.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAElD,UAAU,aAAa;IACrB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,EAAE,UAAU,GAAG,MAAM,CAAC;CACnC;AAED;;;;;;;;;GASG;AACH,wBAAgB,mBAAmB,CACjC,SAAS,EAAE,WAAW,EACtB,OAAO,EAAE,aAAa,GACrB,MAAM,CA8YR"}
@@ -161,9 +161,19 @@ function __catmintErrorPage(statusCode, detail) {
161
161
  }
162
162
 
163
163
  function collectBody(req) {
164
+ const MAX_BODY_SIZE = ${options.maxBodySize};
164
165
  return new Promise((resolve, reject) => {
165
166
  const chunks = [];
166
- req.on("data", (chunk) => chunks.push(chunk));
167
+ let totalLength = 0;
168
+ req.on("data", (chunk) => {
169
+ totalLength += chunk.length;
170
+ if (totalLength > MAX_BODY_SIZE) {
171
+ req.destroy();
172
+ reject(new Error("Request body too large"));
173
+ return;
174
+ }
175
+ chunks.push(chunk);
176
+ });
167
177
  req.on("end", () => resolve(Buffer.concat(chunks)));
168
178
  req.on("error", reject);
169
179
  });
@@ -190,6 +200,13 @@ async function pipeWebStreamToResponse(webStream, res) {
190
200
  }
191
201
 
192
202
  const server = createServer(async (req, res) => {
203
+ ${options.headerPreset === "baseline"
204
+ ? ` // Baseline security headers
205
+ res.setHeader("X-Content-Type-Options", "nosniff");
206
+ res.setHeader("Referrer-Policy", "strict-origin-when-cross-origin");
207
+ res.setHeader("X-Frame-Options", "SAMEORIGIN");
208
+ `
209
+ : ""}
193
210
  const url = new URL(req.url || "/", \`http://\${HOST}:\${PORT}\`);
194
211
  const pathname = url.pathname;
195
212
  const method = (req.method || "GET").toUpperCase();
@@ -218,6 +235,29 @@ const server = createServer(async (req, res) => {
218
235
  // 3. Handle server function RPC calls (/__catmint/fn/*)
219
236
  if (pathname.startsWith("/__catmint/fn/") && ssrEntry.handleServerFn) {
220
237
  try {
238
+ // Enforce POST method for server function calls
239
+ if (method !== "POST") {
240
+ sendJson(res, 405, { error: "Method " + method + " not allowed, expected POST" });
241
+ return;
242
+ }
243
+
244
+ // Enforce Content-Type: application/json
245
+ const ct = (req.headers["content-type"] || "").toLowerCase();
246
+ if (ct && !ct.startsWith("application/json")) {
247
+ sendJson(res, 415, { error: "Unsupported Content-Type, expected application/json" });
248
+ return;
249
+ }
250
+
251
+ // Validate Origin header to mitigate cross-site invocation
252
+ const origin = req.headers["origin"];
253
+ if (origin) {
254
+ const expected = \`http://\${HOST}:\${PORT}\`;
255
+ if (origin !== expected && origin !== \`https://\${HOST}:\${PORT}\`) {
256
+ sendJson(res, 403, { error: "Origin not allowed" });
257
+ return;
258
+ }
259
+ }
260
+
221
261
  const body = await collectBody(req);
222
262
  let parsed;
223
263
  try {
@@ -1 +1 @@
1
- {"version":3,"file":"server-template.js","sourceRoot":"","sources":["../src/server-template.ts"],"names":[],"mappings":"AAAA,gEAAgE;AAShE;;;;;;;;;GASG;AACH,MAAM,UAAU,mBAAmB,CACjC,SAAsB,EACtB,OAAsB;IAEtB,OAAO;;;;;;;;;;mEAU0D,OAAO,CAAC,IAAI;mCAC5C,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,IAAI,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAuV9D,CAAC;AACF,CAAC"}
1
+ {"version":3,"file":"server-template.js","sourceRoot":"","sources":["../src/server-template.ts"],"names":[],"mappings":"AAAA,gEAAgE;AAWhE;;;;;;;;;GASG;AACH,MAAM,UAAU,mBAAmB,CACjC,SAAsB,EACtB,OAAsB;IAEtB,OAAO;;;;;;;;;;mEAU0D,OAAO,CAAC,IAAI;mCAC5C,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,IAAI,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;0BA4IrC,OAAO,CAAC,WAAW;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAwC3C,OAAO,CAAC,YAAY,KAAK,UAAU;QACjC,CAAC,CAAC;;;;CAIL;QACG,CAAC,CAAC,EACN;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAsMC,CAAC;AACF,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@catmint/adapter-node",
3
- "version": "0.0.0-prealpha.3",
3
+ "version": "0.0.0-prealpha.5",
4
4
  "type": "module",
5
5
  "private": false,
6
6
  "license": "MIT",
@@ -14,7 +14,7 @@
14
14
  }
15
15
  },
16
16
  "dependencies": {
17
- "catmint": "0.0.0-prealpha.3"
17
+ "catmint": "0.0.0-prealpha.5"
18
18
  },
19
19
  "devDependencies": {
20
20
  "typescript": "^5.7.0"