yamlover 0.3.4 → 0.3.6

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 (137) hide show
  1. package/bin/yamlover.js +199 -112
  2. package/dist/client/assets/KaTeX_AMS-Regular-BQhdFMY1.woff2 +0 -0
  3. package/dist/client/assets/KaTeX_AMS-Regular-DMm9YOAa.woff +0 -0
  4. package/dist/client/assets/KaTeX_AMS-Regular-DRggAlZN.ttf +0 -0
  5. package/dist/client/assets/KaTeX_Caligraphic-Bold-ATXxdsX0.ttf +0 -0
  6. package/dist/client/assets/KaTeX_Caligraphic-Bold-BEiXGLvX.woff +0 -0
  7. package/dist/client/assets/KaTeX_Caligraphic-Bold-Dq_IR9rO.woff2 +0 -0
  8. package/dist/client/assets/KaTeX_Caligraphic-Regular-CTRA-rTL.woff +0 -0
  9. package/dist/client/assets/KaTeX_Caligraphic-Regular-Di6jR-x-.woff2 +0 -0
  10. package/dist/client/assets/KaTeX_Caligraphic-Regular-wX97UBjC.ttf +0 -0
  11. package/dist/client/assets/KaTeX_Fraktur-Bold-BdnERNNW.ttf +0 -0
  12. package/dist/client/assets/KaTeX_Fraktur-Bold-BsDP51OF.woff +0 -0
  13. package/dist/client/assets/KaTeX_Fraktur-Bold-CL6g_b3V.woff2 +0 -0
  14. package/dist/client/assets/KaTeX_Fraktur-Regular-CB_wures.ttf +0 -0
  15. package/dist/client/assets/KaTeX_Fraktur-Regular-CTYiF6lA.woff2 +0 -0
  16. package/dist/client/assets/KaTeX_Fraktur-Regular-Dxdc4cR9.woff +0 -0
  17. package/dist/client/assets/KaTeX_Main-Bold-Cx986IdX.woff2 +0 -0
  18. package/dist/client/assets/KaTeX_Main-Bold-Jm3AIy58.woff +0 -0
  19. package/dist/client/assets/KaTeX_Main-Bold-waoOVXN0.ttf +0 -0
  20. package/dist/client/assets/KaTeX_Main-BoldItalic-DxDJ3AOS.woff2 +0 -0
  21. package/dist/client/assets/KaTeX_Main-BoldItalic-DzxPMmG6.ttf +0 -0
  22. package/dist/client/assets/KaTeX_Main-BoldItalic-SpSLRI95.woff +0 -0
  23. package/dist/client/assets/KaTeX_Main-Italic-3WenGoN9.ttf +0 -0
  24. package/dist/client/assets/KaTeX_Main-Italic-BMLOBm91.woff +0 -0
  25. package/dist/client/assets/KaTeX_Main-Italic-NWA7e6Wa.woff2 +0 -0
  26. package/dist/client/assets/KaTeX_Main-Regular-B22Nviop.woff2 +0 -0
  27. package/dist/client/assets/KaTeX_Main-Regular-Dr94JaBh.woff +0 -0
  28. package/dist/client/assets/KaTeX_Main-Regular-ypZvNtVU.ttf +0 -0
  29. package/dist/client/assets/KaTeX_Math-BoldItalic-B3XSjfu4.ttf +0 -0
  30. package/dist/client/assets/KaTeX_Math-BoldItalic-CZnvNsCZ.woff2 +0 -0
  31. package/dist/client/assets/KaTeX_Math-BoldItalic-iY-2wyZ7.woff +0 -0
  32. package/dist/client/assets/KaTeX_Math-Italic-DA0__PXp.woff +0 -0
  33. package/dist/client/assets/KaTeX_Math-Italic-flOr_0UB.ttf +0 -0
  34. package/dist/client/assets/KaTeX_Math-Italic-t53AETM-.woff2 +0 -0
  35. package/dist/client/assets/KaTeX_SansSerif-Bold-CFMepnvq.ttf +0 -0
  36. package/dist/client/assets/KaTeX_SansSerif-Bold-D1sUS0GD.woff2 +0 -0
  37. package/dist/client/assets/KaTeX_SansSerif-Bold-DbIhKOiC.woff +0 -0
  38. package/dist/client/assets/KaTeX_SansSerif-Italic-C3H0VqGB.woff2 +0 -0
  39. package/dist/client/assets/KaTeX_SansSerif-Italic-DN2j7dab.woff +0 -0
  40. package/dist/client/assets/KaTeX_SansSerif-Italic-YYjJ1zSn.ttf +0 -0
  41. package/dist/client/assets/KaTeX_SansSerif-Regular-BNo7hRIc.ttf +0 -0
  42. package/dist/client/assets/KaTeX_SansSerif-Regular-CS6fqUqJ.woff +0 -0
  43. package/dist/client/assets/KaTeX_SansSerif-Regular-DDBCnlJ7.woff2 +0 -0
  44. package/dist/client/assets/KaTeX_Script-Regular-C5JkGWo-.ttf +0 -0
  45. package/dist/client/assets/KaTeX_Script-Regular-D3wIWfF6.woff2 +0 -0
  46. package/dist/client/assets/KaTeX_Script-Regular-D5yQViql.woff +0 -0
  47. package/dist/client/assets/KaTeX_Size1-Regular-C195tn64.woff +0 -0
  48. package/dist/client/assets/KaTeX_Size1-Regular-Dbsnue_I.ttf +0 -0
  49. package/dist/client/assets/KaTeX_Size1-Regular-mCD8mA8B.woff2 +0 -0
  50. package/dist/client/assets/KaTeX_Size2-Regular-B7gKUWhC.ttf +0 -0
  51. package/dist/client/assets/KaTeX_Size2-Regular-Dy4dx90m.woff2 +0 -0
  52. package/dist/client/assets/KaTeX_Size2-Regular-oD1tc_U0.woff +0 -0
  53. package/dist/client/assets/KaTeX_Size3-Regular-CTq5MqoE.woff +0 -0
  54. package/dist/client/assets/KaTeX_Size3-Regular-DgpXs0kz.ttf +0 -0
  55. package/dist/client/assets/KaTeX_Size4-Regular-BF-4gkZK.woff +0 -0
  56. package/dist/client/assets/KaTeX_Size4-Regular-DWFBv043.ttf +0 -0
  57. package/dist/client/assets/KaTeX_Size4-Regular-Dl5lxZxV.woff2 +0 -0
  58. package/dist/client/assets/KaTeX_Typewriter-Regular-C0xS9mPB.woff +0 -0
  59. package/dist/client/assets/KaTeX_Typewriter-Regular-CO6r4hn1.woff2 +0 -0
  60. package/dist/client/assets/KaTeX_Typewriter-Regular-D3Ib7_Hf.ttf +0 -0
  61. package/dist/client/assets/_commonjs-dynamic-modules-TDtrdbi3.js +1 -0
  62. package/dist/client/assets/decoded-CFkcuQ1f.js +1 -0
  63. package/dist/client/assets/djvu-B3wuFWwI.js +1 -0
  64. package/dist/client/assets/docx-putHYXzO.js +230 -0
  65. package/dist/client/assets/heic-oIxhIbIW.js +66 -0
  66. package/dist/client/assets/imagemap-CUKUIcGe.js +1 -0
  67. package/dist/client/assets/index-CQ3TGVSx.js +617 -0
  68. package/dist/client/assets/index-wTjOzmSY.css +1 -0
  69. package/dist/client/assets/map-CZS083CS.js +1 -0
  70. package/dist/client/assets/paged-CjxSuuik.js +1 -0
  71. package/dist/client/assets/panzoom-C7OuIIda.js +4 -0
  72. package/dist/client/assets/panzoom-CIGW-MKW.css +1 -0
  73. package/dist/client/assets/pdf-Dz3gUx0B.js +12 -0
  74. package/dist/client/assets/pdf-m5e3jsV4.css +1 -0
  75. package/dist/client/assets/pdf.worker.min-qwK7q_zL.mjs +28 -0
  76. package/dist/client/assets/psd-C8yNwHFw.js +11 -0
  77. package/dist/client/assets/spreadsheet-DBv7aqoN.js +38 -0
  78. package/dist/client/assets/tiff-73RKtIux.js +1 -0
  79. package/{index.html → dist/client/index.html} +2 -1
  80. package/package.json +18 -21
  81. package/src/client/App.tsx +0 -424
  82. package/src/client/NodeView.tsx +0 -422
  83. package/src/client/TaskStrip.tsx +0 -34
  84. package/src/client/Tree.tsx +0 -97
  85. package/src/client/api.ts +0 -213
  86. package/src/client/icons.ts +0 -91
  87. package/src/client/links.tsx +0 -108
  88. package/src/client/live.ts +0 -42
  89. package/src/client/main.tsx +0 -10
  90. package/src/client/paste-html.ts +0 -228
  91. package/src/client/paste-links.ts +0 -42
  92. package/src/client/paths.ts +0 -139
  93. package/src/client/render.tsx +0 -339
  94. package/src/client/renderers/annotate.tsx +0 -641
  95. package/src/client/renderers/asciidoc.tsx +0 -36
  96. package/src/client/renderers/chapter.tsx +0 -142
  97. package/src/client/renderers/csv.tsx +0 -234
  98. package/src/client/renderers/decoded.tsx +0 -72
  99. package/src/client/renderers/djvu.tsx +0 -271
  100. package/src/client/renderers/djvuWorker.ts +0 -99
  101. package/src/client/renderers/doc.tsx +0 -40
  102. package/src/client/renderers/docx.tsx +0 -49
  103. package/src/client/renderers/epub.tsx +0 -147
  104. package/src/client/renderers/explorer.tsx +0 -294
  105. package/src/client/renderers/fb2.tsx +0 -149
  106. package/src/client/renderers/headings.ts +0 -69
  107. package/src/client/renderers/heic.tsx +0 -23
  108. package/src/client/renderers/imagemap.tsx +0 -170
  109. package/src/client/renderers/kml.ts +0 -46
  110. package/src/client/renderers/latex.tsx +0 -37
  111. package/src/client/renderers/map.tsx +0 -205
  112. package/src/client/renderers/marklower.tsx +0 -120
  113. package/src/client/renderers/markup.tsx +0 -64
  114. package/src/client/renderers/media.tsx +0 -19
  115. package/src/client/renderers/paged.ts +0 -137
  116. package/src/client/renderers/panzoom.ts +0 -101
  117. package/src/client/renderers/pdf.tsx +0 -316
  118. package/src/client/renderers/plaintext.tsx +0 -120
  119. package/src/client/renderers/plantuml.tsx +0 -83
  120. package/src/client/renderers/psd.tsx +0 -25
  121. package/src/client/renderers/registry.tsx +0 -411
  122. package/src/client/renderers/rtf.tsx +0 -210
  123. package/src/client/renderers/spreadsheet.tsx +0 -105
  124. package/src/client/renderers/tag.tsx +0 -113
  125. package/src/client/renderers/text.tsx +0 -42
  126. package/src/client/renderers/tiff.tsx +0 -33
  127. package/src/client/styles.css +0 -1212
  128. package/src/client/vendor/README.md +0 -30
  129. package/src/client/vite-env.d.ts +0 -31
  130. package/src/server/api.ts +0 -147
  131. package/src/server/embed.ts +0 -187
  132. package/src/server/engine-api.ts +0 -1563
  133. package/src/server/gitignore.ts +0 -81
  134. package/src/server/node-kind.ts +0 -61
  135. package/src/server/tasks.ts +0 -83
  136. package/src/server/yamlover.ts +0 -1133
  137. /package/{src/client/vendor/djvu.js → dist/client/assets/djvu-Ci0lFKxE.js} +0 -0
