@bendyline/docblocks-cli 1.1.2 → 2.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 (110) hide show
  1. package/README.md +60 -88
  2. package/dist/commands/convert.d.ts +12 -2
  3. package/dist/commands/convert.d.ts.map +1 -1
  4. package/dist/commands/convert.js +272 -101
  5. package/dist/commands/convert.js.map +1 -1
  6. package/dist/commands/mcp.d.ts +1 -1
  7. package/dist/commands/mcp.d.ts.map +1 -1
  8. package/dist/commands/mcp.js +90 -4
  9. package/dist/commands/mcp.js.map +1 -1
  10. package/dist/commands/parse.js +1 -1
  11. package/dist/commands/parse.js.map +1 -1
  12. package/dist/commands/serve.d.ts +9 -1
  13. package/dist/commands/serve.d.ts.map +1 -1
  14. package/dist/commands/serve.js +209 -44
  15. package/dist/commands/serve.js.map +1 -1
  16. package/dist/commands/themes.js +1 -1
  17. package/dist/commands/themes.js.map +1 -1
  18. package/dist/commands/transforms.js +1 -1
  19. package/dist/commands/transforms.js.map +1 -1
  20. package/dist/commands/video.d.ts +8 -1
  21. package/dist/commands/video.d.ts.map +1 -1
  22. package/dist/commands/video.js +50 -30
  23. package/dist/commands/video.js.map +1 -1
  24. package/dist/contained-file.d.ts +8 -0
  25. package/dist/contained-file.d.ts.map +1 -0
  26. package/dist/contained-file.js +77 -0
  27. package/dist/contained-file.js.map +1 -0
  28. package/dist/index.js +1 -1
  29. package/dist/index.js.map +1 -1
  30. package/dist/mcp/agentic-tools.d.ts +16 -0
  31. package/dist/mcp/agentic-tools.d.ts.map +1 -0
  32. package/dist/mcp/agentic-tools.js +967 -0
  33. package/dist/mcp/agentic-tools.js.map +1 -0
  34. package/dist/mcp/artifact-store.d.ts +98 -0
  35. package/dist/mcp/artifact-store.d.ts.map +1 -0
  36. package/dist/mcp/artifact-store.js +542 -0
  37. package/dist/mcp/artifact-store.js.map +1 -0
  38. package/dist/mcp/authority.d.ts +53 -0
  39. package/dist/mcp/authority.d.ts.map +1 -0
  40. package/dist/mcp/authority.js +433 -0
  41. package/dist/mcp/authority.js.map +1 -0
  42. package/dist/mcp/conversion-service.d.ts +111 -0
  43. package/dist/mcp/conversion-service.d.ts.map +1 -0
  44. package/dist/mcp/conversion-service.js +512 -0
  45. package/dist/mcp/conversion-service.js.map +1 -0
  46. package/dist/mcp/discovery-tools.d.ts +4 -0
  47. package/dist/mcp/discovery-tools.d.ts.map +1 -0
  48. package/dist/mcp/discovery-tools.js +114 -0
  49. package/dist/mcp/discovery-tools.js.map +1 -0
  50. package/dist/mcp/document-service.d.ts +47 -0
  51. package/dist/mcp/document-service.d.ts.map +1 -0
  52. package/dist/mcp/document-service.js +424 -0
  53. package/dist/mcp/document-service.js.map +1 -0
  54. package/dist/mcp/error-result.d.ts +17 -0
  55. package/dist/mcp/error-result.d.ts.map +1 -0
  56. package/dist/mcp/error-result.js +82 -0
  57. package/dist/mcp/error-result.js.map +1 -0
  58. package/dist/mcp/intelligence.d.ts +15 -0
  59. package/dist/mcp/intelligence.d.ts.map +1 -0
  60. package/dist/mcp/intelligence.js +855 -0
  61. package/dist/mcp/intelligence.js.map +1 -0
  62. package/dist/mcp/output-bounds.d.ts +13 -0
  63. package/dist/mcp/output-bounds.d.ts.map +1 -0
  64. package/dist/mcp/output-bounds.js +61 -0
  65. package/dist/mcp/output-bounds.js.map +1 -0
  66. package/dist/mcp/preview-service.d.ts +54 -0
  67. package/dist/mcp/preview-service.d.ts.map +1 -0
  68. package/dist/mcp/preview-service.js +454 -0
  69. package/dist/mcp/preview-service.js.map +1 -0
  70. package/dist/mcp/progress.d.ts +18 -0
  71. package/dist/mcp/progress.d.ts.map +1 -0
  72. package/dist/mcp/progress.js +28 -0
  73. package/dist/mcp/progress.js.map +1 -0
  74. package/dist/mcp/prompts.d.ts +4 -0
  75. package/dist/mcp/prompts.d.ts.map +1 -0
  76. package/dist/mcp/prompts.js +124 -0
  77. package/dist/mcp/prompts.js.map +1 -0
  78. package/dist/mcp/rendered-conversion.d.ts +34 -0
  79. package/dist/mcp/rendered-conversion.d.ts.map +1 -0
  80. package/dist/mcp/rendered-conversion.js +364 -0
  81. package/dist/mcp/rendered-conversion.js.map +1 -0
  82. package/dist/mcp/server.d.ts +67 -10
  83. package/dist/mcp/server.d.ts.map +1 -1
  84. package/dist/mcp/server.js +227 -496
  85. package/dist/mcp/server.js.map +1 -1
  86. package/dist/preview-policy.d.ts +8 -0
  87. package/dist/preview-policy.d.ts.map +1 -0
  88. package/dist/preview-policy.js +85 -0
  89. package/dist/preview-policy.js.map +1 -0
  90. package/dist/render-html.d.ts +8 -0
  91. package/dist/render-html.d.ts.map +1 -1
  92. package/dist/render-html.js +32 -7
  93. package/dist/render-html.js.map +1 -1
  94. package/dist/version.d.ts +4 -0
  95. package/dist/version.d.ts.map +1 -1
  96. package/dist/version.js +95 -6
  97. package/dist/version.js.map +1 -1
  98. package/package.json +11 -11
  99. package/dist/converters/docx-to-md.d.ts +0 -10
  100. package/dist/converters/docx-to-md.d.ts.map +0 -1
  101. package/dist/converters/docx-to-md.js +0 -17
  102. package/dist/converters/docx-to-md.js.map +0 -1
  103. package/dist/converters/pdf-to-md.d.ts +0 -14
  104. package/dist/converters/pdf-to-md.d.ts.map +0 -1
  105. package/dist/converters/pdf-to-md.js +0 -51
  106. package/dist/converters/pdf-to-md.js.map +0 -1
  107. package/dist/converters/pptx-to-md.d.ts +0 -13
  108. package/dist/converters/pptx-to-md.d.ts.map +0 -1
  109. package/dist/converters/pptx-to-md.js +0 -67
  110. package/dist/converters/pptx-to-md.js.map +0 -1
