Merge pull request #159 from TxtDot/dev

Add middlewares, fallback engines, code highlight and habr navigation
This commit is contained in:
Artemy Egorov 2024-05-15 20:55:13 +03:00 committed by GitHub
commit d0bc4ff518
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
20 changed files with 477 additions and 61 deletions

View File

@ -20,11 +20,10 @@ Mozilla's Readability library is used under the hood.
- Image compression with Sharp - Image compression with Sharp
- Rendering client-side apps (Vanilla, React, Vue, etc) with [webder](https://github.com/TxtDot/webder) - Rendering client-side apps (Vanilla, React, Vue, etc) with [webder](https://github.com/TxtDot/webder)
- Search with SearXNG - Search with SearXNG
- Custom parsers for StackOverflow and SearXNG
- Handy API endpoints - Handy API endpoints
- No client JavaScript - No client JavaScript
- Some kind of Material Design 3 - Some kind of Material Design 3
- Customization with plugins, see [@txtdot/sdk](https://github.com/TxtDot/sdk) and [@txtdot/plugins](https://github.com/TxtDot/plugins) - Customization with plugins, see [@txtdot/sdk](https://github.com/TxtDot/txtdot/tree/main/packages/sdk) and [@txtdot/plugins](https://github.com/TxtDot/txtdot/tree/main/packages/plugins)
## Running ## Running

View File

@ -1,7 +1,5 @@
import { Readability as OReadability } from '@mozilla/readability'; import { Readability as OReadability } from '@mozilla/readability';
import { Engine, EngineParseError, Route } from '@txtdot/sdk';
import { Engine, EngineParseError } from '@txtdot/sdk';
import { parseHTML } from 'linkedom';
const Readability = new Engine( const Readability = new Engine(
'Readability', 'Readability',
@ -9,8 +7,8 @@ const Readability = new Engine(
['*'] ['*']
); );
Readability.route('*path', async (input, ro) => { Readability.route('*path', async (input, ro: Route<{ path: string }>) => {
const reader = new OReadability(input.document); const reader = new OReadability(input.document.cloneNode(true) as Document);
const parsed = reader.parse(); const parsed = reader.parse();
if (!parsed) { if (!parsed) {

View File

@ -1,6 +1,5 @@
import { Engine, JSX } from '@txtdot/sdk'; import { Engine, JSX } from '@txtdot/sdk';
import { HandlerInput, Route } from '@txtdot/sdk'; import { HandlerInput, Route } from '@txtdot/sdk';
import { parseHTML } from 'linkedom';
import { PageFooter, ResultItem } from '../components/searchers'; import { PageFooter, ResultItem } from '../components/searchers';
const SearX = new Engine('SearX', "Engine for searching with 'SearXNG'", [ const SearX = new Engine('SearX', "Engine for searching with 'SearXNG'", [

View File

@ -1,15 +1,16 @@
import * as engines from './engines'; import * as engines from './engines';
export { engines }; export { engines };
export const engineList = [ export const engineList = [
engines.StackOverflow, engines.StackOverflow,
engines.SearX, engines.SearX,
engines.Readability, engines.Readability,
]; ];
import { compile } from 'html-to-text'; import * as middlewares from './middlewares';
export { middlewares };
export const middlewareList = [middlewares.Highlight, middlewares.HabrNav];
import { compile } from 'html-to-text';
export const html2text = compile({ export const html2text = compile({
longWordSplit: { longWordSplit: {
forceWrapOnLimit: true, forceWrapOnLimit: true,

View File

@ -0,0 +1,39 @@
import { Middleware, JSX } from '@txtdot/sdk';
const Highlight = new Middleware(
'Highlight',
'Highlights code with highlight.js only when needed',
['*']
);
Highlight.use(async (input, ro, out) => {
if (out.content.indexOf('<code') !== -1)
return {
...out,
content: <Highlighter content={out.content} />,
};
return out;
});
function Highlighter({ content }: { content: string }) {
return (
<>
<style>
@import
"https://cdn.jsdelivr.net/gh/highlightjs/cdn-release@11.9.0/build/styles/atom-one-light.min.css";
@import
"https://cdn.jsdelivr.net/gh/highlightjs/cdn-release@11.9.0/build/styles/atom-one-dark.min.css"
screen and (prefers-color-scheme: dark);
</style>
<script
src="https://cdn.jsdelivr.net/gh/highlightjs/cdn-release@11.9.0/build/highlight.min.js"
type="text/javascript"
/>
<script>hljs.highlightAll();</script>
{content}
</>
);
}
export default Highlight;

View File

@ -0,0 +1,4 @@
import Highlight from './highlight';
import { HabrNav } from './navigation';
export { Highlight, HabrNav };

View File

@ -0,0 +1,27 @@
import { Middleware, JSX } from '@txtdot/sdk';
const HabrNav = new Middleware('Habr Nav', 'Adds navigation in habr pages', [
'habr.com',
]);
HabrNav.use(async (input, ro, out) => {
let nav = [...input.document.querySelectorAll('.tm-main-menu__item')];
return {
...out,
content: (
<>
<ul>
{nav.map((item) => (
<li>
<a href={item.getAttribute('href')}>{item.textContent}</a>
</li>
))}
</ul>
{out.content}
</>
),
};
});
export { HabrNav };

View File

@ -34,7 +34,7 @@ export class Engine {
} }
async handle(input: HandlerInput): Promise<EngineOutput> { async handle(input: HandlerInput): Promise<EngineOutput> {
const url = new URL(input.getUrl()); const url = new URL(input.url);
const path = url.pathname + url.search + url.hash; const path = url.pathname + url.search + url.hash;
for (const route of this.routes) { for (const route of this.routes) {
const match = route.route.match(path); const match = route.route.match(path);

View File

@ -24,9 +24,7 @@ export function createElement(
}) })
.join(' '); .join(' ');
return inner.length === 0 return `<${name} ${propsstr}>${content}</${name}>`;
? `<${name} ${propsstr}/>`
: `<${name} ${propsstr}>${content}</${name}>`;
} else if (typeof name === 'function') { } else if (typeof name === 'function') {
return name(props, content); return name(props, content);
} else { } else {

View File

@ -1,4 +1,5 @@
import { Engine } from './engine'; import { Engine } from './engine';
import { Middleware } from './middleware';
import { import {
EngineParseError, EngineParseError,
@ -16,17 +17,22 @@ import {
HandlerOutput, HandlerOutput,
Route, Route,
handlerSchema, handlerSchema,
EngineOutput,
MiddleFunction,
} from './types/handler'; } from './types/handler';
import * as JSX from './jsx'; import * as JSX from './jsx';
export { export {
Engine, Engine,
Middleware,
EngineParseError, EngineParseError,
NoHandlerFoundError, NoHandlerFoundError,
TxtDotError, TxtDotError,
EngineFunction, EngineFunction,
MiddleFunction,
EngineMatch, EngineMatch,
EngineOutput,
Engines, Engines,
RouteValues, RouteValues,
EnginesMatch, EnginesMatch,

View File

@ -0,0 +1,61 @@
import Route from 'route-parser';
import {
HandlerInput,
RouteValues,
EngineOutput,
MiddleFunction,
} from './types/handler';
interface IMiddle<TParams extends RouteValues> {
route: Route;
handler: MiddleFunction<TParams>;
}
export class Middleware {
name: string;
description: string;
domains: string[];
// eslint-disable-next-line @typescript-eslint/no-explicit-any
middles: IMiddle<any>[] = [];
constructor(name: string, description: string, domains: string[] = []) {
this.domains = domains;
this.name = name;
this.description = description;
}
route<TParams extends RouteValues>(
path: string,
handler: MiddleFunction<TParams>
) {
this.middles.push({ route: new Route<TParams>(path), handler });
}
use<TParams extends RouteValues>(handler: MiddleFunction<TParams>) {
this.middles.push({ route: new Route<{ path: string }>('*path'), handler });
}
async handle(input: HandlerInput, out: EngineOutput): Promise<EngineOutput> {
const url = new URL(input.url);
const path = url.pathname + url.search + url.hash;
let processed_out = out;
for (const middle of this.middles) {
const match = middle.route.match(path);
if (match) {
processed_out = await middle.handler(
input,
{
q: match,
reverse: (req) => middle.route.reverse(req),
},
out
);
}
}
return processed_out;
}
}

View File

@ -2,26 +2,30 @@ import { parseHTML } from 'linkedom';
import { Engine } from '../engine'; import { Engine } from '../engine';
export class HandlerInput { export class HandlerInput {
private data: string; private _data: string;
private url: string; private _url: string;
private window?: Window; private _window?: Window;
constructor(data: string, url: string) { constructor(data: string, url: string) {
this.data = data; this._data = data;
this.url = url; this._url = url;
} }
getUrl(): string { get url(): string {
return this.url; return this._url;
}
get data(): string {
return this._data;
} }
get document(): Document { get document(): Document {
if (this.window) { if (this._window) {
return this.window.document; return this._window.document;
} }
this.window = parseHTML(this.data); this._window = parseHTML(this._data);
return this.window.document; return this._window.document;
} }
} }
@ -75,6 +79,12 @@ export type EngineFunction<TParams extends RouteValues> = (
ro: Route<TParams> ro: Route<TParams>
) => Promise<EngineOutput>; ) => Promise<EngineOutput>;
export type MiddleFunction<TParams extends RouteValues> = (
input: HandlerInput,
ro: Route<TParams>,
out: EngineOutput
) => Promise<EngineOutput>;
export type EnginesMatch<TParams extends RouteValues> = EngineMatch<TParams>[]; export type EnginesMatch<TParams extends RouteValues> = EngineMatch<TParams>[];
export interface Route<TParams extends RouteValues> { export interface Route<TParams extends RouteValues> {

View File

@ -26,19 +26,18 @@
"@txtdot/plugins": "workspace:*", "@txtdot/plugins": "workspace:*",
"@txtdot/sdk": "workspace:*", "@txtdot/sdk": "workspace:*",
"axios": "^1.6.8", "axios": "^1.6.8",
"dompurify": "^3.1.2",
"dotenv": "^16.3.1", "dotenv": "^16.3.1",
"ejs": "^3.1.10", "ejs": "^3.1.10",
"fastify": "^4.26.2", "fastify": "^4.26.2",
"iconv-lite": "^0.6.3", "iconv-lite": "^0.6.3",
"ip-range-check": "^0.2.0", "ip-range-check": "^0.2.0",
"isomorphic-dompurify": "^2.10.0",
"json-schema-to-ts": "^3.0.1", "json-schema-to-ts": "^3.0.1",
"linkedom": "^0.18.0", "linkedom": "^0.18.0",
"micromatch": "^4.0.5", "micromatch": "^4.0.5",
"sharp": "^0.33.3" "sharp": "^0.33.3"
}, },
"devDependencies": { "devDependencies": {
"@types/dompurify": "^3.0.5",
"@types/ejs": "^3.1.5", "@types/ejs": "^3.1.5",
"@types/jsdom": "^21.1.6", "@types/jsdom": "^21.1.6",
"@types/micromatch": "^4.0.7", "@types/micromatch": "^4.0.7",

View File

@ -1,5 +1,5 @@
import { IAppConfig } from '../types/pluginConfig'; import { IAppConfig } from '../types/pluginConfig';
import { engineList, html2text } from '@txtdot/plugins'; import { engineList, middlewareList, html2text } from '@txtdot/plugins';
/** /**
* Configuration of plugins * Configuration of plugins
@ -7,6 +7,7 @@ import { engineList, html2text } from '@txtdot/plugins';
*/ */
const plugin_config: IAppConfig = { const plugin_config: IAppConfig = {
engines: [...engineList], engines: [...engineList],
middlewares: [...middlewareList],
html2text, html2text,
}; };

View File

@ -1,16 +1,16 @@
import axios, { oaxios } from './types/axios'; import axios, { oaxios } from './types/axios';
import micromatch from 'micromatch'; import micromatch from 'micromatch';
import DOMPurify from 'dompurify';
import { Readable } from 'stream'; import { Readable } from 'stream';
import { NotHtmlMimetypeError } from './errors/main'; import { NotHtmlMimetypeError } from './errors/main';
import { decodeStream, parseEncodingName } from './utils/http'; import { decodeStream, parseEncodingName } from './utils/http';
import replaceHref from './utils/replace-href'; import replaceHref from './utils/replace-href';
import { Engine } from '@txtdot/sdk'; import { Engine, EngineOutput, Middleware } from '@txtdot/sdk';
import { HandlerInput, HandlerOutput } from '@txtdot/sdk'; import { HandlerInput, HandlerOutput } from '@txtdot/sdk';
import config from './config'; import config from './config';
import { parseHTML } from 'linkedom'; import { parseHTML } from 'linkedom';
import { html2text } from './utils/html2text'; import { html2text } from './utils/html2text';
import DOMPurify from 'isomorphic-dompurify';
interface IEngineId { interface IEngineId {
[key: string]: number; [key: string]: number;
@ -18,14 +18,25 @@ interface IEngineId {
export class Distributor { export class Distributor {
engines_id: IEngineId = {}; engines_id: IEngineId = {};
fallback: Engine[] = []; engines_fallback: Engine[] = [];
list: string[] = []; engines_list: string[] = [];
middles_id: IEngineId = {};
middles_fallback: Middleware[] = [];
middles_list: string[] = [];
constructor() {} constructor() {}
engine(engine: Engine) { engine(engine: Engine) {
this.engines_id[engine.name] = this.list.length; this.engines_id[engine.name] = this.engines_list.length;
this.fallback.push(engine); this.engines_fallback.push(engine);
this.list.push(engine.name); this.engines_list.push(engine.name);
}
middleware(middleware: Middleware) {
this.middles_id[middleware.name] = this.middles_list.length;
this.middles_fallback.push(middleware);
this.middles_list.push(middleware.name);
} }
async handlePage( async handlePage(
@ -52,22 +63,27 @@ export class Distributor {
throw new NotHtmlMimetypeError(); throw new NotHtmlMimetypeError();
} }
const engine = this.getFallbackEngine(urlObj.hostname, engineName); const input = new HandlerInput(
const output = await engine.handle(
new HandlerInput(
await decodeStream(data, parseEncodingName(mime)), await decodeStream(data, parseEncodingName(mime)),
remoteUrl remoteUrl
)
); );
let output = await this.processEngines(urlObj.hostname, input, engineName);
// Sanitize output before middlewares, because middlewares can add unsafe tags
output = {
...output,
content: DOMPurify.sanitize(output.content),
};
output = await this.processMiddlewares(urlObj.hostname, input, output);
const dom = parseHTML(output.content); const dom = parseHTML(output.content);
// Get text content before link replacement, because in text format we need original links // Get text content before link replacement, because in text format we need original links
const stdTextContent = dom.document.documentElement.textContent; const stdTextContent = dom.document.documentElement.textContent;
// post-process // post-process
// TODO: generate dom in handler and not parse here twice
replaceHref( replaceHref(
dom.document, dom.document,
requestUrl, requestUrl,
@ -76,8 +92,6 @@ export class Distributor {
redirectPath redirectPath
); );
const purify = DOMPurify(dom);
const content = purify.sanitize(dom.document.toString());
const title = output.title || dom.document.title; const title = output.title || dom.document.title;
const lang = output.lang || dom.document.documentElement.lang; const lang = output.lang || dom.document.documentElement.lang;
const textContent = const textContent =
@ -85,24 +99,50 @@ export class Distributor {
'Text output cannot be generated.'; 'Text output cannot be generated.';
return { return {
content, content: dom.document.toString(),
textContent, textContent,
title, title,
lang, lang,
}; };
} }
getFallbackEngine(host: string, specified?: string): Engine { async processEngines(
host: string,
input: HandlerInput,
specified?: string
): Promise<EngineOutput> {
if (specified) { if (specified) {
return this.fallback[this.engines_id[specified]]; return await this.engines_fallback[this.engines_id[specified]].handle(
input
);
} }
for (const engine of this.fallback) { for (const engine of this.engines_fallback) {
if (micromatch.isMatch(host, engine.domains)) { if (micromatch.isMatch(host, engine.domains)) {
return engine; try {
return await engine.handle(input);
} catch {
/*Try next engine*/
}
} }
} }
return this.fallback[0]; return await this.engines_fallback[0].handle(input);
}
async processMiddlewares(
host: string,
input: HandlerInput,
output: EngineOutput
): Promise<EngineOutput> {
let processed_output = output;
for (const middle of this.middles_fallback) {
if (micromatch.isMatch(host, middle.domains)) {
processed_output = await middle.handle(input, processed_output);
}
}
return processed_output;
} }
} }

View File

@ -7,5 +7,9 @@ for (const engine of plugin_config.engines) {
distributor.engine(engine); distributor.engine(engine);
} }
export const engineList = distributor.list; for (const middleware of plugin_config.middlewares || []) {
distributor.middleware(middleware);
}
export const engineList = distributor.engines_list;
export { distributor }; export { distributor };

View File

@ -8,7 +8,8 @@ import config from '../../config';
export default async function configurationRoute(fastify: FastifyInstance) { export default async function configurationRoute(fastify: FastifyInstance) {
fastify.get('/configuration', { schema: indexSchema }, async (_, reply) => { fastify.get('/configuration', { schema: indexSchema }, async (_, reply) => {
return reply.view('/templates/configuration.ejs', { return reply.view('/templates/configuration.ejs', {
engines: distributor.fallback, engines: distributor.engines_fallback,
middlewares: distributor.middles_fallback,
config, config,
}); });
}); });

View File

@ -1,4 +1,4 @@
import { Engine } from '@txtdot/sdk'; import { Engine, Middleware } from '@txtdot/sdk';
type Html2TextConverter = (html: string) => string; type Html2TextConverter = (html: string) => string;
@ -7,6 +7,10 @@ export interface IAppConfig {
* List of engines, ordered * List of engines, ordered
*/ */
engines: Engine[]; engines: Engine[];
/**
* List of middlewares, ordered
*/
middlewares?: Middleware[];
/** /**
* HTML to text converter, if engine doesn't support text * HTML to text converter, if engine doesn't support text
*/ */

View File

@ -42,6 +42,14 @@
} }
%> %>
</ol> </ol>
<h2>Available middlewares</h2>
<ol>
<%
for (const middleware of middlewares) {
%><li><%= middleware.name %>: <%= middleware.description %></li><%
}
%>
</ol>
<h2>Available routes</h2> <h2>Available routes</h2>
<% <%
for (const route of config.dyn.routes) { for (const route of config.dyn.routes) {

View File

@ -97,9 +97,6 @@ importers:
axios: axios:
specifier: ^1.6.8 specifier: ^1.6.8
version: 1.6.8 version: 1.6.8
dompurify:
specifier: ^3.1.2
version: 3.1.3
dotenv: dotenv:
specifier: ^16.3.1 specifier: ^16.3.1
version: 16.4.5 version: 16.4.5
@ -115,6 +112,9 @@ importers:
ip-range-check: ip-range-check:
specifier: ^0.2.0 specifier: ^0.2.0
version: 0.2.0 version: 0.2.0
isomorphic-dompurify:
specifier: ^2.10.0
version: 2.10.0
json-schema-to-ts: json-schema-to-ts:
specifier: ^3.0.1 specifier: ^3.0.1
version: 3.1.0 version: 3.1.0
@ -128,9 +128,6 @@ importers:
specifier: ^0.33.3 specifier: ^0.33.3
version: 0.33.3 version: 0.33.3
devDependencies: devDependencies:
'@types/dompurify':
specifier: ^3.0.5
version: 3.0.5
'@types/ejs': '@types/ejs':
specifier: ^3.1.5 specifier: ^3.1.5
version: 3.1.5 version: 3.1.5
@ -1149,10 +1146,18 @@ packages:
cssom@0.5.0: cssom@0.5.0:
resolution: {integrity: sha512-iKuQcq+NdHqlAcwUY0o/HL69XQrUaQdMjmStJ8JFmUaiiQErlhrmuigkg/CU4E2J0IyUKUrMAgl36TvN67MqTw==} resolution: {integrity: sha512-iKuQcq+NdHqlAcwUY0o/HL69XQrUaQdMjmStJ8JFmUaiiQErlhrmuigkg/CU4E2J0IyUKUrMAgl36TvN67MqTw==}
cssstyle@4.0.1:
resolution: {integrity: sha512-8ZYiJ3A/3OkDd093CBT/0UKDWry7ak4BdPTFP2+QEP7cmhouyq/Up709ASSj2cK02BbZiMgk7kYjZNS4QP5qrQ==}
engines: {node: '>=18'}
dargs@7.0.0: dargs@7.0.0:
resolution: {integrity: sha512-2iy1EkLdlBzQGvbweYRFxmFath8+K7+AKB0TlhHWkNuH+TmovaMH/Wp7V7R4u7f4SnX3OgLsU9t1NI9ioDnUpg==} resolution: {integrity: sha512-2iy1EkLdlBzQGvbweYRFxmFath8+K7+AKB0TlhHWkNuH+TmovaMH/Wp7V7R4u7f4SnX3OgLsU9t1NI9ioDnUpg==}
engines: {node: '>=8'} engines: {node: '>=8'}
data-urls@5.0.0:
resolution: {integrity: sha512-ZYP5VBHshaDAiVZxjbRVcFJpc+4xGgT0bK3vzy1HLN8jTO975HEbuYzZJcHoQEY5K1a0z8YayJkyVETa08eNTg==}
engines: {node: '>=18'}
dateformat@3.0.3: dateformat@3.0.3:
resolution: {integrity: sha512-jyCETtSl3VMZMWeRo7iY1FL19ges1t55hMo5yaam4Jrsm5EPL89UQkoQRyiI+Yf4k8r2ZpdngkV8hr1lIdjb3Q==} resolution: {integrity: sha512-jyCETtSl3VMZMWeRo7iY1FL19ges1t55hMo5yaam4Jrsm5EPL89UQkoQRyiI+Yf4k8r2ZpdngkV8hr1lIdjb3Q==}
@ -1176,6 +1181,9 @@ packages:
resolution: {integrity: sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==} resolution: {integrity: sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==}
engines: {node: '>=0.10.0'} engines: {node: '>=0.10.0'}
decimal.js@10.4.3:
resolution: {integrity: sha512-VBBaLc1MgL5XpzgIP7ny5Z6Nx3UrRkIViUkPUdtl9aya5amy3De1gsUUSB1g3+3sExYNjCAsAznmukyxCb1GRA==}
dedent@0.7.0: dedent@0.7.0:
resolution: {integrity: sha512-Q6fKUPqnAHAyhiUgFU7BUzLiv0kd8saH9al7tnu5Q/okj6dnupxyTgFIBjVzJATdfIAm9NAsvXNzjaKa+bxVyA==} resolution: {integrity: sha512-Q6fKUPqnAHAyhiUgFU7BUzLiv0kd8saH9al7tnu5Q/okj6dnupxyTgFIBjVzJATdfIAm9NAsvXNzjaKa+bxVyA==}
@ -1650,6 +1658,10 @@ packages:
resolution: {integrity: sha512-puUZAUKT5m8Zzvs72XWy3HtvVbTWljRE66cP60bxJzAqf2DgICo7lYTY2IHUmLnNpjYvw5bvmoHvPc0QO2a62w==} resolution: {integrity: sha512-puUZAUKT5m8Zzvs72XWy3HtvVbTWljRE66cP60bxJzAqf2DgICo7lYTY2IHUmLnNpjYvw5bvmoHvPc0QO2a62w==}
engines: {node: ^16.14.0 || >=18.0.0} engines: {node: ^16.14.0 || >=18.0.0}
html-encoding-sniffer@4.0.0:
resolution: {integrity: sha512-Y22oTqIU4uuPgEemfz7NDJz6OeKf12Lsu+QC+s3BVpda64lTiMYCyGwg5ki4vFxkMwQdeZDl2adZoqUgdFuTgQ==}
engines: {node: '>=18'}
html-escaper@3.0.3: html-escaper@3.0.3:
resolution: {integrity: sha512-RuMffC89BOWQoY0WKGpIhn5gX3iI54O6nRA0yC124NYVtzjmFWBIiFd8M0x+ZdX0P9R4lADg1mgP8C7PxGOWuQ==} resolution: {integrity: sha512-RuMffC89BOWQoY0WKGpIhn5gX3iI54O6nRA0yC124NYVtzjmFWBIiFd8M0x+ZdX0P9R4lADg1mgP8C7PxGOWuQ==}
@ -1826,6 +1838,9 @@ packages:
resolution: {integrity: sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==} resolution: {integrity: sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==}
engines: {node: '>=0.10.0'} engines: {node: '>=0.10.0'}
is-potential-custom-element-name@1.0.1:
resolution: {integrity: sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==}
is-ssh@1.4.0: is-ssh@1.4.0:
resolution: {integrity: sha512-x7+VxdxOdlV3CYpjvRLBv5Lo9OJerlYanjwFrPR9fuGPjCiNiCzFgAWpiLAohSbsnH4ZAys3SBh+hq5rJosxUQ==} resolution: {integrity: sha512-x7+VxdxOdlV3CYpjvRLBv5Lo9OJerlYanjwFrPR9fuGPjCiNiCzFgAWpiLAohSbsnH4ZAys3SBh+hq5rJosxUQ==}
@ -1862,6 +1877,10 @@ packages:
resolution: {integrity: sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==} resolution: {integrity: sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==}
engines: {node: '>=0.10.0'} engines: {node: '>=0.10.0'}
isomorphic-dompurify@2.10.0:
resolution: {integrity: sha512-rqWVh1tZtHL4NsSn+bifrxhZ0CqNNShGEkV+m2SFLL3d4D4jcIbkSVMva5Eep50uCxiCCNJmCLGbuAWY/QoNcQ==}
engines: {node: '>=18'}
jackspeak@2.3.6: jackspeak@2.3.6:
resolution: {integrity: sha512-N3yCS/NegsOBokc8GAdM8UcmfsKiSS8cipheD/nivzr700H+nsMOxJjQnvwOcRYVuFkdH0wGUvW2WbXGmrZGbQ==} resolution: {integrity: sha512-N3yCS/NegsOBokc8GAdM8UcmfsKiSS8cipheD/nivzr700H+nsMOxJjQnvwOcRYVuFkdH0wGUvW2WbXGmrZGbQ==}
engines: {node: '>=14'} engines: {node: '>=14'}
@ -1897,6 +1916,15 @@ packages:
jsbn@1.1.0: jsbn@1.1.0:
resolution: {integrity: sha512-4bYVV3aAMtDTTu4+xsDYa6sy9GyJ69/amsu9sYF2zqjiEoZA5xJi3BrfX3uY+/IekIu7MwdObdbDWpoZdBv3/A==} resolution: {integrity: sha512-4bYVV3aAMtDTTu4+xsDYa6sy9GyJ69/amsu9sYF2zqjiEoZA5xJi3BrfX3uY+/IekIu7MwdObdbDWpoZdBv3/A==}
jsdom@24.0.0:
resolution: {integrity: sha512-UDS2NayCvmXSXVP6mpTj+73JnNQadZlr9N68189xib2tx5Mls7swlTNao26IoHv46BZJFvXygyRtyXd1feAk1A==}
engines: {node: '>=18'}
peerDependencies:
canvas: ^2.11.2
peerDependenciesMeta:
canvas:
optional: true
json-buffer@3.0.1: json-buffer@3.0.1:
resolution: {integrity: sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==} resolution: {integrity: sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==}
@ -2317,6 +2345,9 @@ packages:
nth-check@2.1.1: nth-check@2.1.1:
resolution: {integrity: sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==} resolution: {integrity: sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==}
nwsapi@2.2.10:
resolution: {integrity: sha512-QK0sRs7MKv0tKe1+5uZIQk/C8XGza4DAnztJG8iD+TpJIORARrCxczA738awHrZoHeTjSSoHqao2teO0dC/gFQ==}
nx@18.3.4: nx@18.3.4:
resolution: {integrity: sha512-7rOHRyxpnZGJ3pHnwmpoAMHt9hNuwibWhOhPBJDhJVcbQJtGfwcWWyV/iSEnVXwKZ2lfHVE3TwE+gXFdT/GFiw==} resolution: {integrity: sha512-7rOHRyxpnZGJ3pHnwmpoAMHt9hNuwibWhOhPBJDhJVcbQJtGfwcWWyV/iSEnVXwKZ2lfHVE3TwE+gXFdT/GFiw==}
hasBin: true hasBin: true
@ -2596,6 +2627,9 @@ packages:
engines: {node: '>= 0.10'} engines: {node: '>= 0.10'}
hasBin: true hasBin: true
psl@1.9.0:
resolution: {integrity: sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag==}
pump@3.0.0: pump@3.0.0:
resolution: {integrity: sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==} resolution: {integrity: sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==}
@ -2603,6 +2637,9 @@ packages:
resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==}
engines: {node: '>=6'} engines: {node: '>=6'}
querystringify@2.2.0:
resolution: {integrity: sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==}
queue-microtask@1.2.3: queue-microtask@1.2.3:
resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==}
@ -2693,6 +2730,9 @@ packages:
resolution: {integrity: sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==} resolution: {integrity: sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==}
engines: {node: '>=0.10.0'} engines: {node: '>=0.10.0'}
requires-port@1.0.0:
resolution: {integrity: sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==}
resolve-cwd@3.0.0: resolve-cwd@3.0.0:
resolution: {integrity: sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==} resolution: {integrity: sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==}
engines: {node: '>=8'} engines: {node: '>=8'}
@ -2741,6 +2781,9 @@ packages:
resolution: {integrity: sha512-nsii+MXoNb7NyF05LP9kaktx6AoBVT/7zUgDnzIb5IoYAvYkbZOAuoLJjVdsyEVxWv0swCxWkKDK4cMva+WDBA==} resolution: {integrity: sha512-nsii+MXoNb7NyF05LP9kaktx6AoBVT/7zUgDnzIb5IoYAvYkbZOAuoLJjVdsyEVxWv0swCxWkKDK4cMva+WDBA==}
engines: {node: '>= 0.9'} engines: {node: '>= 0.9'}
rrweb-cssom@0.6.0:
resolution: {integrity: sha512-APM0Gt1KoXBz0iIkkdB/kfvGOwC4UuJFeG/c+yV7wSc7q96cG/kJ0HiYCnzivD9SB53cLV1MlHFNfOuPaadYSw==}
run-async@2.4.1: run-async@2.4.1:
resolution: {integrity: sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ==} resolution: {integrity: sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ==}
engines: {node: '>=0.12.0'} engines: {node: '>=0.12.0'}
@ -2767,6 +2810,10 @@ packages:
safer-buffer@2.1.2: safer-buffer@2.1.2:
resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==} resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==}
saxes@6.0.0:
resolution: {integrity: sha512-xAg7SOnEhrm5zI3puOOKyy1OMcMlIJZYNJY7xLBwSze0UjhPLnWfj2GF2EpT0jmzaJKIWKHLsaSSajf35bcYnA==}
engines: {node: '>=v12.22.7'}
secure-json-parse@2.7.0: secure-json-parse@2.7.0:
resolution: {integrity: sha512-6aU+Rwsezw7VR8/nyvKTx8QpWH9FrcYiXXlqC4z5d5XQBDRqtbfsRjnwGyqbi3gddNtWHuEk9OANUotL26qKUw==} resolution: {integrity: sha512-6aU+Rwsezw7VR8/nyvKTx8QpWH9FrcYiXXlqC4z5d5XQBDRqtbfsRjnwGyqbi3gddNtWHuEk9OANUotL26qKUw==}
@ -2969,6 +3016,9 @@ packages:
resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==} resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==}
engines: {node: '>= 0.4'} engines: {node: '>= 0.4'}
symbol-tree@3.2.4:
resolution: {integrity: sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==}
tar-stream@2.2.0: tar-stream@2.2.0:
resolution: {integrity: sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==} resolution: {integrity: sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==}
engines: {node: '>=6'} engines: {node: '>=6'}
@ -3017,9 +3067,17 @@ packages:
resolution: {integrity: sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==} resolution: {integrity: sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==}
engines: {node: '>=0.6'} engines: {node: '>=0.6'}
tough-cookie@4.1.4:
resolution: {integrity: sha512-Loo5UUvLD9ScZ6jh8beX1T6sO1w2/MpCRpEP7V280GKMVUQ0Jzar2U3UJPsrdbziLEMMhu3Ujnq//rhiFuIeag==}
engines: {node: '>=6'}
tr46@0.0.3: tr46@0.0.3:
resolution: {integrity: sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==} resolution: {integrity: sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==}
tr46@5.0.0:
resolution: {integrity: sha512-tk2G5R2KRwBd+ZN0zaEXpmzdKyOYksXwywulIX95MBODjSzMIuQnQ3m8JxgbhnL1LeVo7lqQKsYa1O3Htl7K5g==}
engines: {node: '>=18'}
trim-newlines@3.0.1: trim-newlines@3.0.1:
resolution: {integrity: sha512-c1PTsA3tYrIsLGkJkzHF+w9F2EyxfXGo4UyJc4pFL++FMjnq0HJS69T3M7d//gKrFKwy429bouPescbjecU+Zw==} resolution: {integrity: sha512-c1PTsA3tYrIsLGkJkzHF+w9F2EyxfXGo4UyJc4pFL++FMjnq0HJS69T3M7d//gKrFKwy429bouPescbjecU+Zw==}
engines: {node: '>=8'} engines: {node: '>=8'}
@ -3113,6 +3171,10 @@ packages:
universal-user-agent@6.0.1: universal-user-agent@6.0.1:
resolution: {integrity: sha512-yCzhz6FN2wU1NiiQRogkTQszlQSlpWaw8SvVegAc+bDxbzHgh1vX8uIe8OYyMH6DwH+sdTJsgMl36+mSMdRJIQ==} resolution: {integrity: sha512-yCzhz6FN2wU1NiiQRogkTQszlQSlpWaw8SvVegAc+bDxbzHgh1vX8uIe8OYyMH6DwH+sdTJsgMl36+mSMdRJIQ==}
universalify@0.2.0:
resolution: {integrity: sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg==}
engines: {node: '>= 4.0.0'}
universalify@2.0.1: universalify@2.0.1:
resolution: {integrity: sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==} resolution: {integrity: sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==}
engines: {node: '>= 10.0.0'} engines: {node: '>= 10.0.0'}
@ -3128,6 +3190,9 @@ packages:
uri-js@4.4.1: uri-js@4.4.1:
resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==}
url-parse@1.5.10:
resolution: {integrity: sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==}
util-deprecate@1.0.2: util-deprecate@1.0.2:
resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==}
@ -3145,12 +3210,32 @@ packages:
resolution: {integrity: sha512-YuKoXDAhBYxY7SfOKxHBDoSyENFeW5VvIIQp2TGQuit8gpK6MnWaQelBKxso72DoxTZfZdcP3W90LqpSkgPzLQ==} resolution: {integrity: sha512-YuKoXDAhBYxY7SfOKxHBDoSyENFeW5VvIIQp2TGQuit8gpK6MnWaQelBKxso72DoxTZfZdcP3W90LqpSkgPzLQ==}
engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0}
w3c-xmlserializer@5.0.0:
resolution: {integrity: sha512-o8qghlI8NZHU1lLPrpi2+Uq7abh4GGPpYANlalzWxyWteJOCsr/P+oPBA49TOLu5FTZO4d3F9MnWJfiMo4BkmA==}
engines: {node: '>=18'}
wcwidth@1.0.1: wcwidth@1.0.1:
resolution: {integrity: sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg==} resolution: {integrity: sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg==}
webidl-conversions@3.0.1: webidl-conversions@3.0.1:
resolution: {integrity: sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==} resolution: {integrity: sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==}
webidl-conversions@7.0.0:
resolution: {integrity: sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==}
engines: {node: '>=12'}
whatwg-encoding@3.1.1:
resolution: {integrity: sha512-6qN4hJdMwfYBtE3YBTTHhoeuUrDBPZmbQaxWAqSALV/MeEnR5z1xd8UKud2RAkFoPkmB+hli1TZSnyi84xz1vQ==}
engines: {node: '>=18'}
whatwg-mimetype@4.0.0:
resolution: {integrity: sha512-QaKxh0eNIi2mE9p2vEdzfagOKHCcj1pJ56EEHGQOVxp8r9/iszLUUV7v89x9O1p/T+NlTM5W7jW6+cz4Fq1YVg==}
engines: {node: '>=18'}
whatwg-url@14.0.0:
resolution: {integrity: sha512-1lfMEm2IEr7RIV+f4lUNPOqfFL+pO+Xw3fJSqmjX9AbXcXcYOkCe1P6+9VBZB6n94af16NfZf+sSk0JCBZC9aw==}
engines: {node: '>=18'}
whatwg-url@5.0.0: whatwg-url@5.0.0:
resolution: {integrity: sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==} resolution: {integrity: sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==}
@ -3204,6 +3289,25 @@ packages:
resolution: {integrity: sha512-v2UQ+50TNf2rNHJ8NyWttfm/EJUBWMJcx6ZTYZr6Qp52uuegWw/lBkCtCbnYZEmPRNL61m+u67dAmGxo+HTULA==} resolution: {integrity: sha512-v2UQ+50TNf2rNHJ8NyWttfm/EJUBWMJcx6ZTYZr6Qp52uuegWw/lBkCtCbnYZEmPRNL61m+u67dAmGxo+HTULA==}
engines: {node: '>=8'} engines: {node: '>=8'}
ws@8.17.0:
resolution: {integrity: sha512-uJq6108EgZMAl20KagGkzCKfMEjxmKvZHG7Tlq0Z6nOky7YF7aq4mOx6xK8TJ/i1LeK4Qus7INktacctDgY8Ow==}
engines: {node: '>=10.0.0'}
peerDependencies:
bufferutil: ^4.0.1
utf-8-validate: '>=5.0.2'
peerDependenciesMeta:
bufferutil:
optional: true
utf-8-validate:
optional: true
xml-name-validator@5.0.0:
resolution: {integrity: sha512-EvGK8EJ3DhaHfbRlETOWAS5pO9MZITeauHKJyb8wyajUfQUenkIg2MvLDTZ4T/TgIcm3HU0TFBgWWboAZ30UHg==}
engines: {node: '>=18'}
xmlchars@2.2.0:
resolution: {integrity: sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==}
xtend@4.0.2: xtend@4.0.2:
resolution: {integrity: sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==} resolution: {integrity: sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==}
engines: {node: '>=0.4'} engines: {node: '>=0.4'}
@ -4408,8 +4512,17 @@ snapshots:
cssom@0.5.0: {} cssom@0.5.0: {}
cssstyle@4.0.1:
dependencies:
rrweb-cssom: 0.6.0
dargs@7.0.0: {} dargs@7.0.0: {}
data-urls@5.0.0:
dependencies:
whatwg-mimetype: 4.0.0
whatwg-url: 14.0.0
dateformat@3.0.3: {} dateformat@3.0.3: {}
dateformat@4.6.3: {} dateformat@4.6.3: {}
@ -4425,6 +4538,8 @@ snapshots:
decamelize@1.2.0: {} decamelize@1.2.0: {}
decimal.js@10.4.3: {}
dedent@0.7.0: {} dedent@0.7.0: {}
deep-is@0.1.4: {} deep-is@0.1.4: {}
@ -4944,6 +5059,10 @@ snapshots:
dependencies: dependencies:
lru-cache: 10.2.2 lru-cache: 10.2.2
html-encoding-sniffer@4.0.0:
dependencies:
whatwg-encoding: 3.1.1
html-escaper@3.0.3: {} html-escaper@3.0.3: {}
html-to-text@9.0.5: html-to-text@9.0.5:
@ -5139,6 +5258,8 @@ snapshots:
is-plain-object@5.0.0: {} is-plain-object@5.0.0: {}
is-potential-custom-element-name@1.0.1: {}
is-ssh@1.4.0: is-ssh@1.4.0:
dependencies: dependencies:
protocols: 2.0.1 protocols: 2.0.1
@ -5165,6 +5286,17 @@ snapshots:
isobject@3.0.1: {} isobject@3.0.1: {}
isomorphic-dompurify@2.10.0:
dependencies:
'@types/dompurify': 3.0.5
dompurify: 3.1.3
jsdom: 24.0.0
transitivePeerDependencies:
- bufferutil
- canvas
- supports-color
- utf-8-validate
jackspeak@2.3.6: jackspeak@2.3.6:
dependencies: dependencies:
'@isaacs/cliui': 8.0.2 '@isaacs/cliui': 8.0.2
@ -5202,6 +5334,34 @@ snapshots:
jsbn@1.1.0: {} jsbn@1.1.0: {}
jsdom@24.0.0:
dependencies:
cssstyle: 4.0.1
data-urls: 5.0.0
decimal.js: 10.4.3
form-data: 4.0.0
html-encoding-sniffer: 4.0.0
http-proxy-agent: 7.0.2
https-proxy-agent: 7.0.4
is-potential-custom-element-name: 1.0.1
nwsapi: 2.2.10
parse5: 7.1.2
rrweb-cssom: 0.6.0
saxes: 6.0.0
symbol-tree: 3.2.4
tough-cookie: 4.1.4
w3c-xmlserializer: 5.0.0
webidl-conversions: 7.0.0
whatwg-encoding: 3.1.1
whatwg-mimetype: 4.0.0
whatwg-url: 14.0.0
ws: 8.17.0
xml-name-validator: 5.0.0
transitivePeerDependencies:
- bufferutil
- supports-color
- utf-8-validate
json-buffer@3.0.1: {} json-buffer@3.0.1: {}
json-parse-better-errors@1.0.2: {} json-parse-better-errors@1.0.2: {}
@ -5779,6 +5939,8 @@ snapshots:
dependencies: dependencies:
boolbase: 1.0.0 boolbase: 1.0.0
nwsapi@2.2.10: {}
nx@18.3.4: nx@18.3.4:
dependencies: dependencies:
'@nrwl/tao': 18.3.4 '@nrwl/tao': 18.3.4
@ -6116,6 +6278,8 @@ snapshots:
dependencies: dependencies:
event-stream: 3.3.4 event-stream: 3.3.4
psl@1.9.0: {}
pump@3.0.0: pump@3.0.0:
dependencies: dependencies:
end-of-stream: 1.4.4 end-of-stream: 1.4.4
@ -6123,6 +6287,8 @@ snapshots:
punycode@2.3.1: {} punycode@2.3.1: {}
querystringify@2.2.0: {}
queue-microtask@1.2.3: {} queue-microtask@1.2.3: {}
quick-format-unescaped@4.0.4: {} quick-format-unescaped@4.0.4: {}
@ -6232,6 +6398,8 @@ snapshots:
require-from-string@2.0.2: {} require-from-string@2.0.2: {}
requires-port@1.0.0: {}
resolve-cwd@3.0.0: resolve-cwd@3.0.0:
dependencies: dependencies:
resolve-from: 5.0.0 resolve-from: 5.0.0
@ -6269,6 +6437,8 @@ snapshots:
route-parser@0.0.5: {} route-parser@0.0.5: {}
rrweb-cssom@0.6.0: {}
run-async@2.4.1: {} run-async@2.4.1: {}
run-parallel@1.2.0: run-parallel@1.2.0:
@ -6291,6 +6461,10 @@ snapshots:
safer-buffer@2.1.2: {} safer-buffer@2.1.2: {}
saxes@6.0.0:
dependencies:
xmlchars: 2.2.0
secure-json-parse@2.7.0: {} secure-json-parse@2.7.0: {}
selderee@0.11.0: selderee@0.11.0:
@ -6513,6 +6687,8 @@ snapshots:
supports-preserve-symlinks-flag@1.0.0: {} supports-preserve-symlinks-flag@1.0.0: {}
symbol-tree@3.2.4: {}
tar-stream@2.2.0: tar-stream@2.2.0:
dependencies: dependencies:
bl: 4.1.0 bl: 4.1.0
@ -6561,8 +6737,19 @@ snapshots:
toidentifier@1.0.1: {} toidentifier@1.0.1: {}
tough-cookie@4.1.4:
dependencies:
psl: 1.9.0
punycode: 2.3.1
universalify: 0.2.0
url-parse: 1.5.10
tr46@0.0.3: {} tr46@0.0.3: {}
tr46@5.0.0:
dependencies:
punycode: 2.3.1
trim-newlines@3.0.1: {} trim-newlines@3.0.1: {}
ts-algebra@2.0.0: {} ts-algebra@2.0.0: {}
@ -6640,6 +6827,8 @@ snapshots:
universal-user-agent@6.0.1: {} universal-user-agent@6.0.1: {}
universalify@0.2.0: {}
universalify@2.0.1: {} universalify@2.0.1: {}
untildify@4.0.0: {} untildify@4.0.0: {}
@ -6650,6 +6839,11 @@ snapshots:
dependencies: dependencies:
punycode: 2.3.1 punycode: 2.3.1
url-parse@1.5.10:
dependencies:
querystringify: 2.2.0
requires-port: 1.0.0
util-deprecate@1.0.2: {} util-deprecate@1.0.2: {}
uuid@9.0.1: {} uuid@9.0.1: {}
@ -6667,12 +6861,29 @@ snapshots:
dependencies: dependencies:
builtins: 5.1.0 builtins: 5.1.0
w3c-xmlserializer@5.0.0:
dependencies:
xml-name-validator: 5.0.0
wcwidth@1.0.1: wcwidth@1.0.1:
dependencies: dependencies:
defaults: 1.0.4 defaults: 1.0.4
webidl-conversions@3.0.1: {} webidl-conversions@3.0.1: {}
webidl-conversions@7.0.0: {}
whatwg-encoding@3.1.1:
dependencies:
iconv-lite: 0.6.3
whatwg-mimetype@4.0.0: {}
whatwg-url@14.0.0:
dependencies:
tr46: 5.0.0
webidl-conversions: 7.0.0
whatwg-url@5.0.0: whatwg-url@5.0.0:
dependencies: dependencies:
tr46: 0.0.3 tr46: 0.0.3
@ -6740,6 +6951,12 @@ snapshots:
type-fest: 0.4.1 type-fest: 0.4.1
write-json-file: 3.2.0 write-json-file: 3.2.0
ws@8.17.0: {}
xml-name-validator@5.0.0: {}
xmlchars@2.2.0: {}
xtend@4.0.2: {} xtend@4.0.2: {}
y18n@5.0.8: {} y18n@5.0.8: {}