package/bin/yamlover.js CHANGED
@@ -8,70 +8,59 @@
8
8
  * yamlover node (with `.yamlover/`), a plain directory, or a single file — the
9
9
  * same shapes `tools/walker` understands.
10
10
  *
11
- * The server runs Vite in middleware mode: the client (`src/client`) is served
12
- * with HMR straight from source, and the server-side materializer
13
- * (`src/server`) is loaded through Vite's `ssrLoadModule`, so there is no build
14
- * step. API routes are handled before Vite; every other route falls back to the
15
- * SPA's index.html (client-side routing on the JSON path).
11
+ * Two serve modes, chosen automatically:
12
+ *
13
+ * PRODUCTION (the published package, or `--prod`): the engine source is not on
14
+ * disk, so the client is served as a prebuilt static SPA from `dist/client`
15
+ * and the server handler comes from the bundled `dist/server.js`. No Vite at
16
+ * runtime, no `src/` shipped — `npx yamlover` installs with ~zero deps.
17
+ *
18
+ * • LIVE (the repo checkout): the engine source IS reachable, so Vite runs in
19
+ * middleware mode — the client is served from `src/client` with HMR and the
20
+ * server materializer is loaded via `ssrLoadModule`, transpiling TS on the
21
+ * fly (edits take effect with no rebuild). `--prod` forces production mode
22
+ * here too, for testing the static build.
23
+ *
24
+ * Either way: API routes (`/api/*`) are handled first; live data updates flow
25
+ * over the `/api/events` SSE stream (FS watcher → reindex → client `useDiffBump`),
26
+ * independent of Vite. Every other route falls back to the SPA shell (client-side
27
+ * routing on the JSON path).
28
+ *
29
+ * Binds 127.0.0.1 (local only) by default — the safe default for a personal viewer
30
+ * and for the desktop wrapper (tools/desktop). `--headless` binds 0.0.0.0 to serve
31
+ * the tree across the network (a server box with no GUI).
16
32
  */
