@jini-ai/platform 0.6.22 → 0.6.23

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/CHANGELOG.md CHANGED
@@ -1,3 +1,7 @@
1
+ ## 0.6.23
2
+
3
+ - Security hardening.
4
+
1
5
  # @jini-ai/platform
2
6
 
3
7
  ## 0.6.22
@@ -3,4 +3,5 @@
3
3
  export * from "./web-page.js";
4
4
  export * from "./html-document.js";
5
5
  export { htmlToMarkdown } from "./html-to-markdown.js";
6
+ export { stripHtmlPresentation } from "./strip-html-presentation.js";
6
7
  //# sourceMappingURL=index.d.ts.map
package/dist/web/index.js CHANGED
@@ -3,4 +3,5 @@
3
3
  export * from "./web-page.js";
4
4
  export * from "./html-document.js";
5
5
  export { htmlToMarkdown } from "./html-to-markdown.js";
6
+ export { stripHtmlPresentation } from "./strip-html-presentation.js";
6
7
  //# sourceMappingURL=index.js.map
@@ -0,0 +1,15 @@
1
+ /** Remove presentation using source ranges; untouched bytes (including comments) stay exact.
2
+ * Scripts, classes and functional attributes are preserved. This is not an HTML sanitizer.
3
+ * @param required.html - Document or fragment to transform; never mutated.
4
+ * @param optional.preservedStylesheetHrefs - Exact hrefs retained for host sentinels/vendor CSS.
5
+ * @returns HTML without style elements/attributes or unretained stylesheet links; no I/O.
6
+ * @complexity O(n + p + r log r) time and O(n + p + r) space for HTML bytes n,
7
+ * preserved href bytes p and removal ranges r.
8
+ * @example stripHtmlPresentation({ html: '<p style="color:red">Hi</p>' })
9
+ */
10
+ export declare function stripHtmlPresentation({ html }: {
11
+ html: string;
12
+ }, { preservedStylesheetHrefs }?: {
13
+ preservedStylesheetHrefs?: readonly string[];
14
+ }): string;
15
+ //# sourceMappingURL=strip-html-presentation.d.ts.map
@@ -0,0 +1,60 @@
1
+ import { parse } from "parse5";
2
+ import { attr } from "./html-document.js";
3
+ /** Select whole elements before attributes; the ordered edit pass skips overlapping ranges. */
4
+ function presentationRange(node, preserved) {
5
+ const location = node.sourceCodeLocation;
6
+ if (!location)
7
+ return undefined;
8
+ const rel = (attr({ element: node, name: "rel" }) ?? "").toLowerCase().split(/\s+/);
9
+ const href = attr({ element: node, name: "href" }) ?? "";
10
+ if (node.tagName === "style")
11
+ return location;
12
+ if (node.tagName === "link" && rel.includes("stylesheet") && !preserved.has(href))
13
+ return location;
14
+ return location.attrs?.style;
15
+ }
16
+ /** Iterative traversal includes inert template content without recursion or argument spreading. */
17
+ function* walk(root) {
18
+ const pending = [root];
19
+ while (pending.length) {
20
+ const node = pending.pop();
21
+ yield node;
22
+ if ("childNodes" in node)
23
+ for (const child of node.childNodes)
24
+ pending.push(child);
25
+ if ("content" in node)
26
+ pending.push(node.content);
27
+ }
28
+ }
29
+ /** Remove presentation using source ranges; untouched bytes (including comments) stay exact.
30
+ * Scripts, classes and functional attributes are preserved. This is not an HTML sanitizer.
31
+ * @param required.html - Document or fragment to transform; never mutated.
32
+ * @param optional.preservedStylesheetHrefs - Exact hrefs retained for host sentinels/vendor CSS.
33
+ * @returns HTML without style elements/attributes or unretained stylesheet links; no I/O.
34
+ * @complexity O(n + p + r log r) time and O(n + p + r) space for HTML bytes n,
35
+ * preserved href bytes p and removal ranges r.
36
+ * @example stripHtmlPresentation({ html: '<p style="color:red">Hi</p>' })
37
+ */
38
+ export function stripHtmlPresentation({ html }, { preservedStylesheetHrefs = [] } = {}) {
39
+ const preserved = new Set(preservedStylesheetHrefs);
40
+ const ranges = [];
41
+ for (const node of walk(parse(html, { sourceCodeLocationInfo: true, scriptingEnabled: false }))) {
42
+ if (!("tagName" in node))
43
+ continue;
44
+ const range = presentationRange(node, preserved);
45
+ if (range)
46
+ ranges.push(range);
47
+ }
48
+ ranges.sort((a, b) => a.startOffset - b.startOffset);
49
+ const parts = [];
50
+ let end = 0;
51
+ for (const range of ranges) {
52
+ if (range.startOffset < end)
53
+ continue;
54
+ parts.push(html.slice(end, range.startOffset));
55
+ end = range.endOffset;
56
+ }
57
+ parts.push(html.slice(end));
58
+ return parts.join("");
59
+ }
60
+ //# sourceMappingURL=strip-html-presentation.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jini-ai/platform",
3
- "version": "0.6.22",
3
+ "version": "0.6.23",
4
4
  "description": "Generic OS/platform primitives: process exec and lifecycle, filesystem containment, HTTP readiness polling, toolchain discovery, blob storage, AWS signing, and an SSRF-safe asset cache.",
5
5
  "license": "Apache-2.0",
6
6
  "repository": {