mdv-live 0.5.11 → 0.5.12

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/CHANGELOG.md CHANGED
@@ -5,6 +5,23 @@ All notable changes to this project will be documented in this file.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
+ ## [0.5.12] - 2026-05-09
9
+
10
+ ### Fixed
11
+
12
+ - **Server fails to boot when `@marp-team/marp-cli` is missing** (codex P1):
13
+ - 0.5.11 で `require.resolve('@marp-team/marp-cli/package.json')` を
14
+ `src/api/pdf.js` の **module top-level** で実行していたため、optionalDependency
15
+ が欠ける環境 (`npm install --omit=optional`、platform 起因の install 失敗等)
16
+ で `import` 時に throw → サーバー全体が起動不能
17
+ - 解決を `runMarp()` 呼出時の lazy 実行に変更 (`resolveMarpEntry()`)
18
+ - 解決失敗時は `code: 'MARP_CLI_UNAVAILABLE'` を投げ、route handler 側で
19
+ 503 (+ 案内メッセージ) に変換。markdown / 415 経路は marp 不在でも動く
20
+
21
+ ### Tests
22
+
23
+ - 243 → **244 件 (+1)**: `src/api/pdf.js` の import が throw しない regression test
24
+
8
25
  ## [0.5.11] - 2026-05-09
9
26
 
10
27
  ### Fixed
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mdv-live",
3
- "version": "0.5.11",
3
+ "version": "0.5.12",
4
4
  "description": "Markdown Viewer - File tree + Live preview + Marp support + Hot reload",
5
5
  "main": "src/server.js",
6
6
  "bin": {
package/src/api/pdf.js CHANGED
@@ -7,20 +7,42 @@ import { isMarp } from '../rendering/markdown.js';
7
7
  import { validatePath } from '../utils/path.js';
8
8
 
9
9
  const require = createRequire(import.meta.url);
10
- // marp-cli npm hoisting によりインストール先が変わる (top-level / nested)。
11
- // require.resolve でパッケージの実体を特定し、その bin スクリプトを node で
12
- // 直接実行する。`node_modules/.bin/marp` 直叩きは fresh install で nested
13
- // パスが無い時に ENOENT する罠。
14
- const marpEntry = (() => {
15
- const pkgPath = require.resolve('@marp-team/marp-cli/package.json');
10
+ const PDF_EXPORT_TIMEOUT_MS = 180000;
11
+
12
+ /**
13
+ * Lazily resolve the marp-cli bin script.
14
+ *
15
+ * `@marp-team/marp-cli` は optionalDependencies。`npm install --omit=optional` や
16
+ * platform 起因の install 失敗で欠けることがあるため、サーバー起動時に解決
17
+ * すると import 段階で throw → サーバー全体が起動できなくなる。PDF export
18
+ * 経路でだけ解決し、欠けていれば export だけ 503 を返す設計に倒す。
19
+ *
20
+ * npm hoisting により実体パスは top-level / nested で変わる。`node_modules/
21
+ * .bin/marp` 直叩きは fresh install で ENOENT に落ちる罠なので、package.json
22
+ * の bin エントリ経由で解決する。
23
+ *
24
+ * @returns {string} Absolute path to the marp-cli bin script.
25
+ * @throws {Error} `code === 'MARP_CLI_UNAVAILABLE'` if the package is missing.
26
+ */
27
+ function resolveMarpEntry() {
28
+ let pkgPath;
29
+ try {
30
+ pkgPath = require.resolve('@marp-team/marp-cli/package.json');
31
+ } catch (err) {
32
+ const e = new Error('@marp-team/marp-cli is not installed (optionalDependency missing).');
33
+ e.code = 'MARP_CLI_UNAVAILABLE';
34
+ e.cause = err;
35
+ throw e;
36
+ }
16
37
  const pkg = require('@marp-team/marp-cli/package.json');
17
38
  const binRel = typeof pkg.bin === 'string' ? pkg.bin : pkg.bin?.marp;
18
39
  if (!binRel) {
19
- throw new Error('@marp-team/marp-cli does not declare a "marp" bin entry');
40
+ const e = new Error('@marp-team/marp-cli does not declare a "marp" bin entry.');
41
+ e.code = 'MARP_CLI_UNAVAILABLE';
42
+ throw e;
20
43
  }
21
44
  return path.join(path.dirname(pkgPath), binRel);
22
- })();
23
- const PDF_EXPORT_TIMEOUT_MS = 180000;
45
+ }
24
46
 
25
47
  /**
26
48
  * Spawn marp-cli with stdin closed.
@@ -28,6 +50,7 @@ const PDF_EXPORT_TIMEOUT_MS = 180000;
28
50
  * 注意: execFile は stdio オプションを受け付けない (Node 仕様) ため spawn を使う。
29
51
  */
30
52
  function runMarp(args) {
53
+ const marpEntry = resolveMarpEntry();
31
54
  return new Promise((resolve, reject) => {
32
55
  const child = spawn(process.execPath, [marpEntry, ...args], {
33
56
  stdio: ['ignore', 'pipe', 'pipe'],
@@ -114,6 +137,11 @@ export function setupPdfRoutes(app) {
114
137
  } catch (err) {
115
138
  console.error('PDF export error:', err);
116
139
  try { await fs.unlink(outputPath); } catch { /* ignore */ }
140
+ if (err.code === 'MARP_CLI_UNAVAILABLE') {
141
+ return res.status(503).json({
142
+ error: 'Marp PDF export is unavailable: install @marp-team/marp-cli or run `npm install` without --omit=optional.',
143
+ });
144
+ }
117
145
  res.status(500).json({ error: 'PDF export failed' });
118
146
  }
119
147
  });