@bendyline/squisq-formats 2.6.16 → 2.6.18

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.
@@ -285,8 +285,11 @@ function escapeHtml(str) {
285
285
 
286
286
  // src/html/plainHtml.ts
287
287
  import {
288
+ findBlockVideoEmbed,
288
289
  sanitizeHtmlNodes,
289
290
  sanitizeUrl,
291
+ videoEmbedFromIframe,
292
+ videoEmbedIframeAttributes,
290
293
  readFrontmatterThemeId as readFrontmatterThemeId2
291
294
  } from "@bendyline/squisq/markdown";
292
295
  import { resolveFontFamily, buildGoogleFontsUrl } from "@bendyline/squisq/schemas";
@@ -299,12 +302,13 @@ function markdownDocToPlainHtml(doc, options = {}) {
299
302
  themeId,
300
303
  iconsCss,
301
304
  htmlPolicy = "sanitize",
302
- externalResources = "deny"
305
+ externalResources = "deny",
306
+ videoEmbeds
303
307
  } = options;
304
308
  const resolveId = themeId ?? readFrontmatterThemeId2(doc.frontmatter);
305
309
  const theme = options.theme ?? (resolveId ? resolveThemeForDoc(doc, resolveId, options.themeRegistry) : void 0);
306
310
  const footnotes = new FootnoteIndex(doc);
307
- const ctx = { images, links, htmlPolicy, footnotes };
311
+ const ctx = { images, links, htmlPolicy, footnotes, videoEmbeds };
308
312
  const body = renderTopLevel(doc.children, ctx) + renderFootnotesSection(footnotes, ctx);
309
313
  const fontsLink = theme && externalResources === "allow" ? renderFontsLink(theme) : "";
310
314
  const usesIcons = docUsesIcons(doc);
@@ -316,8 +320,10 @@ ${escapeStyleText(iconsCss)}
316
320
  ` : externalResources === "allow" ? FONT_AWESOME_LINK : "";
317
321
  }
318
322
  const themedCss = theme ? renderThemedCss(theme) : DEFAULT_CSS;
323
+ const videoCss = docUsesVideoEmbeds(doc, htmlPolicy) ? `
324
+ ${VIDEO_EMBED_CSS}` : "";
319
325
  const safeCss = escapeStyleText(`${themedCss}
320
- ${FEATURE_CSS}`);
326
+ ${FEATURE_CSS}${videoCss}`);
321
327
  return `<!DOCTYPE html>
322
328
  <html lang="en">
323
329
  <head>
@@ -350,6 +356,22 @@ function docUsesIcons(doc) {
350
356
  }
351
357
  return visit(doc);
352
358
  }
359
+ function docUsesVideoEmbeds(doc, htmlPolicy) {
360
+ const iframeIn = (nodes) => nodes.some(
361
+ (node) => node.type === "htmlElement" && (videoEmbedFromIframe(node) !== null || iframeIn(node.children))
362
+ );
363
+ const visit = (node) => {
364
+ if (!node || typeof node !== "object") return false;
365
+ const n = node;
366
+ if (htmlPolicy !== "strip" && Array.isArray(n.htmlChildren) && iframeIn(n.htmlChildren)) {
367
+ return true;
368
+ }
369
+ return Array.isArray(n.children) && n.children.some(visit);
370
+ };
371
+ return doc.children.some(
372
+ (node) => node.type === "paragraph" && findBlockVideoEmbed(node) !== null || visit(node)
373
+ );
374
+ }
353
375
  function renderTopLevel(children, ctx) {
354
376
  const out = [];
355
377
  for (let i = 0; i < children.length; i++) {
@@ -365,6 +387,11 @@ function renderTopLevel(children, ctx) {
365
387
  continue;
366
388
  }
367
389
  }
390
+ const video = node && node.type === "paragraph" ? findBlockVideoEmbed(node) : null;
391
+ if (video) {
392
+ out.push(videoEmbedToHtml(video.embed, video.title, ctx));
393
+ continue;
394
+ }
368
395
  out.push(nodeToHtml(node, ctx));
369
396
  }
370
397
  return out.join("\n");
@@ -541,7 +568,8 @@ var FEATURE_CSS = ` .squisq-feature {
541
568
  .squisq-feature, .squisq-feature--right { flex-direction: column; }
542
569
  .squisq-feature__media { flex-basis: auto; width: 100%; }
543
570
  }`;
544
- var DEFAULT_CSS = ` body { font-family: system-ui, -apple-system, sans-serif; max-width: 800px; margin: 2em auto; padding: 0 1em; line-height: 1.6; color: #1f2937; }
571
+ var DEFAULT_CSS = ` :root { color-scheme: light; }
572
+ body { font-family: system-ui, -apple-system, sans-serif; max-width: 800px; margin: 2em auto; padding: 0 1em; line-height: 1.6; color: #1f2937; background: #fff; }
545
573
  h1, h2, h3, h4, h5, h6 { margin-top: 1.5em; margin-bottom: 0.5em; }
546
574
  pre { background: #f3f4f6; padding: 1em; border-radius: 4px; overflow-x: auto; }
547
575
  code { background: #f3f4f6; padding: 0.15em 0.3em; border-radius: 3px; font-size: 0.9em; }
@@ -735,9 +763,12 @@ function nodeToHtml(node, ctx) {
735
763
  return `<i class="fa-${family} fa-${name}" data-icon="${token}" aria-hidden="true"></i>`;
736
764
  }
737
765
  case "htmlBlock":
738
- case "htmlInline":
766
+ case "htmlInline": {
739
767
  if (resolveHtmlPolicy(ctx) === "strip") return "";
768
+ const video = node.type === "htmlBlock" ? findBlockVideoEmbed(node) : null;
769
+ if (video) return videoEmbedToHtml(video.embed, video.title, ctx);
740
770
  return htmlChildrenToHtml(resolveHtmlNodes(node.htmlChildren, ctx), ctx);
771
+ }
741
772
  default: {
742
773
  const withChildren = node;
743
774
  if (Array.isArray(withChildren.children)) {
@@ -799,6 +830,13 @@ function htmlChildrenToHtml(nodes, ctx) {
799
830
  continue;
800
831
  }
801
832
  const tag = node.tagName.toLowerCase();
833
+ if (tag === "iframe") {
834
+ const video = videoEmbedFromIframe(node);
835
+ if (video) {
836
+ out.push(videoEmbedToHtml(video.embed, video.title, ctx, true));
837
+ continue;
838
+ }
839
+ }
802
840
  const attrs = { ...node.attributes };
803
841
  if ((tag === "img" || tag === "video" || tag === "audio" || tag === "source") && typeof attrs.src === "string") {
804
842
  attrs.src = ctx?.images?.get(attrs.src) ?? attrs.src;
@@ -832,6 +870,32 @@ function htmlChildrenToHtml(nodes, ctx) {
832
870
  }
833
871
  return out.join("");
834
872
  }
873
+ function videoEmbedToHtml(embed, title, ctx, inline = false) {
874
+ const root = inline ? "span" : "figure";
875
+ const orientation = embed.aspectRatio < 1 ? "portrait" : "landscape";
876
+ const ratio = `aspect-ratio: ${embed.aspectRatio < 1 ? "9 / 16" : "16 / 9"}`;
877
+ const watchUrl = escapeAttr(embed.watchUrl);
878
+ let frame;
879
+ if (ctx?.videoEmbeds === "poster") {
880
+ const label = title ? `Watch \u201C${title}\u201D on ${embed.providerName}` : `Watch on ${embed.providerName}`;
881
+ const thumbnail = embed.thumbnailUrl ? `<img src="${escapeAttr(embed.thumbnailUrl)}" alt="" loading="lazy" />` : "";
882
+ frame = `<a class="squisq-video-embed-frame squisq-video-embed-poster" href="${watchUrl}" style="${ratio}" aria-label="${escapeAttr(label)}">${thumbnail}<span class="squisq-video-embed-play" aria-hidden="true"></span><span class="squisq-video-embed-provider" aria-hidden="true">${escapeHtml2(embed.providerName)}</span></a>`;
883
+ } else {
884
+ const attrs = Object.entries(videoEmbedIframeAttributes(embed, title)).map(([name, value]) => value === "" ? ` ${name}` : ` ${name}="${escapeAttr(value)}"`).join("");
885
+ frame = `<span class="squisq-video-embed-frame" style="${ratio}"><iframe${attrs}></iframe></span>`;
886
+ }
887
+ const caption = title && !inline ? `<figcaption class="squisq-video-embed-caption"><a href="${watchUrl}">${escapeHtml2(title)}</a></figcaption>` : "";
888
+ return `<${root} class="squisq-video-embed" data-provider="${embed.provider}" data-orientation="${orientation}">${frame}${caption}</${root}>`;
889
+ }
890
+ var VIDEO_EMBED_CSS = ` .squisq-video-embed { display: block; max-width: 720px; margin: 1.25em 0; }
891
+ .squisq-video-embed[data-orientation="portrait"] { max-width: 340px; }
892
+ .squisq-video-embed-frame { position: relative; display: block; overflow: hidden; border-radius: 6px; background: #000; }
893
+ .squisq-video-embed-frame iframe { position: absolute; inset: 0; width: 100%; height: 100%; border: 0; }
894
+ .squisq-video-embed-poster img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; }
895
+ .squisq-video-embed-play { position: absolute; left: 50%; top: 50%; width: 64px; height: 44px; margin: -22px 0 0 -32px; border-radius: 12px; background: rgba(0, 0, 0, 0.72); }
896
+ .squisq-video-embed-play::after { content: ''; position: absolute; left: 26px; top: 12px; border-style: solid; border-width: 10px 0 10px 16px; border-color: transparent transparent transparent #fff; }
897
+ .squisq-video-embed-provider { position: absolute; left: 12px; bottom: 10px; color: #fff; font-size: 0.8em; font-weight: 600; text-shadow: 0 1px 2px rgba(0, 0, 0, 0.8); }
898
+ .squisq-video-embed-caption { margin-top: 0.4em; font-size: 0.875em; opacity: 0.8; }`;
835
899
  function escapeHtml2(s) {
836
900
  return s.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
837
901
  }
@@ -1301,7 +1365,8 @@ function titleForDoc(path, mdDoc) {
1301
1365
  import {
1302
1366
  parseHtmlToNodes,
1303
1367
  sanitizeHtmlNodes as sanitizeHtmlNodes2,
1304
- stringifyMarkdown
1368
+ stringifyMarkdown,
1369
+ videoEmbedFromIframe as videoEmbedFromIframe2
1305
1370
  } from "@bendyline/squisq/markdown";
1306
1371
  import { docToMarkdown } from "@bendyline/squisq/doc";
1307
1372
 
@@ -1532,6 +1597,151 @@ var INLINE_TRANSPARENT = /* @__PURE__ */ new Set(["span", "font", "abbr", "mark"
1532
1597
  var isElement2 = (n) => n.type === "htmlElement";
1533
1598
  var isText = (n) => n.type === "htmlText";
1534
1599
  var collapseWs = (s) => s.replace(/\s+/g, " ");
1600
+ var HEAD_METADATA_MAX_CHARS = 1024;
1601
+ function headMetadataValue(raw) {
1602
+ const value = collapseWs(raw.replace(/[\u0000-\u001f\u007f]/g, " ")).trim();
1603
+ return value ? value.slice(0, HEAD_METADATA_MAX_CHARS) : void 0;
1604
+ }
1605
+ function readHeadMetadata(nodes) {
1606
+ const metadata = {};
1607
+ const visit = (list) => {
1608
+ for (const node of list) {
1609
+ if (!isElement2(node)) continue;
1610
+ const tag = node.tagName.toLowerCase();
1611
+ if (tag === "html" || tag === "head") {
1612
+ visit(node.children);
1613
+ } else if (tag === "title" && metadata.title === void 0) {
1614
+ const title = headMetadataValue(textContent(node));
1615
+ if (title) metadata.title = title;
1616
+ } else if (tag === "meta" && metadata.description === void 0 && node.attributes.name?.toLowerCase() === "description") {
1617
+ const description = headMetadataValue(node.attributes.content ?? "");
1618
+ if (description) metadata.description = description;
1619
+ }
1620
+ }
1621
+ };
1622
+ visit(nodes);
1623
+ return metadata;
1624
+ }
1625
+ function dropContentlessElements(nodes) {
1626
+ return nodes.flatMap((node) => {
1627
+ if (!isElement2(node)) return [node];
1628
+ if (DROP.has(node.tagName.toLowerCase())) return [];
1629
+ return [{ ...node, children: dropContentlessElements(node.children) }];
1630
+ });
1631
+ }
1632
+ var INLINE_PARENT_TYPES = /* @__PURE__ */ new Set([
1633
+ "strong",
1634
+ "emphasis",
1635
+ "delete",
1636
+ "link",
1637
+ "superscript",
1638
+ "subscript"
1639
+ ]);
1640
+ var isInlineParent = (node) => INLINE_PARENT_TYPES.has(node.type);
1641
+ function trimRunEnd(run) {
1642
+ for (let last = run[run.length - 1]; last?.type === "text"; last = run[run.length - 1]) {
1643
+ const value = last.value.replace(/ +$/, "");
1644
+ if (value) {
1645
+ run[run.length - 1] = { ...last, value };
1646
+ return;
1647
+ }
1648
+ run.pop();
1649
+ }
1650
+ }
1651
+ function mergeAdjacentText(run) {
1652
+ const out = [];
1653
+ for (const node of run) {
1654
+ const previous = out[out.length - 1];
1655
+ if (node.type === "text" && previous?.type === "text") {
1656
+ out[out.length - 1] = { ...previous, value: previous.value + node.value };
1657
+ } else if (isInlineParent(node)) {
1658
+ out.push({ ...node, children: mergeAdjacentText(node.children) });
1659
+ } else {
1660
+ out.push(node);
1661
+ }
1662
+ }
1663
+ return out;
1664
+ }
1665
+ function normalizeInlineWhitespace(inlines) {
1666
+ const state = { spaced: true };
1667
+ const walk = (run) => {
1668
+ const out2 = [];
1669
+ for (const node of run) {
1670
+ if (node.type === "text") {
1671
+ const value = state.spaced ? node.value.replace(/^ +/, "") : node.value;
1672
+ if (!value) continue;
1673
+ out2.push({ ...node, value });
1674
+ state.spaced = value.endsWith(" ");
1675
+ } else if (node.type === "break") {
1676
+ trimRunEnd(out2);
1677
+ out2.push(node);
1678
+ state.spaced = true;
1679
+ } else if (isInlineParent(node)) {
1680
+ const children = walk(node.children);
1681
+ const first = children[0];
1682
+ if (first?.type === "text" && first.value.startsWith(" ")) {
1683
+ const value = first.value.replace(/^ +/, "");
1684
+ if (value) children[0] = { ...first, value };
1685
+ else children.shift();
1686
+ out2.push({ type: "text", value: " " });
1687
+ }
1688
+ const last = children[children.length - 1];
1689
+ const trailing = last?.type === "text" && last.value.endsWith(" ");
1690
+ if (trailing) trimRunEnd(children);
1691
+ if (children.length > 0) {
1692
+ out2.push({ ...node, children });
1693
+ } else if (node.type === "link") {
1694
+ out2.push({ ...node, children: [{ type: "text", value: node.url }] });
1695
+ }
1696
+ if (trailing) {
1697
+ out2.push({ type: "text", value: " " });
1698
+ state.spaced = true;
1699
+ } else if (children.length > 0 || node.type === "link") {
1700
+ state.spaced = false;
1701
+ }
1702
+ } else {
1703
+ out2.push(node);
1704
+ state.spaced = false;
1705
+ }
1706
+ }
1707
+ return out2;
1708
+ };
1709
+ const out = walk(inlines);
1710
+ trimRunEnd(out);
1711
+ return mergeAdjacentText(out);
1712
+ }
1713
+ var blockInlines = (nodes) => normalizeInlineWhitespace(inlinesFromNodes(nodes));
1714
+ function appendMarkedInlines(output, type, input) {
1715
+ const children = [...input];
1716
+ let leading = "";
1717
+ let trailing = "";
1718
+ while (children[0]?.type === "text") {
1719
+ const first = children[0];
1720
+ const space = /^ +/.exec(first.value)?.[0] ?? "";
1721
+ if (!space) break;
1722
+ leading += space;
1723
+ if (space.length === first.value.length) children.shift();
1724
+ else {
1725
+ children[0] = { ...first, value: first.value.slice(space.length) };
1726
+ break;
1727
+ }
1728
+ }
1729
+ while (children[children.length - 1]?.type === "text") {
1730
+ const last = children[children.length - 1];
1731
+ if (last.type !== "text") break;
1732
+ const space = / +$/.exec(last.value)?.[0] ?? "";
1733
+ if (!space) break;
1734
+ trailing = space + trailing;
1735
+ if (space.length === last.value.length) children.pop();
1736
+ else {
1737
+ children[children.length - 1] = { ...last, value: last.value.slice(0, -space.length) };
1738
+ break;
1739
+ }
1740
+ }
1741
+ if (leading) output.push({ type: "text", value: leading });
1742
+ if (children.length) output.push({ type, children });
1743
+ if (trailing) output.push({ type: "text", value: trailing });
1744
+ }
1535
1745
  function inlinesFromNodes(nodes) {
1536
1746
  const out = [];
1537
1747
  for (const node of nodes) {
@@ -1546,11 +1756,11 @@ function inlinesFromNodes(nodes) {
1546
1756
  if (tag === "br") {
1547
1757
  out.push({ type: "break" });
1548
1758
  } else if (INLINE_STRONG.has(tag)) {
1549
- out.push({ type: "strong", children: inlinesFromNodes(node.children) });
1759
+ appendMarkedInlines(out, "strong", inlinesFromNodes(node.children));
1550
1760
  } else if (INLINE_EM.has(tag)) {
1551
- out.push({ type: "emphasis", children: inlinesFromNodes(node.children) });
1761
+ appendMarkedInlines(out, "emphasis", inlinesFromNodes(node.children));
1552
1762
  } else if (INLINE_DEL.has(tag)) {
1553
- out.push({ type: "delete", children: inlinesFromNodes(node.children) });
1763
+ appendMarkedInlines(out, "delete", inlinesFromNodes(node.children));
1554
1764
  } else if (INLINE_SUP.has(tag)) {
1555
1765
  out.push({ type: "superscript", children: inlinesFromNodes(node.children) });
1556
1766
  } else if (INLINE_SUB.has(tag)) {
@@ -1580,17 +1790,14 @@ function textContent(node) {
1580
1790
  if (isElement2(node)) return node.children.map(textContent).join("");
1581
1791
  return "";
1582
1792
  }
1583
- var onlyWhitespace = (inlines) => inlines.every((n) => n.type === "text" && n.value.trim() === "");
1584
1793
  function blocksFromNodes(nodes) {
1585
1794
  const out = [];
1586
1795
  let inlineBuffer = [];
1587
1796
  const flush = () => {
1588
1797
  if (inlineBuffer.length === 0) return;
1589
- const inlines = inlinesFromNodes(inlineBuffer);
1798
+ const inlines = blockInlines(inlineBuffer);
1590
1799
  inlineBuffer = [];
1591
- if (inlines.length > 0 && !onlyWhitespace(inlines)) {
1592
- out.push({ type: "paragraph", children: inlines });
1593
- }
1800
+ if (inlines.length > 0) out.push({ type: "paragraph", children: inlines });
1594
1801
  };
1595
1802
  for (const node of nodes) {
1596
1803
  if (isText(node)) {
@@ -1613,15 +1820,26 @@ function blocksFromNodes(nodes) {
1613
1820
  }
1614
1821
  function blockForElement(node, tag) {
1615
1822
  if (tag in HEADINGS) {
1616
- const children = inlinesFromNodes(node.children);
1823
+ const children = blockInlines(node.children);
1617
1824
  return [{ type: "heading", depth: HEADINGS[tag], children }];
1618
1825
  }
1619
1826
  if (tag === "p") {
1620
- const children = inlinesFromNodes(node.children);
1621
- return children.length > 0 && !onlyWhitespace(children) ? [{ type: "paragraph", children }] : [];
1827
+ const children = blockInlines(node.children);
1828
+ return children.length > 0 ? [{ type: "paragraph", children }] : [];
1622
1829
  }
1623
1830
  if (tag === "br") return "inline";
1624
1831
  if (tag === "hr") return [{ type: "thematicBreak" }];
1832
+ if (tag === "iframe") {
1833
+ const video = videoEmbedFromIframe2(node);
1834
+ if (!video) return [];
1835
+ const url = video.embed.watchUrl;
1836
+ return [
1837
+ {
1838
+ type: "paragraph",
1839
+ children: [{ type: "link", url, children: [{ type: "text", value: video.title ?? url }] }]
1840
+ }
1841
+ ];
1842
+ }
1625
1843
  if (tag === "blockquote") {
1626
1844
  return [{ type: "blockquote", children: blocksFromNodes(node.children) }];
1627
1845
  }
@@ -1670,7 +1888,7 @@ function tableFromElement(node) {
1670
1888
  const cells = [];
1671
1889
  for (const cell of child.children) {
1672
1890
  if (isElement2(cell) && (cell.tagName.toLowerCase() === "td" || cell.tagName.toLowerCase() === "th")) {
1673
- cells.push({ type: "tableCell", children: inlinesFromNodes(cell.children) });
1891
+ cells.push({ type: "tableCell", children: blockInlines(cell.children) });
1674
1892
  }
1675
1893
  }
1676
1894
  if (cells.length > 0) rows.push({ type: "tableRow", children: cells });
@@ -1728,7 +1946,12 @@ function htmlToMarkdownDocSync(html, options = {}) {
1728
1946
  const nodes = parseHtmlToNodes(html);
1729
1947
  const embedded = findEmbeddedSquisqDoc(nodes);
1730
1948
  if (embedded) return docToMarkdown(parseEmbeddedSquisqDoc(embedded));
1731
- const { nodes: bodyNodes, bodies, identifiers } = extractFootnoteSection(nodes);
1949
+ const headMetadata = options.headMetadata === false ? {} : readHeadMetadata(nodes);
1950
+ const {
1951
+ nodes: bodyNodes,
1952
+ bodies,
1953
+ identifiers
1954
+ } = extractFootnoteSection(dropContentlessElements(nodes));
1732
1955
  const clean = (input) => options.sanitize === false ? input : sanitizeHtmlNodes2(input);
1733
1956
  const children = blocksFromNodes(clean(bodyNodes));
1734
1957
  if (bodies.size > 0) {
@@ -1737,7 +1960,11 @@ function htmlToMarkdownDocSync(html, options = {}) {
1737
1960
  for (const [id, body] of bodies) definitions.set(id, blocksFromNodes(clean(body)));
1738
1961
  children.push(...buildFootnoteDefinitions(definitions));
1739
1962
  }
1740
- return { type: "document", children };
1963
+ return {
1964
+ type: "document",
1965
+ children,
1966
+ ...Object.keys(headMetadata).length > 0 ? { frontmatter: headMetadata } : {}
1967
+ };
1741
1968
  }
1742
1969
  async function htmlToMarkdownDoc(data, options = {}) {
1743
1970
  return htmlToMarkdownDocSync(toHtmlString(data), options);
@@ -1,3 +1,6 @@
1
+ import {
2
+ upngEncoder
3
+ } from "./chunk-34KECNZO.js";
1
4
  import {
2
5
  FootnoteIndex
3
6
  } from "./chunk-BXWNU4T5.js";
@@ -1182,20 +1185,6 @@ function hexToRgb(hex) {
1182
1185
  // src/pdf/import.ts
1183
1186
  import { markdownToDoc } from "@bendyline/squisq/doc";
1184
1187
  import { stringifyMarkdown } from "@bendyline/squisq/markdown";
1185
-
1186
- // src/pdf/upng.ts
1187
- import UPNG from "@pdf-lib/upng";
1188
- function isUpngEncoder(value) {
1189
- return typeof value === "object" && value !== null && "encode" in value && typeof value.encode === "function";
1190
- }
1191
- function resolveUpngEncoder(value) {
1192
- if (isUpngEncoder(value)) return value;
1193
- if (typeof value !== "object" || value === null || !("default" in value)) return null;
1194
- return isUpngEncoder(value.default) ? value.default : null;
1195
- }
1196
- var upngEncoder = resolveUpngEncoder(UPNG);
1197
-
1198
- // src/pdf/import.ts
1199
1188
  async function pdfToMarkdownDoc(data, options = {}) {
1200
1189
  options.signal?.throwIfAborted();
1201
1190
  const bytes = data instanceof Blob ? new Uint8Array(await data.arrayBuffer()) : data instanceof ArrayBuffer ? new Uint8Array(data) : data;