@carlonicora/nextjs-jsonapi 6.14.1 → 6.15.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.
@@ -12,4 +12,10 @@ declare function BlockNoteServerContent({ content, size, className, }: {
12
12
  className?: string;
13
13
  }): Promise<React.JSX.Element | null>;
14
14
 
15
- export { BlockNoteServerContent };
15
+ /**
16
+ * Renders a BlockNote blocks array to Markdown through BlockNote's own server
17
+ * editor (`blocksToMarkdownLossy`). Server only.
18
+ */
19
+ declare function renderBlockNoteMarkdown(blocks: PartialBlock[]): Promise<string>;
20
+
21
+ export { BlockNoteServerContent, renderBlockNoteMarkdown };
@@ -12,4 +12,10 @@ declare function BlockNoteServerContent({ content, size, className, }: {
12
12
  className?: string;
13
13
  }): Promise<React.JSX.Element | null>;
14
14
 
15
- export { BlockNoteServerContent };
15
+ /**
16
+ * Renders a BlockNote blocks array to Markdown through BlockNote's own server
17
+ * editor (`blocksToMarkdownLossy`). Server only.
18
+ */
19
+ declare function renderBlockNoteMarkdown(blocks: PartialBlock[]): Promise<string>;
20
+
21
+ export { BlockNoteServerContent, renderBlockNoteMarkdown };
@@ -6,18 +6,24 @@ var _chunk7QVYU63Ejs = require('../../chunk-7QVYU63E.js');
6
6
  require('@blocknote/shadcn/style.css');
7
7
  var _components = require('@carlonicora/nextjs-jsonapi/components');
8
8
 
9
- // src/components/editors/server/renderBlockNoteHTML.ts
9
+ // src/components/editors/server/serverEditor.ts
10
10
  var _serverutil = require('@blocknote/server-util');
11
11
  var editor;
12
12
  var queue = Promise.resolve();
