@panaversity/ksor 0.0.44 → 0.0.45

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.
@@ -6,6 +6,7 @@
6
6
  "scripts": {
7
7
  "dev": "pnpm -C system/site dev",
8
8
  "build": "ksor build && pnpm -C system/site build",
9
+ "preview": "node system/site/preview.mjs",
9
10
  "check": "node .agents/skills/format-checker/check.mjs",
10
11
  "provision": "pnpm schema && pnpm grant",
11
12
  "serve": "ksor serve",
@@ -0,0 +1,93 @@
1
+ /**
2
+ * Serve the STATIC EXPORT, so the build has somewhere to land.
3
+ *
4
+ * The site is `output: "export"` — there is no server to start, which is what
5
+ * makes the record hostable anywhere. But it also means the `start` script
6
+ * every other project has does not exist here, and running one is the first
7
+ * instinct after a build; the package manager then reports a missing script,
8
+ * which explains nothing about why there is nothing to start.
9
+ *
10
+ * So this is the answer to "and now how do I look at it". It is node:http and
11
+ * nothing else — no dependency to install and no network fetch, so it works
12
+ * offline and behind a firewall, for the same reason the build itself
13
+ * downloads nothing.
14
+ *
15
+ * Names no package manager on purpose: this file ships in the npm and bun
16
+ * scaffolds too, and those must not carry another manager's vocabulary
17
+ * (asserted by `init-manager.integration.test.ts`).
18
+ *
19
+ * It is a PREVIEW, not a deployment: single process, no compression, no
20
+ * caching headers. Put the directory behind a real web server or a static
21
+ * host for anything else.
22
+ */
23
+ import { createReadStream, statSync } from "node:fs";
24
+ import { createServer } from "node:http";
25
+ import path from "node:path";
26
+ import process from "node:process";
27
+
28
+ const ROOT = path.resolve(import.meta.dirname, "out");
29
+ const PORT = Number(process.env.PORT ?? 3000);
30
+
31
+ const TYPES = new Map([
32
+ [".html", "text/html; charset=utf-8"],
33
+ [".md", "text/markdown; charset=utf-8"],
34
+ [".txt", "text/plain; charset=utf-8"],
35
+ [".json", "application/json; charset=utf-8"],
36
+ [".js", "text/javascript; charset=utf-8"],
37
+ [".css", "text/css; charset=utf-8"],
38
+ [".svg", "image/svg+xml"],
39
+ [".png", "image/png"],
40
+ [".jpg", "image/jpeg"],
41
+ [".webp", "image/webp"],
42
+ [".ico", "image/x-icon"],
43
+ [".woff2", "font/woff2"],
44
+ ]);
45
+
46
+ try {
47
+ statSync(ROOT);
48
+ } catch {
49
+ console.error(`preview: ${ROOT} does not exist — run the build first.`);
50
+ process.exit(3);
51
+ }
52
+
53
+ /** The file a request resolves to, or null when it escapes the export. */
54
+ function resolve(urlPath) {
55
+ const decoded = decodeURIComponent(urlPath.split("?")[0]);
56
+ // Contain every request inside the export: a `..` that resolves outside it
57
+ // is refused rather than served, even in a preview.
58
+ const target = path.resolve(ROOT, `.${decoded}`);
59
+ if (target !== ROOT && !target.startsWith(ROOT + path.sep)) return null;
60
+
61
+ for (const candidate of [target, path.join(target, "index.html"), `${target}.html`]) {
62
+ try {
63
+ if (statSync(candidate).isFile()) return candidate;
64
+ } catch {
65
+ // Try the next shape.
66
+ }
67
+ }
68
+ return null;
69
+ }
70
+
71
+ createServer((req, res) => {
72
+ const file = resolve(req.url ?? "/");
73
+ if (file === null) {
74
+ const notFound = path.join(ROOT, "404.html");
75
+ try {
76
+ statSync(notFound);
77
+ res.writeHead(404, { "content-type": "text/html; charset=utf-8" });
78
+ createReadStream(notFound).pipe(res);
79
+ return;
80
+ } catch {
81
+ res.writeHead(404, { "content-type": "text/plain; charset=utf-8" });
82
+ res.end("404\n");
83
+ return;
84
+ }
85
+ }
86
+ res.writeHead(200, {
87
+ "content-type": TYPES.get(path.extname(file)) ?? "application/octet-stream",
88
+ });
89
+ createReadStream(file).pipe(res);
90
+ }).listen(PORT, () => {
91
+ console.log(`preview: serving ${path.relative(process.cwd(), ROOT)} on http://localhost:${PORT}`);
92
+ console.log(" this is the STATIC EXPORT — the same bytes a host would serve.");
93
+ });