@catmint/adapter-node 0.0.0-prealpha.6 → 0.0.0-prealpha.8
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.
|
@@ -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;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,
|
|
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,CA+fR"}
|
package/dist/server-template.js
CHANGED
|
@@ -19,6 +19,7 @@ import { fileURLToPath } from "node:url";
|
|
|
19
19
|
const __dirname = fileURLToPath(new URL(".", import.meta.url));
|
|
20
20
|
const CLIENT_DIR = resolve(__dirname, "../client");
|
|
21
21
|
const STATIC_DIR = resolve(__dirname, "../static");
|
|
22
|
+
const PRERENDERED_DIR = resolve(__dirname, "../prerendered");
|
|
22
23
|
|
|
23
24
|
const PORT = process.env.PORT ? parseInt(process.env.PORT, 10) : ${options.port};
|
|
24
25
|
const HOST = process.env.HOST ?? ${JSON.stringify(options.host)};
|
|
@@ -199,6 +200,28 @@ async function pipeWebStreamToResponse(webStream, res) {
|
|
|
199
200
|
}
|
|
200
201
|
}
|
|
201
202
|
|
|
203
|
+
function nodeReqToWebRequest(req) {
|
|
204
|
+
const protocol = "http";
|
|
205
|
+
const host = req.headers.host || \`\${HOST}:\${PORT}\`;
|
|
206
|
+
const reqUrl = new URL(req.url || "/", \`\${protocol}://\${host}\`);
|
|
207
|
+
const headers = new Headers();
|
|
208
|
+
for (const [key, value] of Object.entries(req.headers)) {
|
|
209
|
+
if (value) {
|
|
210
|
+
if (Array.isArray(value)) {
|
|
211
|
+
for (const v of value) {
|
|
212
|
+
headers.append(key, v);
|
|
213
|
+
}
|
|
214
|
+
} else {
|
|
215
|
+
headers.set(key, value);
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
return new Request(reqUrl.href, {
|
|
220
|
+
method: req.method || "GET",
|
|
221
|
+
headers,
|
|
222
|
+
});
|
|
223
|
+
}
|
|
224
|
+
|
|
202
225
|
const server = createServer(async (req, res) => {
|
|
203
226
|
${options.headerPreset === "baseline"
|
|
204
227
|
? ` // Baseline security headers
|
|
@@ -212,8 +235,17 @@ ${options.headerPreset === "baseline"
|
|
|
212
235
|
const method = (req.method || "GET").toUpperCase();
|
|
213
236
|
|
|
214
237
|
try {
|
|
215
|
-
// 1. Serve
|
|
238
|
+
// 1. Serve client assets from dist/client/ (immutable for hashed assets)
|
|
239
|
+
// These have hashed filenames and never conflict with app routes.
|
|
216
240
|
{
|
|
241
|
+
const filePath = join(CLIENT_DIR, pathname);
|
|
242
|
+
const served = await serveStaticFile(res, filePath, pathname.includes("/assets/"));
|
|
243
|
+
if (served) return;
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
// 2. Pre-rendered static pages WITHOUT middleware: serve directly from
|
|
247
|
+
// dist/static/ as a fast path — no middleware execution needed.
|
|
248
|
+
if (method === "GET") {
|
|
217
249
|
let staticPath = pathname;
|
|
218
250
|
if (!extname(staticPath)) {
|
|
219
251
|
staticPath = staticPath.endsWith("/")
|
|
@@ -225,14 +257,54 @@ ${options.headerPreset === "baseline"
|
|
|
225
257
|
if (served) return;
|
|
226
258
|
}
|
|
227
259
|
|
|
228
|
-
//
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
260
|
+
// 3. Middleware execution — runs for all remaining routes (server functions,
|
|
261
|
+
// endpoints, prerendered pages with middleware, RSC-rendered pages).
|
|
262
|
+
// For RSC flight requests, run middleware against the TARGET page path
|
|
263
|
+
// (from ?path= query param), not the literal /__catmint/rsc pathname.
|
|
264
|
+
var middlewareHeaders = null;
|
|
265
|
+
if (ssrEntry.executeMiddleware) {
|
|
266
|
+
try {
|
|
267
|
+
var middlewarePath = pathname;
|
|
268
|
+
if (pathname === "/__catmint/rsc") {
|
|
269
|
+
var rscTargetPath = url.searchParams.get("path");
|
|
270
|
+
if (rscTargetPath) middlewarePath = rscTargetPath;
|
|
271
|
+
}
|
|
272
|
+
var webRequest = nodeReqToWebRequest(req);
|
|
273
|
+
var mwResult = await ssrEntry.executeMiddleware(middlewarePath, webRequest);
|
|
274
|
+
|
|
275
|
+
if (mwResult.shortCircuit) {
|
|
276
|
+
// Middleware short-circuited — return its response directly
|
|
277
|
+
res.writeHead(mwResult.shortCircuit.status,
|
|
278
|
+
Object.fromEntries(mwResult.shortCircuit.headers));
|
|
279
|
+
var scBody = await mwResult.shortCircuit.text();
|
|
280
|
+
res.end(scBody);
|
|
281
|
+
return;
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
// Middleware passed — capture headers to merge into final response
|
|
285
|
+
if (mwResult.headers && typeof mwResult.headers.forEach === "function") {
|
|
286
|
+
middlewareHeaders = mwResult.headers;
|
|
287
|
+
}
|
|
288
|
+
} catch (err) {
|
|
289
|
+
console.error("Middleware error:", err);
|
|
290
|
+
if (!res.headersSent) {
|
|
291
|
+
res.writeHead(500);
|
|
292
|
+
res.end("Internal Server Error");
|
|
293
|
+
}
|
|
294
|
+
return;
|
|
295
|
+
}
|
|
233
296
|
}
|
|
234
297
|
|
|
235
|
-
//
|
|
298
|
+
// Helper: merge middleware headers into the response before sending.
|
|
299
|
+
function applyMiddlewareHeaders() {
|
|
300
|
+
if (middlewareHeaders) {
|
|
301
|
+
middlewareHeaders.forEach(function(value, key) {
|
|
302
|
+
res.setHeader(key, value);
|
|
303
|
+
});
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
// 4. Handle server function RPC calls (/__catmint/fn/*)
|
|
236
308
|
if (pathname.startsWith("/__catmint/fn/") && ssrEntry.handleServerFn) {
|
|
237
309
|
try {
|
|
238
310
|
// Enforce POST method for server function calls
|
|
@@ -268,6 +340,7 @@ ${options.headerPreset === "baseline"
|
|
|
268
340
|
}
|
|
269
341
|
const result = await ssrEntry.handleServerFn(pathname, parsed);
|
|
270
342
|
if (result) {
|
|
343
|
+
applyMiddlewareHeaders();
|
|
271
344
|
sendJson(res, 200, result.result);
|
|
272
345
|
return;
|
|
273
346
|
}
|
|
@@ -279,7 +352,7 @@ ${options.headerPreset === "baseline"
|
|
|
279
352
|
return;
|
|
280
353
|
}
|
|
281
354
|
|
|
282
|
-
//
|
|
355
|
+
// 5. RSC flight stream for client-side navigation (/__catmint/rsc?path=...)
|
|
283
356
|
if (pathname === "/__catmint/rsc" && method === "GET" && rscEntry.render) {
|
|
284
357
|
const targetPath = url.searchParams.get("path");
|
|
285
358
|
if (!targetPath) {
|
|
@@ -291,6 +364,7 @@ ${options.headerPreset === "baseline"
|
|
|
291
364
|
try {
|
|
292
365
|
const rscResult = await rscEntry.render(targetPath);
|
|
293
366
|
if (rscResult) {
|
|
367
|
+
applyMiddlewareHeaders();
|
|
294
368
|
res.writeHead(200, {
|
|
295
369
|
"Content-Type": "text/x-component; charset=utf-8",
|
|
296
370
|
"Cache-Control": "no-cache, no-store, must-revalidate",
|
|
@@ -312,7 +386,7 @@ ${options.headerPreset === "baseline"
|
|
|
312
386
|
return;
|
|
313
387
|
}
|
|
314
388
|
|
|
315
|
-
//
|
|
389
|
+
// 6. API endpoint handling
|
|
316
390
|
if (ssrEntry.hasEndpoint && ssrEntry.hasEndpoint(pathname)) {
|
|
317
391
|
try {
|
|
318
392
|
const protocol = "http";
|
|
@@ -335,7 +409,10 @@ ${options.headerPreset === "baseline"
|
|
|
335
409
|
const result = await ssrEntry.handleEndpoint(pathname, method, webRequest);
|
|
336
410
|
|
|
337
411
|
if (result) {
|
|
338
|
-
|
|
412
|
+
// Copy response headers then merge middleware headers
|
|
413
|
+
var epHeaders = Object.fromEntries(result.response.headers);
|
|
414
|
+
res.writeHead(result.response.status, epHeaders);
|
|
415
|
+
applyMiddlewareHeaders();
|
|
339
416
|
if (result.response.body) {
|
|
340
417
|
await pipeWebStreamToResponse(result.response.body, res);
|
|
341
418
|
} else {
|
|
@@ -357,12 +434,41 @@ ${options.headerPreset === "baseline"
|
|
|
357
434
|
}
|
|
358
435
|
}
|
|
359
436
|
|
|
360
|
-
//
|
|
437
|
+
// 7. Pre-rendered pages WITH middleware: serve from dist/prerendered/
|
|
438
|
+
// These are static routes that have middleware ancestors — their HTML
|
|
439
|
+
// was pre-rendered but they must go through the middleware pipeline.
|
|
440
|
+
if (method === "GET") {
|
|
441
|
+
let prerenderedPath = pathname;
|
|
442
|
+
if (!extname(prerenderedPath)) {
|
|
443
|
+
prerenderedPath = prerenderedPath.endsWith("/")
|
|
444
|
+
? prerenderedPath + "index.html"
|
|
445
|
+
: prerenderedPath + ".html";
|
|
446
|
+
}
|
|
447
|
+
try {
|
|
448
|
+
const prFilePath = join(PRERENDERED_DIR, prerenderedPath);
|
|
449
|
+
const prStats = await stat(prFilePath);
|
|
450
|
+
if (prStats.isFile()) {
|
|
451
|
+
const content = await readFile(prFilePath);
|
|
452
|
+
applyMiddlewareHeaders();
|
|
453
|
+
res.setHeader("Content-Type", "text/html; charset=utf-8");
|
|
454
|
+
res.setHeader("Content-Length", content.byteLength);
|
|
455
|
+
res.setHeader("Cache-Control", "public, max-age=0, must-revalidate");
|
|
456
|
+
res.writeHead(200);
|
|
457
|
+
res.end(content);
|
|
458
|
+
return;
|
|
459
|
+
}
|
|
460
|
+
} catch {
|
|
461
|
+
// No prerendered file — continue to RSC rendering
|
|
462
|
+
}
|
|
463
|
+
}
|
|
464
|
+
|
|
465
|
+
// 8. RSC → SSR page rendering pipeline
|
|
361
466
|
if (method === "GET" && rscEntry.render) {
|
|
362
467
|
try {
|
|
363
468
|
const rscResult = await rscEntry.render(pathname);
|
|
364
469
|
if (rscResult) {
|
|
365
470
|
const htmlStream = await ssrEntry.renderToHtml(rscResult.stream, rscResult.headConfig);
|
|
471
|
+
applyMiddlewareHeaders();
|
|
366
472
|
res.writeHead(200, { "Content-Type": "text/html; charset=utf-8" });
|
|
367
473
|
await pipeWebStreamToResponse(htmlStream, res);
|
|
368
474
|
return;
|
|
@@ -376,7 +482,14 @@ ${options.headerPreset === "baseline"
|
|
|
376
482
|
}
|
|
377
483
|
}
|
|
378
484
|
|
|
379
|
-
//
|
|
485
|
+
// 9. Static assets fallback (dist/static/ for public files like favicon, etc.)
|
|
486
|
+
{
|
|
487
|
+
const filePath = join(STATIC_DIR, pathname);
|
|
488
|
+
const served = await serveStaticFile(res, filePath, false);
|
|
489
|
+
if (served) return;
|
|
490
|
+
}
|
|
491
|
+
|
|
492
|
+
// 10. 404
|
|
380
493
|
await sendStatusPage(res, 404, pathname);
|
|
381
494
|
} catch (err) {
|
|
382
495
|
console.error("Request error:", err);
|
|
@@ -1 +1 @@
|
|
|
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
|
|
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;;;;;;;;;;;mEAW0D,OAAO,CAAC,IAAI;mCAC5C,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,IAAI,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;0BA4IrC,OAAO,CAAC,WAAW;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EA8D3C,OAAO,CAAC,YAAY,KAAK,UAAU;QACjC,CAAC,CAAC;;;;CAIL;QACG,CAAC,CAAC,EACN;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAgSC,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
|
+
"version": "0.0.0-prealpha.8",
|
|
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.
|
|
17
|
+
"catmint": "0.0.0-prealpha.8"
|
|
18
18
|
},
|
|
19
19
|
"devDependencies": {
|
|
20
20
|
"typescript": "^5.7.0"
|