@json-to-office/jto 0.28.0 → 0.28.1
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/dist/cli.js +205 -75
- package/dist/cli.js.map +1 -1
- package/dist/client/assets/{HomePage-BX2wX21e.js → HomePage-g8gOpx6G.js} +3 -3
- package/dist/client/assets/{HomePage-BX2wX21e.js.map → HomePage-g8gOpx6G.js.map} +1 -1
- package/dist/client/assets/{JsonEditorPage-DseCjMok.js → JsonEditorPage-CzMTUrNe.js} +3 -3
- package/dist/client/assets/{JsonEditorPage-DseCjMok.js.map → JsonEditorPage-CzMTUrNe.js.map} +1 -1
- package/dist/client/assets/{MonacoPluginProvider-DvO7h20V.js → MonacoPluginProvider-CmMAmp3u.js} +3 -3
- package/dist/client/assets/{MonacoPluginProvider-DvO7h20V.js.map → MonacoPluginProvider-CmMAmp3u.js.map} +1 -1
- package/dist/client/assets/{button-DzgfrDEj.js → button-BEg2__r6.js} +2 -2
- package/dist/client/assets/{button-DzgfrDEj.js.map → button-BEg2__r6.js.map} +1 -1
- package/dist/client/assets/{editor-BDi6QWgh.js → editor-DPs_adn-.js} +2 -2
- package/dist/client/assets/{editor-BDi6QWgh.js.map → editor-DPs_adn-.js.map} +1 -1
- package/dist/client/assets/{editor-monaco-json-CsQqBG2A.js → editor-monaco-json-xnoKHnLp.js} +2 -2
- package/dist/client/assets/{editor-monaco-json-CsQqBG2A.js.map → editor-monaco-json-xnoKHnLp.js.map} +1 -1
- package/dist/client/assets/{index-Cxjik2Rg.js → index-DgKS-gEZ.js} +4 -4
- package/dist/client/assets/index-DgKS-gEZ.js.map +1 -0
- package/dist/client/assets/{preview-BOF6SWhK.js → preview-RxIHvUjz.js} +2 -2
- package/dist/client/assets/{preview-BOF6SWhK.js.map → preview-RxIHvUjz.js.map} +1 -1
- package/dist/client/index.html +1 -1
- package/package.json +3 -3
- package/dist/client/assets/index-Cxjik2Rg.js.map +0 -1
package/dist/cli.js
CHANGED
|
@@ -234,10 +234,10 @@ function collectReferencedNames(config2, customThemes, adapterName) {
|
|
|
234
234
|
}
|
|
235
235
|
function collectReferencedWeights(config2, customThemes) {
|
|
236
236
|
const weights = /* @__PURE__ */ new Set();
|
|
237
|
-
const
|
|
237
|
+
const visit3 = (node) => {
|
|
238
238
|
if (node == null) return;
|
|
239
239
|
if (Array.isArray(node)) {
|
|
240
|
-
for (const item of node)
|
|
240
|
+
for (const item of node) visit3(item);
|
|
241
241
|
return;
|
|
242
242
|
}
|
|
243
243
|
if (typeof node === "object") {
|
|
@@ -245,21 +245,21 @@ function collectReferencedWeights(config2, customThemes) {
|
|
|
245
245
|
if (k === "fontWeight" && typeof v === "number" && v >= 100 && v <= 900) {
|
|
246
246
|
weights.add(v);
|
|
247
247
|
} else {
|
|
248
|
-
|
|
248
|
+
visit3(v);
|
|
249
249
|
}
|
|
250
250
|
}
|
|
251
251
|
}
|
|
252
252
|
};
|
|
253
|
-
|
|
254
|
-
for (const theme of Object.values(customThemes ?? {}))
|
|
253
|
+
visit3(config2);
|
|
254
|
+
for (const theme of Object.values(customThemes ?? {})) visit3(theme);
|
|
255
255
|
return weights;
|
|
256
256
|
}
|
|
257
257
|
function collectReferencedItalic(config2, customThemes) {
|
|
258
258
|
let found = false;
|
|
259
|
-
const
|
|
259
|
+
const visit3 = (node) => {
|
|
260
260
|
if (found || node == null) return;
|
|
261
261
|
if (Array.isArray(node)) {
|
|
262
|
-
for (const item of node)
|
|
262
|
+
for (const item of node) visit3(item);
|
|
263
263
|
return;
|
|
264
264
|
}
|
|
265
265
|
if (typeof node === "object") {
|
|
@@ -268,14 +268,14 @@ function collectReferencedItalic(config2, customThemes) {
|
|
|
268
268
|
found = true;
|
|
269
269
|
return;
|
|
270
270
|
}
|
|
271
|
-
|
|
271
|
+
visit3(v);
|
|
272
272
|
}
|
|
273
273
|
}
|
|
274
274
|
};
|
|
275
|
-
|
|
275
|
+
visit3(config2);
|
|
276
276
|
if (!found) {
|
|
277
277
|
for (const theme of Object.values(customThemes ?? {})) {
|
|
278
|
-
|
|
278
|
+
visit3(theme);
|
|
279
279
|
if (found) break;
|
|
280
280
|
}
|
|
281
281
|
}
|
|
@@ -1640,36 +1640,36 @@ function isPrivateHost(host) {
|
|
|
1640
1640
|
const firstIpv6Group = Number.parseInt(normalized.split(":")[0] || "0", 16);
|
|
1641
1641
|
return firstIpv6Group >= 64512 && firstIpv6Group <= 65023 || firstIpv6Group >= 65152 && firstIpv6Group <= 65215;
|
|
1642
1642
|
}
|
|
1643
|
-
function assertAllowedUrl(source,
|
|
1643
|
+
function assertAllowedUrl(source, path8, allowedHosts) {
|
|
1644
1644
|
if (source.startsWith("data:")) return;
|
|
1645
1645
|
let url;
|
|
1646
1646
|
try {
|
|
1647
1647
|
url = new URL(source);
|
|
1648
1648
|
} catch {
|
|
1649
1649
|
throw new UnsafeOutboundSourceError(
|
|
1650
|
-
|
|
1650
|
+
path8,
|
|
1651
1651
|
"local and relative file paths are disabled for HTTP requests"
|
|
1652
1652
|
);
|
|
1653
1653
|
}
|
|
1654
1654
|
if (url.protocol !== "https:") {
|
|
1655
|
-
throw new UnsafeOutboundSourceError(
|
|
1655
|
+
throw new UnsafeOutboundSourceError(path8, "only HTTPS URLs are allowed");
|
|
1656
1656
|
}
|
|
1657
1657
|
if (url.username || url.password) {
|
|
1658
1658
|
throw new UnsafeOutboundSourceError(
|
|
1659
|
-
|
|
1659
|
+
path8,
|
|
1660
1660
|
"URLs containing credentials are not allowed"
|
|
1661
1661
|
);
|
|
1662
1662
|
}
|
|
1663
1663
|
const host = url.hostname.toLowerCase().replace(/\.$/, "");
|
|
1664
1664
|
if (isPrivateHost(host)) {
|
|
1665
1665
|
throw new UnsafeOutboundSourceError(
|
|
1666
|
-
|
|
1666
|
+
path8,
|
|
1667
1667
|
`private or local host "${host}" is not allowed`
|
|
1668
1668
|
);
|
|
1669
1669
|
}
|
|
1670
1670
|
if (!allowedHosts.some((pattern) => hostMatches(host, pattern))) {
|
|
1671
1671
|
throw new UnsafeOutboundSourceError(
|
|
1672
|
-
|
|
1672
|
+
path8,
|
|
1673
1673
|
`host "${host}" is not in OUTBOUND_HOST_ALLOWLIST`
|
|
1674
1674
|
);
|
|
1675
1675
|
}
|
|
@@ -1687,13 +1687,13 @@ function extractCssReferences(input) {
|
|
|
1687
1687
|
function extractAbsoluteUrls(input) {
|
|
1688
1688
|
return input.match(/(?:https?|file):\/\/[^\s'"<>)}\]]+/gi) ?? [];
|
|
1689
1689
|
}
|
|
1690
|
-
function assertSafeSvg(svg,
|
|
1690
|
+
function assertSafeSvg(svg, path8, allowedHosts) {
|
|
1691
1691
|
if (/<\s*script\b/i.test(svg) || /<\s*(?:foreignObject|iframe|object|embed)\b/i.test(svg) || /\bon[a-z]+\s*=/i.test(svg)) {
|
|
1692
|
-
throw new UnsafeOutboundSourceError(
|
|
1692
|
+
throw new UnsafeOutboundSourceError(path8, "active SVG content is disabled");
|
|
1693
1693
|
}
|
|
1694
1694
|
if (/<!\s*(?:DOCTYPE|ENTITY)\b/i.test(svg)) {
|
|
1695
1695
|
throw new UnsafeOutboundSourceError(
|
|
1696
|
-
|
|
1696
|
+
path8,
|
|
1697
1697
|
"SVG document types and entities are disabled"
|
|
1698
1698
|
);
|
|
1699
1699
|
}
|
|
@@ -1702,20 +1702,20 @@ function assertSafeSvg(svg, path7, allowedHosts) {
|
|
|
1702
1702
|
while (match = refPattern.exec(svg)) {
|
|
1703
1703
|
const ref = match[2].trim();
|
|
1704
1704
|
if (!ref || ref.startsWith("#") || ref.startsWith("data:")) continue;
|
|
1705
|
-
assertAllowedUrl(ref,
|
|
1705
|
+
assertAllowedUrl(ref, path8, allowedHosts);
|
|
1706
1706
|
}
|
|
1707
1707
|
for (const ref of extractCssReferences(svg)) {
|
|
1708
1708
|
if (ref.startsWith("#") || ref.startsWith("data:")) continue;
|
|
1709
|
-
assertAllowedUrl(ref,
|
|
1709
|
+
assertAllowedUrl(ref, path8, allowedHosts);
|
|
1710
1710
|
}
|
|
1711
1711
|
}
|
|
1712
|
-
function assertSafeEncodedImage(source,
|
|
1712
|
+
function assertSafeEncodedImage(source, path8, allowedHosts) {
|
|
1713
1713
|
let candidate = source.trim();
|
|
1714
1714
|
let declaredSvg = false;
|
|
1715
1715
|
if (candidate.startsWith("data:")) {
|
|
1716
1716
|
const comma = candidate.indexOf(",");
|
|
1717
1717
|
if (comma < 0) {
|
|
1718
|
-
throw new UnsafeOutboundSourceError(
|
|
1718
|
+
throw new UnsafeOutboundSourceError(path8, "malformed image data URL");
|
|
1719
1719
|
}
|
|
1720
1720
|
const metadata = candidate.slice(5, comma);
|
|
1721
1721
|
declaredSvg = metadata.split(";")[0].toLowerCase() === "image/svg+xml";
|
|
@@ -1724,7 +1724,7 @@ function assertSafeEncodedImage(source, path7, allowedHosts) {
|
|
|
1724
1724
|
try {
|
|
1725
1725
|
candidate = /(?:^|;)base64(?:;|$)/i.test(metadata) ? Buffer.from(payload, "base64").toString("utf8") : decodeURIComponent(payload);
|
|
1726
1726
|
} catch {
|
|
1727
|
-
throw new UnsafeOutboundSourceError(
|
|
1727
|
+
throw new UnsafeOutboundSourceError(path8, "malformed SVG data URL");
|
|
1728
1728
|
}
|
|
1729
1729
|
} else if (!/<\s*svg\b/i.test(candidate)) {
|
|
1730
1730
|
candidate = Buffer.from(candidate, "base64").toString("utf8");
|
|
@@ -1732,37 +1732,37 @@ function assertSafeEncodedImage(source, path7, allowedHosts) {
|
|
|
1732
1732
|
const svgStart = candidate.search(/<\s*svg\b/i);
|
|
1733
1733
|
if (svgStart < 0) {
|
|
1734
1734
|
if (declaredSvg) {
|
|
1735
|
-
throw new UnsafeOutboundSourceError(
|
|
1735
|
+
throw new UnsafeOutboundSourceError(path8, "malformed SVG image data");
|
|
1736
1736
|
}
|
|
1737
1737
|
return;
|
|
1738
1738
|
}
|
|
1739
|
-
assertSafeSvg(candidate,
|
|
1739
|
+
assertSafeSvg(candidate, path8, allowedHosts);
|
|
1740
1740
|
}
|
|
1741
|
-
function assertSafeResources(resources,
|
|
1741
|
+
function assertSafeResources(resources, path8, allowedHosts) {
|
|
1742
1742
|
if (typeof resources.js === "string" && resources.js.trim()) {
|
|
1743
1743
|
throw new UnsafeOutboundSourceError(
|
|
1744
|
-
`${
|
|
1744
|
+
`${path8}.js`,
|
|
1745
1745
|
"remote renderer JavaScript resources are disabled"
|
|
1746
1746
|
);
|
|
1747
1747
|
}
|
|
1748
1748
|
if (typeof resources.css === "string") {
|
|
1749
1749
|
for (const ref of extractCssReferences(resources.css)) {
|
|
1750
1750
|
if (ref.startsWith("data:")) continue;
|
|
1751
|
-
assertAllowedUrl(ref, `${
|
|
1751
|
+
assertAllowedUrl(ref, `${path8}.css`, allowedHosts);
|
|
1752
1752
|
}
|
|
1753
1753
|
}
|
|
1754
1754
|
if (Array.isArray(resources.files) && resources.files.length > 0) {
|
|
1755
1755
|
throw new UnsafeOutboundSourceError(
|
|
1756
|
-
`${
|
|
1756
|
+
`${path8}.files`,
|
|
1757
1757
|
"remote renderer JavaScript resources are disabled"
|
|
1758
1758
|
);
|
|
1759
1759
|
}
|
|
1760
1760
|
}
|
|
1761
|
-
function assertNoRemoteReferences(value,
|
|
1761
|
+
function assertNoRemoteReferences(value, path8, allowedHosts, seen) {
|
|
1762
1762
|
if (typeof value === "string") {
|
|
1763
1763
|
if (/\b(?:fetch|XMLHttpRequest|WebSocket|EventSource)\s*\(/i.test(value) || /\b(?:javascript|file):/i.test(value)) {
|
|
1764
1764
|
throw new UnsafeOutboundSourceError(
|
|
1765
|
-
|
|
1765
|
+
path8,
|
|
1766
1766
|
"network-capable JavaScript and file URLs are disabled"
|
|
1767
1767
|
);
|
|
1768
1768
|
}
|
|
@@ -1771,11 +1771,11 @@ function assertNoRemoteReferences(value, path7, allowedHosts, seen) {
|
|
|
1771
1771
|
...extractCssReferences(value)
|
|
1772
1772
|
]) {
|
|
1773
1773
|
if (url.startsWith("data:")) continue;
|
|
1774
|
-
assertAllowedUrl(url,
|
|
1774
|
+
assertAllowedUrl(url, path8, allowedHosts);
|
|
1775
1775
|
}
|
|
1776
1776
|
if (/^\/\//.test(value.trim())) {
|
|
1777
1777
|
throw new UnsafeOutboundSourceError(
|
|
1778
|
-
|
|
1778
|
+
path8,
|
|
1779
1779
|
"protocol-relative URLs are disabled"
|
|
1780
1780
|
);
|
|
1781
1781
|
}
|
|
@@ -1785,20 +1785,20 @@ function assertNoRemoteReferences(value, path7, allowedHosts, seen) {
|
|
|
1785
1785
|
seen.add(value);
|
|
1786
1786
|
if (Array.isArray(value)) {
|
|
1787
1787
|
value.forEach(
|
|
1788
|
-
(entry, index) => assertNoRemoteReferences(entry, `${
|
|
1788
|
+
(entry, index) => assertNoRemoteReferences(entry, `${path8}[${index}]`, allowedHosts, seen)
|
|
1789
1789
|
);
|
|
1790
1790
|
return;
|
|
1791
1791
|
}
|
|
1792
1792
|
for (const [key, child] of Object.entries(value)) {
|
|
1793
|
-
assertNoRemoteReferences(child, `${
|
|
1793
|
+
assertNoRemoteReferences(child, `${path8}.${key}`, allowedHosts, seen);
|
|
1794
1794
|
}
|
|
1795
1795
|
}
|
|
1796
|
-
function visit(value,
|
|
1796
|
+
function visit(value, path8, containerKey, allowedHosts, seen) {
|
|
1797
1797
|
if (!value || typeof value !== "object" || seen.has(value)) return;
|
|
1798
1798
|
seen.add(value);
|
|
1799
1799
|
if (Array.isArray(value)) {
|
|
1800
1800
|
value.forEach(
|
|
1801
|
-
(entry, index) => visit(entry, `${
|
|
1801
|
+
(entry, index) => visit(entry, `${path8}[${index}]`, containerKey, allowedHosts, seen)
|
|
1802
1802
|
);
|
|
1803
1803
|
return;
|
|
1804
1804
|
}
|
|
@@ -1806,7 +1806,7 @@ function visit(value, path7, containerKey, allowedHosts, seen) {
|
|
|
1806
1806
|
for (const key of Object.keys(record)) {
|
|
1807
1807
|
if (DANGEROUS_KEYS.has(key)) {
|
|
1808
1808
|
throw new UnsafeOutboundSourceError(
|
|
1809
|
-
`${
|
|
1809
|
+
`${path8}.${key}`,
|
|
1810
1810
|
"prototype mutation keys are disabled"
|
|
1811
1811
|
);
|
|
1812
1812
|
}
|
|
@@ -1814,31 +1814,31 @@ function visit(value, path7, containerKey, allowedHosts, seen) {
|
|
|
1814
1814
|
const kind = typeof record.kind === "string" ? record.kind : void 0;
|
|
1815
1815
|
if (kind === "file" && typeof record.path === "string") {
|
|
1816
1816
|
throw new UnsafeOutboundSourceError(
|
|
1817
|
-
`${
|
|
1817
|
+
`${path8}.path`,
|
|
1818
1818
|
"local file sources are disabled for HTTP requests"
|
|
1819
1819
|
);
|
|
1820
1820
|
}
|
|
1821
1821
|
if ((kind === "url" || kind === "variable") && typeof record.url === "string") {
|
|
1822
|
-
assertAllowedUrl(record.url, `${
|
|
1822
|
+
assertAllowedUrl(record.url, `${path8}.url`, allowedHosts);
|
|
1823
1823
|
}
|
|
1824
1824
|
const componentName = typeof record.name === "string" ? record.name.toLowerCase() : void 0;
|
|
1825
1825
|
const props = isRecord(record.props) ? record.props : void 0;
|
|
1826
1826
|
if (componentName && props) {
|
|
1827
1827
|
if (COMPONENT_SOURCE_NAMES.has(componentName) && typeof props.path === "string") {
|
|
1828
|
-
assertAllowedUrl(props.path, `${
|
|
1829
|
-
assertSafeEncodedImage(props.path, `${
|
|
1828
|
+
assertAllowedUrl(props.path, `${path8}.props.path`, allowedHosts);
|
|
1829
|
+
assertSafeEncodedImage(props.path, `${path8}.props.path`, allowedHosts);
|
|
1830
1830
|
}
|
|
1831
1831
|
if (COMPONENT_SOURCE_NAMES.has(componentName) && typeof props.base64 === "string") {
|
|
1832
1832
|
assertSafeEncodedImage(
|
|
1833
1833
|
props.base64,
|
|
1834
|
-
`${
|
|
1834
|
+
`${path8}.props.base64`,
|
|
1835
1835
|
allowedHosts
|
|
1836
1836
|
);
|
|
1837
1837
|
}
|
|
1838
1838
|
if ((componentName === "highcharts" || componentName === "visual") && typeof props.serverUrl === "string") {
|
|
1839
1839
|
assertAllowedUrl(
|
|
1840
1840
|
props.serverUrl,
|
|
1841
|
-
`${
|
|
1841
|
+
`${path8}.props.serverUrl`,
|
|
1842
1842
|
allowedHosts
|
|
1843
1843
|
);
|
|
1844
1844
|
}
|
|
@@ -1846,30 +1846,30 @@ function visit(value, path7, containerKey, allowedHosts, seen) {
|
|
|
1846
1846
|
if (isRecord(props.resources)) {
|
|
1847
1847
|
assertSafeResources(
|
|
1848
1848
|
props.resources,
|
|
1849
|
-
`${
|
|
1849
|
+
`${path8}.props.resources`,
|
|
1850
1850
|
allowedHosts
|
|
1851
1851
|
);
|
|
1852
1852
|
}
|
|
1853
1853
|
assertNoRemoteReferences(
|
|
1854
1854
|
props.options,
|
|
1855
|
-
`${
|
|
1855
|
+
`${path8}.props.options`,
|
|
1856
1856
|
allowedHosts,
|
|
1857
1857
|
/* @__PURE__ */ new WeakSet()
|
|
1858
1858
|
);
|
|
1859
1859
|
}
|
|
1860
1860
|
}
|
|
1861
1861
|
if (containerKey === "image" && typeof record.path === "string") {
|
|
1862
|
-
assertAllowedUrl(record.path, `${
|
|
1863
|
-
assertSafeEncodedImage(record.path, `${
|
|
1862
|
+
assertAllowedUrl(record.path, `${path8}.path`, allowedHosts);
|
|
1863
|
+
assertSafeEncodedImage(record.path, `${path8}.path`, allowedHosts);
|
|
1864
1864
|
}
|
|
1865
1865
|
if (typeof record.svg === "string") {
|
|
1866
|
-
assertSafeSvg(record.svg, `${
|
|
1866
|
+
assertSafeSvg(record.svg, `${path8}.svg`, allowedHosts);
|
|
1867
1867
|
}
|
|
1868
1868
|
if (containerKey === "resources") {
|
|
1869
|
-
assertSafeResources(record,
|
|
1869
|
+
assertSafeResources(record, path8, allowedHosts);
|
|
1870
1870
|
}
|
|
1871
1871
|
for (const [key, child] of Object.entries(record)) {
|
|
1872
|
-
visit(child, `${
|
|
1872
|
+
visit(child, `${path8}.${key}`, key, allowedHosts, seen);
|
|
1873
1873
|
}
|
|
1874
1874
|
}
|
|
1875
1875
|
function assertSafeOutboundSources(value, policy, rootPath = "request") {
|
|
@@ -1890,9 +1890,9 @@ var init_outbound_source_policy = __esm({
|
|
|
1890
1890
|
"use strict";
|
|
1891
1891
|
init_esm_shims();
|
|
1892
1892
|
UnsafeOutboundSourceError = class extends Error {
|
|
1893
|
-
constructor(
|
|
1894
|
-
super(`Unsafe outbound source at ${
|
|
1895
|
-
this.path =
|
|
1893
|
+
constructor(path8, reason) {
|
|
1894
|
+
super(`Unsafe outbound source at ${path8}: ${reason}`);
|
|
1895
|
+
this.path = path8;
|
|
1896
1896
|
this.name = "UnsafeOutboundSourceError";
|
|
1897
1897
|
}
|
|
1898
1898
|
};
|
|
@@ -2008,6 +2008,118 @@ var init_rasterize_route = __esm({
|
|
|
2008
2008
|
}
|
|
2009
2009
|
});
|
|
2010
2010
|
|
|
2011
|
+
// src/server/services/template-media-inliner.ts
|
|
2012
|
+
import { promises as fs5 } from "fs";
|
|
2013
|
+
import path7 from "path";
|
|
2014
|
+
function isRecord2(value) {
|
|
2015
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
2016
|
+
}
|
|
2017
|
+
function isInlineCandidate(source) {
|
|
2018
|
+
if (!source || source.includes("\0")) return false;
|
|
2019
|
+
if (source.startsWith("data:")) return false;
|
|
2020
|
+
if (path7.isAbsolute(source)) return false;
|
|
2021
|
+
try {
|
|
2022
|
+
new URL(source);
|
|
2023
|
+
return false;
|
|
2024
|
+
} catch {
|
|
2025
|
+
return true;
|
|
2026
|
+
}
|
|
2027
|
+
}
|
|
2028
|
+
async function toDataUrl(source, baseDir, state) {
|
|
2029
|
+
let cacheKey = source;
|
|
2030
|
+
let result = null;
|
|
2031
|
+
try {
|
|
2032
|
+
const resolved = await fs5.realpath(path7.resolve(baseDir, source));
|
|
2033
|
+
cacheKey = resolved;
|
|
2034
|
+
const cached2 = state.cache.get(cacheKey);
|
|
2035
|
+
if (cached2 !== void 0) return cached2;
|
|
2036
|
+
const contained = resolved === state.baseDirReal || resolved.startsWith(state.baseDirReal + path7.sep);
|
|
2037
|
+
if (contained) {
|
|
2038
|
+
const mime = MIME_BY_EXTENSION[path7.extname(resolved).toLowerCase()];
|
|
2039
|
+
if (mime) {
|
|
2040
|
+
const stat = await fs5.stat(resolved);
|
|
2041
|
+
if (stat.isFile() && stat.size <= state.maxFileBytes && stat.size <= state.totalBudget) {
|
|
2042
|
+
const buffer = await fs5.readFile(resolved);
|
|
2043
|
+
state.totalBudget -= buffer.length;
|
|
2044
|
+
result = `data:${mime};base64,${buffer.toString("base64")}`;
|
|
2045
|
+
}
|
|
2046
|
+
}
|
|
2047
|
+
}
|
|
2048
|
+
} catch {
|
|
2049
|
+
}
|
|
2050
|
+
state.cache.set(cacheKey, result);
|
|
2051
|
+
return result;
|
|
2052
|
+
}
|
|
2053
|
+
async function visit2(value, containerKey, baseDir, state, seen) {
|
|
2054
|
+
if (!value || typeof value !== "object" || seen.has(value)) return;
|
|
2055
|
+
seen.add(value);
|
|
2056
|
+
if (Array.isArray(value)) {
|
|
2057
|
+
for (const entry of value) {
|
|
2058
|
+
await visit2(entry, containerKey, baseDir, state, seen);
|
|
2059
|
+
}
|
|
2060
|
+
return;
|
|
2061
|
+
}
|
|
2062
|
+
const record = value;
|
|
2063
|
+
const componentName = typeof record.name === "string" ? record.name.toLowerCase() : void 0;
|
|
2064
|
+
const props = isRecord2(record.props) ? record.props : void 0;
|
|
2065
|
+
if (componentName === "image" && props && typeof props.path === "string" && isInlineCandidate(props.path)) {
|
|
2066
|
+
const inlined = await toDataUrl(props.path, baseDir, state);
|
|
2067
|
+
if (inlined !== null) props.path = inlined;
|
|
2068
|
+
}
|
|
2069
|
+
if (containerKey === "image" && typeof record.path === "string" && isInlineCandidate(record.path)) {
|
|
2070
|
+
const inlined = await toDataUrl(record.path, baseDir, state);
|
|
2071
|
+
if (inlined !== null) record.path = inlined;
|
|
2072
|
+
}
|
|
2073
|
+
for (const [key, child] of Object.entries(record)) {
|
|
2074
|
+
await visit2(child, key, baseDir, state, seen);
|
|
2075
|
+
}
|
|
2076
|
+
}
|
|
2077
|
+
async function inlineTemplateMedia(jsonDefinition, baseDir, options = {}) {
|
|
2078
|
+
if (typeof jsonDefinition === "string") {
|
|
2079
|
+
try {
|
|
2080
|
+
jsonDefinition = JSON.parse(jsonDefinition);
|
|
2081
|
+
} catch {
|
|
2082
|
+
return jsonDefinition;
|
|
2083
|
+
}
|
|
2084
|
+
}
|
|
2085
|
+
if (!jsonDefinition || typeof jsonDefinition !== "object") {
|
|
2086
|
+
return jsonDefinition;
|
|
2087
|
+
}
|
|
2088
|
+
let baseDirReal;
|
|
2089
|
+
try {
|
|
2090
|
+
baseDirReal = await fs5.realpath(baseDir);
|
|
2091
|
+
} catch {
|
|
2092
|
+
return jsonDefinition;
|
|
2093
|
+
}
|
|
2094
|
+
const clone = structuredClone(jsonDefinition);
|
|
2095
|
+
const state = {
|
|
2096
|
+
baseDirReal,
|
|
2097
|
+
maxFileBytes: options.maxFileBytes ?? 10 * 1024 * 1024,
|
|
2098
|
+
totalBudget: options.maxTotalBytes ?? 32 * 1024 * 1024,
|
|
2099
|
+
cache: /* @__PURE__ */ new Map()
|
|
2100
|
+
};
|
|
2101
|
+
await visit2(clone, void 0, baseDir, state, /* @__PURE__ */ new WeakSet());
|
|
2102
|
+
return clone;
|
|
2103
|
+
}
|
|
2104
|
+
var MIME_BY_EXTENSION;
|
|
2105
|
+
var init_template_media_inliner = __esm({
|
|
2106
|
+
"src/server/services/template-media-inliner.ts"() {
|
|
2107
|
+
"use strict";
|
|
2108
|
+
init_esm_shims();
|
|
2109
|
+
MIME_BY_EXTENSION = {
|
|
2110
|
+
".png": "image/png",
|
|
2111
|
+
".jpg": "image/jpeg",
|
|
2112
|
+
".jpeg": "image/jpeg",
|
|
2113
|
+
".gif": "image/gif",
|
|
2114
|
+
".svg": "image/svg+xml",
|
|
2115
|
+
".webp": "image/webp",
|
|
2116
|
+
".bmp": "image/bmp",
|
|
2117
|
+
".tiff": "image/tiff",
|
|
2118
|
+
".tif": "image/tiff"
|
|
2119
|
+
};
|
|
2120
|
+
}
|
|
2121
|
+
});
|
|
2122
|
+
|
|
2011
2123
|
// src/server/routes/format.ts
|
|
2012
2124
|
import { Hono as Hono2 } from "hono";
|
|
2013
2125
|
import { HTTPException as HTTPException4 } from "hono/http-exception";
|
|
@@ -2019,9 +2131,9 @@ import {
|
|
|
2019
2131
|
import { dirname } from "path";
|
|
2020
2132
|
function createFormatRouter(adapter) {
|
|
2021
2133
|
const router = new Hono2();
|
|
2022
|
-
const assertRequestSources = (value,
|
|
2134
|
+
const assertRequestSources = (value, path8) => {
|
|
2023
2135
|
try {
|
|
2024
|
-
assertSafeOutboundSources(value, config.outboundSources,
|
|
2136
|
+
assertSafeOutboundSources(value, config.outboundSources, path8);
|
|
2025
2137
|
} catch (error) {
|
|
2026
2138
|
if (error instanceof UnsafeOutboundSourceError) {
|
|
2027
2139
|
throw new HTTPException4(400, { message: error.message });
|
|
@@ -2049,6 +2161,15 @@ function createFormatRouter(adapter) {
|
|
|
2049
2161
|
return void 0;
|
|
2050
2162
|
}
|
|
2051
2163
|
};
|
|
2164
|
+
const inlineDiscoveredMedia = async (jsonDefinition, baseDir) => {
|
|
2165
|
+
if (baseDir === void 0 || config.outboundSources.mode === "development") {
|
|
2166
|
+
return jsonDefinition;
|
|
2167
|
+
}
|
|
2168
|
+
return inlineTemplateMedia(jsonDefinition, baseDir, {
|
|
2169
|
+
maxFileBytes: config.requestLimits.maxFileSize,
|
|
2170
|
+
maxTotalBytes: config.requestLimits.maxBodySize
|
|
2171
|
+
});
|
|
2172
|
+
};
|
|
2052
2173
|
const contentTypeMw = async (c, next) => {
|
|
2053
2174
|
const contentType = c.req.header("content-type");
|
|
2054
2175
|
if (!contentType || !contentType.includes("application/json")) {
|
|
@@ -2072,7 +2193,12 @@ function createFormatRouter(adapter) {
|
|
|
2072
2193
|
const { jsonDefinition, customThemes, options } = getValidated(c, "json");
|
|
2073
2194
|
const requestId = c.get("requestId");
|
|
2074
2195
|
try {
|
|
2075
|
-
|
|
2196
|
+
const baseDir = await resolveSourceBaseDir(options);
|
|
2197
|
+
const effectiveDefinition = await inlineDiscoveredMedia(
|
|
2198
|
+
jsonDefinition,
|
|
2199
|
+
baseDir
|
|
2200
|
+
);
|
|
2201
|
+
assertRequestSources(effectiveDefinition, "jsonDefinition");
|
|
2076
2202
|
assertRequestSources(customThemes, "customThemes");
|
|
2077
2203
|
assertRequestSources(options, "options");
|
|
2078
2204
|
const bypassCache = c.req.header("X-Bypass-Cache") === "true" || c.req.query("bypass-cache") === "true" || options?.bypassCache === true;
|
|
@@ -2084,11 +2210,10 @@ function createFormatRouter(adapter) {
|
|
|
2084
2210
|
} else if (rawFonts) {
|
|
2085
2211
|
sanitizedFonts = rawFonts;
|
|
2086
2212
|
}
|
|
2087
|
-
const baseDir = await resolveSourceBaseDir(options);
|
|
2088
2213
|
const clientOptions = { ...options };
|
|
2089
2214
|
delete clientOptions.baseDir;
|
|
2090
2215
|
const result = await generatorService.generate({
|
|
2091
|
-
jsonDefinition,
|
|
2216
|
+
jsonDefinition: effectiveDefinition,
|
|
2092
2217
|
customThemes,
|
|
2093
2218
|
options: {
|
|
2094
2219
|
...clientOptions,
|
|
@@ -2352,12 +2477,16 @@ function createFormatRouter(adapter) {
|
|
|
2352
2477
|
);
|
|
2353
2478
|
const { jsonDefinition, customThemes, options } = getValidated(c, "json");
|
|
2354
2479
|
try {
|
|
2355
|
-
|
|
2480
|
+
const baseDir = await resolveSourceBaseDir(options);
|
|
2481
|
+
const effectiveDefinition = await inlineDiscoveredMedia(
|
|
2482
|
+
jsonDefinition,
|
|
2483
|
+
baseDir
|
|
2484
|
+
);
|
|
2485
|
+
assertRequestSources(effectiveDefinition, "jsonDefinition");
|
|
2356
2486
|
assertRequestSources(customThemes, "customThemes");
|
|
2357
2487
|
assertRequestSources(options, "options");
|
|
2358
|
-
const baseDir = await resolveSourceBaseDir(options);
|
|
2359
2488
|
const generated = await generatorService.generate({
|
|
2360
|
-
jsonDefinition,
|
|
2489
|
+
jsonDefinition: effectiveDefinition,
|
|
2361
2490
|
customThemes,
|
|
2362
2491
|
options: {
|
|
2363
2492
|
bypassCache: true,
|
|
@@ -2530,6 +2659,7 @@ var init_format = __esm({
|
|
|
2530
2659
|
init_config();
|
|
2531
2660
|
init_outbound_source_policy();
|
|
2532
2661
|
init_libreoffice_converter();
|
|
2662
|
+
init_template_media_inliner();
|
|
2533
2663
|
}
|
|
2534
2664
|
});
|
|
2535
2665
|
|
|
@@ -3863,9 +3993,9 @@ var init_unified_server = __esm({
|
|
|
3863
3993
|
return await apiApp.fetch(c.req.raw, c.env);
|
|
3864
3994
|
});
|
|
3865
3995
|
this.app.use("*", async (c, next) => {
|
|
3866
|
-
const
|
|
3867
|
-
if (
|
|
3868
|
-
if (/\.(ts|tsx|js|jsx|css|map)$/.test(
|
|
3996
|
+
const path8 = c.req.path;
|
|
3997
|
+
if (path8.startsWith("/api")) {
|
|
3998
|
+
if (/\.(ts|tsx|js|jsx|css|map)$/.test(path8)) {
|
|
3869
3999
|
return next();
|
|
3870
4000
|
}
|
|
3871
4001
|
const response = await apiApp.fetch(c.req.raw, c.env);
|
|
@@ -3968,8 +4098,8 @@ var init_unified_server = __esm({
|
|
|
3968
4098
|
}
|
|
3969
4099
|
if (this.viteServer) {
|
|
3970
4100
|
this.app.use("*", async (c, next) => {
|
|
3971
|
-
const
|
|
3972
|
-
if ((
|
|
4101
|
+
const path8 = c.req.path;
|
|
4102
|
+
if ((path8.startsWith("/api") || path8 === "/health") && !/\.(ts|tsx|js|jsx|css|map)$/.test(path8)) {
|
|
3973
4103
|
return next();
|
|
3974
4104
|
}
|
|
3975
4105
|
const env = c.env;
|
|
@@ -3988,7 +4118,7 @@ var init_unified_server = __esm({
|
|
|
3988
4118
|
}
|
|
3989
4119
|
async setupBuiltClient(clientPath) {
|
|
3990
4120
|
const { serveStatic } = await import("@hono/node-server/serve-static");
|
|
3991
|
-
const
|
|
4121
|
+
const fs6 = await import("fs");
|
|
3992
4122
|
const { extname } = await import("path");
|
|
3993
4123
|
const mime = await import("mime-types");
|
|
3994
4124
|
const format = this.adapter.name.replace(/[^a-zA-Z0-9]/g, "");
|
|
@@ -3996,7 +4126,7 @@ var init_unified_server = __esm({
|
|
|
3996
4126
|
"/assets/*",
|
|
3997
4127
|
serveStatic({
|
|
3998
4128
|
root: clientPath,
|
|
3999
|
-
rewriteRequestPath: (
|
|
4129
|
+
rewriteRequestPath: (path8) => path8.replace(/^\/assets/, "/assets")
|
|
4000
4130
|
})
|
|
4001
4131
|
);
|
|
4002
4132
|
this.app.use("/*", async (c, next) => {
|
|
@@ -4005,9 +4135,9 @@ var init_unified_server = __esm({
|
|
|
4005
4135
|
const ext = extname(reqPath);
|
|
4006
4136
|
if (ext) {
|
|
4007
4137
|
const filePath = resolve(clientPath, reqPath.slice(1));
|
|
4008
|
-
if (
|
|
4138
|
+
if (fs6.existsSync(filePath)) {
|
|
4009
4139
|
const mimeType = mime.lookup(filePath) || "application/octet-stream";
|
|
4010
|
-
const content =
|
|
4140
|
+
const content = fs6.readFileSync(filePath);
|
|
4011
4141
|
c.header("Content-Type", mimeType);
|
|
4012
4142
|
return c.body(content);
|
|
4013
4143
|
}
|
|
@@ -4019,8 +4149,8 @@ var init_unified_server = __esm({
|
|
|
4019
4149
|
if (reqPath.startsWith("/api") || reqPath === "/health")
|
|
4020
4150
|
return c.notFound();
|
|
4021
4151
|
const indexPath = resolve(clientPath, "index.html");
|
|
4022
|
-
if (
|
|
4023
|
-
let html =
|
|
4152
|
+
if (fs6.existsSync(indexPath)) {
|
|
4153
|
+
let html = fs6.readFileSync(indexPath, "utf-8");
|
|
4024
4154
|
html = html.replace(
|
|
4025
4155
|
"</head>",
|
|
4026
4156
|
`<script>window.__JTO_FORMAT__ = '${format}';</script>
|
|
@@ -4181,7 +4311,7 @@ function createDevCommand(adapter) {
|
|
|
4181
4311
|
}
|
|
4182
4312
|
|
|
4183
4313
|
// src/cli.ts
|
|
4184
|
-
var PACKAGE_VERSION = true ? "0.28.
|
|
4314
|
+
var PACKAGE_VERSION = true ? "0.28.1" : "dev-mode";
|
|
4185
4315
|
var program = new Command2();
|
|
4186
4316
|
program.name("jto").description("JSON to Office CLI - Generate .docx and .pptx from JSON").version(PACKAGE_VERSION);
|
|
4187
4317
|
registerCoreCommands(program, {
|