@toaq-oss/omni-mdx 1.1.1 โ†’ 1.1.2

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/README.md CHANGED
@@ -1,41 +1,69 @@
1
1
  # @toaq-oss/omni-mdx
2
2
 
3
+ [![Build][build-badge]][build]
4
+ [![Coverage][coverage-badge]][coverage]
5
+ [![Downloads][downloads-badge]][downloads]
6
+ [![Size][size-badge]][size]
7
+ [![Chat][chat-badge]][chat]
8
+
3
9
  **The high-performance MDX engine.** A unified React & Next.js rendering layer powered by a dual Rust backend (Native Node.js + WebAssembly).
4
10
 
5
- [![GitHub](https://img.shields.io/badge/GitHub-TOAQ--oss-181717?logo=github)](https://github.com/toaq-oss)
6
- [![Documentation](https://img.shields.io/badge/Docs-omni--core.org-blue)](https://omni-core.org/mdx)
11
+ ---
12
+
13
+ ## Contents
14
+
15
+ * [What is this?](#what-is-this)
16
+ * [Why Omni-MDX?](#why-omni-mdx)
17
+ * [Install](#install)
18
+ * [Use](#use)
19
+ * [Server-Side Rendering (RSC)](#server-side-rendering-rsc)
20
+ * [Live Client Editor (WASM)](#live-client-editor-wasm)
21
+ * [Monorepo Structure](#monorepo-structure)
22
+ * [Next.js Configuration](#nextjs-configuration)
23
+ * [Contributing](#contributing)
24
+ * [License](#license)
7
25
 
8
26
  ---
9
27
 
10
- ## โšก Why Omni-MDX?
28
+ ## What is this?
11
29
 
12
- Traditional MDX pipelines can be slow and often require heavy client-side hydration. `omni-mdx` offloads the heavy lifting to Rust while providing a **seamless bridge to the JS ecosystem**.
30
+ `omni-mdx` is an ecosystem designed to overcome the performance bottlenecks of traditional MDX pipelines. Instead of relying on heavy JavaScript regular expressions, it utilizes a core written in **Rust** to transform MDX into a structured Abstract Syntax Tree (AST) nearly instantaneously.
13
31
 
14
- * ๐Ÿš€ **Extreme Performance:** Parsing is done in native Rust (Server) or WASM (Client), up to 10x faster than pure JS alternatives.
32
+ Whether you are building for the Web (Next.js, React), or the Server (Node.js), Omni-MDX provides a unified interface for smooth and precise rendering.
15
33
 
16
- * ๐Ÿ”Œ **Unified/Rehype Bridge:** Native Rust core with full support for standard **Rehype plugins** (Highlighting, Slugs, Autolink, etc.).
34
+ ---
17
35
 
18
- * ๐Ÿ“ **Built-in Features:** GFM Tables, KaTeX math, and JSX components are handled nativelyโ€”no extra configuration required.
36
+ ## Why Omni-MDX?
19
37
 
20
- * โš›๏ธ ***RSC Optimized:*** Built for Next.js App Router and Server Components with zero-hydration math rendering.
38
+ * ๐Ÿš€ **Extreme Performance:** Parsing is offloaded to Rust, performing up to 10x faster than pure JS alternatives.
39
+ * ๐Ÿ”Œ **Unified/Rehype Bridge:** Native Rust core with full support for standard **Rehype plugins** (Highlighting, Slugs, Autolink, etc.).
40
+ * ๐Ÿ“ **Built-in Features:** GFM Tables, KaTeX math, and JSX components handled nativelyโ€”no extra configuration required.
41
+ * โš›๏ธ **RSC Optimized:** Built for Next.js App Router and Server Components with zero-hydration math rendering.
21
42
  * ๐Ÿงต **Non-Blocking:** Offloads parsing from the Node.js main thread, keeping your server responsive.
22
43
 
23
44
  ---
24
45
 
25
- ## ๐Ÿš€ Usage
26
- ### 1. Server-Side Rendering (RSC) with Plugins
27
- Recommended for documentation, blogs, and research papers.
46
+ ## Install
47
+
48
+ This package is [ESM only](https://gist.github.com/sindresorhus/a39789f98801d908bbc7ff3ecc99d99c). In Node.js, install with [npm]:
49
+
50
+ ```bash
51
+ npm install @toaq-oss/omni-mdx
52
+ # Required for math styles
53
+ npm install katex
54
+ ```
28
55
 
29
- *Plugins are optional. Omni-Core lets you choose whether to use plugins or not !*
56
+ ---
57
+
58
+ ## Use
30
59
 
31
- > Full example available here :
32
- > * Basic setup: [TOAQ-oss/omni-core-sandox](https://github.com/TOAQ-oss/omni-mdx-sandbox/tree/main/next/basic-setup)
33
- > * Advanced rendering : [TOAQ-oss/omni-core-sandox](https://github.com/TOAQ-oss/omni-mdx-sandbox/tree/main/next/advanced-rendering)
60
+ ### Server-Side Rendering (RSC)
61
+
62
+ Recommended for documentation, blogs, and research papers.
34
63
 
35
64
  ```tsx
36
65
  import { parseMdx, MDXServerRenderer } from "@toaq-oss/omni-mdx/server";
37
66
  import rehypeHighlight from "rehype-highlight";
38
- import { MyComponent } from "@/components/mdx";
39
67
 
40
68
  export default async function Page({ content }) {
41
69
  // 1. Parse via Native Rust Addon (.node)
@@ -52,10 +80,9 @@ export default async function Page({ content }) {
52
80
  }
53
81
  ```
54
82
 
55
- ### 2. Live Client Editor (WASM)
56
- Perfect for real-time previews or CMS interfaces.
83
+ ### Live Client Editor (WASM)
57
84
 
58
- > Full example available here : [TOAQ-oss/omni-core-sandox](https://github.com/TOAQ-oss/omni-mdx-sandbox/tree/main/next/client-rendering)
85
+ Perfect for real-time previews or CMS interfaces.
59
86
 
60
87
  ```tsx
61
88
  "use client";
@@ -80,16 +107,23 @@ export default function Editor() {
80
107
  }
81
108
  ```
82
109
 
83
- ## ๐Ÿ“ฆ Installation
110
+ ---
84
111
 
85
- ```bash
86
- npm install @toaq-oss/omni-mdx
87
- # Required for math styles
88
- npm install katex
89
- ```
112
+ ## Monorepo Structure
113
+
114
+ This repository houses the various components of the ecosystem:
115
+
116
+ | Package | Language | Description |
117
+ | :--- | :---: | :--- |
118
+ | [**`core-parser`**](./packages/core-parser) | ![Rust] | The high-performance parsing core. |
119
+ | [**`mdx-next`**](./packages/mdx-next) | ![TypeScript] | React/Next.js layer (Native + WASM). |
120
+
121
+ ---
90
122
 
91
123
  ## Next.js Configuration
124
+
92
125
  To enable the WebAssembly engine for client-side rendering, update your `next.config.js`:
126
+
93
127
  ```typescript
94
128
  /** @type {import('next').NextConfig} */
95
129
  const nextConfig = {
@@ -108,34 +142,41 @@ export default nextConfig;
108
142
 
109
143
  ---
110
144
 
111
- ## ๐Ÿงฉ Features
112
- ### ๐Ÿ”Œ Extensibility (Rehype Support)
113
- Omni-MDX uses a unique "Bridge" architecture. It parses Markdown to a high-performance AST in Rust, then optionally passes it through the Unified/Rehype pipeline in JS for transformations.
114
- * **Support:** `rehype-slug`, `rehype-highlight`, `rehype-autolink-headings`, etc.
115
- * **Performance:** Plugins only run on the final tree, keeping the heavy parsing phase in Rust.
145
+ ## Contributing
116
146
 
117
- ### ๐Ÿ“ Native Professional Math
118
- Math is handled via KaTeX. Include the CSS in your `layout.tsx`:
119
- `import "katex/dist/katex.min.css";`
120
- * **Inline:** `$E=mc^2$`
121
- * **Block:** `$$\zeta(s) = \sum_{1}^{\infty} n^{-s}$$`
147
+ We enthusiastically welcome contributions! Omni-MDX is a sophisticated project blending Rust, C++, TypeScript, and Python.
122
148
 
123
- ### ๐ŸŽจ Hybrid Components
124
- Mix standard HTML tags with custom React components. Omni-MDX preserves props and nested children perfectly between the Rust parser and your React tree.
149
+ 1. **Clone the repository:**
150
+ ```bash
151
+ git clone https://github.com/TOAQ-oss/omni-mdx-core.git
152
+ ```
153
+ 2. **Check the contribution guide:** [CONTRIBUTING.md](./CONTRIBUTING.md) to learn how to set up your local development environment.
125
154
 
126
155
  ---
127
- ## ๐Ÿ“– Documentation & Support
128
156
 
129
- Full guides and API references: **[omni-core.org/mdx](https://omni-core.org/mdx)**
157
+ ## License
130
158
 
131
- |Environment|Backend|Entry Point|
132
- |:---|:---|:---|
133
- |**Server** (Node.js)|Native Addon (`.node`)|`@toaq-oss/omni-mdx/server`|
134
- |**Client** (Browser)|WebAssembly (`.wasm`)|`@toaq-oss/omni-mdx/client`|
135
- |**Edge** (Vercel)|Native Addon (`.wasm`)|`@toaq-oss/omni-mdx/client`|
159
+ [MIT][license] ยฉ [TOAQ-oss][author-url]
136
160
 
137
161
  ---
138
- ## ๐Ÿค Contributing
139
- This package is part of the TOAQ open-source ecosystem.
140
- * **Core Parser (Rust):** [TOAQ-oss/omni-mdx-core](https://github.com/TOAQ-oss/omni-mdx-core)
141
- * **Reporting Issues:** Please use the GitHub issue tracker for bugs or feature requests.
162
+
163
+ [build-badge]: https://github.com/TOAQ-oss/omni-mdx-core/actions/workflows/publish-next.yml/badge.svg
164
+ [build]: https://github.com/TOAQ-oss/omni-mdx-core/actions
165
+
166
+ [coverage-badge]: https://img.shields.io/codecov/c/github/TOAQ-oss/omni-mdx-core/main.svg?flag=npm&logo=codecov
167
+ [coverage]: https://codecov.io/github/TOAQ-oss/omni-mdx-core
168
+
169
+ [downloads-badge]: https://img.shields.io/npm/dm/@toaq-oss/omni-mdx.svg?style=flat-square&color=blue
170
+ [downloads]: https://www.npmjs.com/package/@toaq-oss/omni-mdx
171
+
172
+ [size-badge]: https://img.shields.io/bundlejs/size/@toaq-oss/omni-mdx?color=brightgreen
173
+ [size]: https://bundlejs.com/?q=@toaq-oss/omni-mdx
174
+
175
+ [chat-badge]: https://img.shields.io/badge/chat-discussions-success.svg?logo=github
176
+ [chat]: https://github.com/TOAQ-oss/omni-mdx-core/discussions
177
+
178
+ [license]: https://github.com/TOAQ-oss/omni-mdx-core/blob/main/LICENSE
179
+ [author-url]: https://github.com/toaq-oss
180
+
181
+ [Rust]: https://img.shields.io/badge/rust-000000?logo=rust
182
+ [TypeScript]: https://img.shields.io/badge/typescript-3178C6?logo=typescript
package/dist/client.cjs CHANGED
@@ -109,7 +109,7 @@ function parse_to_binary(mdx_input) {
109
109
  function __wbg_get_imports() {
110
110
  const import0 = {
111
111
  __proto__: null,
112
- __wbg_Error_83742b46f01ce22d: function(arg0, arg1) {
112
+ __wbg_Error_960c155d3d49e4c2: function(arg0, arg1) {
113
113
  const ret = Error(getStringFromWasm0(arg0, arg1));
114
114
  return ret;
115
115
  },
@@ -310,6 +310,7 @@ module.exports = __toCommonJS(client_exports);
310
310
  // src/MDXClientRenderer.tsx
311
311
  var import_react2 = __toESM(require("react"), 1);
312
312
  var import_katex = __toESM(require("katex"), 1);
313
+ var import_json5 = __toESM(require("json5"), 1);
313
314
 
314
315
  // src/MDXErrorBoundary.tsx
315
316
  var import_react = require("react");
@@ -384,7 +385,7 @@ var BASIC_STYLES = {
384
385
  table: (props) => /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "overflow-x-auto mb-6", children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("table", { className: "w-full text-sm text-left border-collapse", ...props }) }),
385
386
  th: (props) => /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("th", { className: "border-b border-white/10 p-2 font-semibold text-neutral-200", ...props }),
386
387
  td: (props) => /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("td", { className: "border-b border-white/5 p-2 text-neutral-400", ...props }),
387
- img: (props) => /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("img", { className: "rounded-xl border border-white/10 my-8 mx-auto max-w-full h-auto", ...props }),
388
+ img: ({ children, ...props }) => /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("img", { className: "rounded-xl border border-white/10 my-8 mx-auto max-w-full h-auto", ...props }),
388
389
  a: (props) => /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("a", { className: "text-blue-400 hover:text-blue-300 underline underline-offset-4 decoration-blue-500/30 transition-colors", ...props })
389
390
  };
390
391
 
@@ -403,7 +404,7 @@ function resolveAttr(attr, components) {
403
404
  } catch {
404
405
  }
405
406
  try {
406
- return new Function(`return (${raw})`)();
407
+ return import_json5.default.parse(raw);
407
408
  } catch {
408
409
  }
409
410
  return raw;
@@ -488,27 +489,77 @@ function renderNode(node, index, components) {
488
489
  if (node.node_type === "fragment") {
489
490
  return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react2.default.Fragment, { children: node.children?.map((c, i) => renderNode(c, i, components)) }, key);
490
491
  }
492
+ const getMathFormula = (node2) => {
493
+ let formula = "";
494
+ if (node2.attributes) {
495
+ const attrs = typeof node2.attributes === "string" ? JSON.parse(node2.attributes) : node2.attributes;
496
+ const mathData = attrs?.["data-math"];
497
+ if (mathData && mathData.value) {
498
+ formula = String(mathData.value);
499
+ }
500
+ }
501
+ if (!formula) {
502
+ formula = extractText(node2);
503
+ }
504
+ return formula;
505
+ };
491
506
  if (node.node_type === "InlineMath") {
492
- const formula = extractText(node);
507
+ const formula = getMathFormula(node);
493
508
  try {
494
- const html = import_katex.default.renderToString(formula, { displayMode: false, throwOnError: false, output: "html" });
495
- return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "math math-inline", dangerouslySetInnerHTML: { __html: html } }, key);
509
+ const html = import_katex.default.renderToString(formula, {
510
+ displayMode: false,
511
+ throwOnError: false,
512
+ output: "html"
513
+ });
514
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
515
+ "span",
516
+ {
517
+ className: "math math-inline",
518
+ dangerouslySetInnerHTML: { __html: html }
519
+ },
520
+ key
521
+ );
496
522
  } catch {
497
523
  return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "math math-inline", children: formula }, key);
498
524
  }
499
525
  }
500
- if (node.node_type === "BlockMath") {
501
- const formula = extractText(node);
526
+ if (node.node_type === "BlockMath" || node.node_type === "math") {
527
+ const formula = getMathFormula(node);
502
528
  try {
503
- const html = import_katex.default.renderToString(formula, { displayMode: true, throwOnError: false, output: "html" });
504
- return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "math math-display", dangerouslySetInnerHTML: { __html: html } }, key);
529
+ const html = import_katex.default.renderToString(formula, {
530
+ displayMode: true,
531
+ throwOnError: false,
532
+ output: "html"
533
+ });
534
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
535
+ "div",
536
+ {
537
+ className: "math math-display",
538
+ dangerouslySetInnerHTML: { __html: html }
539
+ },
540
+ key
541
+ );
505
542
  } catch {
506
543
  return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "math math-display", children: formula }, key);
507
544
  }
508
545
  }
509
546
  const resolvedProps = {};
510
547
  if (node.attributes) {
511
- const attrs = typeof node.attributes === "string" ? JSON.parse(node.attributes) : node.attributes;
548
+ let attrs = {};
549
+ if (typeof node.attributes === "string") {
550
+ try {
551
+ attrs = JSON.parse(node.attributes);
552
+ } catch (error) {
553
+ if (true) {
554
+ console.warn(
555
+ `[toaq-oss/omni-mdx] Failed to parse attributes JSON for <${node.node_type}>`,
556
+ error
557
+ );
558
+ }
559
+ }
560
+ } else {
561
+ attrs = node.attributes;
562
+ }
512
563
  for (const [k, v] of Object.entries(attrs)) {
513
564
  resolvedProps[k] = resolveAttr(v, components);
514
565
  }
@@ -537,7 +588,6 @@ function MDXClientRenderer({
537
588
  ast,
538
589
  components = {}
539
590
  }) {
540
- const rootRef = (0, import_react2.useRef)(null);
541
591
  if (!ast || !Array.isArray(ast)) return null;
542
592
  const finalComponents = {
543
593
  ...BASIC_STYLES,
@@ -670,6 +720,9 @@ var MdxBinaryDecoder = class {
670
720
  */
671
721
  readStringU16() {
672
722
  const len = this.readU16();
723
+ if (this.offset + len > this.buffer.byteLength) {
724
+ throw new Error(`Binary corruption: string (u16) out of bounds at offset ${this.offset}`);
725
+ }
673
726
  const str = this.decoder.decode(this.buffer.subarray(this.offset, this.offset + len));
674
727
  this.offset += len;
675
728
  let cached = this.stringCache.get(str);
@@ -684,6 +737,9 @@ var MdxBinaryDecoder = class {
684
737
  */
685
738
  readStringU32() {
686
739
  const len = this.readU32();
740
+ if (this.offset + len > this.buffer.byteLength) {
741
+ throw new Error(`Binary corruption: string (u32) out of bounds at offset ${this.offset}`);
742
+ }
687
743
  const str = this.decoder.decode(this.buffer.subarray(this.offset, this.offset + len));
688
744
  this.offset += len;
689
745
  return str;
@@ -818,7 +874,7 @@ function getClientParser() {
818
874
  const wasm2 = await Promise.resolve().then(() => (init_omni_mdx_core(), omni_mdx_core_exports));
819
875
  if (typeof wasm2.default === "function") {
820
876
  const wasmUrl = new URL("./omni_mdx_core_bg.wasm", import_meta2.url);
821
- await wasm2.default(wasmUrl);
877
+ await wasm2.default({ module_or_path: wasmUrl });
822
878
  }
823
879
  return (mdx) => wasm2.parse_to_binary(mdx);
824
880
  })();