@@ -4,10 +4,15 @@ export interface ServeOptions {
4
4
  port: number;
5
5
  dir: string;
6
6
  theme?: string;
7
+ host?: string;
8
+ allowNetwork?: boolean;
9
+ maxFileBytes?: number;
10
+ maxConcurrentReads?: number;
7
11
  }
8
12
  export interface PreviewServer {
9
13
  server: Server;
10
14
  root: string;
15
+ host: string;
11
16
  url: string;
12
17
  }
13
18
  export declare function startPreviewServer(opts: ServeOptions): Promise<PreviewServer>;
@@ -20,9 +25,12 @@ type ServeTarget = {
20
25
  kind: 'missing';
21
26
  } | {
22
27
  kind: 'forbidden';
28
+ } | {
29
+ kind: 'too-large';
23
30
  } | {
24
31
  kind: 'bad-request';
25
32
  };
26
- export declare function resolveServeTarget(root: string, requestUrl: string): Promise<ServeTarget>;
33
+ export declare function resolveServeTarget(root: string, requestUrl: string, maxFileBytes?: number): Promise<ServeTarget>;
34
+ export declare function isAllowedPreviewRequestAuthority(header: string | undefined, configuredHost: string, configuredPort: number): boolean;
27
35
  export {};
28
36
  //# sourceMappingURL=serve.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"serve.d.ts","sourceRoot":"","sources":["../../src/commands/serve.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAsC,KAAK,MAAM,EAAuB,MAAM,WAAW,CAAC;AAKjG,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,aAAa;IAC5B,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,MAAM,CAAC;CACb;AAED,wBAAsB,kBAAkB,CAAC,IAAI,EAAE,YAAY,GAAG,OAAO,CAAC,aAAa,CAAC,CAyBnF;AAED,eAAO,MAAM,YAAY,SAkBrB,CAAC;AA4CL,KAAK,WAAW,GACZ;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,OAAO,CAAA;CAAE,GACrD;IAAE,IAAI,EAAE,SAAS,CAAA;CAAE,GACnB;IAAE,IAAI,EAAE,WAAW,CAAA;CAAE,GACrB;IAAE,IAAI,EAAE,aAAa,CAAA;CAAE,CAAC;AAE5B,wBAAsB,kBAAkB,CAAC,IAAI,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,CAAC,CAoB/F"}
