@favish/staffbase-utils 0.6.0 → 0.8.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.
- package/README.md +1 -0
- package/dist/dom.cjs.js +2 -0
- package/dist/dom.cjs.js.map +1 -0
- package/dist/dom.es.mjs +6 -0
- package/dist/dom.es.mjs.map +1 -0
- package/dist/html.cjs.js +1 -1
- package/dist/html.cjs.js.map +1 -1
- package/dist/html.es.mjs +25 -10
- package/dist/html.es.mjs.map +1 -1
- package/dist/src/dom/getDynamicClasses.d.ts +13 -0
- package/dist/src/dom/getDynamicClasses.d.ts.map +1 -0
- package/dist/src/dom/index.d.ts +2 -0
- package/dist/src/dom/index.d.ts.map +1 -0
- package/dist/src/html/logRemovedEmbeds.d.ts +11 -0
- package/dist/src/html/logRemovedEmbeds.d.ts.map +1 -0
- package/dist/src/html/sanitizeArticleHtml.d.ts.map +1 -1
- package/dist/src/html/sanitizeHtml.d.ts.map +1 -1
- package/package.json +6 -1
package/README.md
CHANGED
|
@@ -24,6 +24,7 @@ minimumReleaseAgeExclude:
|
|
|
24
24
|
| Subpath | Exports |
|
|
25
25
|
| --- | --- |
|
|
26
26
|
| `@favish/staffbase-utils/log` | `logError`, `logWarn`, `logDebug`, `setLoggingEnabled` |
|
|
27
|
+
| `@favish/staffbase-utils/dom` | `getDynamicClasses` |
|
|
27
28
|
|
|
28
29
|
More modules (`/env`, `/device`, `/html`, `/links`, `/widgets`) are added per the
|
|
29
30
|
delivery roadmap; each is its own subpath so consumers only bundle what they import.
|
package/dist/dom.cjs.js
ADDED
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});var e=(e=`.fullscreen-preview-wrapper section`,t=`rich-text news-detail-post-content`)=>typeof document>`u`?t:document.querySelector(e)?.className||t;exports.getDynamicClasses=e;
|
|
2
|
+
//# sourceMappingURL=dom.cjs.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dom.cjs.js","names":[],"sources":["../src/dom/getDynamicClasses.ts"],"sourcesContent":["/**\n * Reads the host's dynamic rich-text CSS classes from the rendered article DOM.\n *\n * Staffbase applies tenant/theme-specific classes to the article body; mirroring\n * them on the widget's own rich-text container keeps typography consistent with\n * the host. Falls back to the stable default classes when the element is absent\n * or when there is no DOM (SSR/tests), so callers always get a usable string.\n * @param {string} [query] - CSS selector locating the source element.\n * @param {string} [defaultClasses] - Classes returned when the element is not found.\n * @returns {string} The host's dynamic rich-text classes, or the defaults.\n */\nexport const getDynamicClasses = (\n query = '.fullscreen-preview-wrapper section',\n defaultClasses = 'rich-text news-detail-post-content',\n): string => {\n if (typeof document === 'undefined') return defaultClasses\n\n const sectionElement = document.querySelector(query)\n return sectionElement?.className || defaultClasses\n}\n"],"mappings":"mEAWA,IAAa,GACX,EAAQ,sCACR,EAAiB,uCAEb,OAAO,SAAa,IAAoB,EAErB,SAAS,cAAc,CACvC,GAAgB,WAAa"}
|
package/dist/dom.es.mjs
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
//#region src/dom/getDynamicClasses.ts
|
|
2
|
+
var e = (e = ".fullscreen-preview-wrapper section", t = "rich-text news-detail-post-content") => typeof document > "u" ? t : document.querySelector(e)?.className || t;
|
|
3
|
+
//#endregion
|
|
4
|
+
export { e as getDynamicClasses };
|
|
5
|
+
|
|
6
|
+
//# sourceMappingURL=dom.es.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dom.es.mjs","names":[],"sources":["../src/dom/getDynamicClasses.ts"],"sourcesContent":["/**\n * Reads the host's dynamic rich-text CSS classes from the rendered article DOM.\n *\n * Staffbase applies tenant/theme-specific classes to the article body; mirroring\n * them on the widget's own rich-text container keeps typography consistent with\n * the host. Falls back to the stable default classes when the element is absent\n * or when there is no DOM (SSR/tests), so callers always get a usable string.\n * @param {string} [query] - CSS selector locating the source element.\n * @param {string} [defaultClasses] - Classes returned when the element is not found.\n * @returns {string} The host's dynamic rich-text classes, or the defaults.\n */\nexport const getDynamicClasses = (\n query = '.fullscreen-preview-wrapper section',\n defaultClasses = 'rich-text news-detail-post-content',\n): string => {\n if (typeof document === 'undefined') return defaultClasses\n\n const sectionElement = document.querySelector(query)\n return sectionElement?.className || defaultClasses\n}\n"],"mappings":";AAWA,IAAa,KACX,IAAQ,uCACR,IAAiB,yCAEb,OAAO,WAAa,MAAoB,IAErB,SAAS,cAAc,CACvC,GAAgB,aAAa"}
|
package/dist/html.cjs.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});var e=Object.create,t=Object.defineProperty,n=Object.getOwnPropertyDescriptor,r=Object.getOwnPropertyNames,i=Object.getPrototypeOf,a=Object.prototype.hasOwnProperty,o=(e,i,o,s)=>{if(i&&typeof i==`object`||typeof i==`function`)for(var c=r(i),l=0,u=c.length,d;l<u;l++)d=c[l],!a.call(e,d)&&d!==o&&t(e,d,{get:(e=>i[e]).bind(null,d),enumerable:!(s=n(i,d))||s.enumerable});return e},s=(n,r,a)=>(a=n==null?{}:e(i(n)),o(r||!n||!n.__esModule?t(a,`default`,{value:n,enumerable:!0}):a,n));let c=require("dompurify");c=s(c);var l=e=>{if(!e)return``;try{return c.default.sanitize(e,{ALLOWED_TAGS:[],KEEP_CONTENT:!0})}catch{return e.replace(/<\/?[^>]+(>|$)/g,``)}},u=e=>l(e).toLowerCase().replace(/[.,!?;:"'()[\]\-_/\\]/g,` `).replace(/\s+/g,` `).trim(),d={tagNameCheck:/^[a-z][a-z0-9]*-[a-z0-9-]*$/,attributeNameCheck:/^(?!on)[a-z][a-z0-9]*([-:][a-z0-9]+)*$/,allowCustomizedBuiltInElements:!0},f=(0,c.default)(window),
|
|
1
|
+
Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});var e=Object.create,t=Object.defineProperty,n=Object.getOwnPropertyDescriptor,r=Object.getOwnPropertyNames,i=Object.getPrototypeOf,a=Object.prototype.hasOwnProperty,o=(e,i,o,s)=>{if(i&&typeof i==`object`||typeof i==`function`)for(var c=r(i),l=0,u=c.length,d;l<u;l++)d=c[l],!a.call(e,d)&&d!==o&&t(e,d,{get:(e=>i[e]).bind(null,d),enumerable:!(s=n(i,d))||s.enumerable});return e},s=(n,r,a)=>(a=n==null?{}:e(i(n)),o(r||!n||!n.__esModule?t(a,`default`,{value:n,enumerable:!0}):a,n));let c=require("dompurify");c=s(c);var l=e=>{if(!e)return``;try{return c.default.sanitize(e,{ALLOWED_TAGS:[],KEEP_CONTENT:!0})}catch{return e.replace(/<\/?[^>]+(>|$)/g,``)}},u=e=>l(e).toLowerCase().replace(/[.,!?;:"'()[\]\-_/\\]/g,` `).replace(/\s+/g,` `).trim(),d={tagNameCheck:/^[a-z][a-z0-9]*-[a-z0-9-]*$/,attributeNameCheck:/^(?!on)[a-z][a-z0-9]*([-:][a-z0-9]+)*$/,allowCustomizedBuiltInElements:!0},f=e=>{let t=[];for(let n of e){if(!n||typeof n!=`object`||!(`element`in n))continue;let e=n.element;if(e instanceof Element){let n=e.tagName.toLowerCase();n.includes(`-`)&&t.push(n)}}t.length>0&&console.warn(`[staffbase-utils] sanitizer removed ${t.length} possible widget embed(s): ${t.join(`, `)} — they will not render. If these are valid embeds, the sanitizer config may need updating.`)},p=(0,c.default)(window),m=null;p.addHook(`afterSanitizeAttributes`,e=>{if(e instanceof Element&&(e.tagName===`A`&&e.getAttribute(`target`)===`_blank`&&e.setAttribute(`rel`,`noopener noreferrer`),e.tagName===`IFRAME`&&m)){let t=e.getAttribute(`src`)??``;m(t)||e.parentNode?.removeChild(e)}});var h=(e,t={})=>{m=t.isAllowedIframeSrc??null;try{let t=p.sanitize(e,{USE_PROFILES:{html:!0},CUSTOM_ELEMENT_HANDLING:d,ADD_TAGS:[`iframe`],ADD_ATTR:[`target`,`allow`,`allowfullscreen`,`frameborder`,`scrolling`,`loading`,`referrerpolicy`],FORBID_TAGS:[`script`,`style`],FORBID_ATTR:[`onerror`,`onload`,`onclick`]});return f(p.removed),t}finally{m=null}},g=e=>{let t=c.default.sanitize(e,{CUSTOM_ELEMENT_HANDLING:d});return f(c.default.removed),t};exports.cleanHTML=u,exports.sanitizeArticleHtml=h,exports.sanitizeHtml=g,exports.stripHtmlTags=l;
|
|
2
2
|
//# sourceMappingURL=html.cjs.js.map
|
package/dist/html.cjs.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"html.cjs.js","names":[],"sources":["../src/html/stripHtmlTags.ts","../src/html/cleanHTML.ts","../src/html/customElementHandling.ts","../src/html/sanitizeArticleHtml.ts","../src/html/sanitizeHtml.ts"],"sourcesContent":["import DOMPurify from 'dompurify'\n\n/**\n * Strips all HTML tags, keeping the text content. From smart-search's\n * stripHtmlTags; its html-react-parser fallback is intentionally dropped to\n * avoid a heavy runtime dependency — the DOMPurify path plus a regex fallback is\n * sufficient and never throws in practice.\n * @param {string | undefined} html - String that may contain HTML tags.\n * @returns {string} The text content with tags removed.\n */\nexport const stripHtmlTags = (html?: string): string => {\n if (!html) return ''\n\n try {\n return DOMPurify.sanitize(html, { ALLOWED_TAGS: [], KEEP_CONTENT: true })\n } catch {\n return html.replace(/<\\/?[^>]+(>|$)/g, '')\n }\n}\n","import { stripHtmlTags } from './stripHtmlTags'\n\n/**\n * Normalizes HTML into a lowercase, punctuation-free, single-spaced token string\n * for search indexing/matching. From alerts' cleanHTML; builds on stripHtmlTags\n * so tag removal stays single-sourced.\n * @param {string} html - The HTML string to clean.\n * @returns {string} The cleaned, normalized text.\n */\nexport const cleanHTML = (html: string): string =>\n stripHtmlTags(html)\n .toLowerCase()\n .replace(/[.,!?;:\"'()[\\]\\-_/\\\\]/g, ' ')\n .replace(/\\s+/g, ' ')\n .trim()\n","import type { Config } from 'dompurify'\n\n/**\n * DOMPurify custom-element handling that preserves embedded-widget custom\n * elements (any hyphenated tag, e.g. `<news-teaser>`) and their kebab-case /\n * `data-` attributes so the host widget manager (renderWidgets) can hydrate\n * them. Without this, DOMPurify's default profile silently strips unknown custom\n * elements AND their attributes, wiping embeds out of the content before they can\n * render. `on*` event-handler attributes are still rejected (defense in depth\n * alongside DOMPurify's own XSS stripping). Promoted from staffbase-global-content.\n */\nexport const customElementHandling: NonNullable<\n Config['CUSTOM_ELEMENT_HANDLING']\n> = {\n // Any valid custom-element tag name (must contain a hyphen per the spec).\n tagNameCheck: /^[a-z][a-z0-9]*-[a-z0-9-]*$/,\n // Allow kebab-case / data- attributes on custom elements, but never `on*`.\n attributeNameCheck: /^(?!on)[a-z][a-z0-9]*([-:][a-z0-9]+)*$/,\n // Permit `<div is=\"some-widget\">`-style customized built-in elements.\n allowCustomizedBuiltInElements: true,\n}\n","import createDOMPurify from 'dompurify'\n\nimport type { SanitizeArticleHtmlOptions } from '../types/html/SanitizeArticleHtmlOptions'\nimport { customElementHandling } from './customElementHandling'\n\n// Dedicated DOMPurify instance so the hardening hook below is scoped to this\n// sanitizer and never pollutes the consumer's shared default DOMPurify instance\n// (other code may sanitize through the default instance directly).\nconst purifier = createDOMPurify(window)\n\n// Set synchronously around each (synchronous) sanitize call. JS is\n// single-threaded, so the guard cannot leak across calls.\nlet activeIframeGuard: ((src: string) => boolean) | null = null\n\n// afterSanitizeAttributes hook: force rel=\"noopener noreferrer\" on\n// target=\"_blank\" anchors (reverse-tabnabbing), and drop iframes whose src fails\n// the injected allowlist predicate when one is active.\npurifier.addHook('afterSanitizeAttributes', (node) => {\n if (!(node instanceof Element)) return\n\n if (node.tagName === 'A' && node.getAttribute('target') === '_blank') {\n node.setAttribute('rel', 'noopener noreferrer')\n }\n\n if (node.tagName === 'IFRAME' && activeIframeGuard) {\n const src = node.getAttribute('src') ?? ''\n if (!activeIframeGuard(src)) node.parentNode?.removeChild(node)\n }\n})\n\n/**\n * Canonical sanitizer for rich article HTML rendered into a session-bearing\n * webview. Superset of the alerts and unacknowledged-bulletins variants: keeps\n * iframes and data-* attributes (renderWidgets discovers embedded sub-widgets via\n * data-*), strips scripts/inline handlers/javascript:, and forces\n * rel=\"noopener noreferrer\" on target=\"_blank\" anchors. When options.isAllowedIframeSrc\n * is provided, iframes whose src fails it are dropped (injected so this module\n * does not depend on /links, which owns isAllowedIframeSrc).\n * @param {string} html - Raw article HTML from the Staffbase API.\n * @param {SanitizeArticleHtmlOptions} options - Optional iframe-src allowlist.\n * @returns {string} Sanitized HTML safe to inject/parse.\n */\nexport const sanitizeArticleHtml = (\n html: string,\n options: SanitizeArticleHtmlOptions = {},\n): string => {\n activeIframeGuard = options.isAllowedIframeSrc ?? null\n try {\n
|
|
1
|
+
{"version":3,"file":"html.cjs.js","names":[],"sources":["../src/html/stripHtmlTags.ts","../src/html/cleanHTML.ts","../src/html/customElementHandling.ts","../src/html/logRemovedEmbeds.ts","../src/html/sanitizeArticleHtml.ts","../src/html/sanitizeHtml.ts"],"sourcesContent":["import DOMPurify from 'dompurify'\n\n/**\n * Strips all HTML tags, keeping the text content. From smart-search's\n * stripHtmlTags; its html-react-parser fallback is intentionally dropped to\n * avoid a heavy runtime dependency — the DOMPurify path plus a regex fallback is\n * sufficient and never throws in practice.\n * @param {string | undefined} html - String that may contain HTML tags.\n * @returns {string} The text content with tags removed.\n */\nexport const stripHtmlTags = (html?: string): string => {\n if (!html) return ''\n\n try {\n return DOMPurify.sanitize(html, { ALLOWED_TAGS: [], KEEP_CONTENT: true })\n } catch {\n return html.replace(/<\\/?[^>]+(>|$)/g, '')\n }\n}\n","import { stripHtmlTags } from './stripHtmlTags'\n\n/**\n * Normalizes HTML into a lowercase, punctuation-free, single-spaced token string\n * for search indexing/matching. From alerts' cleanHTML; builds on stripHtmlTags\n * so tag removal stays single-sourced.\n * @param {string} html - The HTML string to clean.\n * @returns {string} The cleaned, normalized text.\n */\nexport const cleanHTML = (html: string): string =>\n stripHtmlTags(html)\n .toLowerCase()\n .replace(/[.,!?;:\"'()[\\]\\-_/\\\\]/g, ' ')\n .replace(/\\s+/g, ' ')\n .trim()\n","import type { Config } from 'dompurify'\n\n/**\n * DOMPurify custom-element handling that preserves embedded-widget custom\n * elements (any hyphenated tag, e.g. `<news-teaser>`) and their kebab-case /\n * `data-` attributes so the host widget manager (renderWidgets) can hydrate\n * them. Without this, DOMPurify's default profile silently strips unknown custom\n * elements AND their attributes, wiping embeds out of the content before they can\n * render. `on*` event-handler attributes are still rejected (defense in depth\n * alongside DOMPurify's own XSS stripping). Promoted from staffbase-global-content.\n */\nexport const customElementHandling: NonNullable<\n Config['CUSTOM_ELEMENT_HANDLING']\n> = {\n // Any valid custom-element tag name (must contain a hyphen per the spec).\n tagNameCheck: /^[a-z][a-z0-9]*-[a-z0-9-]*$/,\n // Allow kebab-case / data- attributes on custom elements, but never `on*`.\n attributeNameCheck: /^(?!on)[a-z][a-z0-9]*([-:][a-z0-9]+)*$/,\n // Permit `<div is=\"some-widget\">`-style customized built-in elements.\n allowCustomizedBuiltInElements: true,\n}\n","/**\n * Warns (once per call) when the sanitizer dropped what looks like an embedded\n * widget — a custom-element tag (any hyphenated tag name). These removals are the\n * silent failure mode that makes embedded widgets \"disappear\" before the host can\n * render them, so surfacing them aids diagnosis. Scripts, styles and on*\n * handlers are intentionally removed and are NOT reported (they would be noise).\n * @param {readonly unknown[]} removed - DOMPurify's `removed` array after sanitize.\n * @returns {void}\n */\nexport const logRemovedEmbeds = (removed: readonly unknown[]): void => {\n const tags: string[] = []\n\n for (const entry of removed) {\n if (!entry || typeof entry !== 'object' || !('element' in entry)) continue\n const element = (entry as { element: unknown }).element\n if (element instanceof Element) {\n const tag = element.tagName.toLowerCase()\n if (tag.includes('-')) tags.push(tag)\n }\n }\n\n if (tags.length > 0) {\n console.warn(\n `[staffbase-utils] sanitizer removed ${tags.length} possible widget embed(s): ${tags.join(', ')} — they will not render. If these are valid embeds, the sanitizer config may need updating.`,\n )\n }\n}\n","import createDOMPurify from 'dompurify'\n\nimport type { SanitizeArticleHtmlOptions } from '../types/html/SanitizeArticleHtmlOptions'\nimport { customElementHandling } from './customElementHandling'\nimport { logRemovedEmbeds } from './logRemovedEmbeds'\n\n// Dedicated DOMPurify instance so the hardening hook below is scoped to this\n// sanitizer and never pollutes the consumer's shared default DOMPurify instance\n// (other code may sanitize through the default instance directly).\nconst purifier = createDOMPurify(window)\n\n// Set synchronously around each (synchronous) sanitize call. JS is\n// single-threaded, so the guard cannot leak across calls.\nlet activeIframeGuard: ((src: string) => boolean) | null = null\n\n// afterSanitizeAttributes hook: force rel=\"noopener noreferrer\" on\n// target=\"_blank\" anchors (reverse-tabnabbing), and drop iframes whose src fails\n// the injected allowlist predicate when one is active.\npurifier.addHook('afterSanitizeAttributes', (node) => {\n if (!(node instanceof Element)) return\n\n if (node.tagName === 'A' && node.getAttribute('target') === '_blank') {\n node.setAttribute('rel', 'noopener noreferrer')\n }\n\n if (node.tagName === 'IFRAME' && activeIframeGuard) {\n const src = node.getAttribute('src') ?? ''\n if (!activeIframeGuard(src)) node.parentNode?.removeChild(node)\n }\n})\n\n/**\n * Canonical sanitizer for rich article HTML rendered into a session-bearing\n * webview. Superset of the alerts and unacknowledged-bulletins variants: keeps\n * iframes and data-* attributes (renderWidgets discovers embedded sub-widgets via\n * data-*), strips scripts/inline handlers/javascript:, and forces\n * rel=\"noopener noreferrer\" on target=\"_blank\" anchors. When options.isAllowedIframeSrc\n * is provided, iframes whose src fails it are dropped (injected so this module\n * does not depend on /links, which owns isAllowedIframeSrc).\n * @param {string} html - Raw article HTML from the Staffbase API.\n * @param {SanitizeArticleHtmlOptions} options - Optional iframe-src allowlist.\n * @returns {string} Sanitized HTML safe to inject/parse.\n */\nexport const sanitizeArticleHtml = (\n html: string,\n options: SanitizeArticleHtmlOptions = {},\n): string => {\n activeIframeGuard = options.isAllowedIframeSrc ?? null\n try {\n const clean = purifier.sanitize(html, {\n USE_PROFILES: { html: true },\n CUSTOM_ELEMENT_HANDLING: customElementHandling,\n ADD_TAGS: ['iframe'],\n ADD_ATTR: [\n 'target',\n 'allow',\n 'allowfullscreen',\n 'frameborder',\n 'scrolling',\n 'loading',\n 'referrerpolicy',\n ],\n FORBID_TAGS: ['script', 'style'],\n FORBID_ATTR: ['onerror', 'onload', 'onclick'],\n })\n logRemovedEmbeds(purifier.removed)\n return clean\n } finally {\n activeIframeGuard = null\n }\n}\n","import DOMPurify from 'dompurify'\n\nimport { customElementHandling } from './customElementHandling'\nimport { logRemovedEmbeds } from './logRemovedEmbeds'\n\n/**\n * Strict sanitizer for untrusted snippet/teaser HTML rendered through a\n * non-sanitizing parser (e.g. html-react-parser). The default DOMPurify profile\n * strips scripts, inline handlers and dangerous URLs AND drops iframes, keeping\n * only basic rich-text markup. Embedded-widget custom elements (and their\n * kebab/data attributes) are preserved so the host can hydrate them. From\n * global-content's sanitizeHtml.\n *\n * Use sanitizeArticleHtml instead when rendering full article bodies that must\n * keep iframes / data-* embeds.\n * @param {string} html - Raw HTML string from the API.\n * @returns {string} Sanitized HTML.\n */\nexport const sanitizeHtml = (html: string): string => {\n const clean = DOMPurify.sanitize(html, {\n CUSTOM_ELEMENT_HANDLING: customElementHandling,\n })\n logRemovedEmbeds(DOMPurify.removed)\n return clean\n}\n"],"mappings":"mkBAUA,IAAa,EAAiB,GAA0B,CACtD,GAAI,CAAC,EAAM,MAAO,GAElB,GAAI,CACF,OAAO,EAAA,QAAU,SAAS,EAAM,CAAE,aAAc,CAAC,EAAG,aAAc,EAAK,CAAC,CAC1E,MAAQ,CACN,OAAO,EAAK,QAAQ,kBAAmB,EAAE,CAC3C,CACF,ECTa,EAAa,GACxB,EAAc,CAAI,EACf,YAAY,EACZ,QAAQ,yBAA0B,GAAG,EACrC,QAAQ,OAAQ,GAAG,EACnB,KAAK,ECHG,EAET,CAEF,aAAc,8BAEd,mBAAoB,yCAEpB,+BAAgC,EAClC,ECXa,EAAoB,GAAsC,CACrE,IAAM,EAAiB,CAAC,EAExB,IAAK,IAAM,KAAS,EAAS,CAC3B,GAAI,CAAC,GAAS,OAAO,GAAU,UAAY,EAAE,YAAa,GAAQ,SAClE,IAAM,EAAW,EAA+B,QAChD,GAAI,aAAmB,QAAS,CAC9B,IAAM,EAAM,EAAQ,QAAQ,YAAY,EACpC,EAAI,SAAS,GAAG,GAAG,EAAK,KAAK,CAAG,CACtC,CACF,CAEI,EAAK,OAAS,GAChB,QAAQ,KACN,uCAAuC,EAAK,OAAO,6BAA6B,EAAK,KAAK,IAAI,EAAE,4FAClG,CAEJ,ECjBM,GAAA,EAAA,EAAA,SAA2B,MAAM,EAInC,EAAuD,KAK3D,EAAS,QAAQ,0BAA4B,GAAS,CAC9C,gBAAgB,UAElB,EAAK,UAAY,KAAO,EAAK,aAAa,QAAQ,IAAM,UAC1D,EAAK,aAAa,MAAO,qBAAqB,EAG5C,EAAK,UAAY,UAAY,GAAmB,CAClD,IAAM,EAAM,EAAK,aAAa,KAAK,GAAK,GACnC,EAAkB,CAAG,GAAG,EAAK,YAAY,YAAY,CAAI,CAChE,CACF,CAAC,EAcD,IAAa,GACX,EACA,EAAsC,CAAC,IAC5B,CACX,EAAoB,EAAQ,oBAAsB,KAClD,GAAI,CACF,IAAM,EAAQ,EAAS,SAAS,EAAM,CACpC,aAAc,CAAE,KAAM,EAAK,EAC3B,wBAAyB,EACzB,SAAU,CAAC,QAAQ,EACnB,SAAU,CACR,SACA,QACA,kBACA,cACA,YACA,UACA,gBACF,EACA,YAAa,CAAC,SAAU,OAAO,EAC/B,YAAa,CAAC,UAAW,SAAU,SAAS,CAC9C,CAAC,EAED,OADA,EAAiB,EAAS,OAAO,EAC1B,CACT,QAAU,CACR,EAAoB,IACtB,CACF,ECpDa,EAAgB,GAAyB,CACpD,IAAM,EAAQ,EAAA,QAAU,SAAS,EAAM,CACrC,wBAAyB,CAC3B,CAAC,EAED,OADA,EAAiB,EAAA,QAAU,OAAO,EAC3B,CACT"}
|
package/dist/html.es.mjs
CHANGED
|
@@ -14,17 +14,28 @@ var t = (t) => {
|
|
|
14
14
|
tagNameCheck: /^[a-z][a-z0-9]*-[a-z0-9-]*$/,
|
|
15
15
|
attributeNameCheck: /^(?!on)[a-z][a-z0-9]*([-:][a-z0-9]+)*$/,
|
|
16
16
|
allowCustomizedBuiltInElements: !0
|
|
17
|
-
}, i = e
|
|
18
|
-
|
|
19
|
-
|
|
17
|
+
}, i = (e) => {
|
|
18
|
+
let t = [];
|
|
19
|
+
for (let n of e) {
|
|
20
|
+
if (!n || typeof n != "object" || !("element" in n)) continue;
|
|
21
|
+
let e = n.element;
|
|
22
|
+
if (e instanceof Element) {
|
|
23
|
+
let n = e.tagName.toLowerCase();
|
|
24
|
+
n.includes("-") && t.push(n);
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
t.length > 0 && console.warn(`[staffbase-utils] sanitizer removed ${t.length} possible widget embed(s): ${t.join(", ")} — they will not render. If these are valid embeds, the sanitizer config may need updating.`);
|
|
28
|
+
}, a = e(window), o = null;
|
|
29
|
+
a.addHook("afterSanitizeAttributes", (e) => {
|
|
30
|
+
if (e instanceof Element && (e.tagName === "A" && e.getAttribute("target") === "_blank" && e.setAttribute("rel", "noopener noreferrer"), e.tagName === "IFRAME" && o)) {
|
|
20
31
|
let t = e.getAttribute("src") ?? "";
|
|
21
|
-
|
|
32
|
+
o(t) || e.parentNode?.removeChild(e);
|
|
22
33
|
}
|
|
23
34
|
});
|
|
24
|
-
var
|
|
25
|
-
|
|
35
|
+
var s = (e, t = {}) => {
|
|
36
|
+
o = t.isAllowedIframeSrc ?? null;
|
|
26
37
|
try {
|
|
27
|
-
|
|
38
|
+
let t = a.sanitize(e, {
|
|
28
39
|
USE_PROFILES: { html: !0 },
|
|
29
40
|
CUSTOM_ELEMENT_HANDLING: r,
|
|
30
41
|
ADD_TAGS: ["iframe"],
|
|
@@ -44,11 +55,15 @@ var o = (e, t = {}) => {
|
|
|
44
55
|
"onclick"
|
|
45
56
|
]
|
|
46
57
|
});
|
|
58
|
+
return i(a.removed), t;
|
|
47
59
|
} finally {
|
|
48
|
-
|
|
60
|
+
o = null;
|
|
49
61
|
}
|
|
50
|
-
},
|
|
62
|
+
}, c = (t) => {
|
|
63
|
+
let n = e.sanitize(t, { CUSTOM_ELEMENT_HANDLING: r });
|
|
64
|
+
return i(e.removed), n;
|
|
65
|
+
};
|
|
51
66
|
//#endregion
|
|
52
|
-
export { n as cleanHTML,
|
|
67
|
+
export { n as cleanHTML, s as sanitizeArticleHtml, c as sanitizeHtml, t as stripHtmlTags };
|
|
53
68
|
|
|
54
69
|
//# sourceMappingURL=html.es.mjs.map
|
package/dist/html.es.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"html.es.mjs","names":[],"sources":["../src/html/stripHtmlTags.ts","../src/html/cleanHTML.ts","../src/html/customElementHandling.ts","../src/html/sanitizeArticleHtml.ts","../src/html/sanitizeHtml.ts"],"sourcesContent":["import DOMPurify from 'dompurify'\n\n/**\n * Strips all HTML tags, keeping the text content. From smart-search's\n * stripHtmlTags; its html-react-parser fallback is intentionally dropped to\n * avoid a heavy runtime dependency — the DOMPurify path plus a regex fallback is\n * sufficient and never throws in practice.\n * @param {string | undefined} html - String that may contain HTML tags.\n * @returns {string} The text content with tags removed.\n */\nexport const stripHtmlTags = (html?: string): string => {\n if (!html) return ''\n\n try {\n return DOMPurify.sanitize(html, { ALLOWED_TAGS: [], KEEP_CONTENT: true })\n } catch {\n return html.replace(/<\\/?[^>]+(>|$)/g, '')\n }\n}\n","import { stripHtmlTags } from './stripHtmlTags'\n\n/**\n * Normalizes HTML into a lowercase, punctuation-free, single-spaced token string\n * for search indexing/matching. From alerts' cleanHTML; builds on stripHtmlTags\n * so tag removal stays single-sourced.\n * @param {string} html - The HTML string to clean.\n * @returns {string} The cleaned, normalized text.\n */\nexport const cleanHTML = (html: string): string =>\n stripHtmlTags(html)\n .toLowerCase()\n .replace(/[.,!?;:\"'()[\\]\\-_/\\\\]/g, ' ')\n .replace(/\\s+/g, ' ')\n .trim()\n","import type { Config } from 'dompurify'\n\n/**\n * DOMPurify custom-element handling that preserves embedded-widget custom\n * elements (any hyphenated tag, e.g. `<news-teaser>`) and their kebab-case /\n * `data-` attributes so the host widget manager (renderWidgets) can hydrate\n * them. Without this, DOMPurify's default profile silently strips unknown custom\n * elements AND their attributes, wiping embeds out of the content before they can\n * render. `on*` event-handler attributes are still rejected (defense in depth\n * alongside DOMPurify's own XSS stripping). Promoted from staffbase-global-content.\n */\nexport const customElementHandling: NonNullable<\n Config['CUSTOM_ELEMENT_HANDLING']\n> = {\n // Any valid custom-element tag name (must contain a hyphen per the spec).\n tagNameCheck: /^[a-z][a-z0-9]*-[a-z0-9-]*$/,\n // Allow kebab-case / data- attributes on custom elements, but never `on*`.\n attributeNameCheck: /^(?!on)[a-z][a-z0-9]*([-:][a-z0-9]+)*$/,\n // Permit `<div is=\"some-widget\">`-style customized built-in elements.\n allowCustomizedBuiltInElements: true,\n}\n","import createDOMPurify from 'dompurify'\n\nimport type { SanitizeArticleHtmlOptions } from '../types/html/SanitizeArticleHtmlOptions'\nimport { customElementHandling } from './customElementHandling'\n\n// Dedicated DOMPurify instance so the hardening hook below is scoped to this\n// sanitizer and never pollutes the consumer's shared default DOMPurify instance\n// (other code may sanitize through the default instance directly).\nconst purifier = createDOMPurify(window)\n\n// Set synchronously around each (synchronous) sanitize call. JS is\n// single-threaded, so the guard cannot leak across calls.\nlet activeIframeGuard: ((src: string) => boolean) | null = null\n\n// afterSanitizeAttributes hook: force rel=\"noopener noreferrer\" on\n// target=\"_blank\" anchors (reverse-tabnabbing), and drop iframes whose src fails\n// the injected allowlist predicate when one is active.\npurifier.addHook('afterSanitizeAttributes', (node) => {\n if (!(node instanceof Element)) return\n\n if (node.tagName === 'A' && node.getAttribute('target') === '_blank') {\n node.setAttribute('rel', 'noopener noreferrer')\n }\n\n if (node.tagName === 'IFRAME' && activeIframeGuard) {\n const src = node.getAttribute('src') ?? ''\n if (!activeIframeGuard(src)) node.parentNode?.removeChild(node)\n }\n})\n\n/**\n * Canonical sanitizer for rich article HTML rendered into a session-bearing\n * webview. Superset of the alerts and unacknowledged-bulletins variants: keeps\n * iframes and data-* attributes (renderWidgets discovers embedded sub-widgets via\n * data-*), strips scripts/inline handlers/javascript:, and forces\n * rel=\"noopener noreferrer\" on target=\"_blank\" anchors. When options.isAllowedIframeSrc\n * is provided, iframes whose src fails it are dropped (injected so this module\n * does not depend on /links, which owns isAllowedIframeSrc).\n * @param {string} html - Raw article HTML from the Staffbase API.\n * @param {SanitizeArticleHtmlOptions} options - Optional iframe-src allowlist.\n * @returns {string} Sanitized HTML safe to inject/parse.\n */\nexport const sanitizeArticleHtml = (\n html: string,\n options: SanitizeArticleHtmlOptions = {},\n): string => {\n activeIframeGuard = options.isAllowedIframeSrc ?? null\n try {\n
|
|
1
|
+
{"version":3,"file":"html.es.mjs","names":[],"sources":["../src/html/stripHtmlTags.ts","../src/html/cleanHTML.ts","../src/html/customElementHandling.ts","../src/html/logRemovedEmbeds.ts","../src/html/sanitizeArticleHtml.ts","../src/html/sanitizeHtml.ts"],"sourcesContent":["import DOMPurify from 'dompurify'\n\n/**\n * Strips all HTML tags, keeping the text content. From smart-search's\n * stripHtmlTags; its html-react-parser fallback is intentionally dropped to\n * avoid a heavy runtime dependency — the DOMPurify path plus a regex fallback is\n * sufficient and never throws in practice.\n * @param {string | undefined} html - String that may contain HTML tags.\n * @returns {string} The text content with tags removed.\n */\nexport const stripHtmlTags = (html?: string): string => {\n if (!html) return ''\n\n try {\n return DOMPurify.sanitize(html, { ALLOWED_TAGS: [], KEEP_CONTENT: true })\n } catch {\n return html.replace(/<\\/?[^>]+(>|$)/g, '')\n }\n}\n","import { stripHtmlTags } from './stripHtmlTags'\n\n/**\n * Normalizes HTML into a lowercase, punctuation-free, single-spaced token string\n * for search indexing/matching. From alerts' cleanHTML; builds on stripHtmlTags\n * so tag removal stays single-sourced.\n * @param {string} html - The HTML string to clean.\n * @returns {string} The cleaned, normalized text.\n */\nexport const cleanHTML = (html: string): string =>\n stripHtmlTags(html)\n .toLowerCase()\n .replace(/[.,!?;:\"'()[\\]\\-_/\\\\]/g, ' ')\n .replace(/\\s+/g, ' ')\n .trim()\n","import type { Config } from 'dompurify'\n\n/**\n * DOMPurify custom-element handling that preserves embedded-widget custom\n * elements (any hyphenated tag, e.g. `<news-teaser>`) and their kebab-case /\n * `data-` attributes so the host widget manager (renderWidgets) can hydrate\n * them. Without this, DOMPurify's default profile silently strips unknown custom\n * elements AND their attributes, wiping embeds out of the content before they can\n * render. `on*` event-handler attributes are still rejected (defense in depth\n * alongside DOMPurify's own XSS stripping). Promoted from staffbase-global-content.\n */\nexport const customElementHandling: NonNullable<\n Config['CUSTOM_ELEMENT_HANDLING']\n> = {\n // Any valid custom-element tag name (must contain a hyphen per the spec).\n tagNameCheck: /^[a-z][a-z0-9]*-[a-z0-9-]*$/,\n // Allow kebab-case / data- attributes on custom elements, but never `on*`.\n attributeNameCheck: /^(?!on)[a-z][a-z0-9]*([-:][a-z0-9]+)*$/,\n // Permit `<div is=\"some-widget\">`-style customized built-in elements.\n allowCustomizedBuiltInElements: true,\n}\n","/**\n * Warns (once per call) when the sanitizer dropped what looks like an embedded\n * widget — a custom-element tag (any hyphenated tag name). These removals are the\n * silent failure mode that makes embedded widgets \"disappear\" before the host can\n * render them, so surfacing them aids diagnosis. Scripts, styles and on*\n * handlers are intentionally removed and are NOT reported (they would be noise).\n * @param {readonly unknown[]} removed - DOMPurify's `removed` array after sanitize.\n * @returns {void}\n */\nexport const logRemovedEmbeds = (removed: readonly unknown[]): void => {\n const tags: string[] = []\n\n for (const entry of removed) {\n if (!entry || typeof entry !== 'object' || !('element' in entry)) continue\n const element = (entry as { element: unknown }).element\n if (element instanceof Element) {\n const tag = element.tagName.toLowerCase()\n if (tag.includes('-')) tags.push(tag)\n }\n }\n\n if (tags.length > 0) {\n console.warn(\n `[staffbase-utils] sanitizer removed ${tags.length} possible widget embed(s): ${tags.join(', ')} — they will not render. If these are valid embeds, the sanitizer config may need updating.`,\n )\n }\n}\n","import createDOMPurify from 'dompurify'\n\nimport type { SanitizeArticleHtmlOptions } from '../types/html/SanitizeArticleHtmlOptions'\nimport { customElementHandling } from './customElementHandling'\nimport { logRemovedEmbeds } from './logRemovedEmbeds'\n\n// Dedicated DOMPurify instance so the hardening hook below is scoped to this\n// sanitizer and never pollutes the consumer's shared default DOMPurify instance\n// (other code may sanitize through the default instance directly).\nconst purifier = createDOMPurify(window)\n\n// Set synchronously around each (synchronous) sanitize call. JS is\n// single-threaded, so the guard cannot leak across calls.\nlet activeIframeGuard: ((src: string) => boolean) | null = null\n\n// afterSanitizeAttributes hook: force rel=\"noopener noreferrer\" on\n// target=\"_blank\" anchors (reverse-tabnabbing), and drop iframes whose src fails\n// the injected allowlist predicate when one is active.\npurifier.addHook('afterSanitizeAttributes', (node) => {\n if (!(node instanceof Element)) return\n\n if (node.tagName === 'A' && node.getAttribute('target') === '_blank') {\n node.setAttribute('rel', 'noopener noreferrer')\n }\n\n if (node.tagName === 'IFRAME' && activeIframeGuard) {\n const src = node.getAttribute('src') ?? ''\n if (!activeIframeGuard(src)) node.parentNode?.removeChild(node)\n }\n})\n\n/**\n * Canonical sanitizer for rich article HTML rendered into a session-bearing\n * webview. Superset of the alerts and unacknowledged-bulletins variants: keeps\n * iframes and data-* attributes (renderWidgets discovers embedded sub-widgets via\n * data-*), strips scripts/inline handlers/javascript:, and forces\n * rel=\"noopener noreferrer\" on target=\"_blank\" anchors. When options.isAllowedIframeSrc\n * is provided, iframes whose src fails it are dropped (injected so this module\n * does not depend on /links, which owns isAllowedIframeSrc).\n * @param {string} html - Raw article HTML from the Staffbase API.\n * @param {SanitizeArticleHtmlOptions} options - Optional iframe-src allowlist.\n * @returns {string} Sanitized HTML safe to inject/parse.\n */\nexport const sanitizeArticleHtml = (\n html: string,\n options: SanitizeArticleHtmlOptions = {},\n): string => {\n activeIframeGuard = options.isAllowedIframeSrc ?? null\n try {\n const clean = purifier.sanitize(html, {\n USE_PROFILES: { html: true },\n CUSTOM_ELEMENT_HANDLING: customElementHandling,\n ADD_TAGS: ['iframe'],\n ADD_ATTR: [\n 'target',\n 'allow',\n 'allowfullscreen',\n 'frameborder',\n 'scrolling',\n 'loading',\n 'referrerpolicy',\n ],\n FORBID_TAGS: ['script', 'style'],\n FORBID_ATTR: ['onerror', 'onload', 'onclick'],\n })\n logRemovedEmbeds(purifier.removed)\n return clean\n } finally {\n activeIframeGuard = null\n }\n}\n","import DOMPurify from 'dompurify'\n\nimport { customElementHandling } from './customElementHandling'\nimport { logRemovedEmbeds } from './logRemovedEmbeds'\n\n/**\n * Strict sanitizer for untrusted snippet/teaser HTML rendered through a\n * non-sanitizing parser (e.g. html-react-parser). The default DOMPurify profile\n * strips scripts, inline handlers and dangerous URLs AND drops iframes, keeping\n * only basic rich-text markup. Embedded-widget custom elements (and their\n * kebab/data attributes) are preserved so the host can hydrate them. From\n * global-content's sanitizeHtml.\n *\n * Use sanitizeArticleHtml instead when rendering full article bodies that must\n * keep iframes / data-* embeds.\n * @param {string} html - Raw HTML string from the API.\n * @returns {string} Sanitized HTML.\n */\nexport const sanitizeHtml = (html: string): string => {\n const clean = DOMPurify.sanitize(html, {\n CUSTOM_ELEMENT_HANDLING: customElementHandling,\n })\n logRemovedEmbeds(DOMPurify.removed)\n return clean\n}\n"],"mappings":";;AAUA,IAAa,KAAiB,MAA0B;CACtD,IAAI,CAAC,GAAM,OAAO;CAElB,IAAI;EACF,OAAO,EAAU,SAAS,GAAM;GAAE,cAAc,CAAC;GAAG,cAAc;EAAK,CAAC;CAC1E,QAAQ;EACN,OAAO,EAAK,QAAQ,mBAAmB,EAAE;CAC3C;AACF,GCTa,KAAa,MACxB,EAAc,CAAI,EACf,YAAY,EACZ,QAAQ,0BAA0B,GAAG,EACrC,QAAQ,QAAQ,GAAG,EACnB,KAAK,GCHG,IAET;CAEF,cAAc;CAEd,oBAAoB;CAEpB,gCAAgC;AAClC,GCXa,KAAoB,MAAsC;CACrE,IAAM,IAAiB,CAAC;CAExB,KAAK,IAAM,KAAS,GAAS;EAC3B,IAAI,CAAC,KAAS,OAAO,KAAU,YAAY,EAAE,aAAa,IAAQ;EAClE,IAAM,IAAW,EAA+B;EAChD,IAAI,aAAmB,SAAS;GAC9B,IAAM,IAAM,EAAQ,QAAQ,YAAY;GACxC,AAAI,EAAI,SAAS,GAAG,KAAG,EAAK,KAAK,CAAG;EACtC;CACF;CAEA,AAAI,EAAK,SAAS,KAChB,QAAQ,KACN,uCAAuC,EAAK,OAAO,6BAA6B,EAAK,KAAK,IAAI,EAAE,4FAClG;AAEJ,GCjBM,IAAW,EAAgB,MAAM,GAInC,IAAuD;AAK3D,EAAS,QAAQ,4BAA4B,MAAS;CAC9C,iBAAgB,YAElB,EAAK,YAAY,OAAO,EAAK,aAAa,QAAQ,MAAM,YAC1D,EAAK,aAAa,OAAO,qBAAqB,GAG5C,EAAK,YAAY,YAAY,IAAmB;EAClD,IAAM,IAAM,EAAK,aAAa,KAAK,KAAK;EACxC,AAAK,EAAkB,CAAG,KAAG,EAAK,YAAY,YAAY,CAAI;CAChE;AACF,CAAC;AAcD,IAAa,KACX,GACA,IAAsC,CAAC,MAC5B;CACX,IAAoB,EAAQ,sBAAsB;CAClD,IAAI;EACF,IAAM,IAAQ,EAAS,SAAS,GAAM;GACpC,cAAc,EAAE,MAAM,GAAK;GAC3B,yBAAyB;GACzB,UAAU,CAAC,QAAQ;GACnB,UAAU;IACR;IACA;IACA;IACA;IACA;IACA;IACA;GACF;GACA,aAAa,CAAC,UAAU,OAAO;GAC/B,aAAa;IAAC;IAAW;IAAU;GAAS;EAC9C,CAAC;EAED,OADA,EAAiB,EAAS,OAAO,GAC1B;CACT,UAAU;EACR,IAAoB;CACtB;AACF,GCpDa,KAAgB,MAAyB;CACpD,IAAM,IAAQ,EAAU,SAAS,GAAM,EACrC,yBAAyB,EAC3B,CAAC;CAED,OADA,EAAiB,EAAU,OAAO,GAC3B;AACT"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Reads the host's dynamic rich-text CSS classes from the rendered article DOM.
|
|
3
|
+
*
|
|
4
|
+
* Staffbase applies tenant/theme-specific classes to the article body; mirroring
|
|
5
|
+
* them on the widget's own rich-text container keeps typography consistent with
|
|
6
|
+
* the host. Falls back to the stable default classes when the element is absent
|
|
7
|
+
* or when there is no DOM (SSR/tests), so callers always get a usable string.
|
|
8
|
+
* @param {string} [query] - CSS selector locating the source element.
|
|
9
|
+
* @param {string} [defaultClasses] - Classes returned when the element is not found.
|
|
10
|
+
* @returns {string} The host's dynamic rich-text classes, or the defaults.
|
|
11
|
+
*/
|
|
12
|
+
export declare const getDynamicClasses: (query?: string, defaultClasses?: string) => string;
|
|
13
|
+
//# sourceMappingURL=getDynamicClasses.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"getDynamicClasses.d.ts","sourceRoot":"","sources":["../../../src/dom/getDynamicClasses.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AACH,eAAO,MAAM,iBAAiB,GAC5B,cAA6C,EAC7C,uBAAqD,KACpD,MAKF,CAAA"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/dom/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAA"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Warns (once per call) when the sanitizer dropped what looks like an embedded
|
|
3
|
+
* widget — a custom-element tag (any hyphenated tag name). These removals are the
|
|
4
|
+
* silent failure mode that makes embedded widgets "disappear" before the host can
|
|
5
|
+
* render them, so surfacing them aids diagnosis. Scripts, styles and on*
|
|
6
|
+
* handlers are intentionally removed and are NOT reported (they would be noise).
|
|
7
|
+
* @param {readonly unknown[]} removed - DOMPurify's `removed` array after sanitize.
|
|
8
|
+
* @returns {void}
|
|
9
|
+
*/
|
|
10
|
+
export declare const logRemovedEmbeds: (removed: readonly unknown[]) => void;
|
|
11
|
+
//# sourceMappingURL=logRemovedEmbeds.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"logRemovedEmbeds.d.ts","sourceRoot":"","sources":["../../../src/html/logRemovedEmbeds.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,eAAO,MAAM,gBAAgB,GAAI,SAAS,SAAS,OAAO,EAAE,KAAG,IAiB9D,CAAA"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sanitizeArticleHtml.d.ts","sourceRoot":"","sources":["../../../src/html/sanitizeArticleHtml.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,0BAA0B,EAAE,MAAM,0CAA0C,CAAA;
|
|
1
|
+
{"version":3,"file":"sanitizeArticleHtml.d.ts","sourceRoot":"","sources":["../../../src/html/sanitizeArticleHtml.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,0BAA0B,EAAE,MAAM,0CAA0C,CAAA;AA6B1F;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,mBAAmB,GAC9B,MAAM,MAAM,EACZ,UAAS,0BAA+B,KACvC,MAwBF,CAAA"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sanitizeHtml.d.ts","sourceRoot":"","sources":["../../../src/html/sanitizeHtml.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"sanitizeHtml.d.ts","sourceRoot":"","sources":["../../../src/html/sanitizeHtml.ts"],"names":[],"mappings":"AAKA;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,YAAY,GAAI,MAAM,MAAM,KAAG,MAM3C,CAAA"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@favish/staffbase-utils",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.8.0",
|
|
4
4
|
"description": "Shared internal/host utilities for Staffbase widgets",
|
|
5
5
|
"author": "Favish <dev@favish.com>",
|
|
6
6
|
"license": "UNLICENSED",
|
|
@@ -18,6 +18,11 @@
|
|
|
18
18
|
"import": "./dist/device.es.mjs",
|
|
19
19
|
"require": "./dist/device.cjs.js"
|
|
20
20
|
},
|
|
21
|
+
"./dom": {
|
|
22
|
+
"types": "./dist/src/dom/index.d.ts",
|
|
23
|
+
"import": "./dist/dom.es.mjs",
|
|
24
|
+
"require": "./dist/dom.cjs.js"
|
|
25
|
+
},
|
|
21
26
|
"./html": {
|
|
22
27
|
"types": "./dist/src/html/index.d.ts",
|
|
23
28
|
"import": "./dist/html.es.mjs",
|