@agentsean/daemon 1.0.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.
Files changed (82) hide show
  1. package/LICENSE +661 -0
  2. package/dist/action-routes.d.ts +10 -0
  3. package/dist/action-routes.d.ts.map +1 -0
  4. package/dist/action-routes.js +303 -0
  5. package/dist/action-routes.js.map +1 -0
  6. package/dist/activity-page.d.ts +2 -0
  7. package/dist/activity-page.d.ts.map +1 -0
  8. package/dist/activity-page.js +115 -0
  9. package/dist/activity-page.js.map +1 -0
  10. package/dist/bind.d.ts +12 -0
  11. package/dist/bind.d.ts.map +1 -0
  12. package/dist/bind.js +62 -0
  13. package/dist/bind.js.map +1 -0
  14. package/dist/boot.d.ts +15 -0
  15. package/dist/boot.d.ts.map +1 -0
  16. package/dist/boot.js +113 -0
  17. package/dist/boot.js.map +1 -0
  18. package/dist/connect-page.d.ts +2 -0
  19. package/dist/connect-page.d.ts.map +1 -0
  20. package/dist/connect-page.js +170 -0
  21. package/dist/connect-page.js.map +1 -0
  22. package/dist/dashboard-routes.d.ts +16 -0
  23. package/dist/dashboard-routes.d.ts.map +1 -0
  24. package/dist/dashboard-routes.js +1059 -0
  25. package/dist/dashboard-routes.js.map +1 -0
  26. package/dist/events.d.ts +6 -0
  27. package/dist/events.d.ts.map +1 -0
  28. package/dist/events.js +16 -0
  29. package/dist/events.js.map +1 -0
  30. package/dist/google-routes.d.ts +13 -0
  31. package/dist/google-routes.d.ts.map +1 -0
  32. package/dist/google-routes.js +297 -0
  33. package/dist/google-routes.js.map +1 -0
  34. package/dist/hosted-routes.d.ts +7 -0
  35. package/dist/hosted-routes.d.ts.map +1 -0
  36. package/dist/hosted-routes.js +88 -0
  37. package/dist/hosted-routes.js.map +1 -0
  38. package/dist/index.d.ts +10 -0
  39. package/dist/index.d.ts.map +1 -0
  40. package/dist/index.js +10 -0
  41. package/dist/index.js.map +1 -0
  42. package/dist/main.d.ts +3 -0
  43. package/dist/main.d.ts.map +1 -0
  44. package/dist/main.js +25 -0
  45. package/dist/main.js.map +1 -0
  46. package/dist/paths.d.ts +13 -0
  47. package/dist/paths.d.ts.map +1 -0
  48. package/dist/paths.js +49 -0
  49. package/dist/paths.js.map +1 -0
  50. package/dist/pdf.d.ts +3 -0
  51. package/dist/pdf.d.ts.map +1 -0
  52. package/dist/pdf.js +51 -0
  53. package/dist/pdf.js.map +1 -0
  54. package/dist/pid.d.ts +11 -0
  55. package/dist/pid.d.ts.map +1 -0
  56. package/dist/pid.js +38 -0
  57. package/dist/pid.js.map +1 -0
  58. package/dist/security.d.ts +14 -0
  59. package/dist/security.d.ts.map +1 -0
  60. package/dist/security.js +93 -0
  61. package/dist/security.js.map +1 -0
  62. package/dist/server.d.ts +25 -0
  63. package/dist/server.d.ts.map +1 -0
  64. package/dist/server.js +84 -0
  65. package/dist/server.js.map +1 -0
  66. package/dist/settings.d.ts +5 -0
  67. package/dist/settings.d.ts.map +1 -0
  68. package/dist/settings.js +25 -0
  69. package/dist/settings.js.map +1 -0
  70. package/dist/spa.d.ts +4 -0
  71. package/dist/spa.d.ts.map +1 -0
  72. package/dist/spa.js +95 -0
  73. package/dist/spa.js.map +1 -0
  74. package/dist/token.d.ts +6 -0
  75. package/dist/token.d.ts.map +1 -0
  76. package/dist/token.js +35 -0
  77. package/dist/token.js.map +1 -0
  78. package/dist/version.d.ts +2 -0
  79. package/dist/version.d.ts.map +1 -0
  80. package/dist/version.js +2 -0
  81. package/dist/version.js.map +1 -0
  82. package/package.json +81 -0
