@json-to-office/jto 0.26.0 → 0.28.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 (30) hide show
  1. package/dist/cli.js +134 -77
  2. package/dist/cli.js.map +1 -1
  3. package/dist/client/assets/{HomePage-CcmtpSuV.js → HomePage-BX2wX21e.js} +3 -3
  4. package/dist/client/assets/HomePage-BX2wX21e.js.map +1 -0
  5. package/dist/client/assets/{JsonEditorPage-RDa8GWDd.js → JsonEditorPage-DseCjMok.js} +3 -3
  6. package/dist/client/assets/{JsonEditorPage-RDa8GWDd.js.map → JsonEditorPage-DseCjMok.js.map} +1 -1
  7. package/dist/client/assets/{MonacoPluginProvider-DM63WAJx.js → MonacoPluginProvider-DvO7h20V.js} +3 -3
  8. package/dist/client/assets/{MonacoPluginProvider-DM63WAJx.js.map → MonacoPluginProvider-DvO7h20V.js.map} +1 -1
  9. package/dist/client/assets/{button-CyTe9rTl.js → button-DzgfrDEj.js} +2 -2
  10. package/dist/client/assets/{button-CyTe9rTl.js.map → button-DzgfrDEj.js.map} +1 -1
  11. package/dist/client/assets/{editor-DCtGYNz2.js → editor-BDi6QWgh.js} +2 -2
  12. package/dist/client/assets/{editor-DCtGYNz2.js.map → editor-BDi6QWgh.js.map} +1 -1
  13. package/dist/client/assets/{editor-monaco-json-CU9ciwPv.js → editor-monaco-json-CsQqBG2A.js} +2 -2
  14. package/dist/client/assets/{editor-monaco-json-CU9ciwPv.js.map → editor-monaco-json-CsQqBG2A.js.map} +1 -1
  15. package/dist/client/assets/{index-CHAIoQtG.js → index-Cxjik2Rg.js} +3 -3
  16. package/dist/client/assets/{index-CHAIoQtG.js.map → index-Cxjik2Rg.js.map} +1 -1
  17. package/dist/client/assets/preview-BOF6SWhK.js +3 -0
  18. package/dist/client/assets/preview-BOF6SWhK.js.map +1 -0
  19. package/dist/client/index.html +1 -1
  20. package/dist/client/templates/management-plan.pptx.json +18 -18
  21. package/dist/client/templates/minimalist-pitch-deck.pptx.json +19 -19
  22. package/dist/client/templates/modern-annual-report-2.docx.json +12 -12
  23. package/dist/client/templates/modern-annual-report-3.docx.json +14 -14
  24. package/dist/client/templates/standard-annual-report.docx.json +2 -2
  25. package/dist/render-server.js +62 -48
  26. package/dist/render-server.js.map +1 -1
  27. package/package.json +7 -8
  28. package/dist/client/assets/HomePage-CcmtpSuV.js.map +0 -1
  29. package/dist/client/assets/preview-oxnxMi4x.js +0 -3
  30. package/dist/client/assets/preview-oxnxMi4x.js.map +0 -1
