@pi-harness/web-app 0.1.0
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/cordis.patch.yml +12 -0
- package/dist/index.d.ts +12 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +63 -0
- package/dist/index.js.map +1 -0
- package/package.json +22 -0
package/cordis.patch.yml
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
- id: webserver
|
|
2
|
+
name: "@pi-harness/host-webserver"
|
|
3
|
+
config:
|
|
4
|
+
host: 127.0.0.1
|
|
5
|
+
port: 3080
|
|
6
|
+
- id: api
|
|
7
|
+
name: "@pi-harness/api-gateway"
|
|
8
|
+
config: {}
|
|
9
|
+
- id: web-app
|
|
10
|
+
name: "@pi-harness/web-app"
|
|
11
|
+
config:
|
|
12
|
+
staticDir: !!js process.env.PI_HARNESS_WEB_DIST
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { Context } from "@deepseek-ai/cordis";
|
|
2
|
+
import "@pi-harness/host-webserver";
|
|
3
|
+
export interface WebAppConfig {
|
|
4
|
+
readonly staticDir?: string;
|
|
5
|
+
}
|
|
6
|
+
declare const _default: {
|
|
7
|
+
name: string;
|
|
8
|
+
inject: string[];
|
|
9
|
+
apply(context: Context, config: WebAppConfig): void;
|
|
10
|
+
};
|
|
11
|
+
export default _default;
|
|
12
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAC;AAEnD,OAAO,4BAA4B,CAAC;AAEpC,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;CAC7B;;;;mBAuCgB,OAAO,UAAU,YAAY;;AAH9C,wBAsBE"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { createReadStream, existsSync } from "node:fs";
|
|
2
|
+
import { realpath, stat } from "node:fs/promises";
|
|
3
|
+
import { join, resolve } from "node:path";
|
|
4
|
+
import { pipeline } from "node:stream/promises";
|
|
5
|
+
import "@pi-harness/host-webserver";
|
|
6
|
+
const MIME_TYPES = {
|
|
7
|
+
".css": "text/css; charset=utf-8",
|
|
8
|
+
".html": "text/html; charset=utf-8",
|
|
9
|
+
".js": "text/javascript; charset=utf-8",
|
|
10
|
+
".json": "application/json; charset=utf-8",
|
|
11
|
+
".svg": "image/svg+xml",
|
|
12
|
+
};
|
|
13
|
+
function contentType(path) {
|
|
14
|
+
const extension = path.slice(path.lastIndexOf(".")).toLowerCase();
|
|
15
|
+
return MIME_TYPES[extension] ?? "application/octet-stream";
|
|
16
|
+
}
|
|
17
|
+
function safePath(root, pathname) {
|
|
18
|
+
const candidate = resolve(root, "." + pathname);
|
|
19
|
+
const rootWithSlash = root.endsWith("/") ? root : root + "/";
|
|
20
|
+
if (candidate !== root && !candidate.startsWith(rootWithSlash))
|
|
21
|
+
return undefined;
|
|
22
|
+
return candidate;
|
|
23
|
+
}
|
|
24
|
+
async function sendFile(path, response) {
|
|
25
|
+
const info = await stat(path);
|
|
26
|
+
if (!info.isFile())
|
|
27
|
+
throw new Error("Not a file");
|
|
28
|
+
response.writeHead(200, { "content-type": contentType(path), "content-length": info.size, "cache-control": "no-cache" });
|
|
29
|
+
await pipeline(createReadStream(path), response);
|
|
30
|
+
}
|
|
31
|
+
async function sendSafeFile(root, path, response) {
|
|
32
|
+
const [rootReal, pathReal] = await Promise.all([realpath(root), realpath(path)]);
|
|
33
|
+
const rootWithSlash = rootReal.endsWith("/") ? rootReal : rootReal + "/";
|
|
34
|
+
if (pathReal !== rootReal && !pathReal.startsWith(rootWithSlash))
|
|
35
|
+
throw new Error("Static file escapes web root");
|
|
36
|
+
await sendFile(pathReal, response);
|
|
37
|
+
}
|
|
38
|
+
export default {
|
|
39
|
+
name: "pi-web-app",
|
|
40
|
+
inject: ["webServer"],
|
|
41
|
+
apply(context, config) {
|
|
42
|
+
const root = resolve(config.staticDir ?? "dist");
|
|
43
|
+
if (!existsSync(root))
|
|
44
|
+
throw new Error("Web frontend dist does not exist: " + root);
|
|
45
|
+
const dispose = context.webServer.registerFallback(async (request, response) => {
|
|
46
|
+
const requestPath = new URL(request.url ?? "/", context.webServer.url).pathname;
|
|
47
|
+
const requested = safePath(root, requestPath);
|
|
48
|
+
const index = join(root, "index.html");
|
|
49
|
+
if (requested !== undefined) {
|
|
50
|
+
try {
|
|
51
|
+
await sendSafeFile(root, requested, response);
|
|
52
|
+
return;
|
|
53
|
+
}
|
|
54
|
+
catch {
|
|
55
|
+
// SPA fallback below.
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
await sendSafeFile(root, index, response);
|
|
59
|
+
});
|
|
60
|
+
context.effect(() => dispose);
|
|
61
|
+
},
|
|
62
|
+
};
|
|
63
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/package.json
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@pi-harness/web-app",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Patchable Web application bundle for Pi Harness",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "./dist/index.js",
|
|
7
|
+
"types": "./dist/index.d.ts",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"types": "./dist/index.d.ts",
|
|
11
|
+
"import": "./dist/index.js"
|
|
12
|
+
},
|
|
13
|
+
"./cordis.patch.yml": "./cordis.patch.yml"
|
|
14
|
+
},
|
|
15
|
+
"files": ["dist", "cordis.patch.yml"],
|
|
16
|
+
"engines": {"node": ">=22.19.0"},
|
|
17
|
+
"scripts": {"build": "tsc -p tsconfig.build.json", "typecheck": "tsc -p tsconfig.json"},
|
|
18
|
+
"dependencies": {
|
|
19
|
+
"@deepseek-ai/cordis": "4.0.1",
|
|
20
|
+
"@pi-harness/host-webserver": "0.1.0"
|
|
21
|
+
}
|
|
22
|
+
}
|