@stacksjs/stx 0.2.138 → 0.2.139

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.
@@ -24,6 +24,7 @@ import {
24
24
  } from "../route-middleware.js";
25
25
  import { getPageMeta, resetHead } from "../head.js";
26
26
  import { clearComponentCache } from "../utils.js";
27
+ import { extractPageResponseStatus } from "../page-response.js";
27
28
  import {
28
29
  buildCrosswindCSS,
29
30
  colors,
@@ -34,6 +35,13 @@ import {
34
35
  rebuildCrosswindCSS,
35
36
  setupKeyboardShortcuts
36
37
  } from "./index.js";
38
+ async function readPageResponseStatus(filePath) {
39
+ try {
40
+ return extractPageResponseStatus(await Bun.file(filePath).text());
41
+ } catch {
42
+ return;
43
+ }
44
+ }
37
45
  function serveStaticFile(filePath) {
38
46
  const file = Bun.file(filePath), ext = path.extname(filePath).toLowerCase(), contentTypes = {
39
47
  ".html": "text/html",
@@ -207,7 +215,7 @@ export async function serveApp(appDir = ".", options = {}) {
207
215
  let output = memEntry.output;
208
216
  if (shell)
209
217
  output = stripDocumentWrapper(output, { preserveHead: !0 });
210
- return { route, content: output };
218
+ return { route, content: output, status: await readPageResponseStatus(route.filePath) };
211
219
  }
212
220
  }
213
221
  } catch {}
@@ -216,10 +224,10 @@ export async function serveApp(appDir = ".", options = {}) {
216
224
  let output = cached;
217
225
  if (shell)
218
226
  output = stripDocumentWrapper(output, { preserveHead: !0 });
219
- return { route, content: output };
227
+ return { route, content: output, status: await readPageResponseStatus(route.filePath) };
220
228
  }
221
229
  }
222
- const content = cacheEnabled ? await readFileCached(route.filePath) : await Bun.file(route.filePath).text(), { classifyAllScripts } = await import("../index.js"), classified = classifyAllScripts(content), serverScripts = classified.server.map((s) => s.content);
230
+ const content = cacheEnabled ? await readFileCached(route.filePath) : await Bun.file(route.filePath).text(), responseStatus = extractPageResponseStatus(content), { classifyAllScripts } = await import("../index.js"), classified = classifyAllScripts(content), serverScripts = classified.server.map((s) => s.content);
223
231
  let templateContent = content;
224
232
  for (const s of classified.server)
225
233
  templateContent = templateContent.replace(s.fullTag, "");
