@localess/richtext 4.0.1-dev.20260916085732 → 4.0.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/SKILL.md CHANGED
@@ -33,7 +33,8 @@ const html = renderRichTextToHtml(data.body);
33
33
  - Output is byte-identical to TipTap's `generateHTML` for the Studio's
34
34
  extension set, except link `href`s pass a protocol allowlist
35
35
  (`http:`/`https:`/`mailto:`/`tel:`/scheme-less); `javascript:`/`data:`
36
- hrefs become `""`.
36
+ hrefs become `""`, including obfuscated forms (`java\tscript:`, leading
37
+ control characters) — the href is normalized like a browser URL parser first.
37
38
  - Never throws; malformed input renders `''`.
38
39
 
39
40
  ## Supported node set
@@ -152,7 +153,7 @@ ordered lists (nested, `start`), fenced and indented code blocks, `**bold**`, `*
152
153
  Anything else goes through `unsupported` and is listed in the result — return the report to the
153
154
  caller, do not assume a clean parse. One warning per element type per parse, silent in production.
154
155
 
155
- Link hrefs pass the renderer's `sanitizeUrl` allowlist: `javascript:` and `data:` become `""`.
156
+ Link hrefs pass the renderer's `sanitizeUrl` allowlist: `javascript:` and `data:` become `""`, including entity-encoded tab/newline/control-character obfuscations.
156
157
 
157
158
  Never throws except under `unsupported: 'throw'`; `null`, `undefined`, and `''` give an empty doc.
158
159
 
package/dist/escape.d.ts CHANGED
@@ -10,5 +10,9 @@ export declare function escapeAttr(value: string): string;
10
10
  * Allowlist URL sanitizer for link hrefs: `http:`, `https:`, `mailto:`, `tel:`
11
11
  * and scheme-less (relative/protocol-relative/fragment/query) URLs pass;
12
12
  * everything else (e.g. `javascript:`, `data:`) becomes `''`.
13
+ *
14
+ * The input is first normalized the way the WHATWG URL parser does it (leading/trailing
15
+ * C0 control or space stripped, tab/newline removed everywhere), so obfuscated schemes
16
+ * such as `java\tscript:` are caught; the normalized URL is what gets returned.
13
17
  */
14
18
  export declare function sanitizeUrl(url: string): string;
@@ -1,5 +1,5 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
- const require_parse_common = require("../parse-common-DEYhfKnK.js");
2
+ const require_parse_common = require("../parse-common-ColxMxGw.js");
3
3
  //#region src/html-parser/to-model.ts
4
4
  /** Tag → mark, the inverse of `MARK_RENDER_MAP`. `b`/`i`/`del`/`s` are accepted as aliases. */
5
5
  var MARK_TAGS = {
@@ -1,4 +1,4 @@
1
- import { n as UnsupportedTracker, o as sanitizeUrl, r as emptyDocument, t as RichTextParseError } from "../parse-common-C-dAtFji.mjs";
1
+ import { n as UnsupportedTracker, o as sanitizeUrl, r as emptyDocument, t as RichTextParseError } from "../parse-common-CmQhI2Da.mjs";
2
2
  //#region src/html-parser/to-model.ts
3
3
  /** Tag → mark, the inverse of `MARK_RENDER_MAP`. `b`/`i`/`del`/`s` are accepted as aliases. */
4
4
  var MARK_TAGS = {
package/dist/index.js CHANGED
@@ -1,5 +1,5 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
- const require_parse_common = require("./parse-common-DEYhfKnK.js");
2
+ const require_parse_common = require("./parse-common-ColxMxGw.js");
3
3
  //#region src/attrs.ts
4
4
  /**
5
5
  * Normalizes a node/mark's stored attrs into the attributes to emit, in the
package/dist/index.mjs CHANGED
@@ -1,4 +1,4 @@
1
- import { a as escapeHtml, i as escapeAttr, n as UnsupportedTracker, o as sanitizeUrl, r as emptyDocument, t as RichTextParseError } from "./parse-common-C-dAtFji.mjs";
1
+ import { a as escapeHtml, i as escapeAttr, n as UnsupportedTracker, o as sanitizeUrl, r as emptyDocument, t as RichTextParseError } from "./parse-common-CmQhI2Da.mjs";
2
2
  //#region src/attrs.ts
3
3
  /**
4
4
  * Normalizes a node/mark's stored attrs into the attributes to emit, in the
@@ -1,5 +1,5 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
- const require_parse_common = require("../parse-common-DEYhfKnK.js");
2
+ const require_parse_common = require("../parse-common-ColxMxGw.js");
3
3
  //#region src/markdown-parser/inline.ts
4
4
  /**
5
5
  * Parses Markdown inline content into text nodes with marks.
@@ -1,4 +1,4 @@
1
- import { n as UnsupportedTracker, o as sanitizeUrl, r as emptyDocument, t as RichTextParseError } from "../parse-common-C-dAtFji.mjs";
1
+ import { n as UnsupportedTracker, o as sanitizeUrl, r as emptyDocument, t as RichTextParseError } from "../parse-common-CmQhI2Da.mjs";
2
2
  //#region src/markdown-parser/inline.ts
3
3
  /**
4
4
  * Parses Markdown inline content into text nodes with marks.
@@ -22,13 +22,19 @@ function escapeAttr(value) {
22
22
  }
23
23
  var SAFE_SCHEME = /^(?:https?:|mailto:|tel:)/i;
24
24
  var HAS_SCHEME = /^[a-z][a-z0-9+.-]*:/i;
25
+ var C0_CONTROL_OR_SPACE_EDGES = /^[\u0000- ]+|[\u0000- ]+$/g;
26
+ var TAB_OR_NEWLINE = /[\t\n\r]/g;
25
27
  /**
26
28
  * Allowlist URL sanitizer for link hrefs: `http:`, `https:`, `mailto:`, `tel:`
27
29
  * and scheme-less (relative/protocol-relative/fragment/query) URLs pass;
28
30
  * everything else (e.g. `javascript:`, `data:`) becomes `''`.
31
+ *
32
+ * The input is first normalized the way the WHATWG URL parser does it (leading/trailing
33
+ * C0 control or space stripped, tab/newline removed everywhere), so obfuscated schemes
34
+ * such as `java\tscript:` are caught; the normalized URL is what gets returned.
29
35
  */
30
36
  function sanitizeUrl(url) {
31
- const trimmed = url.trim();
37
+ const trimmed = url.replace(C0_CONTROL_OR_SPACE_EDGES, "").replace(TAB_OR_NEWLINE, "").trim();
32
38
  if (trimmed === "") return "";
33
39
  if (SAFE_SCHEME.test(trimmed)) return trimmed;
34
40
  if (!HAS_SCHEME.test(trimmed)) return trimmed;
@@ -22,13 +22,19 @@ function escapeAttr(value) {
22
22
  }
23
23
  var SAFE_SCHEME = /^(?:https?:|mailto:|tel:)/i;
24
24
  var HAS_SCHEME = /^[a-z][a-z0-9+.-]*:/i;
25
+ var C0_CONTROL_OR_SPACE_EDGES = /^[\u0000- ]+|[\u0000- ]+$/g;
26
+ var TAB_OR_NEWLINE = /[\t\n\r]/g;
25
27
  /**
26
28
  * Allowlist URL sanitizer for link hrefs: `http:`, `https:`, `mailto:`, `tel:`
27
29
  * and scheme-less (relative/protocol-relative/fragment/query) URLs pass;
28
30
  * everything else (e.g. `javascript:`, `data:`) becomes `''`.
31
+ *
32
+ * The input is first normalized the way the WHATWG URL parser does it (leading/trailing
33
+ * C0 control or space stripped, tab/newline removed everywhere), so obfuscated schemes
34
+ * such as `java\tscript:` are caught; the normalized URL is what gets returned.
29
35
  */
30
36
  function sanitizeUrl(url) {
31
- const trimmed = url.trim();
37
+ const trimmed = url.replace(C0_CONTROL_OR_SPACE_EDGES, "").replace(TAB_OR_NEWLINE, "").trim();
32
38
  if (trimmed === "") return "";
33
39
  if (SAFE_SCHEME.test(trimmed)) return trimmed;
34
40
  if (!HAS_SCHEME.test(trimmed)) return trimmed;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@localess/richtext",
3
- "version": "4.0.1-dev.20260916085732",
3
+ "version": "4.0.1",
4
4
  "description": "Framework-neutral rich text model and renderer for Localess's TipTap JSON content.",
5
5
  "keywords": [
6
6
  "localess",
@@ -58,7 +58,7 @@
58
58
  },
59
59
  "license": "MIT",
60
60
  "dependencies": {
61
- "@localess/model": "4.0.1-dev.20260916085732"
61
+ "@localess/model": "4.0.1"
62
62
  },
63
63
  "devDependencies": {
64
64
  "@tiptap/extension-bold": "^3.22.5",