13
- function renderBlockNoteHTML(blocks) {
13
+ function runWithServerEditor(fn) {
14
14
  const run = queue.then(() => {
15
15
  editor ??= _serverutil.ServerBlockNoteEditor.create();
16
- return editor.blocksToFullHTML(blocks);
16
+ return fn(editor);
17
17
  });
18
18
  queue = run.catch(() => void 0);
19
19
  return run;
20
20
  }
21
+ _chunk7QVYU63Ejs.__name.call(void 0, runWithServerEditor, "runWithServerEditor");
22
+
23
+ // src/components/editors/server/renderBlockNoteHTML.ts
24
+ function renderBlockNoteHTML(blocks) {
25
+ return runWithServerEditor((editor2) => editor2.blocksToFullHTML(blocks));
26
+ }
21
27
  _chunk7QVYU63Ejs.__name.call(void 0, renderBlockNoteHTML, "renderBlockNoteHTML");
22
28
 
23
29
  // src/components/editors/server/BlockNoteServerContent.tsx
@@ -33,6 +39,13 @@ async function BlockNoteServerContent({
33
39
  }
34
40
  _chunk7QVYU63Ejs.__name.call(void 0, BlockNoteServerContent, "BlockNoteServerContent");
35
41
 
42
+ // src/components/editors/server/renderBlockNoteMarkdown.ts
43
+ function renderBlockNoteMarkdown(blocks) {
44
+ return runWithServerEditor((editor2) => editor2.blocksToMarkdownLossy(blocks));
45
+ }
46
+ _chunk7QVYU63Ejs.__name.call(void 0, renderBlockNoteMarkdown, "renderBlockNoteMarkdown");
47
+
48
+
36
49
 
37
- exports.BlockNoteServerContent = BlockNoteServerContent;
50
+ exports.BlockNoteServerContent = BlockNoteServerContent; exports.renderBlockNoteMarkdown = renderBlockNoteMarkdown;
38
51
  //# sourceMappingURL=server.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["/home/runner/work/nextjs-jsonapi/nextjs-jsonapi/dist/components/editors/server.js","../../../src/components/editors/server/BlockNoteServerContent.tsx","../../../src/components/editors/server/renderBlockNoteHTML.ts"],"names":[],"mappings":"AAAA;AACE;AACF,0DAAgC;AAChC;AACA;ACHA,uCAAO;AAIP,oEAAsC;ADEtC;AACA;AEPA,oDAAsC;AAKtC,IAAI,MAAA;AAMJ,IAAI,MAAA,EAA0B,OAAA,CAAQ,OAAA,CAAQ,CAAA;AAMvC,SAAS,mBAAA,CAAoB,MAAA,EAAyC;AAC3E,EAAA,MAAM,IAAA,EAAM,KAAA,CAAM,IAAA,CAAK,CAAA,EAAA,GAAM;AAC3B,IAAA,OAAA,IAAW,iCAAA,CAAsB,MAAA,CAAO,CAAA;AACxC,IAAA,OAAO,MAAA,CAAO,gBAAA,CAAiB,MAAM,CAAA;AAAA,EACvC,CAAC,CAAA;AACD,EAAA,MAAA,EAAQ,GAAA,CAAI,KAAA,CAAM,CAAA,EAAA,GAAM,KAAA,CAAS,CAAA;AACjC,EAAA,OAAO,GAAA;AACT;AAPgB,qCAAA,mBAAA,EAAA,qBAAA,CAAA;AFGhB;AACA;ACIS,+CAAA;AAbT,MAAA,SAAsB,sBAAA,CAAuB;AAAA,EAC3C,OAAA;AAAA,EACA,IAAA;AAAA,EACA;AACF,CAAA,EAIG;AACD,EAAA,GAAA,CAAI,CAAC,KAAA,CAAM,OAAA,CAAQ,OAAO,EAAA,GAAK,OAAA,CAAQ,OAAA,IAAW,CAAA,EAAG,OAAO,IAAA;AAE5D,EAAA,MAAM,KAAA,EAAO,MAAM,mBAAA,CAAoB,OAAO,CAAA;AAE9C,EAAA,uBAAO,6BAAA,iCAAC,EAAA,EAAsB,IAAA,EAAY,IAAA,EAAY,UAAA,CAAsB,CAAA;AAC9E;AAdsB,qCAAA,sBAAA,EAAA,wBAAA,CAAA;ADqBtB;AACE;AACF,wDAAC","file":"/home/runner/work/nextjs-jsonapi/nextjs-jsonapi/dist/components/editors/server.js","sourcesContent":[null,"import type { PartialBlock } from \"@blocknote/core\";\nimport \"@blocknote/shadcn/style.css\";\n// Imported through the package's own client subpath, like the analytics server\n// pages: the built server entry must reach the viewer through the \"use client\"\n// bundle, not inline it.\nimport { BlockNoteStaticViewer } from \"@carlonicora/nextjs-jsonapi/components\";\nimport { renderBlockNoteHTML } from \"./renderBlockNoteHTML\";\n\n/**\n * Read-only rich text rendered on the server, so the text is in the HTML that\n * crawlers read. For public read-only pages only: everywhere else, display goes\n * through BlockNoteEditorContainer.\n */\nexport async function BlockNoteServerContent({\n content,\n size,\n className,\n}: {\n content?: PartialBlock[];\n size?: \"default\" | \"sm\";\n className?: string;\n}) {\n if (!Array.isArray(content) || content.length === 0) return null;\n\n const html = await renderBlockNoteHTML(content);\n\n return <BlockNoteStaticViewer html={html} size={size} className={className} />;\n}\n","import type { PartialBlock } from \"@blocknote/core\";\nimport { ServerBlockNoteEditor } from \"@blocknote/server-util\";\n\n// Default schema only, the same one BlockNoteViewer uses: the editor's mention\n// and diff inline specs are React specs from \"use client\" modules (next/link,\n// hover cards), so they cannot run here.\nlet editor: ServerBlockNoteEditor | undefined;\n\n// ServerBlockNoteEditor swaps globalThis.window/document for its JSDOM around\n// each call and restores them after an await. Two overlapping calls would\n// restore each other's values and could leave the JSDOM window on the server's\n// globals, so calls run one at a time.\nlet queue: Promise<unknown> = Promise.resolve();\n\n/**\n * Renders a BlockNote blocks array to the HTML the editor itself would render,\n * through BlockNote's own server editor (`blocksToFullHTML`). Server only.\n */\nexport function renderBlockNoteHTML(blocks: PartialBlock[]): Promise<string> {\n const run = queue.then(() => {\n editor ??= ServerBlockNoteEditor.create();\n return editor.blocksToFullHTML(blocks);\n });\n queue = run.catch(() => undefined);\n return run;\n}\n"]}
1
+ {"version":3,"sources":["/home/runner/work/nextjs-jsonapi/nextjs-jsonapi/dist/components/editors/server.js","../../../src/components/editors/server/BlockNoteServerContent.tsx","../../../src/components/editors/server/serverEditor.ts","../../../src/components/editors/server/renderBlockNoteHTML.ts","../../../src/components/editors/server/renderBlockNoteMarkdown.ts"],"names":["editor"],"mappings":"AAAA;AACE;AACF,0DAAgC;AAChC;AACA;ACHA,uCAAO;AAIP,oEAAsC;ADEtC;AACA;AERA,oDAAsC;AAKtC,IAAI,MAAA;AAMJ,IAAI,MAAA,EAA0B,OAAA,CAAQ,OAAA,CAAQ,CAAA;AAMvC,SAAS,mBAAA,CAAuB,EAAA,EAAmE;AACxG,EAAA,MAAM,IAAA,EAAM,KAAA,CAAM,IAAA,CAAK,CAAA,EAAA,GAAM;AAC3B,IAAA,OAAA,IAAW,iCAAA,CAAsB,MAAA,CAAO,CAAA;AACxC,IAAA,OAAO,EAAA,CAAG,MAAM,CAAA;AAAA,EAClB,CAAC,CAAA;AACD,EAAA,MAAA,EAAQ,GAAA,CAAI,KAAA,CAAM,CAAA,EAAA,GAAM,KAAA,CAAS,CAAA;AACjC,EAAA,OAAO,GAAA;AACT;AAPgB,qCAAA,mBAAA,EAAA,qBAAA,CAAA;AFIhB;AACA;AGfO,SAAS,mBAAA,CAAoB,MAAA,EAAyC;AAC3E,EAAA,OAAO,mBAAA,CAAoB,CAACA,OAAAA,EAAAA,GAAWA,OAAAA,CAAO,gBAAA,CAAiB,MAAM,CAAC,CAAA;AACxE;AAFgB,qCAAA,mBAAA,EAAA,qBAAA,CAAA;AHoBhB;AACA;ACFS,+CAAA;AAbT,MAAA,SAAsB,sBAAA,CAAuB;AAAA,EAC3C,OAAA;AAAA,EACA,IAAA;AAAA,EACA;AACF,CAAA,EAIG;AACD,EAAA,GAAA,CAAI,CAAC,KAAA,CAAM,OAAA,CAAQ,OAAO,EAAA,GAAK,OAAA,CAAQ,OAAA,IAAW,CAAA,EAAG,OAAO,IAAA;AAE5D,EAAA,MAAM,KAAA,EAAO,MAAM,mBAAA,CAAoB,OAAO,CAAA;AAE9C,EAAA,uBAAO,6BAAA,iCAAC,EAAA,EAAsB,IAAA,EAAY,IAAA,EAAY,UAAA,CAAsB,CAAA;AAC9E;AAdsB,qCAAA,sBAAA,EAAA,wBAAA,CAAA;AD2BtB;AACA;AIlCO,SAAS,uBAAA,CAAwB,MAAA,EAAyC;AAC/E,EAAA,OAAO,mBAAA,CAAoB,CAACA,OAAAA,EAAAA,GAAWA,OAAAA,CAAO,qBAAA,CAAsB,MAAM,CAAC,CAAA;AAC7E;AAFgB,qCAAA,uBAAA,EAAA,yBAAA,CAAA;AJuChB;AACE;AACA;AACF,mHAAC","file":"/home/runner/work/nextjs-jsonapi/nextjs-jsonapi/dist/components/editors/server.js","sourcesContent":[null,"import type { PartialBlock } from \"@blocknote/core\";\nimport \"@blocknote/shadcn/style.css\";\n// Imported through the package's own client subpath, like the analytics server\n// pages: the built server entry must reach the viewer through the \"use client\"\n// bundle, not inline it.\nimport { BlockNoteStaticViewer } from \"@carlonicora/nextjs-jsonapi/components\";\nimport { renderBlockNoteHTML } from \"./renderBlockNoteHTML\";\n\n/**\n * Read-only rich text rendered on the server, so the text is in the HTML that\n * crawlers read. For public read-only pages only: everywhere else, display goes\n * through BlockNoteEditorContainer.\n */\nexport async function BlockNoteServerContent({\n content,\n size,\n className,\n}: {\n content?: PartialBlock[];\n size?: \"default\" | \"sm\";\n className?: string;\n}) {\n if (!Array.isArray(content) || content.length === 0) return null;\n\n const html = await renderBlockNoteHTML(content);\n\n return <BlockNoteStaticViewer html={html} size={size} className={className} />;\n}\n","import { ServerBlockNoteEditor } from \"@blocknote/server-util\";\n\n// Default schema only, the same one BlockNoteViewer uses: the editor's mention\n// and diff inline specs are React specs from \"use client\" modules (next/link,\n// hover cards), so they cannot run here.\nlet editor: ServerBlockNoteEditor | undefined;\n\n// ServerBlockNoteEditor swaps globalThis.window/document for its JSDOM around\n// each call and restores them after an await. Two overlapping calls would\n// restore each other's values and could leave the JSDOM window on the server's\n// globals, so calls run one at a time.\nlet queue: Promise<unknown> = Promise.resolve();\n\n/**\n * Runs `fn` with the shared server editor, one call at a time. Server only.\n * Internal to the library: not exported from the barrel.\n */\nexport function runWithServerEditor<T>(fn: (editor: ServerBlockNoteEditor) => T | Promise<T>): Promise<T> {\n const run = queue.then(() => {\n editor ??= ServerBlockNoteEditor.create();\n return fn(editor);\n });\n queue = run.catch(() => undefined);\n return run;\n}\n","import type { PartialBlock } from \"@blocknote/core\";\nimport { runWithServerEditor } from \"./serverEditor\";\n\n/**\n * Renders a BlockNote blocks array to the HTML the editor itself would render,\n * through BlockNote's own server editor (`blocksToFullHTML`). Server only.\n */\nexport function renderBlockNoteHTML(blocks: PartialBlock[]): Promise<string> {\n return runWithServerEditor((editor) => editor.blocksToFullHTML(blocks));\n}\n","import type { PartialBlock } from \"@blocknote/core\";\nimport { runWithServerEditor } from \"./serverEditor\";\n\n/**\n * Renders a BlockNote blocks array to Markdown through BlockNote's own server\n * editor (`blocksToMarkdownLossy`). Server only.\n */\nexport function renderBlockNoteMarkdown(blocks: PartialBlock[]): Promise<string> {\n return runWithServerEditor((editor) => editor.blocksToMarkdownLossy(blocks));\n}\n"]}
@@ -6,18 +6,24 @@ import {
6
6
  import "@blocknote/shadcn/style.css";
7
7
  import { BlockNoteStaticViewer } from "@carlonicora/nextjs-jsonapi/components";
8
8
 
9
- // src/components/editors/server/renderBlockNoteHTML.ts
9
+ // src/components/editors/server/serverEditor.ts
10
10
  import { ServerBlockNoteEditor } from "@blocknote/server-util";
11
11
  var editor;
12
12
  var queue = Promise.resolve();
13
- function renderBlockNoteHTML(blocks) {
13
+ function runWithServerEditor(fn) {
14
14
  const run = queue.then(() => {
15
15
  editor ??= ServerBlockNoteEditor.create();
16
- return editor.blocksToFullHTML(blocks);
16
+ return fn(editor);
17
17
  });
18
18
  queue = run.catch(() => void 0);
19
19
  return run;
20
20
  }
21
+ __name(runWithServerEditor, "runWithServerEditor");
22
+
23
+ // src/components/editors/server/renderBlockNoteHTML.ts
24
+ function renderBlockNoteHTML(blocks) {
25
+ return runWithServerEditor((editor2) => editor2.blocksToFullHTML(blocks));
26
+ }
21
27
  __name(renderBlockNoteHTML, "renderBlockNoteHTML");
22
28
 
23
29
  // src/components/editors/server/BlockNoteServerContent.tsx
@@ -32,7 +38,14 @@ async function BlockNoteServerContent({
32
38
  return /* @__PURE__ */ jsx(BlockNoteStaticViewer, { html, size, className });
33
39
  }
34
40
  __name(BlockNoteServerContent, "BlockNoteServerContent");
41
+
42
+ // src/components/editors/server/renderBlockNoteMarkdown.ts
43
+ function renderBlockNoteMarkdown(blocks) {
44
+ return runWithServerEditor((editor2) => editor2.blocksToMarkdownLossy(blocks));
45
+ }
46
+ __name(renderBlockNoteMarkdown, "renderBlockNoteMarkdown");
35
47
  export {
36
- BlockNoteServerContent
48
+ BlockNoteServerContent,
49
+ renderBlockNoteMarkdown
37
50
  };
38
51
  //# sourceMappingURL=server.mjs.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/components/editors/server/BlockNoteServerContent.tsx","../../../src/components/editors/server/renderBlockNoteHTML.ts"],"sourcesContent":["import type { PartialBlock } from \"@blocknote/core\";\nimport \"@blocknote/shadcn/style.css\";\n// Imported through the package's own client subpath, like the analytics server\n// pages: the built server entry must reach the viewer through the \"use client\"\n// bundle, not inline it.\nimport { BlockNoteStaticViewer } from \"@carlonicora/nextjs-jsonapi/components\";\nimport { renderBlockNoteHTML } from \"./renderBlockNoteHTML\";\n\n/**\n * Read-only rich text rendered on the server, so the text is in the HTML that\n * crawlers read. For public read-only pages only: everywhere else, display goes\n * through BlockNoteEditorContainer.\n */\nexport async function BlockNoteServerContent({\n content,\n size,\n className,\n}: {\n content?: PartialBlock[];\n size?: \"default\" | \"sm\";\n className?: string;\n}) {\n if (!Array.isArray(content) || content.length === 0) return null;\n\n const html = await renderBlockNoteHTML(content);\n\n return <BlockNoteStaticViewer html={html} size={size} className={className} />;\n}\n","import type { PartialBlock } from \"@blocknote/core\";\nimport { ServerBlockNoteEditor } from \"@blocknote/server-util\";\n\n// Default schema only, the same one BlockNoteViewer uses: the editor's mention\n// and diff inline specs are React specs from \"use client\" modules (next/link,\n// hover cards), so they cannot run here.\nlet editor: ServerBlockNoteEditor | undefined;\n\n// ServerBlockNoteEditor swaps globalThis.window/document for its JSDOM around\n// each call and restores them after an await. Two overlapping calls would\n// restore each other's values and could leave the JSDOM window on the server's\n// globals, so calls run one at a time.\nlet queue: Promise<unknown> = Promise.resolve();\n\n/**\n * Renders a BlockNote blocks array to the HTML the editor itself would render,\n * through BlockNote's own server editor (`blocksToFullHTML`). Server only.\n */\nexport function renderBlockNoteHTML(blocks: PartialBlock[]): Promise<string> {\n const run = queue.then(() => {\n editor ??= ServerBlockNoteEditor.create();\n return editor.blocksToFullHTML(blocks);\n });\n queue = run.catch(() => undefined);\n return run;\n}\n"],"mappings":";;;;;AACA,OAAO;AAIP,SAAS,6BAA6B;;;ACJtC,SAAS,6BAA6B;AAKtC,IAAI;AAMJ,IAAI,QAA0B,QAAQ,QAAQ;AAMvC,SAAS,oBAAoB,QAAyC;AAC3E,QAAM,MAAM,MAAM,KAAK,MAAM;AAC3B,eAAW,sBAAsB,OAAO;AACxC,WAAO,OAAO,iBAAiB,MAAM;AAAA,EACvC,CAAC;AACD,UAAQ,IAAI,MAAM,MAAM,MAAS;AACjC,SAAO;AACT;AAPgB;;;ADQP;AAbT,eAAsB,uBAAuB;AAAA,EAC3C;AAAA,EACA;AAAA,EACA;AACF,GAIG;AACD,MAAI,CAAC,MAAM,QAAQ,OAAO,KAAK,QAAQ,WAAW,EAAG,QAAO;AAE5D,QAAM,OAAO,MAAM,oBAAoB,OAAO;AAE9C,SAAO,oBAAC,yBAAsB,MAAY,MAAY,WAAsB;AAC9E;AAdsB;","names":[]}
1
+ {"version":3,"sources":["../../../src/components/editors/server/BlockNoteServerContent.tsx","../../../src/components/editors/server/serverEditor.ts","../../../src/components/editors/server/renderBlockNoteHTML.ts","../../../src/components/editors/server/renderBlockNoteMarkdown.ts"],"sourcesContent":["import type { PartialBlock } from \"@blocknote/core\";\nimport \"@blocknote/shadcn/style.css\";\n// Imported through the package's own client subpath, like the analytics server\n// pages: the built server entry must reach the viewer through the \"use client\"\n// bundle, not inline it.\nimport { BlockNoteStaticViewer } from \"@carlonicora/nextjs-jsonapi/components\";\nimport { renderBlockNoteHTML } from \"./renderBlockNoteHTML\";\n\n/**\n * Read-only rich text rendered on the server, so the text is in the HTML that\n * crawlers read. For public read-only pages only: everywhere else, display goes\n * through BlockNoteEditorContainer.\n */\nexport async function BlockNoteServerContent({\n content,\n size,\n className,\n}: {\n content?: PartialBlock[];\n size?: \"default\" | \"sm\";\n className?: string;\n}) {\n if (!Array.isArray(content) || content.length === 0) return null;\n\n const html = await renderBlockNoteHTML(content);\n\n return <BlockNoteStaticViewer html={html} size={size} className={className} />;\n}\n","import { ServerBlockNoteEditor } from \"@blocknote/server-util\";\n\n// Default schema only, the same one BlockNoteViewer uses: the editor's mention\n// and diff inline specs are React specs from \"use client\" modules (next/link,\n// hover cards), so they cannot run here.\nlet editor: ServerBlockNoteEditor | undefined;\n\n// ServerBlockNoteEditor swaps globalThis.window/document for its JSDOM around\n// each call and restores them after an await. Two overlapping calls would\n// restore each other's values and could leave the JSDOM window on the server's\n// globals, so calls run one at a time.\nlet queue: Promise<unknown> = Promise.resolve();\n\n/**\n * Runs `fn` with the shared server editor, one call at a time. Server only.\n * Internal to the library: not exported from the barrel.\n */\nexport function runWithServerEditor<T>(fn: (editor: ServerBlockNoteEditor) => T | Promise<T>): Promise<T> {\n const run = queue.then(() => {\n editor ??= ServerBlockNoteEditor.create();\n return fn(editor);\n });\n queue = run.catch(() => undefined);\n return run;\n}\n","import type { PartialBlock } from \"@blocknote/core\";\nimport { runWithServerEditor } from \"./serverEditor\";\n\n/**\n * Renders a BlockNote blocks array to the HTML the editor itself would render,\n * through BlockNote's own server editor (`blocksToFullHTML`). Server only.\n */\nexport function renderBlockNoteHTML(blocks: PartialBlock[]): Promise<string> {\n return runWithServerEditor((editor) => editor.blocksToFullHTML(blocks));\n}\n","import type { PartialBlock } from \"@blocknote/core\";\nimport { runWithServerEditor } from \"./serverEditor\";\n\n/**\n * Renders a BlockNote blocks array to Markdown through BlockNote's own server\n * editor (`blocksToMarkdownLossy`). Server only.\n */\nexport function renderBlockNoteMarkdown(blocks: PartialBlock[]): Promise<string> {\n return runWithServerEditor((editor) => editor.blocksToMarkdownLossy(blocks));\n}\n"],"mappings":";;;;;AACA,OAAO;AAIP,SAAS,6BAA6B;;;ACLtC,SAAS,6BAA6B;AAKtC,IAAI;AAMJ,IAAI,QAA0B,QAAQ,QAAQ;AAMvC,SAAS,oBAAuB,IAAmE;AACxG,QAAM,MAAM,MAAM,KAAK,MAAM;AAC3B,eAAW,sBAAsB,OAAO;AACxC,WAAO,GAAG,MAAM;AAAA,EAClB,CAAC;AACD,UAAQ,IAAI,MAAM,MAAM,MAAS;AACjC,SAAO;AACT;AAPgB;;;ACVT,SAAS,oBAAoB,QAAyC;AAC3E,SAAO,oBAAoB,CAACA,YAAWA,QAAO,iBAAiB,MAAM,CAAC;AACxE;AAFgB;;;AFmBP;AAbT,eAAsB,uBAAuB;AAAA,EAC3C;AAAA,EACA;AAAA,EACA;AACF,GAIG;AACD,MAAI,CAAC,MAAM,QAAQ,OAAO,KAAK,QAAQ,WAAW,EAAG,QAAO;AAE5D,QAAM,OAAO,MAAM,oBAAoB,OAAO;AAE9C,SAAO,oBAAC,yBAAsB,MAAY,MAAY,WAAsB;AAC9E;AAdsB;;;AGNf,SAAS,wBAAwB,QAAyC;AAC/E,SAAO,oBAAoB,CAACC,YAAWA,QAAO,sBAAsB,MAAM,CAAC;AAC7E;AAFgB;","names":["editor","editor"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@carlonicora/nextjs-jsonapi",
3
- "version": "6.14.1",
3
+ "version": "6.15.0",
4
4
  "description": "Next.js JSON:API client with server/client support and caching",
5
5
  "author": "Carlo Nicora",
6
6
  "license": "GPL-3.0-or-later",
@@ -0,0 +1,45 @@
1
+ // @vitest-environment node
2
+ // The server render runs in Node, where there is no window or document of our own:
3
+ // BlockNote's ServerBlockNoteEditor brings its JSDOM.
4
+ import type { PartialBlock } from "@blocknote/core";
5
+ import { describe, expect, it } from "vitest";
6
+ import { renderBlockNoteHTML } from "../renderBlockNoteHTML";
7
+ import { renderBlockNoteMarkdown } from "../renderBlockNoteMarkdown";
8
+
9
+ const blocks: PartialBlock[] = [
10
+ { type: "heading", props: { level: 2 }, content: "Think of the Campaign as the lid on the box" },
11
+ { type: "paragraph", content: "One Campaign is one story arc." },
12
+ { type: "bulletListItem", content: "Characters" },
13
+ {
14
+ type: "paragraph",
15
+ content: [{ type: "link", href: "https://wyrd.li/help", content: "help" }],
16
+ },
17
+ { type: "image", props: { url: "https://wyrd.li/marketing/og.png", caption: "Wyrdli" } },
18
+ { type: "image", props: { url: "https://wyrd.li/marketing/plain.png" } },
19
+ ];
20
+
21
+ describe("renderBlockNoteMarkdown", () => {
22
+ it("renders headings, paragraphs, bullet lists and links", async () => {
23
+ const markdown = await renderBlockNoteMarkdown(blocks);
24
+
25
+ expect(markdown).toContain("## Think of the Campaign as the lid on the box");
26
+ expect(markdown).toContain("One Campaign is one story arc.");
27
+ expect(markdown).toMatch(/^\s*[-*+] Characters\s*$/m);
28
+ expect(markdown).toContain("[help](https://wyrd.li/help)");
29
+ // blocksToMarkdownLossy keeps a captioned image as an HTML <figure> (valid
30
+ // CommonMark HTML block); an image with no caption becomes ![](url).
31
+ expect(markdown).toMatch(/<img[^>]*src="https:\/\/wyrd\.li\/marketing\/og\.png"/);
32
+ expect(markdown).toContain("<figcaption>Wyrdli</figcaption>");
33
+ expect(markdown).toMatch(/!\[[^\]]*\]\(https:\/\/wyrd\.li\/marketing\/plain\.png\)/);
34
+ });
35
+
36
+ it("two overlapping calls both resolve and leave no JSDOM window on globalThis", async () => {
37
+ const before = typeof (globalThis as { window?: unknown }).window;
38
+
39
+ const [markdown, html] = await Promise.all([renderBlockNoteMarkdown(blocks), renderBlockNoteHTML(blocks)]);
40
+
41
+ expect(markdown).toContain("One Campaign is one story arc.");
42
+ expect(html).toContain("One Campaign is one story arc.");
43
+ expect(typeof (globalThis as { window?: unknown }).window).toBe(before);
44
+ });
45
+ });
@@ -1,26 +1,10 @@
1
1
  import type { PartialBlock } from "@blocknote/core";
2
- import { ServerBlockNoteEditor } from "@blocknote/server-util";
3
-
4
- // Default schema only, the same one BlockNoteViewer uses: the editor's mention
5
- // and diff inline specs are React specs from "use client" modules (next/link,
6
- // hover cards), so they cannot run here.
7
- let editor: ServerBlockNoteEditor | undefined;
8
-
9
- // ServerBlockNoteEditor swaps globalThis.window/document for its JSDOM around
10
- // each call and restores them after an await. Two overlapping calls would
11
- // restore each other's values and could leave the JSDOM window on the server's
12
- // globals, so calls run one at a time.
13
- let queue: Promise<unknown> = Promise.resolve();
2
+ import { runWithServerEditor } from "./serverEditor";
14
3
 
15
4
  /**
16
5
  * Renders a BlockNote blocks array to the HTML the editor itself would render,
17
6
  * through BlockNote's own server editor (`blocksToFullHTML`). Server only.
18
7
  */
19
8
  export function renderBlockNoteHTML(blocks: PartialBlock[]): Promise<string> {
20
- const run = queue.then(() => {
21
- editor ??= ServerBlockNoteEditor.create();
22
- return editor.blocksToFullHTML(blocks);
23
- });
24
- queue = run.catch(() => undefined);
25
- return run;
9
+ return runWithServerEditor((editor) => editor.blocksToFullHTML(blocks));
26
10
  }
@@ -0,0 +1,10 @@
1
+ import type { PartialBlock } from "@blocknote/core";
2
+ import { runWithServerEditor } from "./serverEditor";
3
+
4
+ /**
5
+ * Renders a BlockNote blocks array to Markdown through BlockNote's own server
6
+ * editor (`blocksToMarkdownLossy`). Server only.
7
+ */
8
+ export function renderBlockNoteMarkdown(blocks: PartialBlock[]): Promise<string> {
9
+ return runWithServerEditor((editor) => editor.blocksToMarkdownLossy(blocks));
10
+ }
@@ -0,0 +1,25 @@
1
+ import { ServerBlockNoteEditor } from "@blocknote/server-util";
2
+
3
+ // Default schema only, the same one BlockNoteViewer uses: the editor's mention
4
+ // and diff inline specs are React specs from "use client" modules (next/link,
5
+ // hover cards), so they cannot run here.
6
+ let editor: ServerBlockNoteEditor | undefined;
7
+
8
+ // ServerBlockNoteEditor swaps globalThis.window/document for its JSDOM around
9
+ // each call and restores them after an await. Two overlapping calls would
10
+ // restore each other's values and could leave the JSDOM window on the server's
11
+ // globals, so calls run one at a time.
12
+ let queue: Promise<unknown> = Promise.resolve();
13
+
14
+ /**
15
+ * Runs `fn` with the shared server editor, one call at a time. Server only.
16
+ * Internal to the library: not exported from the barrel.
17
+ */
18
+ export function runWithServerEditor<T>(fn: (editor: ServerBlockNoteEditor) => T | Promise<T>): Promise<T> {
19
+ const run = queue.then(() => {
20
+ editor ??= ServerBlockNoteEditor.create();
21
+ return fn(editor);
22
+ });
23
+ queue = run.catch(() => undefined);
24
+ return run;
25
+ }
@@ -5,3 +5,4 @@
5
5
  // `serverExternalPackages` so Node loads it instead of the bundler.
6
6
 
7
7
  export { BlockNoteServerContent } from "./server/BlockNoteServerContent";
8
+ export { renderBlockNoteMarkdown } from "./server/renderBlockNoteMarkdown";