1
+ {"version":3,"file":"serve.d.ts","sourceRoot":"","sources":["../../src/commands/serve.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAsC,KAAK,MAAM,EAAuB,MAAM,WAAW,CAAC;AAQjG,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,kBAAkB,CAAC,EAAE,MAAM,CAAC;CAC7B;AAED,MAAM,WAAW,aAAa;IAC5B,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,MAAM,CAAC;CACb;AAKD,wBAAsB,kBAAkB,CAAC,IAAI,EAAE,YAAY,GAAG,OAAO,CAAC,aAAa,CAAC,CA8CnF;AAED,eAAO,MAAM,YAAY,SA8BtB,CAAC;AAuDJ,KAAK,WAAW,GACZ;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,OAAO,CAAA;CAAE,GACrD;IAAE,IAAI,EAAE,SAAS,CAAA;CAAE,GACnB;IAAE,IAAI,EAAE,WAAW,CAAA;CAAE,GACrB;IAAE,IAAI,EAAE,WAAW,CAAA;CAAE,GACrB;IAAE,IAAI,EAAE,aAAa,CAAA;CAAE,CAAC;AAE5B,wBAAsB,kBAAkB,CACtC,IAAI,EAAE,MAAM,EACZ,UAAU,EAAE,MAAM,EAClB,YAAY,SAAyB,GACpC,OAAO,CAAC,WAAW,CAAC,CAkCtB;AAqHD,wBAAgB,gCAAgC,CAC9C,MAAM,EAAE,MAAM,GAAG,SAAS,EAC1B,cAAc,EAAE,MAAM,EACtB,cAAc,EAAE,MAAM,GACrB,OAAO,CAOT"}
@@ -1,42 +1,69 @@
1
1
  import { Command } from 'commander';
2
2
  import { createServer } from 'node:http';
3
- import { readFile, stat } from 'node:fs/promises';
3
+ import { realpath, stat } from 'node:fs/promises';
4
+ import { isIP } from 'node:net';
4
5
  import path from 'node:path';
5
6
  import { renderMarkdownHtml } from '../render-html.js';
7
+ import { readContainedFile } from '../contained-file.js';
8
+ import { isAllowedPreviewPath } from '../preview-policy.js';
9
+ const DEFAULT_HOST = '127.0.0.1';
10
+ const DEFAULT_MAX_FILE_BYTES = 50 * 1024 * 1024;
11
+ const DEFAULT_MAX_CONCURRENT_READS = 16;
6
12
  export async function startPreviewServer(opts) {
7
- const root = path.resolve(opts.dir);
13
+ const requestedRoot = path.resolve(opts.dir);
14
+ const root = await realpath(requestedRoot).catch(() => requestedRoot);
8
15
  const rootStat = await stat(root).catch(() => null);
9
16
  if (!rootStat?.isDirectory()) {
10
17
  throw new Error(`Directory not found: ${root}`);
11
18
  }
19
+ const host = validateHost(opts.host ?? DEFAULT_HOST, opts.allowNetwork === true);
20
+ const maxFileBytes = positiveLimit(opts.maxFileBytes, DEFAULT_MAX_FILE_BYTES, 'file size');
21
+ const maxConcurrentReads = positiveLimit(opts.maxConcurrentReads, DEFAULT_MAX_CONCURRENT_READS, 'concurrent request');
22
+ let activeRequests = 0;
12
23
  const server = createServer((req, res) => {
13
- handlePreviewRequest(req, res, root, opts.theme).catch((err) => {
14
- const message = err instanceof Error ? err.message : String(err);
15
- sendText(res, 500, `Internal server error: ${message}`);
24
+ const address = server.address();
25
+ const port = typeof address === 'object' && address ? address.port : opts.port;
26
+ if (!isAllowedPreviewRequestAuthority(req.headers.host, host, port)) {
27
+ sendText(res, 421, 'Misdirected request', req.method === 'HEAD');
28
+ return;
29
+ }
30
+ if (activeRequests >= maxConcurrentReads) {
31
+ sendText(res, 503, 'Server busy', req.method === 'HEAD');
32
+ return;
33
+ }
34
+ activeRequests += 1;
35
+ handlePreviewRequest(req, res, root, opts.theme, maxFileBytes)
36
+ .catch(() => sendText(res, 500, 'Internal server error', req.method === 'HEAD'))
37
+ .finally(() => {
38
+ activeRequests -= 1;
16
39
  });
17
40
  });
18
41
  await new Promise((resolve, reject) => {
19
42
  server.once('error', reject);
20
- server.listen(opts.port, () => {
43
+ server.listen(opts.port, host, () => {
21
44
  server.off('error', reject);
22
45
  resolve();
23
46
  });
24
47
  });
25
48
  const address = server.address();
26
49
  const port = typeof address === 'object' && address ? address.port : opts.port;
27
- return { server, root, url: `http://localhost:${port}/` };
50
+ return { server, root, host, url: `http://${urlHost(host)}:${port}/` };
28
51
  }
29
52
  export const serveCommand = new Command('serve')
30
53
  .description('Start a local dev server for previewing markdown files')
31
54
  .option('-p, --port <port>', 'port to listen on', '3000')
32
55
  .option('-d, --dir <dir>', 'directory to serve', '.')
33
56
  .option('-t, --theme <id>', 'Squisq theme ID to apply')
57
+ .option('--host <host>', 'interface to bind (loopback by default)', DEFAULT_HOST)
58
+ .option('--allow-network', 'allow a non-loopback --host')
34
59
  .action(async (opts) => {
35
60
  try {
36
61
  const server = await startPreviewServer({
37
62
  port: parsePort(opts.port),
38
63
  dir: opts.dir,
39
64
  theme: opts.theme,
65
+ host: opts.host,
66
+ allowNetwork: opts.allowNetwork,
40
67
  });
41
68
  console.error(`Serving ${server.root} at ${server.url}`);
42
69
  }
@@ -46,57 +73,74 @@ export const serveCommand = new Command('serve')
46
73
  process.exitCode = 1;
47
74
  }
48
75
  });
49
- async function handlePreviewRequest(req, res, root, themeId) {
76
+ async function handlePreviewRequest(req, res, root, themeId, maxFileBytes) {
50
77
  if (req.method !== 'GET' && req.method !== 'HEAD') {
51
78
  sendText(res, 405, 'Method not allowed');
52
79
  return;
53
80
  }
54
- const target = await resolveServeTarget(root, req.url ?? '/');
81
+ const headOnly = req.method === 'HEAD';
82
+ const target = await resolveServeTarget(root, req.url ?? '/', maxFileBytes);
55
83
  if (target.kind === 'bad-request') {
56
- sendText(res, 400, 'Bad request');
84
+ sendText(res, 400, 'Bad request', headOnly);
57
85
  return;
58
86
  }
59
87
  if (target.kind === 'forbidden') {
60
- sendText(res, 403, 'Forbidden');
88
+ sendText(res, 403, 'Forbidden', headOnly);
61
89
  return;
62
90
  }
63
91
  if (target.kind === 'missing') {
64
- sendText(res, 404, 'Not found');
92
+ sendText(res, 404, 'Not found', headOnly);
93
+ return;
94
+ }
95
+ if (target.kind === 'too-large') {
96
+ sendText(res, 413, 'File too large', headOnly);
65
97
  return;
66
98
  }
67
99
  if (target.markdown) {
68
- const markdown = await readFile(target.filePath, 'utf-8');
100
+ const markdown = (await readContainedFile(root, target.filePath, maxFileBytes)).toString('utf8');
69
101
  const html = await renderMarkdownHtml(markdown, {
70
102
  title: path.basename(target.filePath).replace(/\.(md|markdown)$/i, ''),
71
103
  sourcePath: target.filePath,
72
104
  assetRoot: root,
73
105
  themeId,
74
106
  mode: 'static',
107
+ allowReferencedAsset: ({ assetRoot, requestedPath, physicalPath }) => isAllowedPreviewPath(assetRoot, requestedPath, physicalPath, 'embedded-image'),
75
108
  });
76
- sendBody(res, 200, html, 'text/html; charset=utf-8', req.method === 'HEAD');
109
+ sendBody(res, 200, html, 'text/html; charset=utf-8', headOnly);
77
110
  return;
78
111
  }
79
- const body = await readFile(target.filePath);
80
- sendBody(res, 200, body, contentTypeFor(target.filePath), req.method === 'HEAD');
112
+ const body = await readContainedFile(root, target.filePath, maxFileBytes);
113
+ sendBody(res, 200, body, contentTypeFor(target.filePath), headOnly);
81
114
  }
82
- export async function resolveServeTarget(root, requestUrl) {
115
+ export async function resolveServeTarget(root, requestUrl, maxFileBytes = DEFAULT_MAX_FILE_BYTES) {
116
+ if (requestUrl.length > 8192 || requestUrl.includes('\0'))
117
+ return { kind: 'bad-request' };
118
+ const physicalRoot = await realpath(path.resolve(root)).catch(() => null);
119
+ if (!physicalRoot)
120
+ return { kind: 'missing' };
83
121
  const decodedPath = decodeRequestPath(requestUrl);
84
122
  if (!decodedPath)
85
123
  return { kind: 'bad-request' };
86
124
  const requestedPath = decodedPath.replace(/^\/+/, '');
87
- const candidate = path.resolve(root, requestedPath);
88
- if (!isPathInside(root, candidate))
125
+ const candidate = path.resolve(physicalRoot, requestedPath);
126
+ if (!isAllowedPreviewPath(physicalRoot, candidate, candidate, 'directory')) {
89
127
  return { kind: 'forbidden' };
90
- const direct = await fileTarget(candidate);
91
- if (direct)
128
+ }
129
+ const direct = await inspectTarget(physicalRoot, candidate, maxFileBytes);
130
+ if (direct.kind === 'file')
92
131
  return direct;
93
- const dirIndex = await directoryIndexTarget(candidate);
94
- if (dirIndex)
95
- return dirIndex;
132
+ if (direct.kind === 'forbidden' || direct.kind === 'too-large')
133
+ return direct;
134
+ if (direct.kind === 'directory') {
135
+ const dirIndex = await directoryIndexTarget(physicalRoot, direct.filePath, maxFileBytes);
136
+ if (dirIndex.kind !== 'missing')
137
+ return dirIndex;
138
+ }
96
139
  if (/\.html?$/i.test(candidate)) {
97
- const markdownTarget = await fileTarget(candidate.replace(/\.html?$/i, '.md'));
98
- if (markdownTarget)
140
+ const markdownTarget = await inspectTarget(physicalRoot, candidate.replace(/\.html?$/i, '.md'), maxFileBytes);
141
+ if (markdownTarget.kind !== 'directory' && markdownTarget.kind !== 'missing') {
99
142
  return markdownTarget;
143
+ }
100
144
  }
101
145
  return { kind: 'missing' };
102
146
  }
@@ -109,22 +153,39 @@ function decodeRequestPath(requestUrl) {
109
153
  return '';
110
154
  }
111
155
  }
112
- async function fileTarget(filePath) {
113
- const info = await stat(filePath).catch(() => null);
114
- if (!info?.isFile())
115
- return null;
116
- return { kind: 'file', filePath, markdown: /\.(md|markdown)$/i.test(filePath) };
156
+ async function inspectTarget(root, candidate, maxFileBytes) {
157
+ let physical;
158
+ try {
159
+ physical = await realpath(candidate);
160
+ }
161
+ catch {
162
+ return { kind: 'missing' };
163
+ }
164
+ const info = await stat(physical).catch(() => null);
165
+ if (!info)
166
+ return { kind: 'missing' };
167
+ if (info.isDirectory()) {
168
+ return isAllowedPreviewPath(root, candidate, physical, 'directory')
169
+ ? { kind: 'directory', filePath: physical }
170
+ : { kind: 'forbidden' };
171
+ }
172
+ if (!info.isFile())
173
+ return { kind: 'forbidden' };
174
+ if (!isAllowedPreviewPath(root, candidate, physical, 'document-or-asset')) {
175
+ return { kind: 'forbidden' };
176
+ }
177
+ if (info.size > maxFileBytes)
178
+ return { kind: 'too-large' };
179
+ return { kind: 'file', filePath: physical, markdown: /\.(md|markdown)$/i.test(physical) };
117
180
  }
118
- async function directoryIndexTarget(dirPath) {
119
- const info = await stat(dirPath).catch(() => null);
120
- if (!info?.isDirectory())
121
- return null;
181
+ async function directoryIndexTarget(root, dirPath, maxFileBytes) {
122
182
  for (const fileName of ['index.html', 'index.htm', 'index.md', 'index.markdown']) {
123
- const target = await fileTarget(path.join(dirPath, fileName));
124
- if (target)
183
+ const target = await inspectTarget(root, path.join(dirPath, fileName), maxFileBytes);
184
+ if (target.kind === 'file' || target.kind === 'forbidden' || target.kind === 'too-large') {
125
185
  return target;
186
+ }
126
187
  }
127
- return null;
188
+ return { kind: 'missing' };
128
189
  }
129
190
  function parsePort(value) {
130
191
  const port = Number(value);
@@ -133,18 +194,108 @@ function parsePort(value) {
133
194
  }
134
195
  return port;
135
196
  }
136
- function sendText(res, status, message) {
137
- sendBody(res, status, `${message}\n`, 'text/plain; charset=utf-8', false);
197
+ function sendText(res, status, message, headOnly = false) {
198
+ sendBody(res, status, `${message}\n`, 'text/plain; charset=utf-8', headOnly);
138
199
  }
139
200
  function sendBody(res, status, body, contentType, headOnly) {
140
201
  res.statusCode = status;
141
202
  res.setHeader('content-type', contentType);
203
+ res.setHeader('x-content-type-options', 'nosniff');
204
+ res.setHeader('referrer-policy', 'no-referrer');
205
+ res.setHeader('cache-control', 'no-store');
142
206
  if (headOnly) {
143
207
  res.end();
144
208
  return;
145
209
  }
146
210
  res.end(body);
147
211
  }
212
+ function validateHost(value, allowNetwork) {
213
+ const rawHost = value.trim().toLowerCase();
214
+ const host = rawHost.startsWith('[') && rawHost.endsWith(']') ? rawHost.slice(1, -1) : rawHost;
215
+ if (!host ||
216
+ host.length > 255 ||
217
+ /[\s/\\\0]/.test(host) ||
218
+ (isIP(host) === 0 && !isValidHostname(host))) {
219
+ throw new Error('Invalid host');
220
+ }
221
+ if (!allowNetwork && !isLoopbackHost(host)) {
222
+ throw new Error('Non-loopback hosts require --allow-network');
223
+ }
224
+ return host;
225
+ }
226
+ function isLoopbackHost(host) {
227
+ if (host === 'localhost' || host === '::1')
228
+ return true;
229
+ const octets = host.split('.');
230
+ return (octets.length === 4 &&
231
+ octets[0] === '127' &&
232
+ octets.every((octet) => /^\d{1,3}$/.test(octet) && Number(octet) <= 255));
233
+ }
234
+ export function isAllowedPreviewRequestAuthority(header, configuredHost, configuredPort) {
235
+ const authority = parseRequestAuthority(header);
236
+ if (!authority || authority.port !== configuredPort)
237
+ return false;
238
+ if (configuredHost === '0.0.0.0')
239
+ return isIP(authority.host) === 4;
240
+ if (configuredHost === '::')
241
+ return isIP(authority.host) === 6;
242
+ return authority.host === configuredHost;
243
+ }
244
+ function parseRequestAuthority(header) {
245
+ if (!header || header.length > 512 || /[\s,\\/\0]/.test(header))
246
+ return null;
247
+ let host;
248
+ let portText = '';
249
+ let hasPortSeparator = false;
250
+ if (header.startsWith('[')) {
251
+ const closingBracket = header.indexOf(']');
252
+ if (closingBracket < 0)
253
+ return null;
254
+ host = header.slice(1, closingBracket).toLowerCase();
255
+ const remainder = header.slice(closingBracket + 1);
256
+ if (remainder && !remainder.startsWith(':'))
257
+ return null;
258
+ hasPortSeparator = remainder.startsWith(':');
259
+ portText = remainder.slice(1);
260
+ if (isIP(host) !== 6)
261
+ return null;
262
+ }
263
+ else {
264
+ const separator = header.lastIndexOf(':');
265
+ if (separator >= 0) {
266
+ if (header.indexOf(':') !== separator)
267
+ return null;
268
+ hasPortSeparator = true;
269
+ host = header.slice(0, separator).toLowerCase();
270
+ portText = header.slice(separator + 1);
271
+ }
272
+ else {
273
+ host = header.toLowerCase();
274
+ }
275
+ if (isIP(host) === 0 && !isValidHostname(host))
276
+ return null;
277
+ }
278
+ if (hasPortSeparator && !/^\d{1,5}$/.test(portText))
279
+ return null;
280
+ const port = portText ? Number(portText) : 80;
281
+ if (!Number.isInteger(port) || port < 1 || port > 65535)
282
+ return null;
283
+ return { host, port };
284
+ }
285
+ function isValidHostname(host) {
286
+ return (host.length <= 253 &&
287
+ !host.endsWith('.') &&
288
+ host.split('.').every((label) => /^(?!-)[a-z0-9-]{1,63}(?<!-)$/.test(label)));
289
+ }
290
+ function urlHost(host) {
291
+ return host.includes(':') && !host.startsWith('[') ? `[${host}]` : host;
292
+ }
293
+ function positiveLimit(value, fallback, label) {
294
+ const selected = value ?? fallback;
295
+ if (!Number.isSafeInteger(selected) || selected < 1)
296
+ throw new Error(`Invalid ${label} limit`);
297
+ return selected;
298
+ }
148
299
  function contentTypeFor(filePath) {
149
300
  const ext = path.extname(filePath).toLowerCase();
150
301
  switch (ext) {
@@ -171,12 +322,26 @@ function contentTypeFor(filePath) {
171
322
  return 'image/webp';
172
323
  case '.ico':
173
324
  return 'image/x-icon';
325
+ case '.woff':
326
+ return 'font/woff';
327
+ case '.woff2':
328
+ return 'font/woff2';
329
+ case '.ttf':
330
+ return 'font/ttf';
331
+ case '.otf':
332
+ return 'font/otf';
333
+ case '.mp3':
334
+ return 'audio/mpeg';
335
+ case '.wav':
336
+ return 'audio/wav';
337
+ case '.ogg':
338
+ return 'audio/ogg';
339
+ case '.mp4':
340
+ return 'video/mp4';
341
+ case '.webm':
342
+ return 'video/webm';
174
343
  default:
175
344
  return 'application/octet-stream';
176
345
  }
177
346
  }
178
- function isPathInside(rootAbs, candidateAbs) {
179
- const rel = path.relative(path.resolve(rootAbs), path.resolve(candidateAbs));
180
- return rel === '' || (!rel.startsWith(`..${path.sep}`) && rel !== '..' && !path.isAbsolute(rel));
181
- }
182
347
  //# sourceMappingURL=serve.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"serve.js","sourceRoot":"","sources":["../../src/commands/serve.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"serve.js","sourceRoot":"","sources":["../../src/commands/serve.ts"],"names":[],"mappings":"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"}
@@ -9,7 +9,7 @@ export const themesCommand = new Command('themes')
9
9
  const themes = getAvailableThemes();
10
10
  console.error('Available themes:\n');
11
11
  for (const theme of themes) {
12
- process.stdout.write(` ${theme}\n`);
12
+ process.stdout.write(`${theme}\n`);
13
13
  }
14
14
  });
15
15
  //# sourceMappingURL=themes.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"themes.js","sourceRoot":"","sources":["../../src/commands/themes.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAEpC,MAAM,CAAC,MAAM,aAAa,GAAG,IAAI,OAAO,CAAC,QAAQ,CAAC;KAC/C,WAAW,CAAC,kCAAkC,CAAC;KAC/C,MAAM,CAAC,KAAK,IAAI,EAAE;IACjB,MAAM,EAAE,kBAAkB,EAAE,GAAG,MAAM,MAAM,CAAC,2BAA2B,CAAC,CAAC;IACzE,MAAM,MAAM,GAAG,kBAAkB,EAAE,CAAC;IACpC,OAAO,CAAC,KAAK,CAAC,qBAAqB,CAAC,CAAC;IACrC,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;QAC3B,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,KAAK,KAAK,IAAI,CAAC,CAAC;IACvC,CAAC;AACH,CAAC,CAAC,CAAC"}
1
+ {"version":3,"file":"themes.js","sourceRoot":"","sources":["../../src/commands/themes.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAEpC,MAAM,CAAC,MAAM,aAAa,GAAG,IAAI,OAAO,CAAC,QAAQ,CAAC;KAC/C,WAAW,CAAC,kCAAkC,CAAC;KAC/C,MAAM,CAAC,KAAK,IAAI,EAAE;IACjB,MAAM,EAAE,kBAAkB,EAAE,GAAG,MAAM,MAAM,CAAC,2BAA2B,CAAC,CAAC;IACzE,MAAM,MAAM,GAAG,kBAAkB,EAAE,CAAC;IACpC,OAAO,CAAC,KAAK,CAAC,qBAAqB,CAAC,CAAC;IACrC,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;QAC3B,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,KAAK,IAAI,CAAC,CAAC;IACrC,CAAC;AACH,CAAC,CAAC,CAAC"}
@@ -9,7 +9,7 @@ export const transformsCommand = new Command('transforms')
9
9
  const styles = getTransformStyleIds();
10
10
  console.error('Available transform styles:\n');
11
11
  for (const style of styles) {
12
- process.stdout.write(` ${style}\n`);
12
+ process.stdout.write(`${style}\n`);
13
13
  }
14
14
  });
15
15
  //# sourceMappingURL=transforms.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"transforms.js","sourceRoot":"","sources":["../../src/commands/transforms.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAEpC,MAAM,CAAC,MAAM,iBAAiB,GAAG,IAAI,OAAO,CAAC,YAAY,CAAC;KACvD,WAAW,CAAC,qCAAqC,CAAC;KAClD,MAAM,CAAC,KAAK,IAAI,EAAE;IACjB,MAAM,EAAE,oBAAoB,EAAE,GAAG,MAAM,MAAM,CAAC,6BAA6B,CAAC,CAAC;IAC7E,MAAM,MAAM,GAAG,oBAAoB,EAAE,CAAC;IACtC,OAAO,CAAC,KAAK,CAAC,+BAA+B,CAAC,CAAC;IAC/C,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;QAC3B,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,KAAK,KAAK,IAAI,CAAC,CAAC;IACvC,CAAC;AACH,CAAC,CAAC,CAAC"}
1
+ {"version":3,"file":"transforms.js","sourceRoot":"","sources":["../../src/commands/transforms.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAEpC,MAAM,CAAC,MAAM,iBAAiB,GAAG,IAAI,OAAO,CAAC,YAAY,CAAC;KACvD,WAAW,CAAC,qCAAqC,CAAC;KAClD,MAAM,CAAC,KAAK,IAAI,EAAE;IACjB,MAAM,EAAE,oBAAoB,EAAE,GAAG,MAAM,MAAM,CAAC,6BAA6B,CAAC,CAAC;IAC7E,MAAM,MAAM,GAAG,oBAAoB,EAAE,CAAC;IACtC,OAAO,CAAC,KAAK,CAAC,+BAA+B,CAAC,CAAC;IAC/C,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;QAC3B,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,KAAK,IAAI,CAAC,CAAC;IACrC,CAAC;AACH,CAAC,CAAC,CAAC"}
@@ -16,16 +16,23 @@ export interface VideoOptions {
16
16
  captions?: CaptionOption;
17
17
  width?: number;
18
18
  height?: number;
19
+ /** Cancel input preparation, browser capture, or FFmpeg encoding. */
20
+ signal?: AbortSignal;
19
21
  }
20
22
  export interface VideoResult {
21
23
  outputPath: string;
22
24
  duration: number;
23
25
  frameCount: number;
24
26
  }
27
+ type RenderDocToMp4 = typeof import('@bendyline/squisq-cli/api').renderDocToMp4;
28
+ export interface VideoRunDependencies {
29
+ /** Test/programmatic override; production uses the linked Squisq renderer. */
30
+ renderDocToMp4?: RenderDocToMp4;
31
+ }
25
32
  /**
26
33
  * Core video rendering logic — reusable by both CLI and MCP tools.
27
34
  */
28
- export declare function runVideo(inputPath: string, opts: VideoOptions, onProgress?: (phase: string, percent: number) => void): Promise<VideoResult>;
35
+ export declare function runVideo(inputPath: string, opts: VideoOptions, onProgress?: (phase: string, percent: number) => void, dependencies?: VideoRunDependencies): Promise<VideoResult>;
29
36
  export declare const videoCommand: Command;
30
37
  export {};
31
38
  //# sourceMappingURL=video.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"video.d.ts","sourceRoot":"","sources":["../../src/commands/video.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAIH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,KAAK,EAAE,YAAY,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAI9E,QAAA,MAAM,cAAc,wCAAyC,CAAC;AAE9D,KAAK,aAAa,GAAG,CAAC,OAAO,cAAc,CAAC,CAAC,MAAM,CAAC,CAAC;AAErD,MAAM,WAAW,YAAY;IAC3B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,OAAO,CAAC,EAAE,YAAY,CAAC;IACvB,WAAW,CAAC,EAAE,gBAAgB,CAAC;IAC/B,QAAQ,CAAC,EAAE,aAAa,CAAC;IACzB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,WAAW;IAC1B,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;CACpB;AAED;;GAEG;AACH,wBAAsB,QAAQ,CAC5B,SAAS,EAAE,MAAM,EACjB,IAAI,EAAE,YAAY,EAClB,UAAU,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,KAAK,IAAI,GACpD,OAAO,CAAC,WAAW,CAAC,CAoFtB;AAYD,eAAO,MAAM,YAAY,SAsCrB,CAAC"}
1
+ {"version":3,"file":"video.d.ts","sourceRoot":"","sources":["../../src/commands/video.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAIH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,KAAK,EAAE,YAAY,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAI9E,QAAA,MAAM,cAAc,wCAAyC,CAAC;AAE9D,KAAK,aAAa,GAAG,CAAC,OAAO,cAAc,CAAC,CAAC,MAAM,CAAC,CAAC;AAErD,MAAM,WAAW,YAAY;IAC3B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,OAAO,CAAC,EAAE,YAAY,CAAC;IACvB,WAAW,CAAC,EAAE,gBAAgB,CAAC;IAC/B,QAAQ,CAAC,EAAE,aAAa,CAAC;IACzB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,qEAAqE;IACrE,MAAM,CAAC,EAAE,WAAW,CAAC;CACtB;AAED,MAAM,WAAW,WAAW;IAC1B,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,KAAK,cAAc,GAAG,cAAc,2BAA2B,EAAE,cAAc,CAAC;AAEhF,MAAM,WAAW,oBAAoB;IACnC,8EAA8E;IAC9E,cAAc,CAAC,EAAE,cAAc,CAAC;CACjC;AAED;;GAEG;AACH,wBAAsB,QAAQ,CAC5B,SAAS,EAAE,MAAM,EACjB,IAAI,EAAE,YAAY,EAClB,UAAU,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,KAAK,IAAI,EACrD,YAAY,GAAE,oBAAyB,GACtC,OAAO,CAAC,WAAW,CAAC,CAsFtB;AAoBD,eAAO,MAAM,YAAY,SAkCrB,CAAC"}
@@ -13,10 +13,11 @@ const VALID_CAPTIONS = ['off', 'standard', 'social'];
13
13
  /**
14
14
  * Core video rendering logic — reusable by both CLI and MCP tools.
15
15
  */
16
- export async function runVideo(inputPath, opts, onProgress) {
16
+ export async function runVideo(inputPath, opts, onProgress, dependencies = {}) {
17
+ throwIfAborted(opts.signal);
17
18
  const resolvedInput = resolve(inputPath);
18
19
  const fps = opts.fps ?? 30;
19
- if (fps < 1 || fps > 120) {
20
+ if (!Number.isFinite(fps) || fps < 1 || fps > 120) {
20
21
  throw new Error('FPS must be a number between 1 and 120');
21
22
  }
22
23
  const quality = opts.quality ?? 'normal';
@@ -40,25 +41,20 @@ export async function runVideo(inputPath, opts, onProgress) {
40
41
  ? resolve(opts.output)
41
42
  : resolve(dirname(resolvedInput), `${baseName}.mp4`);
42
43
  await mkdir(dirname(outputPath), { recursive: true });
44
+ throwIfAborted(opts.signal);
43
45
  console.error(`Reading: ${resolvedInput}`);
44
- const { readInput, renderDocToMp4 } = await import('@bendyline/squisq-cli/api');
45
- const result = await readInput(resolvedInput);
46
- const { container } = result;
47
- // Get or parse Doc
48
- let doc;
49
- if (result.doc) {
50
- console.error('Using pre-built Doc JSON');
51
- doc = result.doc;
52
- }
53
- else if (result.markdownDoc) {
54
- const { markdownToDoc } = await import('@bendyline/squisq/doc');
55
- doc = markdownToDoc(result.markdownDoc);
56
- }
57
- else {
58
- throw new Error('No document found in input');
59
- }
46
+ const squisq = await import('@bendyline/squisq-cli/api');
47
+ throwIfAborted(opts.signal);
48
+ const renderDocToMp4 = dependencies.renderDocToMp4 ?? squisq.renderDocToMp4;
49
+ const { readInput } = squisq;
50
+ const result = await readInput(resolvedInput, { signal: opts.signal });
51
+ throwIfAborted(opts.signal);
52
+ const { container, doc } = result;
53
+ console.error(`Using normalized ${result.sourceFormat} document`);
60
54
  console.error(`Rendering: ${fps} fps, quality: ${quality}, orientation: ${orientation}, captions: ${captions}`);
55
+ let latestProgress = 0;
61
56
  const renderResult = await renderDocToMp4(doc, container, {
57
+ signal: opts.signal,
62
58
  outputPath,
63
59
  fps,
64
60
  quality,
@@ -66,11 +62,20 @@ export async function runVideo(inputPath, opts, onProgress) {
66
62
  width: opts.width,
67
63
  height: opts.height,
68
64
  captionStyle,
69
- onProgress: onProgress ??
70
- ((phase, percent) => {
71
- process.stderr.write(`\r ${phase}: ${percent}% `);
72
- }),
65
+ onProgress: (phase, percent) => {
66
+ throwIfAborted(opts.signal);
67
+ const boundedPercent = Math.max(0, Math.min(100, percent));
68
+ if (boundedPercent < latestProgress)
69
+ return;
70
+ latestProgress = boundedPercent;
71
+ if (onProgress)
72
+ onProgress(phase, boundedPercent);
73
+ else
74
+ process.stderr.write(`\r ${phase}: ${boundedPercent}% `);
75
+ throwIfAborted(opts.signal);
76
+ },
73
77
  });
78
+ throwIfAborted(opts.signal);
74
79
  process.stderr.write('\r' + ' '.repeat(60) + '\r');
75
80
  console.error(` ✓ ${outputPath}`);
76
81
  console.error(` Duration: ${renderResult.duration.toFixed(1)}s, ${renderResult.frameCount} frames`);
@@ -81,15 +86,24 @@ export async function runVideo(inputPath, opts, onProgress) {
81
86
  frameCount: renderResult.frameCount,
82
87
  };
83
88
  }
89
+ function throwIfAborted(signal) {
90
+ if (!signal?.aborted)
91
+ return;
92
+ if (signal.reason !== undefined)
93
+ throw signal.reason;
94
+ const error = new Error('Video rendering was cancelled');
95
+ error.name = 'AbortError';
96
+ throw error;
97
+ }
84
98
  export const videoCommand = new Command('video')
85
99
  .description('Render a squisq document to MP4 video')
86
- .argument('<input>', 'Path to .md file, .zip/.dbk container, or folder')
100
+ .argument('<input>', 'Path to a supported document, .zip/.dbk container, or folder')
87
101
  .argument('[output]', 'Output MP4 path (default: <input>.mp4)')
88
102
  .option('-o, --output <path>', 'Output MP4 path (default: <input>.mp4)')
89
- .option('--fps <number>', 'Frames per second (default: 30)', '30')
90
- .option('--quality <level>', `Encoding quality: ${VALID_QUALITIES.join(', ')} (default: normal)`, 'normal')
91
- .option('--orientation <orient>', `Video orientation: ${VALID_ORIENTATIONS.join(', ')} (default: landscape)`, 'landscape')
92
- .option('--captions <style>', `Caption style: ${VALID_CAPTIONS.join(', ')} (default: off)`, 'off')
103
+ .option('--fps <number>', 'Frames per second', '30')
104
+ .option('--quality <level>', `Encoding quality: ${VALID_QUALITIES.join(', ')}`, 'normal')
105
+ .option('--orientation <orient>', `Video orientation: ${VALID_ORIENTATIONS.join(', ')}`, 'landscape')
106
+ .option('--captions <style>', `Caption style: ${VALID_CAPTIONS.join(', ')}`, 'off')
93
107
  .option('--width <pixels>', 'Override video width')
94
108
  .option('--height <pixels>', 'Override video height')
95
109
  .action(async (inputPath, outputArg, opts) => {
@@ -99,12 +113,12 @@ export const videoCommand = new Command('video')
99
113
  }
100
114
  await runVideo(inputPath, {
101
115
  output: opts.output,
102
- fps: parseInt(opts.fps ?? '30', 10),
116
+ fps: parseNumberOption('--fps', opts.fps ?? '30'),
103
117
  quality: opts.quality,
104
118
  orientation: opts.orientation,
105
119
  captions: opts.captions,
106
- width: opts.width ? parseInt(opts.width, 10) : undefined,
107
- height: opts.height ? parseInt(opts.height, 10) : undefined,
120
+ width: opts.width ? parseNumberOption('--width', opts.width) : undefined,
121
+ height: opts.height ? parseNumberOption('--height', opts.height) : undefined,
108
122
  });
109
123
  }
110
124
  catch (err) {
@@ -113,4 +127,10 @@ export const videoCommand = new Command('video')
113
127
  process.exitCode = 1;
114
128
  }
115
129
  });
130
+ function parseNumberOption(name, value) {
131
+ const parsed = Number(value);
132
+ if (!Number.isFinite(parsed))
133
+ throw new Error(`${name} must be a finite number`);
134
+ return parsed;
135
+ }
116
136
  //# sourceMappingURL=video.js.map