17
33
 
18
- import { createServer } from "vite";
19
- import react from "@vitejs/plugin-react";
20
34
  import { createServer as createHttpServer } from "node:http";
21
35
  import { fileURLToPath, pathToFileURL } from "node:url";
22
36
  import { createRequire } from "node:module";
23
- import { dirname, join, resolve } from "node:path";
37
+ import { dirname, join, resolve, extname, sep } from "node:path";
24
38
  import fs from "node:fs";
25
39
 
26
40
  const __dirname = dirname(fileURLToPath(import.meta.url));
27
41
  const pkgRoot = resolve(__dirname, ".."); // tools/server
28
42
 
29
- // Resolve react/react-dom as *this package* sees them, and alias Vite to those
30
- // exact copies, so the SPA never picks up a stale React from a parent
31
- // node_modules (which surfaces as "react-dom … does not provide an export named
32
- // 'createRoot'" — createRoot is React 18+). Best-effort: if resolution fails we
33
- // leave Vite to its defaults.
34
- const reactAlias = {};
35
- // Directories Vite is allowed to serve over `/@fs` (its file-system allowlist).
36
- // Start with this package; below we add the node_modules that actually holds the
37
- // heavy deps. Under `npx`, deps hoist to a `_npx/<hash>/node_modules` *outside*
38
- // `pkgRoot`, and Vite's default workspace-root detection misses it — so a raw asset
39
- // fetch (notably pdf.js's `pdf.worker.min.mjs`) gets denied and falls through to
40
- // index.html, surfacing as the "non-JavaScript MIME type text/html" worker error.
41
- const fsAllow = [pkgRoot];
42
- try {
43
- const req = createRequire(join(pkgRoot, "package.json"));
44
- reactAlias["react"] = dirname(req.resolve("react/package.json"));
45
- reactAlias["react-dom"] = dirname(req.resolve("react-dom/package.json"));
46
- // Allow whichever node_modules each heavy dep resolves from (hoisted under npx,
47
- // or nested in dev) so Vite serves their worker/asset files over `/@fs`.
48
- for (const dep of ["pdfjs-dist", "react-pdf", "leaflet"]) {
49
- try {
50
- const nodeModules = dirname(dirname(req.resolve(`${dep}/package.json`)));
51
- if (!fsAllow.includes(nodeModules)) fsAllow.push(nodeModules);
52
- } catch {
53
- /* dep not resolvable from here — skip */
54
- }
55
- }
56
- } catch {
57
- /* fall back to default resolution */
58
- }
59
-
60
43
  // --- argument parsing ----------------------------------------------------- //
61
44
  let rootArg = null; // the ROOT path as typed (null when omitted)
62
45
  let port = 5173;
63
- let host = "0.0.0.0"; // all interfaces by default reachable from the network
46
+ // Local only by default the safe default for a personal viewer / the desktop app.
47
+ // `--headless` opens it to the network (0.0.0.0); `--host ADDR` is an explicit override.
48
+ let host = "127.0.0.1";
64
49
  let gitignore = true; // hide .gitignore'd stray files by default