package/dist/main.js ADDED
@@ -0,0 +1,25 @@
1
+ #!/usr/bin/env node
2
+ import { startDaemon } from "./boot.js";
3
+ import { DEFAULT_HOST, DEFAULT_PORT, defaultSeanHome } from "./paths.js";
4
+ function arg(name) {
5
+ const idx = process.argv.indexOf(`--${name}`);
6
+ if (idx === -1)
7
+ return undefined;
8
+ return process.argv[idx + 1];
9
+ }
10
+ const host = arg("host") ?? process.env["SEAN_HOST"] ?? DEFAULT_HOST;
11
+ const portRaw = arg("port") ?? process.env["SEAN_PORT"];
12
+ const port = portRaw ? Number(portRaw) : DEFAULT_PORT;
13
+ const seanHome = arg("home") ?? defaultSeanHome();
14
+ if (!Number.isInteger(port) || port < 1 || port > 65535) {
15
+ process.stderr.write(`invalid port: ${portRaw}\n`);
16
+ process.exit(2);
17
+ }
18
+ const running = await startDaemon({ host, port, seanHome });
19
+ process.stdout.write(JSON.stringify({
20
+ ok: true,
21
+ host: running.host,
22
+ port: running.port,
23
+ pid: running.pid,
24
+ }) + "\n");
25
+ //# sourceMappingURL=main.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"main.js","sourceRoot":"","sources":["../src/main.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AACxC,OAAO,EAAE,YAAY,EAAE,YAAY,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAEzE,SAAS,GAAG,CAAC,IAAY;IACvB,MAAM,GAAG,GAAG,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,KAAK,IAAI,EAAE,CAAC,CAAC;IAC9C,IAAI,GAAG,KAAK,CAAC,CAAC;QAAE,OAAO,SAAS,CAAC;IACjC,OAAO,OAAO,CAAC,IAAI,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC;AAC/B,CAAC;AAED,MAAM,IAAI,GAAG,GAAG,CAAC,MAAM,CAAC,IAAI,OAAO,CAAC,GAAG,CAAC,WAAW,CAAC,IAAI,YAAY,CAAC;AACrE,MAAM,OAAO,GAAG,GAAG,CAAC,MAAM,CAAC,IAAI,OAAO,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC;AACxD,MAAM,IAAI,GAAG,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,YAAY,CAAC;AACtD,MAAM,QAAQ,GAAG,GAAG,CAAC,MAAM,CAAC,IAAI,eAAe,EAAE,CAAC;AAElD,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,IAAI,GAAG,CAAC,IAAI,IAAI,GAAG,KAAK,EAAE,CAAC;IACxD,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,iBAAiB,OAAO,IAAI,CAAC,CAAC;IACnD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC;AAED,MAAM,OAAO,GAAG,MAAM,WAAW,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAC,CAAC;AAC5D,OAAO,CAAC,MAAM,CAAC,KAAK,CAClB,IAAI,CAAC,SAAS,CAAC;IACb,EAAE,EAAE,IAAI;IACR,IAAI,EAAE,OAAO,CAAC,IAAI;IAClB,IAAI,EAAE,OAAO,CAAC,IAAI;IAClB,GAAG,EAAE,OAAO,CAAC,GAAG;CACjB,CAAC,GAAG,IAAI,CACV,CAAC"}
@@ -0,0 +1,13 @@
1
+ export declare const DEFAULT_HOST = "127.0.0.1";
2
+ export declare const DEFAULT_PORT = 7777;
3
+ export declare const TOKEN_ACCOUNT = "daemon-auth-token";
4
+ export declare const HALT_FILENAME = "HALT";
5
+ export declare function defaultSeanHome(): string;
6
+ export declare function ensureSeanHome(home: string): string;
7
+ export declare function pidPath(home: string): string;
8
+ export declare function logPath(home: string): string;
9
+ export declare function dbPath(home: string): string;
10
+ export declare function haltPath(home: string): string;
11
+ export declare function isHalted(home: string): boolean;
12
+ export declare function setHalted(home: string, halted: boolean): void;
13
+ //# sourceMappingURL=paths.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"paths.d.ts","sourceRoot":"","sources":["../src/paths.ts"],"names":[],"mappings":"AAIA,eAAO,MAAM,YAAY,cAAc,CAAC;AACxC,eAAO,MAAM,YAAY,OAAO,CAAC;AACjC,eAAO,MAAM,aAAa,sBAAsB,CAAC;AACjD,eAAO,MAAM,aAAa,SAAS,CAAC;AAEpC,wBAAgB,eAAe,IAAI,MAAM,CAExC;AAED,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAUnD;AAED,wBAAgB,OAAO,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAE5C;AAED,wBAAgB,OAAO,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAE5C;AAED,wBAAgB,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAE3C;AAED,wBAAgB,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAE7C;AAED,wBAAgB,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAG9C;AAED,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,GAAG,IAAI,CAO7D"}
package/dist/paths.js ADDED
@@ -0,0 +1,49 @@
1
+ import fs from "node:fs";
2
+ import os from "node:os";
3
+ import path from "node:path";
4
+ export const DEFAULT_HOST = "127.0.0.1";
5
+ export const DEFAULT_PORT = 7777;
6
+ export const TOKEN_ACCOUNT = "daemon-auth-token";
7
+ export const HALT_FILENAME = "HALT";
8
+ export function defaultSeanHome() {
9
+ return process.env["SEAN_HOME"]?.trim() || path.join(os.homedir(), ".sean");
10
+ }
11
+ export function ensureSeanHome(home) {
12
+ fs.mkdirSync(home, { recursive: true, mode: 0o700 });
13
+ if (process.platform !== "win32") {
14
+ try {
15
+ fs.chmodSync(home, 0o700);
16
+ }
17
+ catch {
18
+ // best-effort
19
+ }
20
+ }
21
+ return home;
22
+ }
23
+ export function pidPath(home) {
24
+ return path.join(home, "daemon.pid");
25
+ }
26
+ export function logPath(home) {
27
+ return path.join(home, "daemon.log");
28
+ }
29
+ export function dbPath(home) {
30
+ return path.join(home, "sean.db");
31
+ }
32
+ export function haltPath(home) {
33
+ return path.join(home, HALT_FILENAME);
34
+ }
35
+ export function isHalted(home) {
36
+ if (process.env["SEAN_HALT"] === "1")
37
+ return true;
38
+ return fs.existsSync(haltPath(home));
39
+ }
40
+ export function setHalted(home, halted) {
41
+ const file = haltPath(ensureSeanHome(home));
42
+ if (halted) {
43
+ fs.writeFileSync(file, `halted ${new Date().toISOString()}\n`, { mode: 0o600 });
44
+ return;
45
+ }
46
+ if (fs.existsSync(file))
47
+ fs.unlinkSync(file);
48
+ }
49
+ //# sourceMappingURL=paths.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"paths.js","sourceRoot":"","sources":["../src/paths.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,IAAI,MAAM,WAAW,CAAC;AAE7B,MAAM,CAAC,MAAM,YAAY,GAAG,WAAW,CAAC;AACxC,MAAM,CAAC,MAAM,YAAY,GAAG,IAAI,CAAC;AACjC,MAAM,CAAC,MAAM,aAAa,GAAG,mBAAmB,CAAC;AACjD,MAAM,CAAC,MAAM,aAAa,GAAG,MAAM,CAAC;AAEpC,MAAM,UAAU,eAAe;IAC7B,OAAO,OAAO,CAAC,GAAG,CAAC,WAAW,CAAC,EAAE,IAAI,EAAE,IAAI,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,EAAE,OAAO,CAAC,CAAC;AAC9E,CAAC;AAED,MAAM,UAAU,cAAc,CAAC,IAAY;IACzC,EAAE,CAAC,SAAS,CAAC,IAAI,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;IACrD,IAAI,OAAO,CAAC,QAAQ,KAAK,OAAO,EAAE,CAAC;QACjC,IAAI,CAAC;YACH,EAAE,CAAC,SAAS,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;QAC5B,CAAC;QAAC,MAAM,CAAC;YACP,cAAc;QAChB,CAAC;IACH,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAED,MAAM,UAAU,OAAO,CAAC,IAAY;IAClC,OAAO,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,YAAY,CAAC,CAAC;AACvC,CAAC;AAED,MAAM,UAAU,OAAO,CAAC,IAAY;IAClC,OAAO,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,YAAY,CAAC,CAAC;AACvC,CAAC;AAED,MAAM,UAAU,MAAM,CAAC,IAAY;IACjC,OAAO,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,SAAS,CAAC,CAAC;AACpC,CAAC;AAED,MAAM,UAAU,QAAQ,CAAC,IAAY;IACnC,OAAO,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,aAAa,CAAC,CAAC;AACxC,CAAC;AAED,MAAM,UAAU,QAAQ,CAAC,IAAY;IACnC,IAAI,OAAO,CAAC,GAAG,CAAC,WAAW,CAAC,KAAK,GAAG;QAAE,OAAO,IAAI,CAAC;IAClD,OAAO,EAAE,CAAC,UAAU,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC;AACvC,CAAC;AAED,MAAM,UAAU,SAAS,CAAC,IAAY,EAAE,MAAe;IACrD,MAAM,IAAI,GAAG,QAAQ,CAAC,cAAc,CAAC,IAAI,CAAC,CAAC,CAAC;IAC5C,IAAI,MAAM,EAAE,CAAC;QACX,EAAE,CAAC,aAAa,CAAC,IAAI,EAAE,UAAU,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,IAAI,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;QAChF,OAAO;IACT,CAAC;IACD,IAAI,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC;QAAE,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC;AAC/C,CAAC"}
package/dist/pdf.d.ts ADDED
@@ -0,0 +1,3 @@
1
+ /** Minimal single-page PDF. Enough for an immutable snapshot download. */
2
+ export declare function textToPdf(title: string, body: string): Buffer;
3
+ //# sourceMappingURL=pdf.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pdf.d.ts","sourceRoot":"","sources":["../src/pdf.ts"],"names":[],"mappings":"AAAA,0EAA0E;AAmB1E,wBAAgB,SAAS,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CA+B7D"}
package/dist/pdf.js ADDED
@@ -0,0 +1,51 @@
1
+ /** Minimal single-page PDF. Enough for an immutable snapshot download. */
2
+ function escapePdf(text) {
3
+ return text.replace(/\\/g, "\\\\").replace(/\(/g, "\\(").replace(/\)/g, "\\)");
4
+ }
5
+ function wrap(text, width) {
6
+ const out = [];
7
+ for (const raw of text.split(/\n/)) {
8
+ let line = raw.replace(/\t/g, " ");
9
+ while (line.length > width) {
10
+ out.push(line.slice(0, width));
11
+ line = line.slice(width);
12
+ }
13
+ out.push(line);
14
+ }
15
+ return out.slice(0, 60);
16
+ }
17
+ export function textToPdf(title, body) {
18
+ const lines = [title, "", ...wrap(body, 96)];
19
+ const y0 = 780;
20
+ const cmds = ["BT", "/F1 11 Tf", "14 TL", `50 ${y0} Td`];
21
+ for (let i = 0; i < lines.length; i++) {
22
+ const line = lines[i] ?? "";
23
+ if (i === 0)
24
+ cmds.push("/F1 16 Tf", `(${escapePdf(line)}) Tj`, "T*", "/F1 11 Tf");
25
+ else
26
+ cmds.push(`(${escapePdf(line)}) Tj`, "T*");
27
+ }
28
+ cmds.push("ET");
29
+ const stream = cmds.join("\n");
30
+ const objects = [
31
+ "<< /Type /Catalog /Pages 2 0 R >>",
32
+ "<< /Type /Pages /Kids [3 0 R] /Count 1 >>",
33
+ "<< /Type /Page /Parent 2 0 R /MediaBox [0 0 612 792] /Contents 4 0 R /Resources << /Font << /F1 5 0 R >> >> >>",
34
+ `<< /Length ${Buffer.byteLength(stream)} >>\nstream\n${stream}\nendstream`,
35
+ "<< /Type /Font /Subtype /Type1 /BaseFont /Helvetica >>",
36
+ ];
37
+ let out = "%PDF-1.4\n";
38
+ const offsets = [0];
39
+ for (let i = 0; i < objects.length; i++) {
40
+ offsets.push(Buffer.byteLength(out));
41
+ out += `${i + 1} 0 obj\n${objects[i]}\nendobj\n`;
42
+ }
43
+ const xref = Buffer.byteLength(out);
44
+ out += `xref\n0 ${objects.length + 1}\n0000000000 65535 f \n`;
45
+ for (let i = 1; i < offsets.length; i++) {
46
+ out += `${String(offsets[i]).padStart(10, "0")} 00000 n \n`;
47
+ }
48
+ out += `trailer << /Size ${objects.length + 1} /Root 1 0 R >>\nstartxref\n${xref}\n%%EOF\n`;
49
+ return Buffer.from(out, "utf8");
50
+ }
51
+ //# sourceMappingURL=pdf.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pdf.js","sourceRoot":"","sources":["../src/pdf.ts"],"names":[],"mappings":"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"}
package/dist/pid.d.ts ADDED
@@ -0,0 +1,11 @@
1
+ export type PidInfo = {
2
+ pid: number;
3
+ host: string;
4
+ port: number;
5
+ startedAt: string;
6
+ };
7
+ export declare function readPid(home: string): PidInfo | null;
8
+ export declare function writePid(home: string, info: PidInfo): void;
9
+ export declare function removePid(home: string): void;
10
+ export declare function isPidAlive(pid: number): boolean;
11
+ //# sourceMappingURL=pid.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pid.d.ts","sourceRoot":"","sources":["../src/pid.ts"],"names":[],"mappings":"AAGA,MAAM,MAAM,OAAO,GAAG;IACpB,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;CACnB,CAAC;AAEF,wBAAgB,OAAO,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,GAAG,IAAI,CAUpD;AAED,wBAAgB,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,GAAG,IAAI,CAE1D;AAED,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAO5C;AAED,wBAAgB,UAAU,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAO/C"}
package/dist/pid.js ADDED
@@ -0,0 +1,38 @@
1
+ import fs from "node:fs";
2
+ import { pidPath } from "./paths.js";
3
+ export function readPid(home) {
4
+ const file = pidPath(home);
5
+ if (!fs.existsSync(file))
6
+ return null;
7
+ try {
8
+ const parsed = JSON.parse(fs.readFileSync(file, "utf8"));
9
+ if (typeof parsed.pid !== "number")
10
+ return null;
11
+ return parsed;
12
+ }
13
+ catch {
14
+ return null;
15
+ }
16
+ }
17
+ export function writePid(home, info) {
18
+ fs.writeFileSync(pidPath(home), JSON.stringify(info), { mode: 0o600 });
19
+ }
20
+ export function removePid(home) {
21
+ const file = pidPath(home);
22
+ try {
23
+ fs.unlinkSync(file);
24
+ }
25
+ catch {
26
+ // already gone
27
+ }
28
+ }
29
+ export function isPidAlive(pid) {
30
+ try {
31
+ process.kill(pid, 0);
32
+ return true;
33
+ }
34
+ catch {
35
+ return false;
36
+ }
37
+ }
38
+ //# sourceMappingURL=pid.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pid.js","sourceRoot":"","sources":["../src/pid.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AASrC,MAAM,UAAU,OAAO,CAAC,IAAY;IAClC,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC3B,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC;QAAE,OAAO,IAAI,CAAC;IACtC,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,YAAY,CAAC,IAAI,EAAE,MAAM,CAAC,CAAY,CAAC;QACpE,IAAI,OAAO,MAAM,CAAC,GAAG,KAAK,QAAQ;YAAE,OAAO,IAAI,CAAC;QAChD,OAAO,MAAM,CAAC;IAChB,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AAED,MAAM,UAAU,QAAQ,CAAC,IAAY,EAAE,IAAa;IAClD,EAAE,CAAC,aAAa,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;AACzE,CAAC;AAED,MAAM,UAAU,SAAS,CAAC,IAAY;IACpC,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC3B,IAAI,CAAC;QACH,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC;IACtB,CAAC;IAAC,MAAM,CAAC;QACP,eAAe;IACjB,CAAC;AACH,CAAC;AAED,MAAM,UAAU,UAAU,CAAC,GAAW;IACpC,IAAI,CAAC;QACH,OAAO,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC;QACrB,OAAO,IAAI,CAAC;IACd,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC"}
@@ -0,0 +1,14 @@
1
+ import type { FastifyInstance } from "fastify";
2
+ export declare const CSRF_HEADER = "x-sean-csrf";
3
+ export declare const TOKEN_HEADER = "x-sean-token";
4
+ export declare const TOKEN_COOKIE = "sean_token";
5
+ export type SecurityOptions = {
6
+ port: number;
7
+ token: string;
8
+ authEnabled: boolean;
9
+ /** Used when listen() assigned an ephemeral port (port 0). */
10
+ getPort?: (() => number) | undefined;
11
+ publicOrigin?: string | undefined;
12
+ };
13
+ export declare function registerSecurity(app: FastifyInstance, options: SecurityOptions): void;
14
+ //# sourceMappingURL=security.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"security.d.ts","sourceRoot":"","sources":["../src/security.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAgC,MAAM,SAAS,CAAC;AAI7E,eAAO,MAAM,WAAW,gBAAgB,CAAC;AACzC,eAAO,MAAM,YAAY,iBAAiB,CAAC;AAC3C,eAAO,MAAM,YAAY,eAAe,CAAC;AAUzC,MAAM,MAAM,eAAe,GAAG;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,OAAO,CAAC;IACrB,8DAA8D;IAC9D,OAAO,CAAC,EAAE,CAAC,MAAM,MAAM,CAAC,GAAG,SAAS,CAAC;IACrC,YAAY,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CACnC,CAAC;AAmBF,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,eAAe,EAAE,OAAO,EAAE,eAAe,GAAG,IAAI,CAuErF"}
@@ -0,0 +1,93 @@
1
+ import { allowedHosts, allowedOrigins } from "./bind.js";
2
+ import { tokensEqual } from "./token.js";
3
+ export const CSRF_HEADER = "x-sean-csrf";
4
+ export const TOKEN_HEADER = "x-sean-token";
5
+ export const TOKEN_COOKIE = "sean_token";
6
+ const SAFE_METHODS = new Set(["GET", "HEAD", "OPTIONS"]);
7
+ function pathOnly(url) {
8
+ const q = url.indexOf("?");
9
+ const path = q === -1 ? url : url.slice(0, q);
10
+ return path.endsWith("/") && path.length > 1 ? path.slice(0, -1) : path;
11
+ }
12
+ function readToken(req) {
13
+ const header = req.headers[TOKEN_HEADER];
14
+ if (typeof header === "string" && header.length > 0)
15
+ return header;
16
+ const auth = req.headers.authorization;
17
+ if (typeof auth === "string" && auth.startsWith("Bearer ")) {
18
+ return auth.slice("Bearer ".length);
19
+ }
20
+ const cookie = req.headers.cookie;
21
+ if (cookie) {
22
+ for (const part of cookie.split(";")) {
23
+ const [rawName, ...rest] = part.trim().split("=");
24
+ if (rawName === TOKEN_COOKIE)
25
+ return rest.join("=");
26
+ }
27
+ }
28
+ return undefined;
29
+ }
30
+ export function registerSecurity(app, options) {
31
+ const portOf = () => options.getPort?.() ?? options.port;
32
+ app.addHook("onRequest", async (req, reply) => {
33
+ const hosts = allowedHosts(portOf(), options.publicOrigin);
34
+ const host = req.headers.host ?? "";
35
+ if (!hosts.has(host)) {
36
+ return reply.code(403).send({ error: "forbidden_host" });
37
+ }
38
+ const path = pathOnly(req.url);
39
+ // RFC 8252 loopback: Google / the broker 302 here. Host is still checked.
40
+ if (SAFE_METHODS.has(req.method.toUpperCase()) && path === "/oauth/callback") {
41
+ return;
42
+ }
43
+ // Stripe webhooks cannot send CSRF or the session cookie. Signature is checked in-route.
44
+ if (req.method.toUpperCase() === "POST" && path === "/api/billing/webhook") {
45
+ return;
46
+ }
47
+ const origin = req.headers.origin;
48
+ if (typeof origin === "string" && origin.length > 0) {
49
+ if (!allowedOrigins(portOf(), options.publicOrigin).has(origin)) {
50
+ return reply.code(403).send({ error: "forbidden_origin" });
51
+ }
52
+ }
53
+ const fetchSite = req.headers["sec-fetch-site"];
54
+ if (fetchSite === "cross-site") {
55
+ return reply.code(403).send({ error: "forbidden_fetch_site" });
56
+ }
57
+ const method = req.method.toUpperCase();
58
+ if (SAFE_METHODS.has(method)) {
59
+ if (path === "/api/events") {
60
+ if (!options.authEnabled) {
61
+ return reply.code(401).send({ error: "unauthorized" });
62
+ }
63
+ const presented = readToken(req);
64
+ if (!presented || !tokensEqual(presented, options.token)) {
65
+ return reply.code(401).send({ error: "unauthorized" });
66
+ }
67
+ }
68
+ return;
69
+ }
70
+ const csrf = req.headers[CSRF_HEADER];
71
+ if (csrf !== "1") {
72
+ return reply.code(403).send({ error: "missing_csrf_header" });
73
+ }
74
+ if (!options.authEnabled) {
75
+ return reply.code(401).send({ error: "unauthorized" });
76
+ }
77
+ const presented = readToken(req);
78
+ if (!presented || !tokensEqual(presented, options.token)) {
79
+ return reply.code(401).send({ error: "unauthorized" });
80
+ }
81
+ });
82
+ // No CORS, ever. Strip any plugin that tries.
83
+ app.addHook("onSend", async (_req, reply) => {
84
+ reply.header("X-Content-Type-Options", "nosniff");
85
+ reply.header("X-Frame-Options", "DENY");
86
+ reply.header("Referrer-Policy", "no-referrer");
87
+ reply.removeHeader("access-control-allow-origin");
88
+ reply.removeHeader("access-control-allow-credentials");
89
+ reply.removeHeader("access-control-allow-headers");
90
+ reply.removeHeader("access-control-allow-methods");
91
+ });
92
+ }
93
+ //# sourceMappingURL=security.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"security.js","sourceRoot":"","sources":["../src/security.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,25 @@
1
+ import { type FastifyInstance } from "fastify";
2
+ import type { SqliteDatabase } from "@agentsean/db";
3
+ import { searchFindingsFts } from "@agentsean/db";
4
+ import type { CredentialStore } from "@agentsean/credentials";
5
+ import type { PendingStore } from "@agentsean/google";
6
+ import type { JobQueue } from "@agentsean/scheduler";
7
+ import { type EventBus } from "./events.js";
8
+ export type CreateServerOptions = {
9
+ host: string;
10
+ port: number;
11
+ token: string;
12
+ authEnabled: boolean;
13
+ seanHome: string;
14
+ getPort?: (() => number) | undefined;
15
+ db?: SqliteDatabase | undefined;
16
+ sqlite?: Parameters<typeof searchFindingsFts>[0] | undefined;
17
+ store?: CredentialStore | undefined;
18
+ pending?: PendingStore | undefined;
19
+ fetch?: typeof fetch | undefined;
20
+ queue?: JobQueue | undefined;
21
+ bus?: EventBus | undefined;
22
+ publicOrigin?: string | undefined;
23
+ };
24
+ export declare function createServer(options: CreateServerOptions): Promise<FastifyInstance>;
25
+ //# sourceMappingURL=server.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA,OAAgB,EAAE,KAAK,eAAe,EAAE,MAAM,SAAS,CAAC;AACxD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AACpD,OAAO,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAC;AAClD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AAC9D,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACtD,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AASrD,OAAO,EAAkB,KAAK,QAAQ,EAAE,MAAM,aAAa,CAAC;AAE5D,MAAM,MAAM,mBAAmB,GAAG;IAChC,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,OAAO,CAAC;IACrB,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,CAAC,MAAM,MAAM,CAAC,GAAG,SAAS,CAAC;IACrC,EAAE,CAAC,EAAE,cAAc,GAAG,SAAS,CAAC;IAChC,MAAM,CAAC,EAAE,UAAU,CAAC,OAAO,iBAAiB,CAAC,CAAC,CAAC,CAAC,GAAG,SAAS,CAAC;IAC7D,KAAK,CAAC,EAAE,eAAe,GAAG,SAAS,CAAC;IACpC,OAAO,CAAC,EAAE,YAAY,GAAG,SAAS,CAAC;IACnC,KAAK,CAAC,EAAE,OAAO,KAAK,GAAG,SAAS,CAAC;IACjC,KAAK,CAAC,EAAE,QAAQ,GAAG,SAAS,CAAC;IAC7B,GAAG,CAAC,EAAE,QAAQ,GAAG,SAAS,CAAC;IAC3B,YAAY,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CACnC,CAAC;AAEF,wBAAsB,YAAY,CAChC,OAAO,EAAE,mBAAmB,GAC3B,OAAO,CAAC,eAAe,CAAC,CAkF1B"}
package/dist/server.js ADDED
@@ -0,0 +1,84 @@
1
+ import Fastify, {} from "fastify";
2
+ import { searchFindingsFts } from "@agentsean/db";
3
+ import { VERSION } from "./version.js";
4
+ import { registerSecurity, TOKEN_COOKIE } from "./security.js";
5
+ import { isHalted } from "./paths.js";
6
+ import { registerGoogleRoutes } from "./google-routes.js";
7
+ import { registerActionRoutes } from "./action-routes.js";
8
+ import { registerDashboardRoutes } from "./dashboard-routes.js";
9
+ import { registerHostedRoutes } from "./hosted-routes.js";
10
+ import { registerSpa } from "./spa.js";
11
+ import { createEventBus } from "./events.js";
12
+ export async function createServer(options) {
13
+ const app = Fastify({
14
+ logger: false,
15
+ trustProxy: false,
16
+ routerOptions: { ignoreTrailingSlash: true },
17
+ });
18
+ const security = {
19
+ port: options.port,
20
+ token: options.token,
21
+ authEnabled: options.authEnabled,
22
+ };
23
+ if (options.getPort)
24
+ security.getPort = options.getPort;
25
+ if (options.publicOrigin)
26
+ security.publicOrigin = options.publicOrigin;
27
+ registerSecurity(app, security);
28
+ app.get("/api/health", async () => ({
29
+ ok: true,
30
+ name: "sean",
31
+ version: VERSION,
32
+ bind: `${options.host}:${options.port}`,
33
+ halted: isHalted(options.seanHome),
34
+ }));
35
+ // Sets the SameSite=Strict cookie so the dashboard EventSource can auth.
36
+ app.get("/api/session", async (req, reply) => {
37
+ const presented = (typeof req.headers["x-sean-token"] === "string" &&
38
+ req.headers["x-sean-token"]) ||
39
+ (typeof req.headers.authorization === "string" &&
40
+ req.headers.authorization.startsWith("Bearer ")
41
+ ? req.headers.authorization.slice("Bearer ".length)
42
+ : undefined);
43
+ if (presented !== options.token) {
44
+ return reply.code(401).send({ error: "unauthorized" });
45
+ }
46
+ reply.header("Set-Cookie", `${TOKEN_COOKIE}=${options.token}; HttpOnly; SameSite=Strict; Path=/`);
47
+ return { ok: true };
48
+ });
49
+ if (options.db && options.store && options.pending) {
50
+ registerGoogleRoutes(app, {
51
+ db: options.db,
52
+ store: options.store,
53
+ pending: options.pending,
54
+ getPort: options.getPort ?? (() => options.port),
55
+ fetch: options.fetch,
56
+ });
57
+ }
58
+ if (options.db) {
59
+ registerActionRoutes(app, {
60
+ db: options.db,
61
+ seanHome: options.seanHome,
62
+ token: options.token,
63
+ gitFetch: options.fetch,
64
+ });
65
+ }
66
+ const sqlite = options.sqlite;
67
+ if (options.db) {
68
+ registerHostedRoutes(app, { db: options.db });
69
+ }
70
+ if (options.db && sqlite) {
71
+ registerDashboardRoutes(app, {
72
+ db: options.db,
73
+ sqlite,
74
+ seanHome: options.seanHome,
75
+ token: options.token,
76
+ bus: options.bus ?? createEventBus(),
77
+ queue: options.queue,
78
+ store: options.store,
79
+ });
80
+ }
81
+ registerSpa(app);
82
+ return app;
83
+ }
84
+ //# sourceMappingURL=server.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,5 @@
1
+ import { type SqliteDatabase } from "@agentsean/db";
2
+ export declare function getSetting(db: SqliteDatabase, key: string): string | null;
3
+ export declare function setSetting(db: SqliteDatabase, key: string, value: string): void;
4
+ export declare function getSettingNumber(db: SqliteDatabase, key: string, fallback: number): number;
5
+ //# sourceMappingURL=settings.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"settings.d.ts","sourceRoot":"","sources":["../src/settings.ts"],"names":[],"mappings":"AACA,OAAO,EAAY,KAAK,cAAc,EAAE,MAAM,eAAe,CAAC;AAE9D,wBAAgB,UAAU,CAAC,EAAE,EAAE,cAAc,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAEzE;AAED,wBAAgB,UAAU,CAAC,EAAE,EAAE,cAAc,EAAE,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI,CAW/E;AAED,wBAAgB,gBAAgB,CAC9B,EAAE,EAAE,cAAc,EAClB,GAAG,EAAE,MAAM,EACX,QAAQ,EAAE,MAAM,GACf,MAAM,CAKR"}
@@ -0,0 +1,25 @@
1
+ import { eq } from "drizzle-orm";
2
+ import { settings } from "@agentsean/db";
3
+ export function getSetting(db, key) {
4
+ return db.select().from(settings).where(eq(settings.key, key)).get()?.value ?? null;
5
+ }
6
+ export function setSetting(db, key, value) {
7
+ const now = new Date().toISOString();
8
+ const existing = db.select().from(settings).where(eq(settings.key, key)).get();
9
+ if (existing) {
10
+ db.update(settings)
11
+ .set({ value, updatedAt: now })
12
+ .where(eq(settings.key, key))
13
+ .run();
14
+ return;
15
+ }
16
+ db.insert(settings).values({ key, value, updatedAt: now }).run();
17
+ }
18
+ export function getSettingNumber(db, key, fallback) {
19
+ const raw = getSetting(db, key);
20
+ if (raw === null)
21
+ return fallback;
22
+ const n = Number(raw);
23
+ return Number.isFinite(n) ? n : fallback;
24
+ }
25
+ //# sourceMappingURL=settings.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"settings.js","sourceRoot":"","sources":["../src/settings.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,EAAE,EAAE,MAAM,aAAa,CAAC;AACjC,OAAO,EAAE,QAAQ,EAAuB,MAAM,eAAe,CAAC;AAE9D,MAAM,UAAU,UAAU,CAAC,EAAkB,EAAE,GAAW;IACxD,OAAO,EAAE,CAAC,MAAM,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,QAAQ,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC,CAAC,GAAG,EAAE,EAAE,KAAK,IAAI,IAAI,CAAC;AACtF,CAAC;AAED,MAAM,UAAU,UAAU,CAAC,EAAkB,EAAE,GAAW,EAAE,KAAa;IACvE,MAAM,GAAG,GAAG,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;IACrC,MAAM,QAAQ,GAAG,EAAE,CAAC,MAAM,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,QAAQ,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC;IAC/E,IAAI,QAAQ,EAAE,CAAC;QACb,EAAE,CAAC,MAAM,CAAC,QAAQ,CAAC;aAChB,GAAG,CAAC,EAAE,KAAK,EAAE,SAAS,EAAE,GAAG,EAAE,CAAC;aAC9B,KAAK,CAAC,EAAE,CAAC,QAAQ,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;aAC5B,GAAG,EAAE,CAAC;QACT,OAAO;IACT,CAAC;IACD,EAAE,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,EAAE,GAAG,EAAE,KAAK,EAAE,SAAS,EAAE,GAAG,EAAE,CAAC,CAAC,GAAG,EAAE,CAAC;AACnE,CAAC;AAED,MAAM,UAAU,gBAAgB,CAC9B,EAAkB,EAClB,GAAW,EACX,QAAgB;IAEhB,MAAM,GAAG,GAAG,UAAU,CAAC,EAAE,EAAE,GAAG,CAAC,CAAC;IAChC,IAAI,GAAG,KAAK,IAAI;QAAE,OAAO,QAAQ,CAAC;IAClC,MAAM,CAAC,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC;IACtB,OAAO,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC;AAC3C,CAAC"}
package/dist/spa.d.ts ADDED
@@ -0,0 +1,4 @@
1
+ import type { FastifyInstance } from "fastify";
2
+ export declare function dashboardDist(): string | null;
3
+ export declare function registerSpa(app: FastifyInstance): void;
4
+ //# sourceMappingURL=spa.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"spa.d.ts","sourceRoot":"","sources":["../src/spa.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,eAAe,EAAgC,MAAM,SAAS,CAAC;AAkC7E,wBAAgB,aAAa,IAAI,MAAM,GAAG,IAAI,CAe7C;AAwBD,wBAAgB,WAAW,CAAC,GAAG,EAAE,eAAe,GAAG,IAAI,CA4BtD"}
package/dist/spa.js ADDED
@@ -0,0 +1,95 @@
1
+ import fs from "node:fs";
2
+ import path from "node:path";
3
+ import { fileURLToPath } from "node:url";
4
+ const SPA_PATHS = new Set([
5
+ "/",
6
+ "/findings",
7
+ "/crawls",
8
+ "/changes",
9
+ "/approvals",
10
+ "/automations",
11
+ "/content",
12
+ "/search",
13
+ "/keywords",
14
+ "/evidence",
15
+ "/ai",
16
+ "/local",
17
+ "/mentions",
18
+ "/reports",
19
+ "/billing",
20
+ "/settings",
21
+ "/onboarding",
22
+ ]);
23
+ const MIME = {
24
+ ".html": "text/html; charset=utf-8",
25
+ ".js": "text/javascript; charset=utf-8",
26
+ ".css": "text/css; charset=utf-8",
27
+ ".map": "application/json",
28
+ ".svg": "image/svg+xml",
29
+ ".json": "application/json",
30
+ ".woff2": "font/woff2",
31
+ ".png": "image/png",
32
+ ".ico": "image/x-icon",
33
+ };
34
+ export function dashboardDist() {
35
+ const candidates = [];
36
+ try {
37
+ const pkg = fileURLToPath(import.meta.resolve("@agentsean/dashboard/package.json"));
38
+ candidates.push(path.join(path.dirname(pkg), "dist"));
39
+ }
40
+ catch {
41
+ // not resolvable
42
+ }
43
+ candidates.push(path.resolve(fileURLToPath(new URL("../../../dashboard/dist", import.meta.url))));
44
+ for (const dir of candidates) {
45
+ if (fs.existsSync(path.join(dir, "index.html")))
46
+ return dir;
47
+ }
48
+ return null;
49
+ }
50
+ function fallbackHtml() {
51
+ return `<!doctype html>
52
+ <html lang="en"><head><meta charset="utf-8"/><title>Agent Sean</title>
53
+ <meta name="viewport" content="width=device-width, initial-scale=1"/>
54
+ <style>
55
+ body{font:16px/1.45 system-ui,sans-serif;margin:2rem;background:#f6f7f9;color:#111}
56
+ a{color:#0b57d0}
57
+ </style></head>
58
+ <body>
59
+ <h1>Agent Sean</h1>
60
+ <p>The SEO engineer that never sleeps. URL → 90-second crawl → first findings → then Google.</p>
61
+ <p><a href="/connect">Connect Google</a> · <a href="/activity">Activity</a> — One click reverts it.</p>
62
+ <p>Build <code>packages/dashboard</code> for the full SPA. The daemon already serves the JSON API on this origin — no CORS.</p>
63
+ </body></html>`;
64
+ }
65
+ function sendFile(reply, file) {
66
+ const ext = path.extname(file);
67
+ reply.type(MIME[ext] ?? "application/octet-stream");
68
+ reply.send(fs.readFileSync(file));
69
+ }
70
+ export function registerSpa(app) {
71
+ const dist = dashboardDist();
72
+ const serveIndex = (_req, reply) => {
73
+ if (!dist) {
74
+ reply.type("text/html").send(fallbackHtml());
75
+ return;
76
+ }
77
+ sendFile(reply, path.join(dist, "index.html"));
78
+ };
79
+ for (const p of SPA_PATHS) {
80
+ app.get(p, serveIndex);
81
+ }
82
+ app.get("/assets/*", (req, reply) => {
83
+ if (!dist)
84
+ return reply.code(404).send({ error: "no_dashboard" });
85
+ const rel = req.url.split("?")[0] ?? "";
86
+ const file = path.resolve(dist, rel.replace(/^\/+/, ""));
87
+ if (!file.startsWith(dist) ||
88
+ !fs.existsSync(file) ||
89
+ fs.statSync(file).isDirectory()) {
90
+ return reply.code(404).send({ error: "not_found" });
91
+ }
92
+ sendFile(reply, file);
93
+ });
94
+ }
95
+ //# sourceMappingURL=spa.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"spa.js","sourceRoot":"","sources":["../src/spa.ts"],"names":[],"mappings":"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"}