@@ -360,7 +360,7 @@
360
360
  {
361
361
  "name": "image",
362
362
  "props": {
363
- "path": "packages/jto/src/client/public/templates/media/modern-annual-report-2/hatch-1.88x2.13.png",
363
+ "path": "media/modern-annual-report-2/hatch-1.88x2.13.png",
364
364
  "x": 0.63,
365
365
  "y": 8.43,
366
366
  "w": 1.88,
@@ -1559,7 +1559,7 @@
1559
1559
  {
1560
1560
  "name": "image",
1561
1561
  "props": {
1562
- "path": "packages/jto/src/client/public/templates/media/modern-annual-report-2/hatch-3.53x4.22.png",
1562
+ "path": "media/modern-annual-report-2/hatch-3.53x4.22.png",
1563
1563
  "x": 0.5,
1564
1564
  "y": 1.49,
1565
1565
  "w": 3.53,
@@ -2511,7 +2511,7 @@
2511
2511
  {
2512
2512
  "name": "image",
2513
2513
  "props": {
2514
- "path": "packages/jto/src/client/public/templates/media/modern-annual-report-2/hatch-2.19x2.61.png",
2514
+ "path": "media/modern-annual-report-2/hatch-2.19x2.61.png",
2515
2515
  "x": 0.53,
2516
2516
  "y": 8.62,
2517
2517
  "w": 2.19,
@@ -3985,7 +3985,7 @@
3985
3985
  {
3986
3986
  "name": "image",
3987
3987
  "props": {
3988
- "path": "packages/jto/src/client/public/templates/media/modern-annual-report-2/image2.png",
3988
+ "path": "media/modern-annual-report-2/image2.png",
3989
3989
  "x": 0.53,
3990
3990
  "y": 1.91,
3991
3991
  "w": 7.28,
@@ -4624,7 +4624,7 @@
4624
4624
  {
4625
4625
  "name": "image",
4626
4626
  "props": {
4627
- "path": "packages/jto/src/client/public/templates/media/modern-annual-report-2/hatch-2.57x2.91.png",
4627
+ "path": "media/modern-annual-report-2/hatch-2.57x2.91.png",
4628
4628
  "x": 5.17,
4629
4629
  "y": 0.55,
4630
4630
  "w": 2.57,
@@ -10651,7 +10651,7 @@
10651
10651
  {
10652
10652
  "name": "image",
10653
10653
  "props": {
10654
- "path": "packages/jto/src/client/public/templates/media/modern-annual-report-2/hatch-2.78x3.03.png",
10654
+ "path": "media/modern-annual-report-2/hatch-2.78x3.03.png",
10655
10655
  "x": 4.97,
10656
10656
  "y": 0.44,
10657
10657
  "w": 2.78,
@@ -12075,7 +12075,7 @@
12075
12075
  {
12076
12076
  "name": "image",
12077
12077
  "props": {
12078
- "path": "packages/jto/src/client/public/templates/media/modern-annual-report-2/hatch-3.8x5.41.png",
12078
+ "path": "media/modern-annual-report-2/hatch-3.8x5.41.png",
12079
12079
  "x": 0.45,
12080
12080
  "y": 0.41,
12081
12081
  "w": 3.8,
@@ -12535,7 +12535,7 @@
12535
12535
  {
12536
12536
  "name": "image",
12537
12537
  "props": {
12538
- "path": "packages/jto/src/client/public/templates/media/modern-annual-report-2/image4.png",
12538
+ "path": "media/modern-annual-report-2/image4.png",
12539
12539
  "x": 0.48,
12540
12540
  "y": 7.24,
12541
12541
  "w": 7.27,
@@ -13049,7 +13049,7 @@
13049
13049
  {
13050
13050
  "name": "image",
13051
13051
  "props": {
13052
- "path": "packages/jto/src/client/public/templates/media/modern-annual-report-2/hatch-2.22x2.88.png",
13052
+ "path": "media/modern-annual-report-2/hatch-2.22x2.88.png",
13053
13053
  "x": 2.99,
13054
13054
  "y": 6.26,
13055
13055
  "w": 2.22,
@@ -14376,7 +14376,7 @@
14376
14376
  {
14377
14377
  "name": "image",
14378
14378
  "props": {
14379
- "path": "packages/jto/src/client/public/templates/media/modern-annual-report-2/image6.png",
14379
+ "path": "media/modern-annual-report-2/image6.png",
14380
14380
  "x": 0.44,
14381
14381
  "y": 0.49,
14382
14382
  "w": 7.27,
@@ -14386,7 +14386,7 @@
14386
14386
  {
14387
14387
  "name": "image",
14388
14388
  "props": {
14389
- "path": "packages/jto/src/client/public/templates/media/modern-annual-report-2/hatch-1.86x2.03.png",
14389
+ "path": "media/modern-annual-report-2/hatch-1.86x2.03.png",
14390
14390
  "x": 0.45,
14391
14391
  "y": 9.18,
14392
14392
  "w": 1.86,
@@ -14940,7 +14940,7 @@
14940
14940
  {
14941
14941
  "name": "image",
14942
14942
  "props": {
14943
- "path": "packages/jto/src/client/public/templates/media/modern-annual-report-2/hatch-4.46x6.42.png",
14943
+ "path": "media/modern-annual-report-2/hatch-4.46x6.42.png",
14944
14944
  "x": 3.34,
14945
14945
  "y": 0.52,
14946
14946
  "w": 4.46,
@@ -86,7 +86,7 @@
86
86
  {
87
87
  "name": "image",
88
88
  "props": {
89
- "path": "packages/jto/src/client/public/templates/media/modern-annual-report-3/pct30-7054x10363-v2.png",
89
+ "path": "media/modern-annual-report-3/pct30-7054x10363-v2.png",
90
90
  "x": 0.61,
91
91
  "y": 0.67,
92
92
  "w": 7.054,
@@ -432,7 +432,7 @@
432
432
  {
433
433
  "name": "image",
434
434
  "props": {
435
- "path": "packages/jto/src/client/public/templates/media/modern-annual-report-3/pct30-1817x2117-v2.png",
435
+ "path": "media/modern-annual-report-3/pct30-1817x2117-v2.png",
436
436
  "x": 5.98,
437
437
  "y": 1.57,
438
438
  "w": 1.817,
@@ -840,7 +840,7 @@
840
840
  {
841
841
  "name": "image",
842
842
  "props": {
843
- "path": "packages/jto/src/client/public/templates/media/modern-annual-report-3/pct30-2544x3221-v2.png",
843
+ "path": "media/modern-annual-report-3/pct30-2544x3221-v2.png",
844
844
  "x": 0.51,
845
845
  "y": 7.22,
846
846
  "w": 2.544,
@@ -1621,7 +1621,7 @@
1621
1621
  {
1622
1622
  "name": "image",
1623
1623
  "props": {
1624
- "path": "packages/jto/src/client/public/templates/media/modern-annual-report-3/pct30-2084x2506-v2.png",
1624
+ "path": "media/modern-annual-report-3/pct30-2084x2506-v2.png",
1625
1625
  "x": 3.1,
1626
1626
  "y": 3.06,
1627
1627
  "w": 2.084,
@@ -1896,7 +1896,7 @@
1896
1896
  {
1897
1897
  "name": "image",
1898
1898
  "props": {
1899
- "path": "packages/jto/src/client/public/templates/media/modern-annual-report-3/pct30-1312x1574-v2.png",
1899
+ "path": "media/modern-annual-report-3/pct30-1312x1574-v2.png",
1900
1900
  "x": 6.43,
1901
1901
  "y": 2.1,
1902
1902
  "w": 1.312,
@@ -3132,7 +3132,7 @@
3132
3132
  {
3133
3133
  "name": "image",
3134
3134
  "props": {
3135
- "path": "packages/jto/src/client/public/templates/media/modern-annual-report-3/pct30-1618x1597-v2.png",
3135
+ "path": "media/modern-annual-report-3/pct30-1618x1597-v2.png",
3136
3136
  "x": 0.52,
3137
3137
  "y": 5.62,
3138
3138
  "w": 1.618,
@@ -7603,7 +7603,7 @@
7603
7603
  {
7604
7604
  "name": "image",
7605
7605
  "props": {
7606
- "path": "packages/jto/src/client/public/templates/media/modern-annual-report-3/pct30-1822x2099-v2.png",
7606
+ "path": "media/modern-annual-report-3/pct30-1822x2099-v2.png",
7607
7607
  "x": 5.92,
7608
7608
  "y": 4.96,
7609
7609
  "w": 1.822,
@@ -9110,7 +9110,7 @@
9110
9110
  {
9111
9111
  "name": "image",
9112
9112
  "props": {
9113
- "path": "packages/jto/src/client/public/templates/media/modern-annual-report-3/pct30-7253x2778-v2.png",
9113
+ "path": "media/modern-annual-report-3/pct30-7253x2778-v2.png",
9114
9114
  "x": 0.52,
9115
9115
  "y": 5.26,
9116
9116
  "w": 7.253,
@@ -9403,7 +9403,7 @@
9403
9403
  {
9404
9404
  "name": "image",
9405
9405
  "props": {
9406
- "path": "packages/jto/src/client/public/templates/media/modern-annual-report-3/pct30-1874x2077-v2.png",
9406
+ "path": "media/modern-annual-report-3/pct30-1874x2077-v2.png",
9407
9407
  "x": 4.22,
9408
9408
  "y": 0.5,
9409
9409
  "w": 1.874,
@@ -10199,7 +10199,7 @@
10199
10199
  {
10200
10200
  "name": "image",
10201
10201
  "props": {
10202
- "path": "packages/jto/src/client/public/templates/media/modern-annual-report-3/pct30-7256x6807-v2.png",
10202
+ "path": "media/modern-annual-report-3/pct30-7256x6807-v2.png",
10203
10203
  "x": 0.48,
10204
10204
  "y": 0.45,
10205
10205
  "w": 7.256,
@@ -10752,7 +10752,7 @@
10752
10752
  {
10753
10753
  "name": "image",
10754
10754
  "props": {
10755
- "path": "packages/jto/src/client/public/templates/media/modern-annual-report-3/pct30-1308x1454-v2.png",
10755
+ "path": "media/modern-annual-report-3/pct30-1308x1454-v2.png",
10756
10756
  "x": 5.52,
10757
10757
  "y": 4.2,
10758
10758
  "w": 1.308,
@@ -11382,7 +11382,7 @@
11382
11382
  {
11383
11383
  "name": "image",
11384
11384
  "props": {
11385
- "path": "packages/jto/src/client/public/templates/media/modern-annual-report-3/pct30-1660x1818-v2.png",
11385
+ "path": "media/modern-annual-report-3/pct30-1660x1818-v2.png",
11386
11386
  "x": 0.61,
11387
11387
  "y": 9.24,
11388
11388
  "w": 1.66,
@@ -12381,7 +12381,7 @@
12381
12381
  {
12382
12382
  "name": "image",
12383
12383
  "props": {
12384
- "path": "packages/jto/src/client/public/templates/media/modern-annual-report-3/pct30-2622x3017-v2.png",
12384
+ "path": "media/modern-annual-report-3/pct30-2622x3017-v2.png",
12385
12385
  "x": 0.5,
12386
12386
  "y": 5.08,
12387
12387
  "w": 2.622,
@@ -12763,7 +12763,7 @@
12763
12763
  {
12764
12764
  "name": "image",
12765
12765
  "props": {
12766
- "path": "packages/jto/src/client/public/templates/media/modern-annual-report-3/pct30-7054x10363-v2.png",
12766
+ "path": "media/modern-annual-report-3/pct30-7054x10363-v2.png",
12767
12767
  "x": 0.6,
12768
12768
  "y": 0.61,
12769
12769
  "w": 7.054,
@@ -6719,7 +6719,7 @@
6719
6719
  {
6720
6720
  "name": "image",
6721
6721
  "props": {
6722
- "path": "packages/jto/src/client/public/templates/media/standard-annual-report/image23.png",
6722
+ "path": "media/standard-annual-report/image23.png",
6723
6723
  "width": 755,
6724
6724
  "height": 504,
6725
6725
  "floating": {
@@ -7005,7 +7005,7 @@
7005
7005
  {
7006
7006
  "name": "image",
7007
7007
  "props": {
7008
- "path": "packages/jto/src/client/public/templates/media/standard-annual-report/image25.png",
7008
+ "path": "media/standard-annual-report/image25.png",
7009
7009
  "width": 301,
7010
7010
  "height": 453,
7011
7011
  "floating": {
@@ -7,6 +7,7 @@ import { HTTPException as HTTPException4 } from "hono/http-exception";
7
7
  import { secureHeaders } from "hono/secure-headers";
8
8
 
9
9
  // src/server/rasterize-route.ts
10
+ import path from "path";
10
11
  import { Type } from "@sinclair/typebox";
11
12
  import { bodyLimit } from "hono/body-limit";
12
13
  import { HTTPException as HTTPException2 } from "hono/http-exception";
@@ -69,9 +70,9 @@ function getValidated(c, target) {
69
70
 
70
71
  // src/server/security/outbound-source-policy.ts
71
72
  var UnsafeOutboundSourceError = class extends Error {
72
- constructor(path, reason) {
73
- super(`Unsafe outbound source at ${path}: ${reason}`);
74
- this.path = path;
73
+ constructor(path2, reason) {
74
+ super(`Unsafe outbound source at ${path2}: ${reason}`);
75
+ this.path = path2;
75
76
  this.name = "UnsafeOutboundSourceError";
76
77
  }
77
78
  };
@@ -125,36 +126,36 @@ function isPrivateHost(host) {
125
126
  const firstIpv6Group = Number.parseInt(normalized.split(":")[0] || "0", 16);
126
127
  return firstIpv6Group >= 64512 && firstIpv6Group <= 65023 || firstIpv6Group >= 65152 && firstIpv6Group <= 65215;
127
128
  }
128
- function assertAllowedUrl(source, path, allowedHosts) {
129
+ function assertAllowedUrl(source, path2, allowedHosts) {
129
130
  if (source.startsWith("data:")) return;
130
131
  let url;
131
132
  try {
132
133
  url = new URL(source);
133
134
  } catch {
134
135
  throw new UnsafeOutboundSourceError(
135
- path,
136
+ path2,
136
137
  "local and relative file paths are disabled for HTTP requests"
137
138
  );
138
139
  }
139
140
  if (url.protocol !== "https:") {
140
- throw new UnsafeOutboundSourceError(path, "only HTTPS URLs are allowed");
141
+ throw new UnsafeOutboundSourceError(path2, "only HTTPS URLs are allowed");
141
142
  }
142
143
  if (url.username || url.password) {
143
144
  throw new UnsafeOutboundSourceError(
144
- path,
145
+ path2,
145
146
  "URLs containing credentials are not allowed"
146
147
  );
147
148
  }
148
149
  const host = url.hostname.toLowerCase().replace(/\.$/, "");
149
150
  if (isPrivateHost(host)) {
150
151
  throw new UnsafeOutboundSourceError(
151
- path,
152
+ path2,
152
153
  `private or local host "${host}" is not allowed`
153
154
  );
154
155
  }
155
156
  if (!allowedHosts.some((pattern) => hostMatches(host, pattern))) {
156
157
  throw new UnsafeOutboundSourceError(
157
- path,
158
+ path2,
158
159
  `host "${host}" is not in OUTBOUND_HOST_ALLOWLIST`
159
160
  );
160
161
  }
@@ -172,13 +173,13 @@ function extractCssReferences(input) {
172
173
  function extractAbsoluteUrls(input) {
173
174
  return input.match(/(?:https?|file):\/\/[^\s'"<>)}\]]+/gi) ?? [];
174
175
  }
175
- function assertSafeSvg(svg, path, allowedHosts) {
176
+ function assertSafeSvg(svg, path2, allowedHosts) {
176
177
  if (/<\s*script\b/i.test(svg) || /<\s*(?:foreignObject|iframe|object|embed)\b/i.test(svg) || /\bon[a-z]+\s*=/i.test(svg)) {
177
- throw new UnsafeOutboundSourceError(path, "active SVG content is disabled");
178
+ throw new UnsafeOutboundSourceError(path2, "active SVG content is disabled");
178
179
  }
179
180
  if (/<!\s*(?:DOCTYPE|ENTITY)\b/i.test(svg)) {
180
181
  throw new UnsafeOutboundSourceError(
181
- path,
182
+ path2,
182
183
  "SVG document types and entities are disabled"
183
184
  );
184
185
  }
@@ -187,20 +188,20 @@ function assertSafeSvg(svg, path, allowedHosts) {
187
188
  while (match = refPattern.exec(svg)) {
188
189
  const ref = match[2].trim();
189
190
  if (!ref || ref.startsWith("#") || ref.startsWith("data:")) continue;
190
- assertAllowedUrl(ref, path, allowedHosts);
191
+ assertAllowedUrl(ref, path2, allowedHosts);
191
192
  }
192
193
  for (const ref of extractCssReferences(svg)) {
193
194
  if (ref.startsWith("#") || ref.startsWith("data:")) continue;
194
- assertAllowedUrl(ref, path, allowedHosts);
195
+ assertAllowedUrl(ref, path2, allowedHosts);
195
196
  }
196
197
  }
197
- function assertSafeEncodedImage(source, path, allowedHosts) {
198
+ function assertSafeEncodedImage(source, path2, allowedHosts) {
198
199
  let candidate = source.trim();
199
200
  let declaredSvg = false;
200
201
  if (candidate.startsWith("data:")) {
201
202
  const comma = candidate.indexOf(",");
202
203
  if (comma < 0) {
203
- throw new UnsafeOutboundSourceError(path, "malformed image data URL");
204
+ throw new UnsafeOutboundSourceError(path2, "malformed image data URL");
204
205
  }
205
206
  const metadata = candidate.slice(5, comma);
206
207
  declaredSvg = metadata.split(";")[0].toLowerCase() === "image/svg+xml";
@@ -209,7 +210,7 @@ function assertSafeEncodedImage(source, path, allowedHosts) {
209
210
  try {
210
211
  candidate = /(?:^|;)base64(?:;|$)/i.test(metadata) ? Buffer.from(payload, "base64").toString("utf8") : decodeURIComponent(payload);
211
212
  } catch {
212
- throw new UnsafeOutboundSourceError(path, "malformed SVG data URL");
213
+ throw new UnsafeOutboundSourceError(path2, "malformed SVG data URL");
213
214
  }
214
215
  } else if (!/<\s*svg\b/i.test(candidate)) {
215
216
  candidate = Buffer.from(candidate, "base64").toString("utf8");
@@ -217,37 +218,37 @@ function assertSafeEncodedImage(source, path, allowedHosts) {
217
218
  const svgStart = candidate.search(/<\s*svg\b/i);
218
219
  if (svgStart < 0) {
219
220
  if (declaredSvg) {
220
- throw new UnsafeOutboundSourceError(path, "malformed SVG image data");
221
+ throw new UnsafeOutboundSourceError(path2, "malformed SVG image data");
221
222
  }
222
223
  return;
223
224
  }
224
- assertSafeSvg(candidate, path, allowedHosts);
225
+ assertSafeSvg(candidate, path2, allowedHosts);
225
226
  }
226
- function assertSafeResources(resources, path, allowedHosts) {
227
+ function assertSafeResources(resources, path2, allowedHosts) {
227
228
  if (typeof resources.js === "string" && resources.js.trim()) {
228
229
  throw new UnsafeOutboundSourceError(
229
- `${path}.js`,
230
+ `${path2}.js`,
230
231
  "remote renderer JavaScript resources are disabled"
231
232
  );
232
233
  }
233
234
  if (typeof resources.css === "string") {
234
235
  for (const ref of extractCssReferences(resources.css)) {
235
236
  if (ref.startsWith("data:")) continue;
236
- assertAllowedUrl(ref, `${path}.css`, allowedHosts);
237
+ assertAllowedUrl(ref, `${path2}.css`, allowedHosts);
237
238
  }
238
239
  }
239
240
  if (Array.isArray(resources.files) && resources.files.length > 0) {
240
241
  throw new UnsafeOutboundSourceError(
241
- `${path}.files`,
242
+ `${path2}.files`,
242
243
  "remote renderer JavaScript resources are disabled"
243
244
  );
244
245
  }
245
246
  }
246
- function assertNoRemoteReferences(value, path, allowedHosts, seen) {
247
+ function assertNoRemoteReferences(value, path2, allowedHosts, seen) {
247
248
  if (typeof value === "string") {
248
249
  if (/\b(?:fetch|XMLHttpRequest|WebSocket|EventSource)\s*\(/i.test(value) || /\b(?:javascript|file):/i.test(value)) {
249
250
  throw new UnsafeOutboundSourceError(
250
- path,
251
+ path2,
251
252
  "network-capable JavaScript and file URLs are disabled"
252
253
  );
253
254
  }
@@ -256,11 +257,11 @@ function assertNoRemoteReferences(value, path, allowedHosts, seen) {
256
257
  ...extractCssReferences(value)
257
258
  ]) {
258
259
  if (url.startsWith("data:")) continue;
259
- assertAllowedUrl(url, path, allowedHosts);
260
+ assertAllowedUrl(url, path2, allowedHosts);
260
261
  }
261
262
  if (/^\/\//.test(value.trim())) {
262
263
  throw new UnsafeOutboundSourceError(
263
- path,
264
+ path2,
264
265
  "protocol-relative URLs are disabled"
265
266
  );
266
267
  }
@@ -270,20 +271,20 @@ function assertNoRemoteReferences(value, path, allowedHosts, seen) {
270
271
  seen.add(value);
271
272
  if (Array.isArray(value)) {
272
273
  value.forEach(
273
- (entry, index) => assertNoRemoteReferences(entry, `${path}[${index}]`, allowedHosts, seen)
274
+ (entry, index) => assertNoRemoteReferences(entry, `${path2}[${index}]`, allowedHosts, seen)
274
275
  );
275
276
  return;
276
277
  }
277
278
  for (const [key, child] of Object.entries(value)) {
278
- assertNoRemoteReferences(child, `${path}.${key}`, allowedHosts, seen);
279
+ assertNoRemoteReferences(child, `${path2}.${key}`, allowedHosts, seen);
279
280
  }
280
281
  }
281
- function visit(value, path, containerKey, allowedHosts, seen) {
282
+ function visit(value, path2, containerKey, allowedHosts, seen) {
282
283
  if (!value || typeof value !== "object" || seen.has(value)) return;
283
284
  seen.add(value);
284
285
  if (Array.isArray(value)) {
285
286
  value.forEach(
286
- (entry, index) => visit(entry, `${path}[${index}]`, containerKey, allowedHosts, seen)
287
+ (entry, index) => visit(entry, `${path2}[${index}]`, containerKey, allowedHosts, seen)
287
288
  );
288
289
  return;
289
290
  }
@@ -291,7 +292,7 @@ function visit(value, path, containerKey, allowedHosts, seen) {
291
292
  for (const key of Object.keys(record)) {
292
293
  if (DANGEROUS_KEYS.has(key)) {
293
294
  throw new UnsafeOutboundSourceError(
294
- `${path}.${key}`,
295
+ `${path2}.${key}`,
295
296
  "prototype mutation keys are disabled"
296
297
  );
297
298
  }
@@ -299,31 +300,31 @@ function visit(value, path, containerKey, allowedHosts, seen) {
299
300
  const kind = typeof record.kind === "string" ? record.kind : void 0;
300
301
  if (kind === "file" && typeof record.path === "string") {
301
302
  throw new UnsafeOutboundSourceError(
302
- `${path}.path`,
303
+ `${path2}.path`,
303
304
  "local file sources are disabled for HTTP requests"
304
305
  );
305
306
  }
306
307
  if ((kind === "url" || kind === "variable") && typeof record.url === "string") {
307
- assertAllowedUrl(record.url, `${path}.url`, allowedHosts);
308
+ assertAllowedUrl(record.url, `${path2}.url`, allowedHosts);
308
309
  }
309
310
  const componentName = typeof record.name === "string" ? record.name.toLowerCase() : void 0;
310
311
  const props = isRecord(record.props) ? record.props : void 0;
311
312
  if (componentName && props) {
312
313
  if (COMPONENT_SOURCE_NAMES.has(componentName) && typeof props.path === "string") {
313
- assertAllowedUrl(props.path, `${path}.props.path`, allowedHosts);
314
- assertSafeEncodedImage(props.path, `${path}.props.path`, allowedHosts);
314
+ assertAllowedUrl(props.path, `${path2}.props.path`, allowedHosts);
315
+ assertSafeEncodedImage(props.path, `${path2}.props.path`, allowedHosts);
315
316
  }
316
317
  if (COMPONENT_SOURCE_NAMES.has(componentName) && typeof props.base64 === "string") {
317
318
  assertSafeEncodedImage(
318
319
  props.base64,
319
- `${path}.props.base64`,
320
+ `${path2}.props.base64`,
320
321
  allowedHosts
321
322
  );
322
323
  }
323
324
  if ((componentName === "highcharts" || componentName === "visual") && typeof props.serverUrl === "string") {
324
325
  assertAllowedUrl(
325
326
  props.serverUrl,
326
- `${path}.props.serverUrl`,
327
+ `${path2}.props.serverUrl`,
327
328
  allowedHosts
328
329
  );
329
330
  }
@@ -331,30 +332,30 @@ function visit(value, path, containerKey, allowedHosts, seen) {
331
332
  if (isRecord(props.resources)) {
332
333
  assertSafeResources(
333
334
  props.resources,
334
- `${path}.props.resources`,
335
+ `${path2}.props.resources`,
335
336
  allowedHosts
336
337
  );
337
338
  }
338
339
  assertNoRemoteReferences(
339
340
  props.options,
340
- `${path}.props.options`,
341
+ `${path2}.props.options`,
341
342
  allowedHosts,
342
343
  /* @__PURE__ */ new WeakSet()
343
344
  );
344
345
  }
345
346
  }
346
347
  if (containerKey === "image" && typeof record.path === "string") {
347
- assertAllowedUrl(record.path, `${path}.path`, allowedHosts);
348
- assertSafeEncodedImage(record.path, `${path}.path`, allowedHosts);
348
+ assertAllowedUrl(record.path, `${path2}.path`, allowedHosts);
349
+ assertSafeEncodedImage(record.path, `${path2}.path`, allowedHosts);
349
350
  }
350
351
  if (typeof record.svg === "string") {
351
- assertSafeSvg(record.svg, `${path}.svg`, allowedHosts);
352
+ assertSafeSvg(record.svg, `${path2}.svg`, allowedHosts);
352
353
  }
353
354
  if (containerKey === "resources") {
354
- assertSafeResources(record, path, allowedHosts);
355
+ assertSafeResources(record, path2, allowedHosts);
355
356
  }
356
357
  for (const [key, child] of Object.entries(record)) {
357
- visit(child, `${path}.${key}`, key, allowedHosts, seen);
358
+ visit(child, `${path2}.${key}`, key, allowedHosts, seen);
358
359
  }
359
360
  }
360
361
  function assertSafeOutboundSources(value, policy, rootPath = "request") {
@@ -386,7 +387,8 @@ var RasterizeRequestSchema = Type.Object(
386
387
  presentation: Type.Object({}, { additionalProperties: true }),
387
388
  dpi: Type.Optional(
388
389
  Type.Number({ minimum: MIN_VISUAL_DPI, maximum: MAX_VISUAL_DPI })
389
- )
390
+ ),
391
+ baseDir: Type.Optional(Type.String())
390
392
  },
391
393
  { additionalProperties: false }
392
394
  );
@@ -420,7 +422,18 @@ function registerRasterizeRoute(router, options = {}) {
420
422
  jsonOnly,
421
423
  tbValidator(RasterizeRequestSchema),
422
424
  async (c) => {
423
- const { presentation, dpi } = getValidated(c, "json");
425
+ const { presentation, dpi, baseDir } = getValidated(c, "json");
426
+ let safeBaseDir;
427
+ if (baseDir !== void 0) {
428
+ const resolved = path.resolve(baseDir);
429
+ const cwd = process.cwd();
430
+ if (resolved !== cwd && !resolved.startsWith(cwd + path.sep)) {
431
+ throw new HTTPException2(400, {
432
+ message: "baseDir must be inside the server working directory"
433
+ });
434
+ }
435
+ safeBaseDir = resolved;
436
+ }
424
437
  try {
425
438
  if (options.sourcePolicy) {
426
439
  assertSafeOutboundSources(
@@ -431,7 +444,8 @@ function registerRasterizeRoute(router, options = {}) {
431
444
  }
432
445
  const result = await getRasterizer()({
433
446
  presentation,
434
- dpi: clampVisualDpi(dpi ?? DEFAULT_VISUAL_DPI)
447
+ dpi: clampVisualDpi(dpi ?? DEFAULT_VISUAL_DPI),
448
+ baseDir: safeBaseDir
435
449
  });
436
450
  return c.json(result);
437
451
  } catch (error) {