50
+ let prodFlag = false; // force production (static) mode even in the repo checkout
65
51
  const argv = process.argv.slice(2);
66
52
  for (let i = 0; i < argv.length; i++) {
67
53
  const a = argv[i];
68
54
  if (a === "--port" || a === "-p") port = parseInt(argv[++i], 10);
69
55
  else if (a.startsWith("--port=")) port = parseInt(a.slice("--port=".length), 10);
56
+ else if (a === "--headless") host = "0.0.0.0"; // serve on all interfaces (no GUI / remote access)
70
57
  else if (a === "--host") host = argv[++i];
71
58
  else if (a.startsWith("--host=")) host = a.slice("--host=".length);
72
59
  else if (a === "--no-gitignore") gitignore = false;
60
+ else if (a === "--prod") prodFlag = true;
73
61
  else if (a === "--help" || a === "-h") {
74
- console.log("usage: npx yamlover [ROOT] [--port N] [--host ADDR] [--no-gitignore]");
62
+ console.log("usage: npx yamlover [ROOT] [--port N] [--headless] [--host ADDR] [--no-gitignore] [--prod]");
63
+ console.log(" default: serve on 127.0.0.1 (local only); --headless serves on all interfaces");
75
64
  process.exit(0);
76
65
  } else if (!a.startsWith("-")) rootArg = a;
77
66
  }
@@ -81,12 +70,19 @@ if (!fs.existsSync(dataRoot)) {
81
70
  process.exit(1);
82
71
  }
83
72
 
73
+ // --- mode ----------------------------------------------------------------- //
74
+ // The engine SOURCE is present only in the monorepo checkout; its absence (the
75
+ // published package) — or an explicit `--prod` — selects production/static mode.
76
+ const engineSrc = resolve(pkgRoot, "../engine/ts/src/index.ts");
77
+ const repoLive = fs.existsSync(engineSrc);
78
+ const prod = prodFlag || !repoLive;
79
+
84
80
  // --- server --------------------------------------------------------------- //
85
- // `vite` and `handle` are filled in just below; the request handler closes over
86
- // them and only reads them once requests start arriving, after assignment.
87
- let vite;
81
+ // `handle` (API) and `serveClient` (everything else) are filled in per mode just
82
+ // below; the request handler closes over them and only reads them once requests
83
+ // start arriving — after listen(), so after assignment.
88
84
  let handle;
89
- const indexHtmlPath = join(pkgRoot, "index.html");
85
+ let serveClient;
90
86
 