@@ -276,7 +284,7 @@ export async function serveApp(appDir = ".", options = {}) {
276
284
  streamingRoutes.add(route.pattern);
277
285
  else
278
286
  boundaries = void 0;
279
- return { route, content: output, boundaries };
287
+ return { route, content: output, status: responseStatus, boundaries };
280
288
  } catch (error) {
281
289
  console.error(`${colors.red}Error building ${colors.bright}${route.pattern}${colors.reset}:`, error);
282
290
  return null;
@@ -384,7 +392,7 @@ export async function serveApp(appDir = ".", options = {}) {
384
392
  builtPage = rebuilt;
385
393
  }
386
394
  if (builtPage) {
387
- const pageMeta = getPageMeta();
395
+ const responseStatus = builtPage.status ?? 200, pageMeta = getPageMeta();
388
396
  if (pageMeta.validate) {
389
397
  if (!await pageMeta.validate({ params: routeMatch.params })) {
390
398
  const custom404 = await renderErrorPage(404);
@@ -432,6 +440,7 @@ export async function serveApp(appDir = ".", options = {}) {
432
440
  const routerContainer = projectConfig?.router?.container || "main";
433
441
  content = extractContainerContent(content, routerContainer);
434
442
  return new Response(content, {
443
+ status: responseStatus,
435
444
  headers: {
436
445
  "Content-Type": "text/html",
437
446
  "X-STX-Fragment": "true",
@@ -466,6 +475,7 @@ export async function serveApp(appDir = ".", options = {}) {
466
475
  if (builtPage.boundaries && builtPage.boundaries.length > 0) {
467
476
  const { renderStreamingPage, streamToResponse } = await import("../streaming.js");
468
477
  return streamToResponse(renderStreamingPage(content, builtPage.boundaries, { timeoutMs: 30000 }), {
478
+ status: responseStatus,
469
479
  headers: {
470
480
  "Cache-Control": "no-store, no-cache, must-revalidate",
471
481
  Pragma: "no-cache",
@@ -474,6 +484,7 @@ export async function serveApp(appDir = ".", options = {}) {
474
484
  });
475
485
  }
476
486
  return new Response(content, {
487
+ status: responseStatus,
477
488
  headers: {
478
489
  "Content-Type": "text/html",
479
490
  "Cache-Control": "no-store, no-cache, must-revalidate",
@@ -497,6 +508,7 @@ export async function serveApp(appDir = ".", options = {}) {
497
508
  if (hotReload)
498
509
  content = injectHotReload(content, actualHmrPort);
499
510
  return new Response(content, {
511
+ status: builtPage.status ?? 200,
500
512
  headers: {
501
513
  "Content-Type": "text/html",
502
514
  "Cache-Control": "no-store, no-cache, must-revalidate",
package/dist/head.d.ts CHANGED
@@ -223,6 +223,7 @@ export declare interface SeoMeta {
223
223
  export declare interface PageMeta {
224
224
  title?: string
225
225
  description?: string
226
+ status?: number
226
227
  layout?: string | false
227
228
  middleware?: string | string[]
228
229
  transition?: string | { name: string; mode?: string }
package/dist/index.d.ts CHANGED
@@ -44,6 +44,7 @@ export { preloadIconCollection } from './builtins/index';
44
44
  // Core functionality - these are the primary modules
45
45
  export * from './reactivity';
46
46
  export * from './head';
47
+ export * from './page-response';
47
48
  export * from './route-middleware';
48
49
  export * from './runtime';
49
50
  export * from './forms';
package/dist/index.js CHANGED
@@ -4,6 +4,7 @@ export { fileExists } from "./utils.js";
4
4
  export { preloadIconCollection } from "./builtins/index.js";
5
5
  export * from "./reactivity.js";
6
6
  export * from "./head.js";
7
+ export * from "./page-response.js";
7
8
  export * from "./route-middleware.js";
8
9
  export * from "./runtime.js";
9
10
  export * from "./forms.js";
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Read the static HTTP status declared by `definePageMeta`.
3
+ *
4
+ * The development server needs this before client scripts execute so error
5
+ * pages and other non-200 documents carry the correct response semantics.
6
+ */
7
+ export declare function extractPageResponseStatus(source: string): number | undefined;
@@ -0,0 +1,12 @@
1
+ const MIN_HTTP_STATUS = 100, MAX_HTTP_STATUS = 599;
2
+ export function extractPageResponseStatus(source) {
3
+ for (const call of source.matchAll(/\bdefinePageMeta\s*\(\s*\{([\s\S]*?)\}\s*\)/g)) {
4
+ const match = call[1].match(/(?:^|,)\s*status\s*:\s*(\d{3})(?=\s*(?:,|$))/);
5
+ if (!match)
6
+ continue;
7
+ const status = Number(match[1]);
8
+ if (Number.isInteger(status) && status >= MIN_HTTP_STATUS && status <= MAX_HTTP_STATUS)
9
+ return status;
10
+ }
11
+ return;
12
+ }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@stacksjs/stx",
3
3
  "type": "module",
4
- "version": "0.2.138",
4
+ "version": "0.2.139",
5
5
  "description": "A performant UI Framework. Powered by Bun.",
6
6
  "author": "Chris Breuer <chris@stacksjs.org>",
7
7
  "license": "MIT",
@@ -117,12 +117,12 @@
117
117
  "dependencies": {
118
118
  "@cwcss/crosswind": "^0.2.12",
119
119
  "@stacksjs/clapp": "^0.2.0",
120
- "@stacksjs/desktop": "0.2.138",
121
- "@stacksjs/sanitizer": "0.2.138",
120
+ "@stacksjs/desktop": "0.2.139",
121
+ "@stacksjs/sanitizer": "0.2.139",
122
122
  "@stacksjs/ts-i18n": "^0.1.11",
123
- "bun-plugin-stx": "0.2.138",
123
+ "bun-plugin-stx": "0.2.139",
124
124
  "bunfig": "^0.15.15",
125
- "stx-router": "0.2.138",
125
+ "stx-router": "0.2.139",
126
126
  "ts-broadcasting": "^0.0.9",
127
127
  "ts-images": "^0.1.9",
128
128
  "ts-syntax-highlighter": "^0.2.1"