91
87
  const server = createHttpServer((req, res) => {
92
88
  const url = new URL(req.url, "http://localhost");
@@ -94,76 +90,116 @@ const server = createHttpServer((req, res) => {
94
90
  handle(req, res, url);
95
91
  return;
96
92
  }
97
- vite.middlewares(req, res, async () => {
98
- // SPA fallback: serve the (transformed) index.html for any client route.
99
- try {
100
- let html = fs.readFileSync(indexHtmlPath, "utf-8");
101
- html = await vite.transformIndexHtml(url.pathname, html);
102
- res.setHeader("Content-Type", "text/html; charset=utf-8");
103
- res.end(html);
104
- } catch (e) {
105
- vite.ssrFixStacktrace(e);
106
- res.statusCode = 500;
107
- res.end(e.message);
93
+ serveClient(req, res, url);
94
+ });
95
+
96
+ let createHandlers;
97
+ if (prod) {
98
+ // -- production: prebuilt static client + bundled server, no Vite ---------- //
99
+ const distClient = join(pkgRoot, "dist/client");
100
+ const distIndex = join(distClient, "index.html");
101
+ if (!fs.existsSync(distIndex)) {
102
+ console.error(`yamlover: production build missing at ${distClient}`);
103
+ console.error(" run `npm run build` in tools/server first.");
104
+ process.exit(1);
105
+ }
106
+ ({ createHandlers } = await import(pathToFileURL(join(pkgRoot, "dist/server.js")).href));
107
+ serveClient = (req, res, url) => serveStatic(res, url, distClient, distIndex);
108
+ } else {
109
+ // -- live: Vite middleware + ssrLoadModule (repo checkout) ----------------- //
110
+ // Vite and its plugin are DYNAMIC imports so production mode (where they are not
111
+ // installed) never tries to resolve them.
112
+ const { createServer } = await import("vite");
113
+ const { default: react } = await import("@vitejs/plugin-react");
114
+
115
+ // Resolve react/react-dom as *this package* sees them, and alias Vite to those
116
+ // exact copies, so the SPA never picks up a stale React from a parent
117
+ // node_modules (the "does not provide an export named 'createRoot'" failure).
118
+ const reactAlias = {};
119
+ // Directories Vite is allowed to serve over `/@fs`. Start with this package; add
120
+ // the node_modules that actually holds the heavy deps — under `npx` they hoist to
121
+ // a `_npx/<hash>/node_modules` outside `pkgRoot` and Vite's default root detection
122
+ // misses it, so a raw asset (notably pdf.js's worker) 404s to index.html.
123
+ const fsAllow = [pkgRoot];
124
+ try {
125
+ const req = createRequire(join(pkgRoot, "package.json"));
126
+ reactAlias["react"] = dirname(req.resolve("react/package.json"));
127
+ reactAlias["react-dom"] = dirname(req.resolve("react-dom/package.json"));
128
+ for (const dep of ["pdfjs-dist", "react-pdf", "leaflet"]) {
129
+ try {
130
+ const nodeModules = dirname(dirname(req.resolve(`${dep}/package.json`)));
131
+ if (!fsAllow.includes(nodeModules)) fsAllow.push(nodeModules);
132
+ } catch {
133
+ /* dep not resolvable from here — skip */
134
+ }
108
135
  }
136
+ } catch {
137
+ /* fall back to default resolution */
138
+ }
139
+
140
+ // Run HMR over our own server (`hmr: { server }`) so Vite does not open a second
141
+ // WebSocket port of its own.
142
+ const vite = await createServer({
143
+ root: pkgRoot,
144
+ plugins: [react()],
145
+ appType: "custom",
146
+ // Always use this package's own React: `dedupe` collapses react/react-dom to a
147
+ // single copy, and the aliases pin that copy to the one resolvable from here.
148
+ resolve: { dedupe: ["react", "react-dom"], alias: reactAlias },
149
+ // Pre-bundle the heavy renderer deps up front. These are all lazy-loaded, so
150
+ // Vite would otherwise discover them (and their transitive CJS deps) only on
151
+ // first use and could serve them un-interopped — the "does not provide an
152
+ // export named …" failure. Listing them forces a clean CJS→ESM pre-bundle.
153
+ optimizeDeps: {
154
+ include: [
155
+ "react-pdf",
156
+ "marked",
157
+ "@asciidoctor/core",
158
+ "ag-psd",
159
+ "utif",
160
+ "heic2any",
161
+ // the office/map renderer deps (all CJS/UMD — they need the CJS→ESM interop
162
+ // a pre-bundle gives, or they fail with "does not provide an export named
163
+ // 'default'", e.g. `import L from "leaflet"`)
164
+ "leaflet",
165
+ "xlsx",
166
+ "mammoth/mammoth.browser",
167
+ "@tmcw/togeojson",
168
+ ],
169
+ },
170
+ // `allowedHosts: true` lifts Vite's Host-header allowlist so the SPA is
171
+ // reachable under any hostname/IP (harmless on the default local bind; needed
172
+ // when `--headless` exposes it on the network). `fs.allow` is widened to the
173
+ // dirs holding the heavy deps so their `/@fs` assets are served, not 404'd.
174
+ server: { middlewareMode: true, allowedHosts: true, hmr: { server }, fs: { allow: fsAllow } },
109
175
  });
110
- });
111
176
 
112
- // Run HMR over our own server (`hmr: { server }`) so Vite does not open a
113
- // second WebSocket port of its own.
114
- vite = await createServer({
115
- root: pkgRoot,
116
- plugins: [react()],
117
- appType: "custom",
118
- // Always use this package's own React: `dedupe` collapses react/react-dom to a
119
- // single copy, and the aliases pin that copy to the one resolvable from here —
120
- // so a stale react-dom in a *parent* node_modules (the classic "does not
121
- // provide an export named 'createRoot'" failure) cannot shadow it.
122
- resolve: { dedupe: ["react", "react-dom"], alias: reactAlias },
123
- // Pre-bundle the heavy renderer deps up front. These are all lazy-loaded, so
124
- // Vite would otherwise discover them (and their transitive CJS deps such as
125
- // `warning` for react-pdf or `base64-js` for ag-psd) only on first use and could
126
- // serve them un-interopped — the "does not provide an export named …" failure.
127
- // Listing them forces a clean CJS→ESM bundle before any renderer mounts.
128
- optimizeDeps: {
129
- include: [
130
- "react-pdf",
131
- "marked",
132
- "@asciidoctor/core",
133
- "ag-psd",
134
- "utif",
135
- "heic2any",
136
- // the office/map renderer deps (all CJS/UMD — they need the CJS→ESM interop
137
- // a pre-bundle gives, or they are served raw and fail with "does not provide
138
- // an export named 'default'", e.g. `import L from "leaflet"`)
139
- "leaflet",
140
- "xlsx",
141
- "mammoth/mammoth.browser",
142
- "@tmcw/togeojson",
143
- ],
144
- },
145
- // `allowedHosts: true` lifts Vite's Host-header allowlist so the SPA is
146
- // reachable from the network (any hostname/IP), matching the 0.0.0.0 bind.
147
- // `fs.allow` is widened (above) to the dirs holding the heavy deps so their
148
- // `/@fs` assets — chiefly pdf.js's worker — are served, not 404'd to index.html.
149
- server: { middlewareMode: true, allowedHosts: true, hmr: { server }, fs: { allow: fsAllow } },
150
- });
177
+ // The engine-backed handler (engine-api.ts) is loaded via `ssrLoadModule` so its
178
+ // TS and the engine/parser source it reaches into (`../../../engine`,
179
+ // `../../../parser`) is transpiled live, with no build step.
180
+ ({ createHandlers } = await vite.ssrLoadModule("/src/server/engine-api.ts"));
151
181
 
152
- // Load the server-side materializer. The engine-backed handler (engine-api.ts) supersedes the
153
- // legacy loadEntity materializer (api.ts kept for ref). It reaches OUTSIDE this package
154
- // (../../../engine, ../../../parser), which the npm tarball cannot carry — so at prepack we bundle
155
- // that import graph into a self-contained `dist/server.js` (scripts/build.mjs). We pick the loader
156
- // by whether the engine SOURCE is reachable: in the repo CHECKOUT it is, so we use Vite's
157
- // `ssrLoadModule` to transpile the TS live (edits take effect with no rebuild — never a stale
158
- // bundle); in the PUBLISHED package the source is absent, so we import the prebuilt bundle. Either
159
- // way the client SPA is still served by Vite from src.
160
- // The initial index runs as a BACKGROUND task — the server listens immediately (serving the
161
- // previous on-disk index, or an empty tree on a cold start) while progress lands here and in
162
- // the web UI (SSE task frames + GET /api/tasks).
163
- const engineSrc = resolve(pkgRoot, "../engine/ts/src/index.ts"); // present only in the monorepo
164
- const { createHandlers } = fs.existsSync(engineSrc)
165
- ? await vite.ssrLoadModule("/src/server/engine-api.ts") // repo: live TS, no rebuild needed
166
- : await import(pathToFileURL(join(pkgRoot, "dist/server.js")).href); // published: prebuilt bundle
182
+ const indexHtmlPath = join(pkgRoot, "index.html");
183
+ serveClient = (req, res, url) => {
184
+ vite.middlewares(req, res, async () => {
185
+ // SPA fallback: serve the (transformed) index.html for any client route.
186
+ try {
187
+ let html = fs.readFileSync(indexHtmlPath, "utf-8");
188
+ html = await vite.transformIndexHtml(url.pathname, html);
189
+ res.setHeader("Content-Type", "text/html; charset=utf-8");
190
+ res.end(html);
191
+ } catch (e) {
192
+ vite.ssrFixStacktrace(e);
193
+ res.statusCode = 500;
194
+ res.end(e.message);
195
+ }
196
+ });
197
+ };
198
+ }
199
+
200
+ // The initial index runs as a BACKGROUND task — the server listens immediately
201
+ // (serving the previous on-disk index, or an empty tree on a cold start) while
202
+ // progress lands here and in the web UI (SSE task frames + GET /api/tasks).
167
203
  handle = createHandlers(dataRoot, {
168
204
  gitignore,
169
205
  watch: true, // re-index + push on external edits
@@ -171,6 +207,57 @@ handle = createHandlers(dataRoot, {
171
207
  });
172
208
  handle.ready.catch((e) => console.error("yamlover: indexing failed:", e));
173
209
 
210
+ // --- static file server (production mode) --------------------------------- //
211
+ const MIME = {
212
+ ".html": "text/html; charset=utf-8",
213
+ ".js": "text/javascript; charset=utf-8",
214
+ ".mjs": "text/javascript; charset=utf-8",
215
+ ".css": "text/css; charset=utf-8",
216
+ ".json": "application/json; charset=utf-8",
217
+ ".map": "application/json; charset=utf-8",
218
+ ".wasm": "application/wasm",
219
+ ".svg": "image/svg+xml",
220
+ ".png": "image/png",
221
+ ".jpg": "image/jpeg",
222
+ ".jpeg": "image/jpeg",
223
+ ".gif": "image/gif",
224
+ ".webp": "image/webp",
225
+ ".ico": "image/x-icon",
226
+ ".woff": "font/woff",
227
+ ".woff2": "font/woff2",
228
+ ".ttf": "font/ttf",
229
+ ".txt": "text/plain; charset=utf-8",
230
+ };
231
+
232
+ /** Serve a file from `distClient`, or fall back to the SPA shell (`distIndex`) for
233
+ * any path that isn't a real asset — the client routes on the JSON path. */
234
+ function serveStatic(res, url, distClient, distIndex) {
235
+ const filePath = resolve(distClient, "." + decodeURIComponent(url.pathname));
236
+ // Containment guard: never serve outside dist/client (`..` traversal → shell).
237
+ if (filePath !== distClient && !filePath.startsWith(distClient + sep)) {
238
+ return serveIndex(res, distIndex);
239
+ }
240
+ let stat = null;
241
+ try {
242
+ stat = fs.statSync(filePath);
243
+ } catch {
244
+ /* miss → shell */
245
+ }
246
+ if (!stat || !stat.isFile()) return serveIndex(res, distIndex);
247
+ res.setHeader("Content-Type", MIME[extname(filePath).toLowerCase()] ?? "application/octet-stream");
248
+ // Vite emits content-hashed assets under /assets — safe to cache immutably.
249
+ if (url.pathname.startsWith("/assets/")) {
250
+ res.setHeader("Cache-Control", "public, max-age=31536000, immutable");
251
+ }
252
+ fs.createReadStream(filePath).pipe(res);
253
+ }
254
+
255
+ function serveIndex(res, distIndex) {
256
+ res.setHeader("Content-Type", "text/html; charset=utf-8");
257
+ res.setHeader("Cache-Control", "no-cache");
258
+ fs.createReadStream(distIndex).pipe(res);
259
+ }
260
+
174
261
  // Listen on `port`; if it is already in use, fall back to the next port (up to
175
262
  // `MAX_PORT_TRIES`), so two instances — or a leftover one — don't collide.
176
263
  const shown = host === "0.0.0.0" || host === "::" ? "localhost" : host;
@@ -191,7 +278,7 @@ function listenWithFallback(p, triesLeft) {
191
278
  };
192
279
  const onListening = () => {
193
280
  server.off("error", onError); // bound OK — stop intercepting listen errors
194
- console.log(`yamlover serving ${dataRoot}`);
281
+ console.log(`yamlover serving ${dataRoot}${prod ? "" : " (live/Vite)"}`);
195
282
  console.log(` http://${shown}:${p}/ (bound to ${host})`);
196
283
  };
197
284
  server.once("error", onError);
@@ -0,0 +1 @@
1
+ function r(o){throw new Error('Could not dynamically require "'+o+'". Please configure the dynamicRequireTargets or/and ignoreDynamicRequires option of @rollup/plugin-commonjs appropriately for this require call to work.')}export{r as c};
@@ -0,0 +1 @@
1
+ import{r as f,b as d,j as i}from"./index-CQ3TGVSx.js";import{PanZoomImage as p}from"./imagemap-CUKUIcGe.js";function j({node:r,label:t,decode:a}){const[e,n]=f.useState([]),[c,u]=f.useState(null);return f.useEffect(()=>{let s=!1;const o=[];return n([]),u(null),(async()=>{const l=await fetch(d(r.path)).then(m=>m.arrayBuffer()),g=await a(l);if(!s){for(const m of g)o.push(URL.createObjectURL(m));s||n(o)}})().catch(l=>!s&&u(String(l.message||l))),()=>{s=!0,o.forEach(URL.revokeObjectURL)}},[r.path]),c?i.jsxs("div",{className:"error",children:[t,": ",c]}):e.length?i.jsx(i.Fragment,{children:e.map((s,o)=>i.jsx(p,{src:s,className:"filemap fileimagemap"},o))}):i.jsxs("div",{className:"loading",children:["decoding ",t,"…"]})}async function E(r,t,a){const e=document.createElement("canvas");e.width=t,e.height=a;const n=e.getContext("2d");if(!n)throw new Error("no 2d context");const c=n.createImageData(t,a);return c.data.set(r),n.putImageData(c,0,0),h(e)}function h(r){return new Promise((t,a)=>r.toBlob(e=>e?t(e):a(new Error("canvas export failed")),"image/png"))}export{j as D,h as c,E as r};
@@ -0,0 +1 @@
1
+ import{r as u,f as te,d as ne,e as oe,c as re,D as W,b as se,j as d}from"./index-CQ3TGVSx.js";import{u as ae}from"./paged-CjxSuuik.js";const ce="/assets/djvu-Ci0lFKxE.js";let X=null;function ie(){return window.DjVu?Promise.resolve(window.DjVu):(X??=new Promise((s,c)=>{const i=document.createElement("script");i.src=ce,i.onload=()=>window.DjVu?s(window.DjVu):c(new Error("DjVu failed to load")),i.onerror=()=>c(new Error("could not load djvu.js")),document.head.appendChild(i)}),X)}let m=null,Y=null,_=null;const p=new Map,S=new Map,le=6,F=1500;async function ue(s,c){const i=await ie();return m??=new i.Worker,c!==Y&&(Y=c,p.clear(),S.clear(),_=(async()=>(await m.createDocument(s),Number(await m.doc.getPagesQuantity().run())||0))()),_}async function de(s,c){const i=Math.max(1,Math.round(s.height*c/s.width)),w=await createImageBitmap(s,{resizeWidth:c,resizeHeight:i,resizeQuality:"medium"}),g=document.createElement("canvas");g.width=c,g.height=i;const v=g.getContext("2d");return v.drawImage(w,0,0),w.close(),v.getImageData(0,0,c,i)}function he(s){const c=p.get(s);if(c)return p.delete(s),p.set(s,c),Promise.resolve(c);const i=S.get(s);if(i)return i;const w=(async()=>{const[g,v,x,P]=await m.run(m.doc.getPage(s).getImageData(),m.doc.getPage(s).getNormalizedTextZones(),m.doc.getPage(s).getWidth(),m.doc.getPage(s).getHeight()),M=Number(x)||g.width,N=Number(P)||g.height,y={image:M>F?await de(g,F):g,zones:Array.isArray(v)?v:[],w:M,h:N};for(S.delete(s),p.set(s,y);p.size>le;)p.delete(p.keys().next().value);return y})();return S.set(s,w),w}const C=s=>Number(s)||0;function ge({image:s}){const c=u.useRef(null);return u.useLayoutEffect(()=>{const i=c.current;i&&(i.width=s.width,i.height=s.height,i.getContext("2d")?.putImageData(s,0,0))},[s]),d.jsx("canvas",{className:"djvu-page",ref:c})}function ve({node:s}){const c=u.useRef(null),[i,w]=u.useState(0),[g,v]=u.useState(1),[x,P]=u.useState(0),[M,N]=u.useState(null),[f,y]=u.useState(null),[b,V]=u.useState(()=>new Set),[D,T]=u.useState(()=>new Map),A=u.useRef(new Map),z=te(s.path),{openCreate:H,openEdit:Q,palette:Z,preview:R}=ne(z),q=(R?[...z.annotations,{path:"(preview)",selector:R.selector,tag:R.tag}]:z.annotations).filter(t=>t.selector?.type==="djvu").map(t=>({page:C(t.selector.page)||1,x:C(t.selector.x),y:C(t.selector.y),w:C(t.selector.w),h:C(t.selector.h),title:t.description,color:re(t),ann:oe(t)?t:void 0})),O=R?.color??W,E=u.useRef(new Map),k=ae(c,()=>{const t=[];for(let n=1;n<=i;n++){const e=E.current.get(n);e&&t.push(e)}return t},i>0&&x>0),K=u.useRef(k);K.current=k,u.useLayoutEffect(()=>{k.restoreAnchor()},[g]),u.useEffect(()=>{const t=c.current;t&&!t.closest(".chunk-body")&&t.focus({preventScroll:!0})},[]),u.useLayoutEffect(()=>{const t=c.current;if(!t)return;const n=new ResizeObserver(([e])=>P(e.contentRect.width));return n.observe(t),()=>n.disconnect()},[]);const B=Math.min(x,1e3)*g;u.useEffect(()=>{const t=c.current;if(!t)return;let n=!1,e=0;const o=a=>{(a.ctrlKey||a.altKey||a.metaKey)&&(a.preventDefault(),n||(K.current.captureAnchor(),n=!0),clearTimeout(e),e=window.setTimeout(()=>n=!1,250),v(h=>Math.min(5,Math.max(.4,h*(a.deltaY<0?1.1:1/1.1)))))};return t.addEventListener("wheel",o,{passive:!1}),()=>{t.removeEventListener("wheel",o),clearTimeout(e)}},[]),u.useEffect(()=>{let t=!1;return w(0),N(null),V(new Set),T(new Map),E.current.clear(),A.current.clear(),(async()=>{const n=await fetch(se(s.path)).then(o=>o.arrayBuffer()),e=await ue(n,s.path);t||w(e)})().catch(n=>!t&&N(String(n.message||n))),()=>{t=!0}},[s.path]),u.useEffect(()=>{if(!i)return;const t=new IntersectionObserver(n=>{V(e=>{const o=new Set(e);for(const a of n){const h=Number(a.target.dataset.page);a.isIntersecting?o.add(h):o.delete(h)}return o.size===e.size&&[...o].every(a=>e.has(a))?e:o})},{root:c.current,rootMargin:"2000px 0px"});for(const n of E.current.values())t.observe(n);return()=>t.disconnect()},[i,x>0]),u.useEffect(()=>{let t=!0;return b.forEach(n=>{D.has(n)||he(n).then(e=>{A.current.set(n,{w:e.w,h:e.h}),t&&T(o=>new Map(o).set(n,e))}).catch(()=>{})}),T(n=>{let e=!1;const o=new Map(n);for(const a of o.keys())b.has(a)||(o.delete(a),e=!0);return e?o:n}),()=>{t=!1}},[b]);const G=()=>{const t=window.getSelection();if(!t||t.isCollapsed||!t.anchorNode)return;const e=(t.anchorNode.nodeType===1?t.anchorNode:t.anchorNode.parentElement)?.closest(".djvu-page-wrap");if(!e||!c.current?.contains(e))return;const o=Number(e.dataset.page),a=e.getBoundingClientRect(),h=a.width/(D.get(o)?.w||1);if(!h)return;const l=t.getRangeAt(0).getBoundingClientRect();l.width<2||l.height<2||H({type:"djvu",page:o,x:Math.round((l.left-a.left)/h),y:Math.round((l.top-a.top)/h),w:Math.round(l.width/h),h:Math.round(l.height/h)},{x:l.left,y:l.bottom+6})},I=(t,n)=>n.getBoundingClientRect().width/(D.get(t)?.w||1),J=(t,n)=>{const e=n.currentTarget.getBoundingClientRect(),o=I(t,n.currentTarget);y({page:t,x0:(n.clientX-e.left)/o,y0:(n.clientY-e.top)/o,x1:(n.clientX-e.left)/o,y1:(n.clientY-e.top)/o})},$=(t,n)=>{const e=n.currentTarget.getBoundingClientRect(),o=I(t,n.currentTarget);y(a=>a&&{...a,x1:(n.clientX-e.left)/o,y1:(n.clientY-e.top)/o})},ee=(t,n)=>{const e=f;if(y(null),!e||e.page!==t)return;const o=I(t,n.currentTarget),a=Math.min(e.x0,e.x1),h=Math.min(e.y0,e.y1),l=Math.abs(e.x1-e.x0),r=Math.abs(e.y1-e.y0);if(l*o<3||r*o<3)return;const j=n.currentTarget.getBoundingClientRect();H({type:"djvu",page:t,x:Math.round(a),y:Math.round(h),w:Math.round(l),h:Math.round(r)},{x:j.left+a*o,y:j.top+(h+r)*o+6})};return M?d.jsxs("div",{className:"error",children:["djvu: ",M]}):d.jsxs(d.Fragment,{children:[d.jsxs("div",{className:"filedjvu yo-zoomable",ref:c,tabIndex:0,onMouseUp:G,children:[i===0&&d.jsx("div",{className:"loading",children:"opening djvu…"}),x>0&&Array.from({length:i},(t,n)=>{const e=n+1,o=b.has(e)?D.get(e):void 0,a=A.current.get(e),h=B*(a?a.h/a.w:Math.SQRT2),l=o?B/o.w:0;return d.jsx("div",{className:"djvu-page-wrap","data-page":e,ref:r=>{r?E.current.set(e,r):E.current.delete(e)},style:{width:B,height:o?void 0:h},children:o?d.jsxs(d.Fragment,{children:[d.jsx(ge,{image:o.image}),o.zones.length>0?d.jsx("div",{className:"djvu-textlayer",children:o.zones.map((r,j)=>d.jsx("span",{style:{left:r.x*l,top:r.y*l,width:r.width*l,height:r.height*l,fontSize:r.height*l},children:r.text},j))}):d.jsx("div",{className:"djvu-marquee",onMouseDown:r=>J(e,r),onMouseMove:r=>$(e,r),onMouseUp:r=>ee(e,r),children:f?.page===e&&d.jsx("div",{className:"djvu-region",style:{left:Math.min(f.x0,f.x1)*l,top:Math.min(f.y0,f.y1)*l,width:Math.abs(f.x1-f.x0)*l,height:Math.abs(f.y1-f.y0)*l,borderColor:O,background:O+"2e"}})}),q.filter(r=>r.page===e).map((r,j)=>{const U=r.color||W;return d.jsx("div",{className:"djvu-region"+(r.ann?" editable":""),title:r.ann?r.title||"click to recolor or delete":r.title,onClick:r.ann?L=>{L.stopPropagation(),Q(r.ann,{x:L.clientX,y:L.clientY})}:void 0,style:{left:r.x*l,top:r.y*l,width:r.w*l,height:r.h*l,borderColor:U,background:U+"2e"}},j)})]}):d.jsx("div",{className:"djvu-placeholder",children:b.has(e)?"decoding…":""})},n)})]}),Z]})}export{ve as DjvuView};