diff --git a/app/android/app/src/main/AndroidManifest.xml b/app/android/app/src/main/AndroidManifest.xml index ef7a5d7d..9811d4d2 100644 --- a/app/android/app/src/main/AndroidManifest.xml +++ b/app/android/app/src/main/AndroidManifest.xml @@ -49,6 +49,7 @@ android:launchMode="singleTask" android:taskAffinity="" android:theme="@style/LaunchTheme" + android:supportsPictureInPicture="true" android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode" android:hardwareAccelerated="true" android:windowSoftInputMode="adjustResize"> diff --git a/app/js/readability/dist/readability.min.js b/app/js/readability/dist/readability.min.js deleted file mode 100644 index 669dad5f..00000000 --- a/app/js/readability/dist/readability.min.js +++ /dev/null @@ -1,3 +0,0 @@ -!function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t():"function"==typeof define&&define.amd?define([],t):"object"==typeof exports?exports.ReadabilityBundle=t():e.ReadabilityBundle=t()}(this,(()=>(()=>{var e={804:e=>{var t={unlikelyCandidates:/-ad-|ai2html|banner|breadcrumbs|combx|comment|community|cover-wrap|disqus|extra|footer|gdpr|header|legends|menu|related|remark|replies|rss|shoutbox|sidebar|skyscraper|social|sponsor|supplemental|ad-break|agegate|pagination|pager|popup|yom-remote/i,okMaybeItsACandidate:/and|article|body|column|content|main|shadow/i};function i(e){return(!e.style||"none"!=e.style.display)&&!e.hasAttribute("hidden")&&(!e.hasAttribute("aria-hidden")||"true"!=e.getAttribute("aria-hidden")||e.className&&e.className.indexOf&&-1!==e.className.indexOf("fallback-image"))}e.exports=function(e,n={}){"function"==typeof n&&(n={visibilityChecker:n});var r={minScore:20,minContentLength:140,visibilityChecker:i};n=Object.assign(r,n);var a=e.querySelectorAll("p, pre, article"),o=e.querySelectorAll("div > br");if(o.length){var s=new Set(a);[].forEach.call(o,(function(e){s.add(e.parentNode)})),a=Array.from(s)}var l=0;return[].some.call(a,(function(e){if(!n.visibilityChecker(e))return!1;var i=e.className+" "+e.id;if(t.unlikelyCandidates.test(i)&&!t.okMaybeItsACandidate.test(i))return!1;if(e.matches("li p"))return!1;var r=e.textContent.trim().length;return!(rn.minScore}))}},238:e=>{function t(e,t){if(t&&t.documentElement)e=t,t=arguments[2];else if(!e||!e.documentElement)throw new Error("First argument to Readability constructor should be a document object.");if(t=t||{},this._doc=e,this._docJSDOMParser=this._doc.firstChild.__JSDOMParser__,this._articleTitle=null,this._articleByline=null,this._articleDir=null,this._articleSiteName=null,this._attempts=[],this._debug=!!t.debug,this._maxElemsToParse=t.maxElemsToParse||this.DEFAULT_MAX_ELEMS_TO_PARSE,this._nbTopCandidates=t.nbTopCandidates||this.DEFAULT_N_TOP_CANDIDATES,this._charThreshold=t.charThreshold||this.DEFAULT_CHAR_THRESHOLD,this._classesToPreserve=this.CLASSES_TO_PRESERVE.concat(t.classesToPreserve||[]),this._keepClasses=!!t.keepClasses,this._serializer=t.serializer||function(e){return e.innerHTML},this._disableJSONLD=!!t.disableJSONLD,this._allowedVideoRegex=t.allowedVideoRegex||this.REGEXPS.videos,this._flags=this.FLAG_STRIP_UNLIKELYS|this.FLAG_WEIGHT_CLASSES|this.FLAG_CLEAN_CONDITIONALLY,this._debug){let e=function(e){if(e.nodeType==e.TEXT_NODE)return`${e.nodeName} ("${e.textContent}")`;let t=Array.from(e.attributes||[],(function(e){return`${e.name}="${e.value}"`})).join(" ");return`<${e.localName} ${t}>`};this.log=function(){if("undefined"!=typeof console){let t=Array.from(arguments,(t=>t&&t.nodeType==this.ELEMENT_NODE?e(t):t));t.unshift("Reader: (Readability)"),console.log.apply(console,t)}else if("undefined"!=typeof dump){var t=Array.prototype.map.call(arguments,(function(t){return t&&t.nodeName?e(t):t})).join(" ");dump("Reader: (Readability) "+t+"\n")}}}else this.log=function(){}}t.prototype={FLAG_STRIP_UNLIKELYS:1,FLAG_WEIGHT_CLASSES:2,FLAG_CLEAN_CONDITIONALLY:4,ELEMENT_NODE:1,TEXT_NODE:3,DEFAULT_MAX_ELEMS_TO_PARSE:0,DEFAULT_N_TOP_CANDIDATES:5,DEFAULT_TAGS_TO_SCORE:"section,h2,h3,h4,h5,h6,p,td,pre".toUpperCase().split(","),DEFAULT_CHAR_THRESHOLD:500,REGEXPS:{unlikelyCandidates:/-ad-|ai2html|banner|breadcrumbs|combx|comment|community|cover-wrap|disqus|extra|footer|gdpr|header|legends|menu|related|remark|replies|rss|shoutbox|sidebar|skyscraper|social|sponsor|supplemental|ad-break|agegate|pagination|pager|popup|yom-remote/i,okMaybeItsACandidate:/and|article|body|column|content|main|shadow/i,positive:/article|body|content|entry|hentry|h-entry|main|page|pagination|post|text|blog|story/i,negative:/-ad-|hidden|^hid$| hid$| hid |^hid |banner|combx|comment|com-|contact|foot|footer|footnote|gdpr|masthead|media|meta|outbrain|promo|related|scroll|share|shoutbox|sidebar|skyscraper|sponsor|shopping|tags|tool|widget/i,extraneous:/print|archive|comment|discuss|e[\-]?mail|share|reply|all|login|sign|single|utility/i,byline:/byline|author|dateline|writtenby|p-author/i,replaceFonts:/<(\/?)font[^>]*>/gi,normalize:/\s{2,}/g,videos:/\/\/(www\.)?((dailymotion|youtube|youtube-nocookie|player\.vimeo|v\.qq)\.com|(archive|upload\.wikimedia)\.org|player\.twitch\.tv)/i,shareElements:/(\b|_)(share|sharedaddy)(\b|_)/i,nextLink:/(next|weiter|continue|>([^\|]|$)|»([^\|]|$))/i,prevLink:/(prev|earl|old|new|<|«)/i,tokenize:/\W+/g,whitespace:/^\s*$/,hasContent:/\S$/,hashUrl:/^#.+/,srcsetUrl:/(\S+)(\s+[\d.]+[xw])?(\s*(?:,|$))/g,b64DataUrl:/^data:\s*([^\s;,]+)\s*;\s*base64\s*,/i,commas:/\u002C|\u060C|\uFE50|\uFE10|\uFE11|\u2E41|\u2E34|\u2E32|\uFF0C/g,jsonLdArticleTypes:/^Article|AdvertiserContentArticle|NewsArticle|AnalysisNewsArticle|AskPublicNewsArticle|BackgroundNewsArticle|OpinionNewsArticle|ReportageNewsArticle|ReviewNewsArticle|Report|SatiricalArticle|ScholarlyArticle|MedicalScholarlyArticle|SocialMediaPosting|BlogPosting|LiveBlogPosting|DiscussionForumPosting|TechArticle|APIReference$/},UNLIKELY_ROLES:["menu","menubar","complementary","navigation","alert","alertdialog","dialog"],DIV_TO_P_ELEMS:new Set(["BLOCKQUOTE","DL","DIV","IMG","OL","P","PRE","TABLE","UL"]),ALTER_TO_DIV_EXCEPTIONS:["DIV","ARTICLE","SECTION","P"],PRESENTATIONAL_ATTRIBUTES:["align","background","bgcolor","border","cellpadding","cellspacing","frame","hspace","rules","style","valign","vspace"],DEPRECATED_SIZE_ATTRIBUTE_ELEMS:["TABLE","TH","TD","HR","PRE"],PHRASING_ELEMS:["ABBR","AUDIO","B","BDO","BR","BUTTON","CITE","CODE","DATA","DATALIST","DFN","EM","EMBED","I","IMG","INPUT","KBD","LABEL","MARK","MATH","METER","NOSCRIPT","OBJECT","OUTPUT","PROGRESS","Q","RUBY","SAMP","SCRIPT","SELECT","SMALL","SPAN","STRONG","SUB","SUP","TEXTAREA","TIME","VAR","WBR"],CLASSES_TO_PRESERVE:["page"],HTML_ESCAPE_MAP:{lt:"<",gt:">",amp:"&",quot:'"',apos:"'"},_postProcessContent:function(e){this._fixRelativeUris(e),this._simplifyNestedElements(e),this._keepClasses||this._cleanClasses(e)},_removeNodes:function(e,t){if(this._docJSDOMParser&&e._isLiveNodeList)throw new Error("Do not pass live node lists to _removeNodes");for(var i=e.length-1;i>=0;i--){var n=e[i],r=n.parentNode;r&&(t&&!t.call(this,n,i,e)||r.removeChild(n))}},_replaceNodeTags:function(e,t){if(this._docJSDOMParser&&e._isLiveNodeList)throw new Error("Do not pass live node lists to _replaceNodeTags");for(const i of e)this._setNodeTag(i,t)},_forEachNode:function(e,t){Array.prototype.forEach.call(e,t,this)},_findNode:function(e,t){return Array.prototype.find.call(e,t,this)},_someNode:function(e,t){return Array.prototype.some.call(e,t,this)},_everyNode:function(e,t){return Array.prototype.every.call(e,t,this)},_concatNodeLists:function(){var e=Array.prototype.slice,t=e.call(arguments).map((function(t){return e.call(t)}));return Array.prototype.concat.apply([],t)},_getAllNodesWithTag:function(e,t){return e.querySelectorAll?e.querySelectorAll(t.join(",")):[].concat.apply([],t.map((function(t){var i=e.getElementsByTagName(t);return Array.isArray(i)?i:Array.from(i)})))},_cleanClasses:function(e){var t=this._classesToPreserve,i=(e.getAttribute("class")||"").split(/\s+/).filter((function(e){return-1!=t.indexOf(e)})).join(" ");for(i?e.setAttribute("class",i):e.removeAttribute("class"),e=e.firstElementChild;e;e=e.nextElementSibling)this._cleanClasses(e)},_fixRelativeUris:function(e){var t=this._doc.baseURI,i=this._doc.documentURI;function n(e){if(t==i&&"#"==e.charAt(0))return e;try{return new URL(e,t).href}catch(e){}return e}var r=this._getAllNodesWithTag(e,["a"]);this._forEachNode(r,(function(e){var t=e.getAttribute("href");if(t)if(0===t.indexOf("javascript:"))if(1===e.childNodes.length&&e.childNodes[0].nodeType===this.TEXT_NODE){var i=this._doc.createTextNode(e.textContent);e.parentNode.replaceChild(i,e)}else{for(var r=this._doc.createElement("span");e.firstChild;)r.appendChild(e.firstChild);e.parentNode.replaceChild(r,e)}else e.setAttribute("href",n(t))}));var a=this._getAllNodesWithTag(e,["img","picture","figure","video","audio","source"]);this._forEachNode(a,(function(e){var t=e.getAttribute("src"),i=e.getAttribute("poster"),r=e.getAttribute("srcset");if(t&&e.setAttribute("src",n(t)),i&&e.setAttribute("poster",n(i)),r){var a=r.replace(this.REGEXPS.srcsetUrl,(function(e,t,i,r){return n(t)+(i||"")+r}));e.setAttribute("srcset",a)}}))},_simplifyNestedElements:function(e){for(var t=e;t;){if(t.parentNode&&["DIV","SECTION"].includes(t.tagName)&&(!t.id||!t.id.startsWith("readability"))){if(this._isElementWithoutContent(t)){t=this._removeAndGetNext(t);continue}if(this._hasSingleTagInsideElement(t,"DIV")||this._hasSingleTagInsideElement(t,"SECTION")){for(var i=t.children[0],n=0;n»] /.test(t))n=/ [\\\/>»] /.test(t),r(t=i.replace(/(.*)[\|\-\\\/>»] .*/gi,"$1"))<3&&(t=i.replace(/[^\|\-\\\/>»]*[\|\-\\\/>»](.*)/gi,"$1"));else if(-1!==t.indexOf(": ")){var a=this._concatNodeLists(e.getElementsByTagName("h1"),e.getElementsByTagName("h2")),o=t.trim();this._someNode(a,(function(e){return e.textContent.trim()===o}))||(r(t=i.substring(i.lastIndexOf(":")+1))<3?t=i.substring(i.indexOf(":")+1):r(i.substr(0,i.indexOf(":")))>5&&(t=i))}else if(t.length>150||t.length<15){var s=e.getElementsByTagName("h1");1===s.length&&(t=this._getInnerText(s[0]))}var l=r(t=t.trim().replace(this.REGEXPS.normalize," "));return l<=4&&(!n||l!=r(i.replace(/[\|\-\\\/>»]+/g,""))-1)&&(t=i),t},_prepDocument:function(){var e=this._doc;this._removeNodes(this._getAllNodesWithTag(e,["style"])),e.body&&this._replaceBrs(e.body),this._replaceNodeTags(this._getAllNodesWithTag(e,["font"]),"SPAN")},_nextNode:function(e){for(var t=e;t&&t.nodeType!=this.ELEMENT_NODE&&this.REGEXPS.whitespace.test(t.textContent);)t=t.nextSibling;return t},_replaceBrs:function(e){this._forEachNode(this._getAllNodesWithTag(e,["br"]),(function(e){for(var t=e.nextSibling,i=!1;(t=this._nextNode(t))&&"BR"==t.tagName;){i=!0;var n=t.nextSibling;t.parentNode.removeChild(t),t=n}if(i){var r=this._doc.createElement("p");for(e.parentNode.replaceChild(r,e),t=r.nextSibling;t;){if("BR"==t.tagName){var a=this._nextNode(t.nextSibling);if(a&&"BR"==a.tagName)break}if(!this._isPhrasingContent(t))break;var o=t.nextSibling;r.appendChild(t),t=o}for(;r.lastChild&&this._isWhitespace(r.lastChild);)r.removeChild(r.lastChild);"P"===r.parentNode.tagName&&this._setNodeTag(r.parentNode,"DIV")}}))},_setNodeTag:function(e,t){if(this.log("_setNodeTag",e,t),this._docJSDOMParser)return e.localName=t.toLowerCase(),e.tagName=t.toUpperCase(),e;for(var i=e.ownerDocument.createElement(t);e.firstChild;)i.appendChild(e.firstChild);e.parentNode.replaceChild(i,e),e.readability&&(i.readability=e.readability);for(var n=0;n!i.includes(e))).join(" ").length/n.join(" ").length:0},_checkByline:function(e,t){if(this._articleByline)return!1;if(void 0!==e.getAttribute)var i=e.getAttribute("rel"),n=e.getAttribute("itemprop");return!(!("author"===i||n&&-1!==n.indexOf("author")||this.REGEXPS.byline.test(t))||!this._isValidByline(e.textContent))&&(this._articleByline=e.textContent.trim(),!0)},_getNodeAncestors:function(e,t){t=t||0;for(var i=0,n=[];e.parentNode&&(n.push(e.parentNode),!t||++i!==t);)e=e.parentNode;return n},_grabArticle:function(e){this.log("**** grabArticle ****");var t=this._doc,i=null!==e;if(!(e=e||this._doc.body))return this.log("No body found in document. Abort."),null;for(var n=e.innerHTML;;){this.log("Starting grabArticle loop");var r=this._flagIsActive(this.FLAG_STRIP_UNLIKELYS),a=[],o=this._doc.documentElement;let X=!0;for(;o;){"HTML"===o.tagName&&(this._articleLang=o.getAttribute("lang"));var s=o.className+" "+o.id;if(this._isProbablyVisible(o))if("true"!=o.getAttribute("aria-modal")||"dialog"!=o.getAttribute("role"))if(this._checkByline(o,s))o=this._removeAndGetNext(o);else if(X&&this._headerDuplicatesTitle(o))this.log("Removing header: ",o.textContent.trim(),this._articleTitle.trim()),X=!1,o=this._removeAndGetNext(o);else{if(r){if(this.REGEXPS.unlikelyCandidates.test(s)&&!this.REGEXPS.okMaybeItsACandidate.test(s)&&!this._hasAncestorTag(o,"table")&&!this._hasAncestorTag(o,"code")&&"BODY"!==o.tagName&&"A"!==o.tagName){this.log("Removing unlikely candidate - "+s),o=this._removeAndGetNext(o);continue}if(this.UNLIKELY_ROLES.includes(o.getAttribute("role"))){this.log("Removing content with role "+o.getAttribute("role")+" - "+s),o=this._removeAndGetNext(o);continue}}if("DIV"!==o.tagName&&"SECTION"!==o.tagName&&"HEADER"!==o.tagName&&"H1"!==o.tagName&&"H2"!==o.tagName&&"H3"!==o.tagName&&"H4"!==o.tagName&&"H5"!==o.tagName&&"H6"!==o.tagName||!this._isElementWithoutContent(o)){if(-1!==this.DEFAULT_TAGS_TO_SCORE.indexOf(o.tagName)&&a.push(o),"DIV"===o.tagName){for(var l=null,c=o.firstChild;c;){var h=c.nextSibling;if(this._isPhrasingContent(c))null!==l?l.appendChild(c):this._isWhitespace(c)||(l=t.createElement("p"),o.replaceChild(l,c),l.appendChild(c));else if(null!==l){for(;l.lastChild&&this._isWhitespace(l.lastChild);)l.removeChild(l.lastChild);l=null}c=h}if(this._hasSingleTagInsideElement(o,"P")&&this._getLinkDensity(o)<.25){var d=o.children[0];o.parentNode.replaceChild(d,o),o=d,a.push(o)}else this._hasChildBlockElement(o)||(o=this._setNodeTag(o,"P"),a.push(o))}o=this._getNextNode(o)}else o=this._removeAndGetNext(o)}else o=this._removeAndGetNext(o);else this.log("Removing hidden node - "+s),o=this._removeAndGetNext(o)}var u=[];this._forEachNode(a,(function(e){if(e.parentNode&&void 0!==e.parentNode.tagName){var t=this._getInnerText(e);if(!(t.length<25)){var i=this._getNodeAncestors(e,5);if(0!==i.length){var n=0;n+=1,n+=t.split(this.REGEXPS.commas).length,n+=Math.min(Math.floor(t.length/100),3),this._forEachNode(i,(function(e,t){if(e.tagName&&e.parentNode&&void 0!==e.parentNode.tagName){if(void 0===e.readability&&(this._initializeNode(e),u.push(e)),0===t)var i=1;else i=1===t?2:3*t;e.readability.contentScore+=n/i}}))}}}}));for(var m=[],g=0,p=u.length;gE.readability.contentScore){m.splice(N,0,f),m.length>this._nbTopCandidates&&m.pop();break}}}var T,b=m[0]||null,y=!1;if(null===b||"BODY"===b.tagName){for(b=t.createElement("DIV"),y=!0;e.firstChild;)this.log("Moving child out:",e.firstChild),b.appendChild(e.firstChild);e.appendChild(b),this._initializeNode(b)}else if(b){for(var A=[],v=1;v=.75&&A.push(this._getNodeAncestors(m[v]));if(A.length>=3)for(T=b.parentNode;"BODY"!==T.tagName;){for(var S=0,C=0;C=3){b=T;break}T=T.parentNode}b.readability||this._initializeNode(b),T=b.parentNode;for(var L=b.readability.contentScore,x=L/3;"BODY"!==T.tagName;)if(T.readability){var R=T.readability.contentScore;if(RL){b=T;break}L=T.readability.contentScore,T=T.parentNode}else T=T.parentNode;for(T=b.parentNode;"BODY"!=T.tagName&&1==T.children.length;)T=(b=T).parentNode;b.readability||this._initializeNode(b)}var D=t.createElement("DIV");i&&(D.id="readability-content");for(var I=Math.max(10,.2*b.readability.contentScore),O=(T=b.parentNode).children,w=0,P=O.length;w=I)k=!0;else if("P"===M.nodeName){var U=this._getLinkDensity(M),H=this._getInnerText(M),G=H.length;(G>80&&U<.25||G<80&&G>0&&0===U&&-1!==H.search(/\.( |$)/))&&(k=!0)}}k&&(this.log("Appending node:",M),-1===this.ALTER_TO_DIV_EXCEPTIONS.indexOf(M.nodeName)&&(this.log("Altering sibling:",M,"to div."),M=this._setNodeTag(M,"DIV")),D.appendChild(M),O=T.children,w-=1,P-=1)}if(this._debug&&this.log("Article content pre-prep: "+D.innerHTML),this._prepArticle(D),this._debug&&this.log("Article content post-prep: "+D.innerHTML),y)b.id="readability-page-1",b.className="page";else{var F=t.createElement("DIV");for(F.id="readability-page-1",F.className="page";D.firstChild;)F.appendChild(D.firstChild);D.appendChild(F)}this._debug&&this.log("Article content after paging: "+D.innerHTML);var W=!0,z=this._getInnerText(D,!0).length;if(z0&&e.length<100)},_unescapeHtmlEntities:function(e){if(!e)return e;var t=this.HTML_ESCAPE_MAP;return e.replace(/&(quot|amp|apos|lt|gt);/g,(function(e,i){return t[i]})).replace(/&#(?:x([0-9a-z]{1,4})|([0-9]{1,4}));/gi,(function(e,t,i){var n=parseInt(t||i,t?16:10);return String.fromCharCode(n)}))},_getJSONLD:function(e){var t,i=this._getAllNodesWithTag(e,["script"]);return this._forEachNode(i,(function(e){if(!t&&"application/ld+json"===e.getAttribute("type"))try{var i=e.textContent.replace(/^\s*\s*$/g,""),n=JSON.parse(i);if(!n["@context"]||!n["@context"].match(/^https?\:\/\/schema\.org$/))return;if(!n["@type"]&&Array.isArray(n["@graph"])&&(n=n["@graph"].find((function(e){return(e["@type"]||"").match(this.REGEXPS.jsonLdArticleTypes)}))),!n||!n["@type"]||!n["@type"].match(this.REGEXPS.jsonLdArticleTypes))return;if(t={},"string"==typeof n.name&&"string"==typeof n.headline&&n.name!==n.headline){var r=this._getArticleTitle(),a=this._textSimilarity(n.name,r)>.75,o=this._textSimilarity(n.headline,r)>.75;t.title=o&&!a?n.headline:n.name}else"string"==typeof n.name?t.title=n.name.trim():"string"==typeof n.headline&&(t.title=n.headline.trim());return n.author&&("string"==typeof n.author.name?t.byline=n.author.name.trim():Array.isArray(n.author)&&n.author[0]&&"string"==typeof n.author[0].name&&(t.byline=n.author.filter((function(e){return e&&"string"==typeof e.name})).map((function(e){return e.name.trim()})).join(", "))),"string"==typeof n.description&&(t.excerpt=n.description.trim()),n.publisher&&"string"==typeof n.publisher.name&&(t.siteName=n.publisher.name.trim()),void("string"==typeof n.datePublished&&(t.datePublished=n.datePublished.trim()))}catch(e){this.log(e.message)}})),t||{}},_getArticleMetadata:function(e){var t={},i={},n=this._doc.getElementsByTagName("meta"),r=/\s*(article|dc|dcterm|og|twitter)\s*:\s*(author|creator|description|published_time|title|site_name)\s*/gi,a=/^\s*(?:(dc|dcterm|og|twitter|weibo:(article|webpage))\s*[\.:]\s*)?(author|creator|description|title|site_name)\s*$/i;return this._forEachNode(n,(function(e){var t=e.getAttribute("name"),n=e.getAttribute("property"),o=e.getAttribute("content");if(o){var s=null,l=null;n&&(s=n.match(r))&&(l=s[0].toLowerCase().replace(/\s/g,""),i[l]=o.trim()),!s&&t&&a.test(t)&&(l=t,o&&(l=l.toLowerCase().replace(/\s/g,"").replace(/\./g,":"),i[l]=o.trim()))}})),t.title=e.title||i["dc:title"]||i["dcterm:title"]||i["og:title"]||i["weibo:article:title"]||i["weibo:webpage:title"]||i.title||i["twitter:title"],t.title||(t.title=this._getArticleTitle()),t.byline=e.byline||i["dc:creator"]||i["dcterm:creator"]||i.author,t.excerpt=e.excerpt||i["dc:description"]||i["dcterm:description"]||i["og:description"]||i["weibo:article:description"]||i["weibo:webpage:description"]||i.description||i["twitter:description"],t.siteName=e.siteName||i["og:site_name"],t.publishedTime=e.datePublished||i["article:published_time"]||null,t.title=this._unescapeHtmlEntities(t.title),t.byline=this._unescapeHtmlEntities(t.byline),t.excerpt=this._unescapeHtmlEntities(t.excerpt),t.siteName=this._unescapeHtmlEntities(t.siteName),t.publishedTime=this._unescapeHtmlEntities(t.publishedTime),t},_isSingleImage:function(e){return"IMG"===e.tagName||1===e.children.length&&""===e.textContent.trim()&&this._isSingleImage(e.children[0])},_unwrapNoscriptImages:function(e){var t=Array.from(e.getElementsByTagName("img"));this._forEachNode(t,(function(e){for(var t=0;t0&&r>i)return!1;if(e.parentNode.tagName===t&&(!n||n(e.parentNode)))return!0;e=e.parentNode,r++}return!1},_getRowAndColumnCount:function(e){for(var t=0,i=0,n=e.getElementsByTagName("tr"),r=0;r0)n._readabilityDataTable=!0;else{if(["col","colgroup","tfoot","thead","th"].some((function(e){return!!n.getElementsByTagName(e)[0]})))this.log("Data table because found data-y descendant"),n._readabilityDataTable=!0;else if(n.getElementsByTagName("table")[0])n._readabilityDataTable=!1;else{var a=this._getRowAndColumnCount(n);a.rows>=10||a.columns>4?n._readabilityDataTable=!0:n._readabilityDataTable=a.rows*a.columns>10}}}else n._readabilityDataTable=!1;else n._readabilityDataTable=!1}},_fixLazyImages:function(e){this._forEachNode(this._getAllNodesWithTag(e,["img","picture","figure"]),(function(e){if(e.src&&this.REGEXPS.b64DataUrl.test(e.src)){if("image/svg+xml"===this.REGEXPS.b64DataUrl.exec(e.src)[1])return;for(var t=!1,i=0;in+=this._getInnerText(e,!0).length)),n/i},_cleanConditionally:function(e,t){this._flagIsActive(this.FLAG_CLEAN_CONDITIONALLY)&&this._removeNodes(this._getAllNodesWithTag(e,[t]),(function(e){var i=function(e){return e._readabilityDataTable},n="ul"===t||"ol"===t;if(!n){var r=0,a=this._getAllNodesWithTag(e,["ul","ol"]);this._forEachNode(a,(e=>r+=this._getInnerText(e).length)),n=r/this._getInnerText(e).length>.9}if("table"===t&&i(e))return!1;if(this._hasAncestorTag(e,"table",-1,i))return!1;if(this._hasAncestorTag(e,"code"))return!1;var o=this._getClassWeight(e);this.log("Cleaning Conditionally",e);if(o+0<0)return!0;if(this._getCharCount(e,",")<10){for(var s=e.getElementsByTagName("p").length,l=e.getElementsByTagName("img").length,c=e.getElementsByTagName("li").length-100,h=e.getElementsByTagName("input").length,d=this._getTextDensity(e,["h1","h2","h3","h4","h5","h6"]),u=0,m=this._getAllNodesWithTag(e,["object","embed","iframe"]),g=0;g1&&s/l<.5&&!this._hasAncestorTag(e,"figure")||!n&&c>s||h>Math.floor(s/3)||!n&&d<.9&&_<25&&(0===l||l>2)&&!this._hasAncestorTag(e,"figure")||!n&&o<25&&f>.2||o>=25&&f>.5||1===u&&_<75||u>1;if(n&&N){for(var E=0;E1)return N}if(l==e.getElementsByTagName("li").length)return!1}return N}return!1}))},_cleanMatchedNodes:function(e,t){for(var i=this._getNextNode(e,!0),n=this._getNextNode(e);n&&n!=i;)n=t.call(this,n,n.className+" "+n.id)?this._removeAndGetNext(n):this._getNextNode(n)},_cleanHeaders:function(e){let t=this._getAllNodesWithTag(e,["h1","h2"]);this._removeNodes(t,(function(e){let t=this._getClassWeight(e)<0;return t&&this.log("Removing header with low class weight:",e),t}))},_headerDuplicatesTitle:function(e){if("H1"!=e.tagName&&"H2"!=e.tagName)return!1;var t=this._getInnerText(e,!1);return this.log("Evaluating similarity of header:",t,this._articleTitle),this._textSimilarity(this._articleTitle,t)>.75},_flagIsActive:function(e){return(this._flags&e)>0},_removeFlag:function(e){this._flags=this._flags&~e},_isProbablyVisible:function(e){return(!e.style||"none"!=e.style.display)&&(!e.style||"hidden"!=e.style.visibility)&&!e.hasAttribute("hidden")&&(!e.hasAttribute("aria-hidden")||"true"!=e.getAttribute("aria-hidden")||e.className&&e.className.indexOf&&-1!==e.className.indexOf("fallback-image"))},parse:function(){if(this._maxElemsToParse>0){var e=this._doc.getElementsByTagName("*").length;if(e>this._maxElemsToParse)throw new Error("Aborting parsing document; "+e+" elements found")}this._unwrapNoscriptImages(this._doc);var t=this._disableJSONLD?{}:this._getJSONLD(this._doc);this._removeScripts(this._doc),this._prepDocument();var i=this._getArticleMetadata(t);this._articleTitle=i.title;var n=this._grabArticle();if(!n)return null;if(this.log("Grabbed: "+n.innerHTML),this._postProcessContent(n),!i.excerpt){var r=n.getElementsByTagName("p");r.length>0&&(i.excerpt=r[0].textContent.trim())}var a=n.textContent;return{title:this._articleTitle,byline:i.byline||this._articleByline,dir:this._articleDir,lang:this._articleLang,content:this._serializer(n),textContent:a,length:a.length,excerpt:i.excerpt,siteName:i.siteName||this._articleSiteName,publishedTime:i.publishedTime}}},e.exports=t},396:(e,t,i)=>{var n=i(238),r=i(804);e.exports={Readability:n,isProbablyReaderable:r}},838:function(e){ -/*! @license DOMPurify 3.1.6 | (c) Cure53 and other contributors | Released under the Apache license 2.0 and Mozilla Public License 2.0 | github.com/cure53/DOMPurify/blob/3.1.6/LICENSE */ -e.exports=function(){"use strict";const{entries:e,setPrototypeOf:t,isFrozen:i,getPrototypeOf:n,getOwnPropertyDescriptor:r}=Object;let{freeze:a,seal:o,create:s}=Object,{apply:l,construct:c}="undefined"!=typeof Reflect&&Reflect;a||(a=function(e){return e}),o||(o=function(e){return e}),l||(l=function(e,t,i){return e.apply(t,i)}),c||(c=function(e,t){return new e(...t)});const h=y(Array.prototype.forEach),d=y(Array.prototype.pop),u=y(Array.prototype.push),m=y(String.prototype.toLowerCase),g=y(String.prototype.toString),p=y(String.prototype.match),f=y(String.prototype.replace),_=y(String.prototype.indexOf),N=y(String.prototype.trim),E=y(Object.prototype.hasOwnProperty),T=y(RegExp.prototype.test),b=A(TypeError);function y(e){return function(t){for(var i=arguments.length,n=new Array(i>1?i-1:0),r=1;r2&&void 0!==arguments[2]?arguments[2]:m;t&&t(e,null);let a=n.length;for(;a--;){let t=n[a];if("string"==typeof t){const e=r(t);e!==t&&(i(n)||(n[a]=e),t=e)}e[t]=!0}return e}function S(e){for(let t=0;t/gm),F=o(/\${[\w\W]*}/gm),W=o(/^data-[\-\w.\u00B7-\uFFFF]/),z=o(/^aria-[\-\w]+$/),j=o(/^(?:(?:(?:f|ht)tps?|mailto|tel|callto|sms|cid|xmpp):|[^a-z]|[a-z+.\-]+(?:[^a-z+.\-:]|$))/i),X=o(/^(?:\w+script|data):/i),Y=o(/[\u0000-\u0020\u00A0\u1680\u180E\u2000-\u2029\u205F\u3000]/g),V=o(/^html$/i),$=o(/^[a-z][.\w]*(-[.\w]+)+$/i);var q=Object.freeze({__proto__:null,MUSTACHE_EXPR:H,ERB_EXPR:G,TMPLIT_EXPR:F,DATA_ATTR:W,ARIA_ATTR:z,IS_ALLOWED_URI:j,IS_SCRIPT_OR_DATA:X,ATTR_WHITESPACE:Y,DOCTYPE_NAME:V,CUSTOM_ELEMENT:$});const K={element:1,attribute:2,text:3,cdataSection:4,entityReference:5,entityNode:6,progressingInstruction:7,comment:8,document:9,documentType:10,documentFragment:11,notation:12},J=function(){return"undefined"==typeof window?null:window},Z=function(e,t){if("object"!=typeof e||"function"!=typeof e.createPolicy)return null;let i=null;const n="data-tt-policy-suffix";t&&t.hasAttribute(n)&&(i=t.getAttribute(n));const r="dompurify"+(i?"#"+i:"");try{return e.createPolicy(r,{createHTML:e=>e,createScriptURL:e=>e})}catch(e){return console.warn("TrustedTypes policy "+r+" could not be created."),null}};function Q(){let t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:J();const i=e=>Q(e);if(i.version="3.1.6",i.removed=[],!t||!t.document||t.document.nodeType!==K.document)return i.isSupported=!1,i;let{document:n}=t;const r=n,o=r.currentScript,{DocumentFragment:l,HTMLTemplateElement:c,Node:y,Element:A,NodeFilter:S,NamedNodeMap:H=t.NamedNodeMap||t.MozNamedAttrMap,HTMLFormElement:G,DOMParser:F,trustedTypes:W}=t,z=A.prototype,X=L(z,"cloneNode"),Y=L(z,"remove"),$=L(z,"nextSibling"),ee=L(z,"childNodes"),te=L(z,"parentNode");if("function"==typeof c){const e=n.createElement("template");e.content&&e.content.ownerDocument&&(n=e.content.ownerDocument)}let ie,ne="";const{implementation:re,createNodeIterator:ae,createDocumentFragment:oe,getElementsByTagName:se}=n,{importNode:le}=r;let ce={};i.isSupported="function"==typeof e&&"function"==typeof te&&re&&void 0!==re.createHTMLDocument;const{MUSTACHE_EXPR:he,ERB_EXPR:de,TMPLIT_EXPR:ue,DATA_ATTR:me,ARIA_ATTR:ge,IS_SCRIPT_OR_DATA:pe,ATTR_WHITESPACE:fe,CUSTOM_ELEMENT:_e}=q;let{IS_ALLOWED_URI:Ne}=q,Ee=null;const Te=v({},[...x,...R,...D,...O,...P]);let be=null;const ye=v({},[...M,...k,...B,...U]);let Ae=Object.seal(s(null,{tagNameCheck:{writable:!0,configurable:!1,enumerable:!0,value:null},attributeNameCheck:{writable:!0,configurable:!1,enumerable:!0,value:null},allowCustomizedBuiltInElements:{writable:!0,configurable:!1,enumerable:!0,value:!1}})),ve=null,Se=null,Ce=!0,Le=!0,xe=!1,Re=!0,De=!1,Ie=!0,Oe=!1,we=!1,Pe=!1,Me=!1,ke=!1,Be=!1,Ue=!0,He=!1;const Ge="user-content-";let Fe=!0,We=!1,ze={},je=null;const Xe=v({},["annotation-xml","audio","colgroup","desc","foreignobject","head","iframe","math","mi","mn","mo","ms","mtext","noembed","noframes","noscript","plaintext","script","style","svg","template","thead","title","video","xmp"]);let Ye=null;const Ve=v({},["audio","video","img","source","image","track"]);let $e=null;const qe=v({},["alt","class","for","id","label","name","pattern","placeholder","role","summary","title","value","style","xmlns"]),Ke="http://www.w3.org/1998/Math/MathML",Je="http://www.w3.org/2000/svg",Ze="http://www.w3.org/1999/xhtml";let Qe=Ze,et=!1,tt=null;const it=v({},[Ke,Je,Ze],g);let nt=null;const rt=["application/xhtml+xml","text/html"],at="text/html";let ot=null,st=null;const lt=n.createElement("form"),ct=function(e){return e instanceof RegExp||e instanceof Function},ht=function(){let e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{};if(!st||st!==e){if(e&&"object"==typeof e||(e={}),e=C(e),nt=-1===rt.indexOf(e.PARSER_MEDIA_TYPE)?at:e.PARSER_MEDIA_TYPE,ot="application/xhtml+xml"===nt?g:m,Ee=E(e,"ALLOWED_TAGS")?v({},e.ALLOWED_TAGS,ot):Te,be=E(e,"ALLOWED_ATTR")?v({},e.ALLOWED_ATTR,ot):ye,tt=E(e,"ALLOWED_NAMESPACES")?v({},e.ALLOWED_NAMESPACES,g):it,$e=E(e,"ADD_URI_SAFE_ATTR")?v(C(qe),e.ADD_URI_SAFE_ATTR,ot):qe,Ye=E(e,"ADD_DATA_URI_TAGS")?v(C(Ve),e.ADD_DATA_URI_TAGS,ot):Ve,je=E(e,"FORBID_CONTENTS")?v({},e.FORBID_CONTENTS,ot):Xe,ve=E(e,"FORBID_TAGS")?v({},e.FORBID_TAGS,ot):{},Se=E(e,"FORBID_ATTR")?v({},e.FORBID_ATTR,ot):{},ze=!!E(e,"USE_PROFILES")&&e.USE_PROFILES,Ce=!1!==e.ALLOW_ARIA_ATTR,Le=!1!==e.ALLOW_DATA_ATTR,xe=e.ALLOW_UNKNOWN_PROTOCOLS||!1,Re=!1!==e.ALLOW_SELF_CLOSE_IN_ATTR,De=e.SAFE_FOR_TEMPLATES||!1,Ie=!1!==e.SAFE_FOR_XML,Oe=e.WHOLE_DOCUMENT||!1,Me=e.RETURN_DOM||!1,ke=e.RETURN_DOM_FRAGMENT||!1,Be=e.RETURN_TRUSTED_TYPE||!1,Pe=e.FORCE_BODY||!1,Ue=!1!==e.SANITIZE_DOM,He=e.SANITIZE_NAMED_PROPS||!1,Fe=!1!==e.KEEP_CONTENT,We=e.IN_PLACE||!1,Ne=e.ALLOWED_URI_REGEXP||j,Qe=e.NAMESPACE||Ze,Ae=e.CUSTOM_ELEMENT_HANDLING||{},e.CUSTOM_ELEMENT_HANDLING&&ct(e.CUSTOM_ELEMENT_HANDLING.tagNameCheck)&&(Ae.tagNameCheck=e.CUSTOM_ELEMENT_HANDLING.tagNameCheck),e.CUSTOM_ELEMENT_HANDLING&&ct(e.CUSTOM_ELEMENT_HANDLING.attributeNameCheck)&&(Ae.attributeNameCheck=e.CUSTOM_ELEMENT_HANDLING.attributeNameCheck),e.CUSTOM_ELEMENT_HANDLING&&"boolean"==typeof e.CUSTOM_ELEMENT_HANDLING.allowCustomizedBuiltInElements&&(Ae.allowCustomizedBuiltInElements=e.CUSTOM_ELEMENT_HANDLING.allowCustomizedBuiltInElements),De&&(Le=!1),ke&&(Me=!0),ze&&(Ee=v({},P),be=[],!0===ze.html&&(v(Ee,x),v(be,M)),!0===ze.svg&&(v(Ee,R),v(be,k),v(be,U)),!0===ze.svgFilters&&(v(Ee,D),v(be,k),v(be,U)),!0===ze.mathMl&&(v(Ee,O),v(be,B),v(be,U))),e.ADD_TAGS&&(Ee===Te&&(Ee=C(Ee)),v(Ee,e.ADD_TAGS,ot)),e.ADD_ATTR&&(be===ye&&(be=C(be)),v(be,e.ADD_ATTR,ot)),e.ADD_URI_SAFE_ATTR&&v($e,e.ADD_URI_SAFE_ATTR,ot),e.FORBID_CONTENTS&&(je===Xe&&(je=C(je)),v(je,e.FORBID_CONTENTS,ot)),Fe&&(Ee["#text"]=!0),Oe&&v(Ee,["html","head","body"]),Ee.table&&(v(Ee,["tbody"]),delete ve.tbody),e.TRUSTED_TYPES_POLICY){if("function"!=typeof e.TRUSTED_TYPES_POLICY.createHTML)throw b('TRUSTED_TYPES_POLICY configuration option must provide a "createHTML" hook.');if("function"!=typeof e.TRUSTED_TYPES_POLICY.createScriptURL)throw b('TRUSTED_TYPES_POLICY configuration option must provide a "createScriptURL" hook.');ie=e.TRUSTED_TYPES_POLICY,ne=ie.createHTML("")}else void 0===ie&&(ie=Z(W,o)),null!==ie&&"string"==typeof ne&&(ne=ie.createHTML(""));a&&a(e),st=e}},dt=v({},["mi","mo","mn","ms","mtext"]),ut=v({},["foreignobject","annotation-xml"]),mt=v({},["title","style","font","a","script"]),gt=v({},[...R,...D,...I]),pt=v({},[...O,...w]),ft=function(e){let t=te(e);t&&t.tagName||(t={namespaceURI:Qe,tagName:"template"});const i=m(e.tagName),n=m(t.tagName);return!!tt[e.namespaceURI]&&(e.namespaceURI===Je?t.namespaceURI===Ze?"svg"===i:t.namespaceURI===Ke?"svg"===i&&("annotation-xml"===n||dt[n]):Boolean(gt[i]):e.namespaceURI===Ke?t.namespaceURI===Ze?"math"===i:t.namespaceURI===Je?"math"===i&&ut[n]:Boolean(pt[i]):e.namespaceURI===Ze?!(t.namespaceURI===Je&&!ut[n])&&!(t.namespaceURI===Ke&&!dt[n])&&!pt[i]&&(mt[i]||!gt[i]):!("application/xhtml+xml"!==nt||!tt[e.namespaceURI]))},_t=function(e){u(i.removed,{element:e});try{te(e).removeChild(e)}catch(t){Y(e)}},Nt=function(e,t){try{u(i.removed,{attribute:t.getAttributeNode(e),from:t})}catch(e){u(i.removed,{attribute:null,from:t})}if(t.removeAttribute(e),"is"===e&&!be[e])if(Me||ke)try{_t(t)}catch(e){}else try{t.setAttribute(e,"")}catch(e){}},Et=function(e){let t=null,i=null;if(Pe)e=""+e;else{const t=p(e,/^[\r\n\t ]+/);i=t&&t[0]}"application/xhtml+xml"===nt&&Qe===Ze&&(e=''+e+"");const r=ie?ie.createHTML(e):e;if(Qe===Ze)try{t=(new F).parseFromString(r,nt)}catch(e){}if(!t||!t.documentElement){t=re.createDocument(Qe,"template",null);try{t.documentElement.innerHTML=et?ne:r}catch(e){}}const a=t.body||t.documentElement;return e&&i&&a.insertBefore(n.createTextNode(i),a.childNodes[0]||null),Qe===Ze?se.call(t,Oe?"html":"body")[0]:Oe?t.documentElement:a},Tt=function(e){return ae.call(e.ownerDocument||e,e,S.SHOW_ELEMENT|S.SHOW_COMMENT|S.SHOW_TEXT|S.SHOW_PROCESSING_INSTRUCTION|S.SHOW_CDATA_SECTION,null)},bt=function(e){return e instanceof G&&("string"!=typeof e.nodeName||"string"!=typeof e.textContent||"function"!=typeof e.removeChild||!(e.attributes instanceof H)||"function"!=typeof e.removeAttribute||"function"!=typeof e.setAttribute||"string"!=typeof e.namespaceURI||"function"!=typeof e.insertBefore||"function"!=typeof e.hasChildNodes)},yt=function(e){return"function"==typeof y&&e instanceof y},At=function(e,t,n){ce[e]&&h(ce[e],(e=>{e.call(i,t,n,st)}))},vt=function(e){let t=null;if(At("beforeSanitizeElements",e,null),bt(e))return _t(e),!0;const n=ot(e.nodeName);if(At("uponSanitizeElement",e,{tagName:n,allowedTags:Ee}),e.hasChildNodes()&&!yt(e.firstElementChild)&&T(/<[/\w]/g,e.innerHTML)&&T(/<[/\w]/g,e.textContent))return _t(e),!0;if(e.nodeType===K.progressingInstruction)return _t(e),!0;if(Ie&&e.nodeType===K.comment&&T(/<[/\w]/g,e.data))return _t(e),!0;if(!Ee[n]||ve[n]){if(!ve[n]&&Ct(n)){if(Ae.tagNameCheck instanceof RegExp&&T(Ae.tagNameCheck,n))return!1;if(Ae.tagNameCheck instanceof Function&&Ae.tagNameCheck(n))return!1}if(Fe&&!je[n]){const t=te(e)||e.parentNode,i=ee(e)||e.childNodes;if(i&&t)for(let n=i.length-1;n>=0;--n){const r=X(i[n],!0);r.__removalCount=(e.__removalCount||0)+1,t.insertBefore(r,$(e))}}return _t(e),!0}return e instanceof A&&!ft(e)?(_t(e),!0):"noscript"!==n&&"noembed"!==n&&"noframes"!==n||!T(/<\/no(script|embed|frames)/i,e.innerHTML)?(De&&e.nodeType===K.text&&(t=e.textContent,h([he,de,ue],(e=>{t=f(t,e," ")})),e.textContent!==t&&(u(i.removed,{element:e.cloneNode()}),e.textContent=t)),At("afterSanitizeElements",e,null),!1):(_t(e),!0)},St=function(e,t,i){if(Ue&&("id"===t||"name"===t)&&(i in n||i in lt))return!1;if(Le&&!Se[t]&&T(me,t));else if(Ce&&T(ge,t));else if(!be[t]||Se[t]){if(!(Ct(e)&&(Ae.tagNameCheck instanceof RegExp&&T(Ae.tagNameCheck,e)||Ae.tagNameCheck instanceof Function&&Ae.tagNameCheck(e))&&(Ae.attributeNameCheck instanceof RegExp&&T(Ae.attributeNameCheck,t)||Ae.attributeNameCheck instanceof Function&&Ae.attributeNameCheck(t))||"is"===t&&Ae.allowCustomizedBuiltInElements&&(Ae.tagNameCheck instanceof RegExp&&T(Ae.tagNameCheck,i)||Ae.tagNameCheck instanceof Function&&Ae.tagNameCheck(i))))return!1}else if($e[t]);else if(T(Ne,f(i,fe,"")));else if("src"!==t&&"xlink:href"!==t&&"href"!==t||"script"===e||0!==_(i,"data:")||!Ye[e])if(xe&&!T(pe,f(i,fe,"")));else if(i)return!1;return!0},Ct=function(e){return"annotation-xml"!==e&&p(e,_e)},Lt=function(e){At("beforeSanitizeAttributes",e,null);const{attributes:t}=e;if(!t)return;const n={attrName:"",attrValue:"",keepAttr:!0,allowedAttributes:be};let r=t.length;for(;r--;){const a=t[r],{name:o,namespaceURI:s,value:l}=a,c=ot(o);let u="value"===o?l:N(l);if(n.attrName=c,n.attrValue=u,n.keepAttr=!0,n.forceKeepAttr=void 0,At("uponSanitizeAttribute",e,n),u=n.attrValue,Ie&&T(/((--!?|])>)|<\/(style|title)/i,u)){Nt(o,e);continue}if(n.forceKeepAttr)continue;if(Nt(o,e),!n.keepAttr)continue;if(!Re&&T(/\/>/i,u)){Nt(o,e);continue}De&&h([he,de,ue],(e=>{u=f(u,e," ")}));const m=ot(e.nodeName);if(St(m,c,u)){if(!He||"id"!==c&&"name"!==c||(Nt(o,e),u=Ge+u),ie&&"object"==typeof W&&"function"==typeof W.getAttributeType)if(s);else switch(W.getAttributeType(m,c)){case"TrustedHTML":u=ie.createHTML(u);break;case"TrustedScriptURL":u=ie.createScriptURL(u)}try{s?e.setAttributeNS(s,o,u):e.setAttribute(o,u),bt(e)?_t(e):d(i.removed)}catch(e){}}}At("afterSanitizeAttributes",e,null)},xt=function e(t){let i=null;const n=Tt(t);for(At("beforeSanitizeShadowDOM",t,null);i=n.nextNode();)At("uponSanitizeShadowNode",i,null),vt(i)||(i.content instanceof l&&e(i.content),Lt(i));At("afterSanitizeShadowDOM",t,null)};return i.sanitize=function(e){let t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{},n=null,a=null,o=null,s=null;if(et=!e,et&&(e="\x3c!--\x3e"),"string"!=typeof e&&!yt(e)){if("function"!=typeof e.toString)throw b("toString is not a function");if("string"!=typeof(e=e.toString()))throw b("dirty is not a string, aborting")}if(!i.isSupported)return e;if(we||ht(t),i.removed=[],"string"==typeof e&&(We=!1),We){if(e.nodeName){const t=ot(e.nodeName);if(!Ee[t]||ve[t])throw b("root node is forbidden and cannot be sanitized in-place")}}else if(e instanceof y)n=Et("\x3c!----\x3e"),a=n.ownerDocument.importNode(e,!0),a.nodeType===K.element&&"BODY"===a.nodeName||"HTML"===a.nodeName?n=a:n.appendChild(a);else{if(!Me&&!De&&!Oe&&-1===e.indexOf("<"))return ie&&Be?ie.createHTML(e):e;if(n=Et(e),!n)return Me?null:Be?ne:""}n&&Pe&&_t(n.firstChild);const c=Tt(We?e:n);for(;o=c.nextNode();)vt(o)||(o.content instanceof l&&xt(o.content),Lt(o));if(We)return e;if(Me){if(ke)for(s=oe.call(n.ownerDocument);n.firstChild;)s.appendChild(n.firstChild);else s=n;return(be.shadowroot||be.shadowrootmode)&&(s=le.call(r,s,!0)),s}let d=Oe?n.outerHTML:n.innerHTML;return Oe&&Ee["!doctype"]&&n.ownerDocument&&n.ownerDocument.doctype&&n.ownerDocument.doctype.name&&T(V,n.ownerDocument.doctype.name)&&(d="\n"+d),De&&h([he,de,ue],(e=>{d=f(d,e," ")})),ie&&Be?ie.createHTML(d):d},i.setConfig=function(){ht(arguments.length>0&&void 0!==arguments[0]?arguments[0]:{}),we=!0},i.clearConfig=function(){st=null,we=!1},i.isValidAttribute=function(e,t,i){st||ht({});const n=ot(e),r=ot(t);return St(n,r,i)},i.addHook=function(e,t){"function"==typeof t&&(ce[e]=ce[e]||[],u(ce[e],t))},i.removeHook=function(e){if(ce[e])return d(ce[e])},i.removeHooks=function(e){ce[e]&&(ce[e]=[])},i.removeAllHooks=function(){ce={}},i}return Q()}()}},t={};function i(n){var r=t[n];if(void 0!==r)return r.exports;var a=t[n]={exports:{}};return e[n].call(a.exports,a,a.exports,i),a.exports}i.n=e=>{var t=e&&e.__esModule?()=>e.default:()=>e;return i.d(t,{a:t}),t},i.d=(e,t)=>{for(var n in t)i.o(t,n)&&!i.o(e,n)&&Object.defineProperty(e,n,{enumerable:!0,get:t[n]})},i.o=(e,t)=>Object.prototype.hasOwnProperty.call(e,t),i.r=e=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})};var n={};return(()=>{"use strict";i.r(n),i.d(n,{applyReaderable:()=>o,isReaderable:()=>a});var e=i(396),t=i(838),r=i.n(t);function a(){return(0,e.isProbablyReaderable)(document)}function o(){var t,i=document.cloneNode(!0),n=(t=i,new e.Readability(t).parse()),a=r().sanitize(n.content);a&&(document.body.innerHTML='
'+a+"
")}window.isReaderable=a,window.applyReaderable=o})(),n})())); \ No newline at end of file diff --git a/app/js/readability/dist/readability.min.js.gz b/app/js/readability/dist/readability.min.js.gz deleted file mode 100644 index 477fe80e..00000000 Binary files a/app/js/readability/dist/readability.min.js.gz and /dev/null differ diff --git a/app/js/readability/src/index.js b/app/js/readability/src/index.js deleted file mode 100644 index 44d820dc..00000000 --- a/app/js/readability/src/index.js +++ /dev/null @@ -1,39 +0,0 @@ -import { Readability, isProbablyReaderable } from '@mozilla/readability'; -import DOMPurify from 'dompurify'; - -function isReaderable() { - return isProbablyReaderable(document); -} - -function parseReaderable(doc) { - const reader = new Readability(doc); - const article = reader.parse(); - return article; -} - -function applyReaderable() { - const clonedDoc = document.cloneNode(true); - const article = parseReaderable(clonedDoc); - const markup = DOMPurify.sanitize(article.content); - - // console.log('article title: ', parsed.title); - // console.log('HTML string of processed article content: ', parsed.content); - // console.log('text content of the article, with all the HTML tags removed: ', parsed.textContent); - // console.log('length of an article, in characters: ', parsed.length); - // console.log('article description, or short excerpt from the content: ', parsed.excerpt); - // console.log('author metadata: ', parsed.byline); - // console.log('content direction: ', parsed.dir); - // console.log('name of the site: ', parsed.siteName); - // console.log('content language: ', parsed.lang); - // console.log('published time: ', parsed.publishedTime); - - if (markup) { - document.body.innerHTML = '
' + markup + '
'; - } -} - -// Attach functions to the window object -window.isReaderable = isReaderable; -window.applyReaderable = applyReaderable; - -export { isReaderable, applyReaderable }; diff --git a/app/lib/core/routing/routes.dart b/app/lib/core/routing/routes.dart index 8e879452..e2c537d0 100644 --- a/app/lib/core/routing/routes.dart +++ b/app/lib/core/routing/routes.dart @@ -8,8 +8,9 @@ import 'package:lensai/features/bangs/presentation/screens/search.dart'; import 'package:lensai/features/chat_archive/presentation/screens/detail.dart'; import 'package:lensai/features/chat_archive/presentation/screens/list.dart'; import 'package:lensai/features/chat_archive/presentation/screens/search.dart'; -import 'package:lensai/features/geckoview/features/browser/screens/browser.dart'; +import 'package:lensai/features/geckoview/features/browser/presentation/screens/browser.dart'; import 'package:lensai/features/geckoview/features/tabs/presentation/screens/container_list.dart'; +import 'package:lensai/features/search/presentation/screens/search.dart'; import 'package:lensai/features/settings/presentation/screens/settings.dart'; part 'routes.g.dart'; @@ -22,13 +23,17 @@ part 'routes.g.dart'; name: 'AboutRoute', path: 'about', ), + TypedGoRoute( + name: 'SearchRoute', + path: 'search/:searchText', + ), TypedGoRoute( name: 'BangRoute', path: 'bangs', routes: [ TypedGoRoute( name: 'BangSearchRoute', - path: 'search', + path: 'search/:searchText', ), TypedGoRoute( name: 'BangCategoryRoute', @@ -62,6 +67,24 @@ class AboutRoute extends GoRouteData { } } +class SearchRoute extends GoRouteData { + static const String emptySearchText = ' '; + + //This should be nullable but isnt allowed by go_router + final String searchText; + + const SearchRoute({this.searchText = SearchRoute.emptySearchText}); + + @override + Widget build(BuildContext context, GoRouterState state) { + return SearchScreen( + initialSearchText: (searchText.isEmpty || searchText == emptySearchText) + ? null + : searchText, + ); + } +} + class BangCategoriesRoute extends GoRouteData { @override Widget build(BuildContext context, GoRouterState state) { @@ -96,9 +119,20 @@ class BangSubCategoryRoute extends GoRouteData { } class BangSearchRoute extends GoRouteData { + static const String emptySearchText = ' '; + + //This should be nullable but isnt allowed by go_router + final String searchText; + + const BangSearchRoute({this.searchText = BangSearchRoute.emptySearchText}); + @override Widget build(BuildContext context, GoRouterState state) { - return const BangSearchScreen(); + return BangSearchScreen( + initialSearchText: (searchText.isEmpty || searchText == emptySearchText) + ? null + : searchText, + ); } } diff --git a/app/lib/core/routing/routes.g.dart b/app/lib/core/routing/routes.g.dart index 9097d6ea..b383aefc 100644 --- a/app/lib/core/routing/routes.g.dart +++ b/app/lib/core/routing/routes.g.dart @@ -22,13 +22,18 @@ RouteBase get $browserRoute => GoRouteData.$route( name: 'AboutRoute', factory: $AboutRouteExtension._fromState, ), + GoRouteData.$route( + path: 'search/:searchText', + name: 'SearchRoute', + factory: $SearchRouteExtension._fromState, + ), GoRouteData.$route( path: 'bangs', name: 'BangRoute', factory: $BangCategoriesRouteExtension._fromState, routes: [ GoRouteData.$route( - path: 'search', + path: 'search/:searchText', name: 'BangSearchRoute', factory: $BangSearchRouteExtension._fromState, ), @@ -88,6 +93,26 @@ extension $AboutRouteExtension on AboutRoute { void replace(BuildContext context) => context.replace(location); } +extension $SearchRouteExtension on SearchRoute { + static SearchRoute _fromState(GoRouterState state) => SearchRoute( + searchText: + state.pathParameters['searchText']! ?? SearchRoute.emptySearchText, + ); + + String get location => GoRouteData.$location( + '/search/${Uri.encodeComponent(searchText)}', + ); + + void go(BuildContext context) => context.go(location); + + Future push(BuildContext context) => context.push(location); + + void pushReplacement(BuildContext context) => + context.pushReplacement(location); + + void replace(BuildContext context) => context.replace(location); +} + extension $BangCategoriesRouteExtension on BangCategoriesRoute { static BangCategoriesRoute _fromState(GoRouterState state) => BangCategoriesRoute(); @@ -107,10 +132,13 @@ extension $BangCategoriesRouteExtension on BangCategoriesRoute { } extension $BangSearchRouteExtension on BangSearchRoute { - static BangSearchRoute _fromState(GoRouterState state) => BangSearchRoute(); + static BangSearchRoute _fromState(GoRouterState state) => BangSearchRoute( + searchText: state.pathParameters['searchText']! ?? + BangSearchRoute.emptySearchText, + ); String get location => GoRouteData.$location( - '/bangs/search', + '/bangs/search/${Uri.encodeComponent(searchText)}', ); void go(BuildContext context) => context.go(location); diff --git a/app/lib/domain/services/generic_website.dart b/app/lib/domain/services/generic_website.dart index 646c5a98..5b0d9e0a 100644 --- a/app/lib/domain/services/generic_website.dart +++ b/app/lib/domain/services/generic_website.dart @@ -10,8 +10,8 @@ import 'package:http/http.dart' as http; import 'package:lensai/core/http_error_handler.dart'; import 'package:lensai/data/models/web_page_info.dart'; import 'package:lensai/features/geckoview/domain/entities/browser_icon.dart'; +import 'package:lensai/utils/lru_cache.dart'; import 'package:riverpod_annotation/riverpod_annotation.dart'; -import 'package:universal_io/io.dart'; part 'generic_website.g.dart'; @@ -56,11 +56,11 @@ class GenericWebsiteService extends _$GenericWebsiteService { late http.Client _client; - final Map _httpsCache; + final LRUCache _iconCache; GenericWebsiteService() - : _httpsCache = {}, - _iconsService = GeckoIconService(); + : _iconsService = GeckoIconService(), + _iconCache = LRUCache(50); @override void build() { @@ -207,49 +207,59 @@ class GenericWebsiteService extends _$GenericWebsiteService { required Uri url, List resources = const [], }) async { - final result = await _iconsService.loadIcon(url: url, resources: resources); - return BrowserIcon.fromBytes( - result.image, - dominantColor: (result.color != null) ? Color(result.color!) : null, - source: result.source, - ); - } + final cached = _iconCache.get(url.host); + if (cached == null) { + final result = + await _iconsService.loadIcon(url: url, resources: resources); - Future tryUpgradeToHttps(Uri httpUri) async { - if (httpUri.isScheme('https')) { - return httpUri; - } else if (httpUri.isScheme('http')) { - final cached = _httpsCache[httpUri.host]; - if (cached != null) { - return cached ? httpUri.replace(scheme: 'https') : null; - } - - var sslAvailable = false; - - try { - final context = SecurityContext.defaultContext; - - final socket = await SecureSocket.connect( - httpUri.host, - 443, - context: context, - timeout: const Duration(seconds: 3), - ); - - await socket.close(); - - sslAvailable = true; - } catch (_) { - sslAvailable = false; - } - - _httpsCache[httpUri.host] = sslAvailable; - - if (sslAvailable) { - return httpUri.replace(scheme: 'https'); - } + return _iconCache.set( + url.host, + await BrowserIcon.fromBytes( + result.image, + dominantColor: (result.color != null) ? Color(result.color!) : null, + source: result.source, + ), + ); } - return null; + return cached; } + + // Future tryUpgradeToHttps(Uri httpUri) async { + // if (httpUri.isScheme('https')) { + // return httpUri; + // } else if (httpUri.isScheme('http')) { + // final cached = _httpsCache[httpUri.host]; + // if (cached != null) { + // return cached ? httpUri.replace(scheme: 'https') : null; + // } + + // var sslAvailable = false; + + // try { + // final context = SecurityContext.defaultContext; + + // final socket = await SecureSocket.connect( + // httpUri.host, + // 443, + // context: context, + // timeout: const Duration(seconds: 3), + // ); + + // await socket.close(); + + // sslAvailable = true; + // } catch (_) { + // sslAvailable = false; + // } + + // _httpsCache[httpUri.host] = sslAvailable; + + // if (sslAvailable) { + // return httpUri.replace(scheme: 'https'); + // } + // } + + // return null; + // } } diff --git a/app/lib/domain/services/generic_website.g.dart b/app/lib/domain/services/generic_website.g.dart index 1eb9bf70..edcdd298 100644 --- a/app/lib/domain/services/generic_website.g.dart +++ b/app/lib/domain/services/generic_website.g.dart @@ -7,7 +7,7 @@ part of 'generic_website.dart'; // ************************************************************************** String _$genericWebsiteServiceHash() => - r'0b1d953fe1b30b9dd0396df34e6176424cdaf941'; + r'7dea42d6914b0f06250a96bb425ba10a331ef0d3'; /// See also [GenericWebsiteService]. @ProviderFor(GenericWebsiteService) diff --git a/app/lib/features/bangs/data/database/daos/bang.dart b/app/lib/features/bangs/data/database/daos/bang.dart index d379d35b..d37c8e69 100644 --- a/app/lib/features/bangs/data/database/daos/bang.dart +++ b/app/lib/features/bangs/data/database/daos/bang.dart @@ -91,7 +91,7 @@ class BangDao extends DatabaseAccessor with _$BangDaoMixin { } Selectable queryBangs(String searchString) { - return db.bangQuery(query: db.buildQuery(searchString)); + return db.bangQuery(query: db.buildFtsQuery(searchString)); } // Future upsertBangIcon(String trigger, BrowserIcon icon) async { diff --git a/app/lib/features/bangs/data/database/database.dart b/app/lib/features/bangs/data/database/database.dart index a7d29d55..cc73559f 100644 --- a/app/lib/features/bangs/data/database/database.dart +++ b/app/lib/features/bangs/data/database/database.dart @@ -4,7 +4,7 @@ import 'package:lensai/features/bangs/data/database/daos/sync.dart'; import 'package:lensai/features/bangs/data/database/drift/converters/bang_format.dart'; import 'package:lensai/features/bangs/data/models/bang.dart'; import 'package:lensai/features/bangs/data/models/bang_data.dart'; -import 'package:lensai/features/query/domain/tokenizer.dart'; +import 'package:lensai/features/search/domain/fts_tokenizer.dart'; part 'database.g.dart'; diff --git a/app/lib/features/bangs/domain/providers.dart b/app/lib/features/bangs/domain/providers/bangs.dart similarity index 97% rename from app/lib/features/bangs/domain/providers.dart rename to app/lib/features/bangs/domain/providers/bangs.dart index 75b79622..496cdb11 100644 --- a/app/lib/features/bangs/domain/providers.dart +++ b/app/lib/features/bangs/domain/providers/bangs.dart @@ -5,7 +5,7 @@ import 'package:lensai/features/bangs/domain/repositories/sync.dart'; import 'package:riverpod/riverpod.dart'; import 'package:riverpod_annotation/riverpod_annotation.dart'; -part 'providers.g.dart'; +part 'bangs.g.dart'; @Riverpod() Stream bangData(Ref ref, String? trigger) { @@ -14,7 +14,7 @@ Stream bangData(Ref ref, String? trigger) { } @Riverpod(keepAlive: true) -Stream kagiSearchBangData(Ref ref) { +Stream defaultSearchBangData(Ref ref) { final repository = ref.watch(bangDataRepositoryProvider.notifier); return repository.watchBang('kagi'); } diff --git a/app/lib/features/bangs/domain/providers.g.dart b/app/lib/features/bangs/domain/providers/bangs.g.dart similarity index 98% rename from app/lib/features/bangs/domain/providers.g.dart rename to app/lib/features/bangs/domain/providers/bangs.g.dart index b1db6907..e50ba4bc 100644 --- a/app/lib/features/bangs/domain/providers.g.dart +++ b/app/lib/features/bangs/domain/providers/bangs.g.dart @@ -1,6 +1,6 @@ // GENERATED CODE - DO NOT MODIFY BY HAND -part of 'providers.dart'; +part of 'bangs.dart'; // ************************************************************************** // RiverpodGenerator @@ -156,24 +156,24 @@ class _BangDataProviderElement String? get trigger => (origin as BangDataProvider).trigger; } -String _$kagiSearchBangDataHash() => - r'0bb5014a7af73ef6f5a36b0545d7a73e7ad0580a'; +String _$defaultSearchBangDataHash() => + r'b7547084b261ccb1dc02a6c7230fe57f6902dd58'; -/// See also [kagiSearchBangData]. -@ProviderFor(kagiSearchBangData) -final kagiSearchBangDataProvider = StreamProvider.internal( - kagiSearchBangData, - name: r'kagiSearchBangDataProvider', +/// See also [defaultSearchBangData]. +@ProviderFor(defaultSearchBangData) +final defaultSearchBangDataProvider = StreamProvider.internal( + defaultSearchBangData, + name: r'defaultSearchBangDataProvider', debugGetCreateSourceHash: const bool.fromEnvironment('dart.vm.product') ? null - : _$kagiSearchBangDataHash, + : _$defaultSearchBangDataHash, dependencies: null, allTransitiveDependencies: null, ); @Deprecated('Will be removed in 3.0. Use Ref instead') // ignore: unused_element -typedef KagiSearchBangDataRef = StreamProviderRef; +typedef DefaultSearchBangDataRef = StreamProviderRef; String _$bangCategoriesHash() => r'947fcfd2dffcc7f585c6ed7379d319f4fe72293a'; /// See also [bangCategories]. diff --git a/app/lib/features/bangs/domain/repositories/search.dart b/app/lib/features/bangs/domain/repositories/search.dart index 5a42fa0b..a1241fdf 100644 --- a/app/lib/features/bangs/domain/repositories/search.dart +++ b/app/lib/features/bangs/domain/repositories/search.dart @@ -3,6 +3,7 @@ import 'dart:async'; import 'package:lensai/features/bangs/data/database/database.dart'; import 'package:lensai/features/bangs/data/models/bang_data.dart'; import 'package:lensai/features/bangs/data/providers.dart'; +import 'package:lensai/features/bangs/domain/providers/bangs.dart'; import 'package:riverpod_annotation/riverpod_annotation.dart'; part 'search.g.dart'; @@ -30,3 +31,29 @@ class BangSearch extends _$BangSearch { return _streamController.stream; } } + +@Riverpod() +class SeamlessBangProvider extends _$SeamlessBangProvider { + bool _hasSearch = false; + + void search(String input) { + if (input.isNotEmpty) { + if (!_hasSearch) { + _hasSearch = true; + ref.invalidateSelf(); + } + + unawaited(ref.read(bangSearchProvider.notifier).search(input)); + } else if (_hasSearch) { + _hasSearch = false; + ref.invalidateSelf(); + } + } + + @override + AsyncValue> build() { + return _hasSearch + ? ref.watch(bangSearchProvider) + : ref.watch(frequentBangDataListProvider); + } +} diff --git a/app/lib/features/bangs/domain/repositories/search.g.dart b/app/lib/features/bangs/domain/repositories/search.g.dart index d44b2afa..a0dadc4c 100644 --- a/app/lib/features/bangs/domain/repositories/search.g.dart +++ b/app/lib/features/bangs/domain/repositories/search.g.dart @@ -21,5 +21,23 @@ final bangSearchProvider = ); typedef _$BangSearch = AutoDisposeStreamNotifier>; +String _$seamlessBangProviderHash() => + r'd2c8e94d6305a6a37cc27f8bc3617521f513e537'; + +/// See also [SeamlessBangProvider]. +@ProviderFor(SeamlessBangProvider) +final seamlessBangProviderProvider = AutoDisposeNotifierProvider< + SeamlessBangProvider, AsyncValue>>.internal( + SeamlessBangProvider.new, + name: r'seamlessBangProviderProvider', + debugGetCreateSourceHash: const bool.fromEnvironment('dart.vm.product') + ? null + : _$seamlessBangProviderHash, + dependencies: null, + allTransitiveDependencies: null, +); + +typedef _$SeamlessBangProvider + = AutoDisposeNotifier>>; // ignore_for_file: type=lint // ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member, invalid_use_of_visible_for_testing_member, deprecated_member_use_from_same_package diff --git a/app/lib/features/bangs/presentation/screens/categories.dart b/app/lib/features/bangs/presentation/screens/categories.dart index 3ab66e62..8da57404 100644 --- a/app/lib/features/bangs/presentation/screens/categories.dart +++ b/app/lib/features/bangs/presentation/screens/categories.dart @@ -4,7 +4,7 @@ import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:go_router/go_router.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:lensai/core/routing/routes.dart'; -import 'package:lensai/features/bangs/domain/providers.dart'; +import 'package:lensai/features/bangs/domain/providers/bangs.dart'; import 'package:lensai/presentation/widgets/failure_widget.dart'; class BangCategoriesScreen extends HookConsumerWidget { @@ -19,7 +19,7 @@ class BangCategoriesScreen extends HookConsumerWidget { actions: [ IconButton( onPressed: () async { - await context.push(BangSearchRoute().location); + await context.push(const BangSearchRoute().location); }, icon: const Icon(Icons.search), ), diff --git a/app/lib/features/bangs/presentation/screens/list.dart b/app/lib/features/bangs/presentation/screens/list.dart index 43575c3f..7c92a841 100644 --- a/app/lib/features/bangs/presentation/screens/list.dart +++ b/app/lib/features/bangs/presentation/screens/list.dart @@ -2,7 +2,7 @@ import 'package:flutter/material.dart'; import 'package:go_router/go_router.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:lensai/core/routing/routes.dart'; -import 'package:lensai/features/bangs/domain/providers.dart'; +import 'package:lensai/features/bangs/domain/providers/bangs.dart'; import 'package:lensai/features/bangs/presentation/widgets/bang_details.dart'; import 'package:lensai/features/geckoview/features/browser/domain/entities/sheet.dart'; import 'package:lensai/features/geckoview/features/browser/domain/providers.dart'; diff --git a/app/lib/features/bangs/presentation/screens/search.dart b/app/lib/features/bangs/presentation/screens/search.dart index 0efcee60..b4a94f31 100644 --- a/app/lib/features/bangs/presentation/screens/search.dart +++ b/app/lib/features/bangs/presentation/screens/search.dart @@ -5,20 +5,18 @@ import 'package:flutter/material.dart'; import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:go_router/go_router.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; -import 'package:lensai/core/routing/routes.dart'; import 'package:lensai/features/bangs/domain/repositories/search.dart'; import 'package:lensai/features/bangs/presentation/widgets/bang_details.dart'; -import 'package:lensai/features/geckoview/features/browser/domain/entities/sheet.dart'; import 'package:lensai/features/geckoview/features/browser/domain/providers.dart'; -import 'package:lensai/features/geckoview/features/controllers/bottom_sheet.dart'; -import 'package:lensai/features/kagi/data/entities/modes.dart'; import 'package:lensai/features/settings/data/models/settings.dart'; import 'package:lensai/features/settings/data/repositories/settings_repository.dart'; import 'package:lensai/presentation/hooks/listenable_callback.dart'; import 'package:lensai/presentation/widgets/failure_widget.dart'; class BangSearchScreen extends HookConsumerWidget { - const BangSearchScreen({super.key}); + final String? initialSearchText; + + const BangSearchScreen({super.key, this.initialSearchText}); @override Widget build(BuildContext context, WidgetRef ref) { @@ -29,7 +27,8 @@ class BangSearchScreen extends HookConsumerWidget { ), ); - final textEditingController = useTextEditingController(); + final textEditingController = + useTextEditingController(text: initialSearchText); useListenableCallback(textEditingController, () async { unawaited( @@ -78,14 +77,15 @@ class BangSearchScreen extends HookConsumerWidget { .read(selectedBangTriggerProvider().notifier) .setTrigger(bang.trigger); - if (ref.read(bottomSheetControllerProvider) - is! CreateTabSheet) { - ref.read(bottomSheetControllerProvider.notifier).show( - CreateTabSheet(preferredTool: KagiTool.search), - ); - } + // if (ref.read(bottomSheetControllerProvider) + // is! CreateTabSheet) { + // ref.read(bottomSheetControllerProvider.notifier).show( + // CreateTabSheet(preferredTool: KagiTool.search), + // ); + // } - context.go(BrowserRoute().location); + // context.go(BrowserRoute().location); + context.pop(); }, ); }, diff --git a/app/lib/features/bangs/presentation/widgets/bang_icon.dart b/app/lib/features/bangs/presentation/widgets/bang_icon.dart index 81767104..5613d89b 100644 --- a/app/lib/features/bangs/presentation/widgets/bang_icon.dart +++ b/app/lib/features/bangs/presentation/widgets/bang_icon.dart @@ -2,7 +2,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_material_design_icons/flutter_material_design_icons.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:lensai/features/bangs/data/models/bang_data.dart'; -import 'package:lensai/features/bangs/domain/providers.dart'; +import 'package:lensai/features/bangs/domain/providers/bangs.dart'; import 'package:skeletonizer/skeletonizer.dart'; class BangIcon extends HookConsumerWidget { diff --git a/app/lib/features/bangs/presentation/widgets/search_field.dart b/app/lib/features/bangs/presentation/widgets/search_field.dart index addd392c..af705f64 100644 --- a/app/lib/features/bangs/presentation/widgets/search_field.dart +++ b/app/lib/features/bangs/presentation/widgets/search_field.dart @@ -4,9 +4,9 @@ import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:flutter_material_design_icons/flutter_material_design_icons.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:lensai/features/bangs/data/models/bang_data.dart'; +import 'package:lensai/features/search/domain/providers/search_suggestions.dart'; import 'package:lensai/features/bangs/presentation/widgets/bang_icon.dart'; import 'package:lensai/features/geckoview/features/browser/presentation/widgets/speech_to_text_button.dart'; -import 'package:lensai/features/kagi/domain/repositories/autosuggest.dart'; import 'package:lensai/features/settings/data/models/settings.dart'; import 'package:lensai/features/settings/data/repositories/settings_repository.dart'; import 'package:lensai/presentation/widgets/autocomplete.dart'; @@ -36,7 +36,7 @@ class SearchField extends HookConsumerWidget { ), ); - final optionsStream = ref.watch(autosuggestRepositoryProvider); + final optionsStream = ref.watch(searchSuggestionsProvider()); final focusNode = useFocusNode(); @@ -69,7 +69,7 @@ class SearchField extends HookConsumerWidget { }, onTextChanged: (textEditingValue) { ref - .read(autosuggestRepositoryProvider.notifier) + .read(searchSuggestionsProvider().notifier) .addQuery(textEditingValue.text); }, fieldViewBuilder: ( diff --git a/app/lib/features/chat_archive/data/database/daos/search.dart b/app/lib/features/chat_archive/data/database/daos/search.dart index 1c3b5fb3..8d4ceaa7 100644 --- a/app/lib/features/chat_archive/data/database/daos/search.dart +++ b/app/lib/features/chat_archive/data/database/daos/search.dart @@ -39,7 +39,7 @@ class SearchDao extends DatabaseAccessor required String searchString, }) { return db.chatQuery( - query: db.buildQuery(searchString), + query: db.buildFtsQuery(searchString), snippetLength: snippetLength, beforeMatch: matchPrefix, afterMatch: matchSuffix, diff --git a/app/lib/features/chat_archive/data/database/database.dart b/app/lib/features/chat_archive/data/database/database.dart index 9935957e..165e078b 100644 --- a/app/lib/features/chat_archive/data/database/database.dart +++ b/app/lib/features/chat_archive/data/database/database.dart @@ -1,6 +1,6 @@ import 'package:drift/drift.dart'; import 'package:lensai/features/chat_archive/data/database/daos/search.dart'; -import 'package:lensai/features/query/domain/tokenizer.dart'; +import 'package:lensai/features/search/domain/fts_tokenizer.dart'; part 'database.g.dart'; diff --git a/app/lib/features/chat_archive/data/database/database.drift b/app/lib/features/chat_archive/data/database/database.drift index 8e9e47e0..4afa58f4 100644 --- a/app/lib/features/chat_archive/data/database/database.drift +++ b/app/lib/features/chat_archive/data/database/database.drift @@ -28,7 +28,7 @@ CREATE TRIGGER chat_after_update AFTER UPDATE ON chat BEGIN chat_fts(chat_fts, rowid, title, content) VALUES('delete', old.rowid, old.title, old.content); INSERT INTO - chat_fts(chat_fts, title, content) + chat_fts(rowid, title, content) VALUES (new.rowid, new.title, new.content); END; diff --git a/app/lib/features/chat_archive/data/database/database.g.dart b/app/lib/features/chat_archive/data/database/database.g.dart index 21c0f371..071f393e 100644 --- a/app/lib/features/chat_archive/data/database/database.g.dart +++ b/app/lib/features/chat_archive/data/database/database.g.dart @@ -380,7 +380,7 @@ abstract class _$ChatSearchDatabase extends GeneratedDatabase { 'CREATE TRIGGER chat_after_delete AFTER DELETE ON chat BEGIN INSERT INTO chat_fts (chat_fts, "rowid", title, content) VALUES (\'delete\', old."rowid", old.title, old.content);END', 'chat_after_delete'); late final Trigger chatAfterUpdate = Trigger( - 'CREATE TRIGGER chat_after_update AFTER UPDATE ON chat BEGIN INSERT INTO chat_fts (chat_fts, "rowid", title, content) VALUES (\'delete\', old."rowid", old.title, old.content);INSERT INTO chat_fts (chat_fts, title, content) VALUES (new."rowid", new.title, new.content);END', + 'CREATE TRIGGER chat_after_update AFTER UPDATE ON chat BEGIN INSERT INTO chat_fts (chat_fts, "rowid", title, content) VALUES (\'delete\', old."rowid", old.title, old.content);INSERT INTO chat_fts ("rowid", title, content) VALUES (new."rowid", new.title, new.content);END', 'chat_after_update'); late final SearchDao searchDao = SearchDao(this as ChatSearchDatabase); Selectable chatQuery( diff --git a/app/lib/features/chat_archive/domain/repositories/search.dart b/app/lib/features/chat_archive/domain/repositories/search.dart index 24167f79..0abad769 100644 --- a/app/lib/features/chat_archive/domain/repositories/search.dart +++ b/app/lib/features/chat_archive/domain/repositories/search.dart @@ -83,10 +83,6 @@ class ChatArchiveSearchRepository extends _$ChatArchiveSearchRepository { _streamController = StreamController(); _searchDatabase = ref.watch(chatSearchDatabaseProvider); - ref.onDispose(() async { - await _streamController.close(); - }); - // populate with initial chats await _searchDatabase.searchDao.deleteAllChats(); await _searchDatabase.searchDao.indexChats(await _availableChats()); @@ -112,6 +108,7 @@ class ChatArchiveSearchRepository extends _$ChatArchiveSearchRepository { ref.onDispose(() async { await changeStreamSubscription.cancel(); + await _streamController.close(); }); yield* _streamController.stream; diff --git a/app/lib/features/chat_archive/domain/repositories/search.g.dart b/app/lib/features/chat_archive/domain/repositories/search.g.dart index c8be5d47..a96b13b9 100644 --- a/app/lib/features/chat_archive/domain/repositories/search.g.dart +++ b/app/lib/features/chat_archive/domain/repositories/search.g.dart @@ -7,7 +7,7 @@ part of 'search.dart'; // ************************************************************************** String _$chatArchiveSearchRepositoryHash() => - r'a3decc7975bf49995b20ea578db3c08b69f7c03c'; + r'd7174cfb877c61ee4e9580f44d7ffd11bf3b4b60'; /// See also [ChatArchiveSearchRepository]. @ProviderFor(ChatArchiveSearchRepository) diff --git a/app/lib/features/geckoview/domain/providers.dart b/app/lib/features/geckoview/domain/providers.dart index 1d597e93..e7f03d27 100644 --- a/app/lib/features/geckoview/domain/providers.dart +++ b/app/lib/features/geckoview/domain/providers.dart @@ -2,7 +2,7 @@ import 'dart:async'; import 'package:flutter_mozilla_components/flutter_mozilla_components.dart'; import 'package:lensai/core/logger.dart'; -import 'package:lensai/features/bangs/domain/providers.dart'; +import 'package:lensai/features/bangs/domain/providers/bangs.dart'; import 'package:lensai/features/geckoview/domain/providers/tab_session.dart'; import 'package:lensai/features/geckoview/domain/repositories/tab.dart'; import 'package:riverpod/riverpod.dart'; @@ -22,7 +22,7 @@ GeckoSelectionActionService selectionActionService( service.setActions([ SearchAction((text) async { final defaultSearchBang = - await ref.read(kagiSearchBangDataProvider.future); + await ref.read(defaultSearchBangDataProvider.future); if (defaultSearchBang != null) { await ref @@ -34,7 +34,7 @@ GeckoSelectionActionService selectionActionService( }), PrivateSearchAction((text) async { final defaultSearchBang = - await ref.read(kagiSearchBangDataProvider.future); + await ref.read(defaultSearchBangDataProvider.future); if (defaultSearchBang != null) { await ref.read(tabRepositoryProvider.notifier).addTab( @@ -96,6 +96,17 @@ GeckoAddonService addonService(Ref ref) { return service; } +@Riverpod(keepAlive: true) +GeckoTabContentService tabContentService(Ref ref) { + final service = GeckoTabContentService.setUp(); + + ref.onDispose(() { + service.dispose(); + }); + + return service; +} + @Riverpod(keepAlive: true) class EngineReadyState extends _$EngineReadyState { @override @@ -133,5 +144,5 @@ class EngineReadyState extends _$EngineReadyState { @Riverpod() Raw selectedTabSessionNotifier(Ref ref) { - return ref.watch(tabSessionProvider(null).notifier); + return ref.watch(tabSessionProvider(tabId: null).notifier); } diff --git a/app/lib/features/geckoview/domain/providers.g.dart b/app/lib/features/geckoview/domain/providers.g.dart index 2733fea3..39260be1 100644 --- a/app/lib/features/geckoview/domain/providers.g.dart +++ b/app/lib/features/geckoview/domain/providers.g.dart @@ -7,7 +7,7 @@ part of 'providers.dart'; // ************************************************************************** String _$selectionActionServiceHash() => - r'b5bc6b2bc5496ae84d61a74cc6ff052b55d2a3d3'; + r'd0c04262171976c21441297706273417e3d79b67'; /// See also [selectionActionService]. @ProviderFor(selectionActionService) @@ -57,8 +57,25 @@ final addonServiceProvider = Provider.internal( @Deprecated('Will be removed in 3.0. Use Ref instead') // ignore: unused_element typedef AddonServiceRef = ProviderRef; +String _$tabContentServiceHash() => r'd9a991add907ecc138c62790883e59d8e9aa9266'; + +/// See also [tabContentService]. +@ProviderFor(tabContentService) +final tabContentServiceProvider = Provider.internal( + tabContentService, + name: r'tabContentServiceProvider', + debugGetCreateSourceHash: const bool.fromEnvironment('dart.vm.product') + ? null + : _$tabContentServiceHash, + dependencies: null, + allTransitiveDependencies: null, +); + +@Deprecated('Will be removed in 3.0. Use Ref instead') +// ignore: unused_element +typedef TabContentServiceRef = ProviderRef; String _$selectedTabSessionNotifierHash() => - r'62fcd98a915566d55b5bcb297d87d675fe12786d'; + r'aef19991d5b05a2bb28e8a6ccb57dc75c2f3148f'; /// See also [selectedTabSessionNotifier]. @ProviderFor(selectedTabSessionNotifier) diff --git a/app/lib/features/geckoview/domain/providers/selected_tab.dart b/app/lib/features/geckoview/domain/providers/selected_tab.dart index 1b262995..66b791c5 100644 --- a/app/lib/features/geckoview/domain/providers/selected_tab.dart +++ b/app/lib/features/geckoview/domain/providers/selected_tab.dart @@ -2,22 +2,16 @@ import 'dart:async'; import 'package:flutter_mozilla_components/flutter_mozilla_components.dart'; import 'package:lensai/features/geckoview/domain/providers.dart'; -import 'package:lensai/features/geckoview/features/tabs/data/database/database.dart'; -import 'package:lensai/features/geckoview/features/tabs/data/providers.dart'; import 'package:riverpod_annotation/riverpod_annotation.dart'; part 'selected_tab.g.dart'; @Riverpod(keepAlive: true) class SelectedTab extends _$SelectedTab { - late TabDatabase _db; - @override String? build() { final eventSerivce = ref.watch(eventServiceProvider); - _db = ref.watch(tabDatabaseProvider); - ref.listen( fireImmediately: true, engineReadyStateProvider, @@ -31,10 +25,6 @@ class SelectedTab extends _$SelectedTab { final selectedTabSub = eventSerivce.selectedTabEvents.listen( (tabId) async { state = tabId; - - if (tabId != null) { - await _db.tabDao.touchTab(tabId, timestamp: DateTime.now()); - } }, ); diff --git a/app/lib/features/geckoview/domain/providers/selected_tab.g.dart b/app/lib/features/geckoview/domain/providers/selected_tab.g.dart index 520b1fd7..fb8dc45e 100644 --- a/app/lib/features/geckoview/domain/providers/selected_tab.g.dart +++ b/app/lib/features/geckoview/domain/providers/selected_tab.g.dart @@ -6,7 +6,7 @@ part of 'selected_tab.dart'; // RiverpodGenerator // ************************************************************************** -String _$selectedTabHash() => r'e49fb1c3938a97f384673e158742e56479aa8a8f'; +String _$selectedTabHash() => r'f550ac5b471bab8f8e5d75ef4d7669cde769db9a'; /// See also [SelectedTab]. @ProviderFor(SelectedTab) diff --git a/app/lib/features/geckoview/domain/providers/tab_list.dart b/app/lib/features/geckoview/domain/providers/tab_list.dart index 266f5b17..0926b063 100644 --- a/app/lib/features/geckoview/domain/providers/tab_list.dart +++ b/app/lib/features/geckoview/domain/providers/tab_list.dart @@ -3,22 +3,16 @@ import 'dart:async'; import 'package:collection/collection.dart'; import 'package:flutter_mozilla_components/flutter_mozilla_components.dart'; import 'package:lensai/features/geckoview/domain/providers.dart'; -import 'package:lensai/features/geckoview/features/tabs/data/database/database.dart'; -import 'package:lensai/features/geckoview/features/tabs/data/providers.dart'; import 'package:riverpod_annotation/riverpod_annotation.dart'; part 'tab_list.g.dart'; @Riverpod(keepAlive: true) class TabList extends _$TabList { - late TabDatabase _db; - @override List build() { final eventService = ref.watch(eventServiceProvider); - _db = ref.watch(tabDatabaseProvider); - ref.listen( fireImmediately: true, engineReadyStateProvider, @@ -32,15 +26,7 @@ class TabList extends _$TabList { final tabListSub = eventService.tabListEvents.listen( (tabs) async { if (!const DeepCollectionEquality().equals(state, tabs)) { - //Make sure we only syncing empty lists when there has been tabs - //before as security measurement - final syncTabs = tabs.isNotEmpty || state.isNotEmpty; - state = tabs; - - if (syncTabs) { - await _db.tabDao.syncTabs(retainTabIds: tabs); - } } }, ); diff --git a/app/lib/features/geckoview/domain/providers/tab_list.g.dart b/app/lib/features/geckoview/domain/providers/tab_list.g.dart index 84bdef8c..340db386 100644 --- a/app/lib/features/geckoview/domain/providers/tab_list.g.dart +++ b/app/lib/features/geckoview/domain/providers/tab_list.g.dart @@ -6,7 +6,7 @@ part of 'tab_list.dart'; // RiverpodGenerator // ************************************************************************** -String _$tabListHash() => r'3c17372cc467736ce1cfba937999acf4de7345ef'; +String _$tabListHash() => r'039099bfa102a86fd73c0544ea71f93f91e9d352'; /// See also [TabList]. @ProviderFor(TabList) diff --git a/app/lib/features/geckoview/domain/providers/tab_session.dart b/app/lib/features/geckoview/domain/providers/tab_session.dart index 02c04182..cc7f6bd2 100644 --- a/app/lib/features/geckoview/domain/providers/tab_session.dart +++ b/app/lib/features/geckoview/domain/providers/tab_session.dart @@ -42,7 +42,7 @@ class TabSession extends _$TabSession { } @override - void build(String? tabId) { + void build({required String? tabId}) { _sessionService = (tabId != null) ? GeckoSessionService(tabId: tabId) : GeckoSessionService.forActiveTab(); diff --git a/app/lib/features/geckoview/domain/providers/tab_session.g.dart b/app/lib/features/geckoview/domain/providers/tab_session.g.dart index a29c4f26..72131273 100644 --- a/app/lib/features/geckoview/domain/providers/tab_session.g.dart +++ b/app/lib/features/geckoview/domain/providers/tab_session.g.dart @@ -6,7 +6,7 @@ part of 'tab_session.dart'; // RiverpodGenerator // ************************************************************************** -String _$tabSessionHash() => r'42b44a4d47b9a551d002fdbc6337c14b2c327dde'; +String _$tabSessionHash() => r'e4fbbcd430037cc01adb799783fb7974a11a27bf'; /// Copied from Dart SDK class _SystemHash { @@ -32,9 +32,9 @@ class _SystemHash { abstract class _$TabSession extends BuildlessAutoDisposeNotifier { late final String? tabId; - void build( - String? tabId, - ); + void build({ + required String? tabId, + }); } /// See also [TabSession]. @@ -47,11 +47,11 @@ class TabSessionFamily extends Family { const TabSessionFamily(); /// See also [TabSession]. - TabSessionProvider call( - String? tabId, - ) { + TabSessionProvider call({ + required String? tabId, + }) { return TabSessionProvider( - tabId, + tabId: tabId, ); } @@ -60,7 +60,7 @@ class TabSessionFamily extends Family { covariant TabSessionProvider provider, ) { return call( - provider.tabId, + tabId: provider.tabId, ); } @@ -83,9 +83,9 @@ class TabSessionFamily extends Family { class TabSessionProvider extends AutoDisposeNotifierProviderImpl { /// See also [TabSession]. - TabSessionProvider( - String? tabId, - ) : this._internal( + TabSessionProvider({ + required String? tabId, + }) : this._internal( () => TabSession()..tabId = tabId, from: tabSessionProvider, name: r'tabSessionProvider', @@ -116,7 +116,7 @@ class TabSessionProvider covariant TabSession notifier, ) { return notifier.build( - tabId, + tabId: tabId, ); } diff --git a/app/lib/features/geckoview/domain/repositories/tab.dart b/app/lib/features/geckoview/domain/repositories/tab.dart index 4cae0c30..1bf2de80 100644 --- a/app/lib/features/geckoview/domain/repositories/tab.dart +++ b/app/lib/features/geckoview/domain/repositories/tab.dart @@ -2,10 +2,15 @@ import 'dart:async'; import 'package:drift/drift.dart'; import 'package:flutter_mozilla_components/flutter_mozilla_components.dart'; +import 'package:lensai/features/geckoview/domain/entities/tab_state.dart'; import 'package:lensai/features/geckoview/domain/providers.dart'; +import 'package:lensai/features/geckoview/domain/providers/selected_tab.dart'; +import 'package:lensai/features/geckoview/domain/providers/tab_list.dart'; +import 'package:lensai/features/geckoview/domain/providers/tab_state.dart'; import 'package:lensai/features/geckoview/features/tabs/data/database/database.dart'; import 'package:lensai/features/geckoview/features/tabs/data/providers.dart'; import 'package:lensai/features/geckoview/features/tabs/domain/providers/selected_container.dart'; +import 'package:lensai/utils/debouncer.dart'; import 'package:riverpod_annotation/riverpod_annotation.dart'; part 'tab.g.dart'; @@ -57,6 +62,10 @@ class TabRepository extends _$TabRepository { @override void build() { final eventSerivce = ref.watch(eventServiceProvider); + final tabContentService = ref.watch(tabContentServiceProvider); + + final tabStateDebouncer = Debouncer(const Duration(seconds: 3)); + Map? debounceStartValue; _db = ref.watch(tabDatabaseProvider); @@ -67,8 +76,58 @@ class TabRepository extends _$TabRepository { }, ); + final tabContentSub = + tabContentService.tabContentStream.listen((content) async { + await _db.tabDao.updateTab( + content.tabId, + extractedContentMarkdown: Value(content.extractedContentMarkdown), + extractedContentPlain: Value(content.extractedContentPlain), + fullContentMarkdown: Value(content.fullContentMarkdown), + fullContentPlain: Value(content.fullContentPlain), + ); + }); + + ref.listen( + selectedTabProvider, + (previous, tabId) async { + if (tabId != null) { + await _db.tabDao.touchTab(tabId, timestamp: DateTime.now()); + } + }, + ); + + ref.listen( + tabListProvider, + (previous, next) async { + //Only sync tabs if there has been a previous value or is not empty + final syncTabs = next.isNotEmpty || (previous?.isNotEmpty ?? false); + + if (syncTabs) { + await _db.tabDao.syncTabs(retainTabIds: next); + } + }, + ); + + ref.listen( + tabStatesProvider, + (previous, next) async { + //Since state changes occure pretty often and our map always contains + //the latest state, we cache the value before starting debouncing and + //later diff to that, to avoid frequent database writes + if (!tabStateDebouncer.isDebouncing) { + debounceStartValue = previous; + } + + tabStateDebouncer.eventOccured(() async { + await _db.tabDao.updateTabs(debounceStartValue, next); + }); + }, + ); + ref.onDispose(() { + tabStateDebouncer.dispose(); unawaited(tabAddedSub.cancel()); + unawaited(tabContentSub.cancel()); }); } } diff --git a/app/lib/features/geckoview/domain/repositories/tab.g.dart b/app/lib/features/geckoview/domain/repositories/tab.g.dart index d9cd5ac4..1669d825 100644 --- a/app/lib/features/geckoview/domain/repositories/tab.g.dart +++ b/app/lib/features/geckoview/domain/repositories/tab.g.dart @@ -6,7 +6,7 @@ part of 'tab.dart'; // RiverpodGenerator // ************************************************************************** -String _$tabRepositoryHash() => r'05040223b83cd5ff80afaf89407043a10e4777cb'; +String _$tabRepositoryHash() => r'b151be1c18d87eff3a15f4b70f4e82fcc11047ec'; /// See also [TabRepository]. @ProviderFor(TabRepository) diff --git a/app/lib/features/geckoview/features/browser/presentation/dialogs/web_page_dialog.dart b/app/lib/features/geckoview/features/browser/presentation/dialogs/web_page_dialog.dart index a08e044c..8434d25a 100644 --- a/app/lib/features/geckoview/features/browser/presentation/dialogs/web_page_dialog.dart +++ b/app/lib/features/geckoview/features/browser/presentation/dialogs/web_page_dialog.dart @@ -7,7 +7,7 @@ import 'package:flutter_material_design_icons/flutter_material_design_icons.dart import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:lensai/data/models/web_page_info.dart'; import 'package:lensai/features/bangs/data/models/bang_data.dart'; -import 'package:lensai/features/bangs/domain/providers.dart'; +import 'package:lensai/features/bangs/domain/providers/bangs.dart'; import 'package:lensai/features/bangs/presentation/widgets/site_search.dart'; import 'package:lensai/features/geckoview/domain/providers.dart'; import 'package:lensai/features/geckoview/domain/providers/tab_session.dart'; @@ -92,7 +92,7 @@ class WebPageDialog extends HookConsumerWidget { onPressed: () async { if (formKey.currentState?.validate() ?? false) { await ref - .read(tabSessionProvider(null).notifier) + .read(tabSessionProvider(tabId: null).notifier) .loadUrl( url: uri_parser.tryParseUrl( urlTextController.text, diff --git a/app/lib/features/geckoview/features/browser/screens/browser.dart b/app/lib/features/geckoview/features/browser/presentation/screens/browser.dart similarity index 92% rename from app/lib/features/geckoview/features/browser/screens/browser.dart rename to app/lib/features/geckoview/features/browser/presentation/screens/browser.dart index 9310799b..42b39374 100644 --- a/app/lib/features/geckoview/features/browser/screens/browser.dart +++ b/app/lib/features/geckoview/features/browser/presentation/screens/browser.dart @@ -19,6 +19,7 @@ import 'package:lensai/features/geckoview/features/browser/domain/services/engin import 'package:lensai/features/geckoview/features/browser/presentation/dialogs/web_page_dialog.dart'; import 'package:lensai/features/geckoview/features/browser/presentation/widgets/app_bar_title.dart'; import 'package:lensai/features/geckoview/features/browser/presentation/widgets/browser_view.dart'; +import 'package:lensai/features/geckoview/features/browser/presentation/widgets/extension_badge_icon.dart'; import 'package:lensai/features/geckoview/features/browser/presentation/widgets/sheets/create_tab.dart'; import 'package:lensai/features/geckoview/features/browser/presentation/widgets/sheets/view_tabs.dart'; import 'package:lensai/features/geckoview/features/browser/presentation/widgets/tabs_action_button.dart'; @@ -47,6 +48,9 @@ class BrowserScreen extends HookConsumerWidget { @override Widget build(BuildContext context, WidgetRef ref) { + //Init here to avoid dispose errors of menu items when called + final addonService = ref.watch(addonServiceProvider); + final displayedSheet = ref.watch(bottomSheetControllerProvider); final displayedOverlayDialog = ref.watch(overlayDialogControllerProvider); @@ -186,14 +190,15 @@ class BrowserScreen extends HookConsumerWidget { color: (activeTool == KagiTool.search) ? Theme.of(context).colorScheme.primary : null, - onPressed: () { - ref - .read(createTabStreamProvider.notifier) - .createTab( - CreateTabSheet( - preferredTool: KagiTool.search, - ), - ); + onPressed: () async { + // ref + // .read(createTabStreamProvider.notifier) + // .createTab( + // CreateTabSheet( + // preferredTool: KagiTool.search, + // ), + // ); + await context.push(SearchRoute().location); }, icon: Icon(KagiTool.search.icon), ), @@ -337,30 +342,12 @@ class BrowserScreen extends HookConsumerWidget { (extension) => IconButton( onPressed: () async { //Use parents .ref because after onPressed this consumer gets disposed already - await ref - .read(addonServiceProvider) - .invokeAddonAction( - extension.extensionId, - WebExtensionActionType.page, - ); + await addonService.invokeAddonAction( + extension.extensionId, + WebExtensionActionType.page, + ); }, - icon: Badge( - isLabelVisible: - extension.badgeText?.isNotEmpty ?? - false, - label: (extension.badgeText?.isNotEmpty == - true) - ? Text(extension.badgeText!) - : null, - textColor: extension.badgeTextColor, - backgroundColor: - extension.badgeBackgroundColor, - child: RawImage( - image: extension.icon?.value, - width: 24, - height: 24, - ), - ), + icon: ExtensionBadgeIcon(extension), ), ), ], @@ -383,8 +370,8 @@ class BrowserScreen extends HookConsumerWidget { child: const Text('Settings'), ), Consumer( - builder: (context, childRef, child) { - final browserExtensions = childRef.watch( + builder: (context, ref, child) { + final browserExtensions = ref.watch( webExtensionsStateProvider( WebExtensionActionType.browser, ).select((value) => value.values.toList()), @@ -396,24 +383,18 @@ class BrowserScreen extends HookConsumerWidget { (extension) => MenuItemButton( onPressed: () async { //Use parents .ref because after onPressed this consumer gets disposed already - await ref - .read(addonServiceProvider) - .invokeAddonAction( - extension.extensionId, - WebExtensionActionType.browser, - ); + await addonService.invokeAddonAction( + extension.extensionId, + WebExtensionActionType.browser, + ); }, - leadingIcon: RawImage( - image: extension.icon?.value, - width: 24, - height: 24, - ), + leadingIcon: ExtensionBadgeIcon(extension), child: Text(extension.title ?? ''), ), ), MenuItemButton( onPressed: () async { - await childRef + await ref .read(addonServiceProvider) .startAddonManagerActivity(); }, @@ -530,7 +511,8 @@ class BrowserScreen extends HookConsumerWidget { MenuItemButton( onPressed: () async { final controller = ref.read( - tabSessionProvider(selectedTabId).notifier, + tabSessionProvider(tabId: selectedTabId) + .notifier, ); await controller.reload(); @@ -556,7 +538,7 @@ class BrowserScreen extends HookConsumerWidget { onPressed: () async { final controller = ref.read( tabSessionProvider( - selectedTabId, + tabId: selectedTabId, ).notifier, ); @@ -588,7 +570,7 @@ class BrowserScreen extends HookConsumerWidget { ? () async { final controller = ref.read( tabSessionProvider( - selectedTabId, + tabId: selectedTabId, ).notifier, ); @@ -664,7 +646,7 @@ class BrowserScreen extends HookConsumerWidget { lastBackButtonPress.value = null; final controller = ref.read( - tabSessionProvider(selectedTabId).notifier, + tabSessionProvider(tabId: selectedTabId).notifier, ); await controller.goBack(); diff --git a/app/lib/features/geckoview/features/browser/presentation/widgets/browser_view.dart b/app/lib/features/geckoview/features/browser/presentation/widgets/browser_view.dart index 80867aab..22e2b14c 100644 --- a/app/lib/features/geckoview/features/browser/presentation/widgets/browser_view.dart +++ b/app/lib/features/geckoview/features/browser/presentation/widgets/browser_view.dart @@ -7,6 +7,7 @@ import 'package:lensai/core/logger.dart'; import 'package:lensai/features/geckoview/domain/providers.dart'; import 'package:lensai/features/geckoview/domain/providers/tab_state.dart'; import 'package:lensai/features/geckoview/domain/providers/web_extensions_state.dart'; +import 'package:lensai/features/geckoview/domain/repositories/tab.dart'; class BrowserView extends StatefulHookConsumerWidget { final Duration screenshotPeriod; @@ -84,6 +85,8 @@ class _BrowserViewState extends ConsumerState WidgetsBinding.instance.addObserver(this); //Initialize and register dependencies + ref.listenManual(tabRepositoryProvider, (previous, next) {}); + ref.listenManual( selectionActionServiceProvider, (previous, next) {}, diff --git a/app/lib/features/geckoview/features/browser/presentation/widgets/extension_badge_icon.dart b/app/lib/features/geckoview/features/browser/presentation/widgets/extension_badge_icon.dart new file mode 100644 index 00000000..ea0ab257 --- /dev/null +++ b/app/lib/features/geckoview/features/browser/presentation/widgets/extension_badge_icon.dart @@ -0,0 +1,25 @@ +import 'package:flutter/material.dart'; +import 'package:lensai/features/geckoview/domain/entities/web_extension_state.dart'; + +class ExtensionBadgeIcon extends StatelessWidget { + final WebExtensionState state; + + const ExtensionBadgeIcon(this.state); + + @override + Widget build(BuildContext context) { + final hasBadge = state.badgeText?.isNotEmpty ?? false; + + return Badge( + isLabelVisible: hasBadge, + label: hasBadge ? Text(state.badgeText!) : null, + textColor: state.badgeTextColor, + backgroundColor: state.badgeBackgroundColor, + child: RawImage( + image: state.icon?.value, + width: 24, + height: 24, + ), + ); + } +} diff --git a/app/lib/features/geckoview/features/browser/presentation/widgets/sheets/view_tabs.dart b/app/lib/features/geckoview/features/browser/presentation/widgets/sheets/view_tabs.dart index 6d33b768..8e650848 100644 --- a/app/lib/features/geckoview/features/browser/presentation/widgets/sheets/view_tabs.dart +++ b/app/lib/features/geckoview/features/browser/presentation/widgets/sheets/view_tabs.dart @@ -67,7 +67,31 @@ class _SliverHeaderDelagate extends SliverPersistentHeaderDelegate { ), ], ), - ContainerChips(), + Padding( + padding: const EdgeInsets.only(left: 16.0), + child: Consumer( + builder: (context, ref, child) { + final selectedContainer = ref.watch( + selectedContainerDataProvider + .select((value) => value.valueOrNull), + ); + + return ContainerChips( + selectedContainer: selectedContainer, + onSelected: (container) { + ref + .read(selectedContainerProvider.notifier) + .setContainerId(container.id); + }, + onDeleted: (container) async { + ref + .read(selectedContainerProvider.notifier) + .clearContainer(); + }, + ); + }, + ), + ), const SizedBox(height: 8), ], ), diff --git a/app/lib/features/geckoview/features/tabs/data/database/daos/tab.dart b/app/lib/features/geckoview/features/tabs/data/database/daos/tab.dart index e7d51138..0d11c6af 100644 --- a/app/lib/features/geckoview/features/tabs/data/database/daos/tab.dart +++ b/app/lib/features/geckoview/features/tabs/data/database/daos/tab.dart @@ -1,7 +1,11 @@ import 'dart:async'; +import 'package:collection/collection.dart'; import 'package:drift/drift.dart'; +import 'package:lensai/core/logger.dart'; +import 'package:lensai/features/geckoview/domain/entities/tab_state.dart'; import 'package:lensai/features/geckoview/features/tabs/data/database/database.dart'; +import 'package:lensai/features/geckoview/features/tabs/data/models/tab_query_result.dart'; import 'package:lexo_rank/lexo_rank.dart'; part 'tab.g.dart'; @@ -10,6 +14,14 @@ part 'tab.g.dart'; class TabDao extends DatabaseAccessor with _$TabDaoMixin { TabDao(super.db); + UpdateStatement _updateByIdStatement(String id) => + db.tab.update()..where((t) => t.id.equals(id)); + + Selectable allTabData() => db.tab.select(); + + SingleOrNullSelectable tabDataById(String id) => + db.tab.select()..where((t) => t.id.equals(id)); + Selectable containerTabIds(String? containerId) { final query = selectOnly(db.tab) ..addColumns([db.tab.id]) @@ -74,7 +86,7 @@ class TabDao extends DatabaseAccessor with _$TabDaoMixin { String id, { required String? containerId, }) { - final statement = db.tab.update()..where((t) => t.id.equals(id)); + final statement = _updateByIdStatement(id); return statement.write( TabCompanion(containerId: Value(containerId)), ); @@ -84,7 +96,7 @@ class TabDao extends DatabaseAccessor with _$TabDaoMixin { String id, { required String orderKey, }) { - final statement = db.tab.update()..where((t) => t.id.equals(id)); + final statement = _updateByIdStatement(id); return statement.write( TabCompanion(orderKey: Value(orderKey)), ); @@ -94,12 +106,71 @@ class TabDao extends DatabaseAccessor with _$TabDaoMixin { String id, { required DateTime timestamp, }) { - final statement = db.tab.update()..where((t) => t.id.equals(id)); + final statement = _updateByIdStatement(id); return statement.write( TabCompanion(timestamp: Value(timestamp)), ); } + Future updateTab( + String id, { + Value url = const Value.absent(), + Value title = const Value.absent(), + Value extractedContentMarkdown = const Value.absent(), + Value extractedContentPlain = const Value.absent(), + Value fullContentMarkdown = const Value.absent(), + Value fullContentPlain = const Value.absent(), + }) async { + final doUpdate = url != const Value.absent() || + title != const Value.absent() || + extractedContentMarkdown != const Value.absent() || + extractedContentPlain != const Value.absent() || + fullContentMarkdown != const Value.absent() || + fullContentPlain != const Value.absent(); + + if (doUpdate) { + final statement = _updateByIdStatement(id); + await statement.write( + TabCompanion( + url: url, + title: title, + extractedContentMarkdown: extractedContentMarkdown, + extractedContentPlain: extractedContentPlain, + fullContentMarkdown: fullContentMarkdown, + fullContentPlain: fullContentPlain, + ), + ); + } + } + + Future updateTabs( + Map? previous, + Map next, + ) async { + await batch((batch) async { + for (final state in next.values) { + final previousState = previous?[state.id]; + + if (previousState == null || + previousState.url != state.url || + previousState.title != state.title) { + batch.update( + db.tab, + TabCompanion( + url: (previousState?.url != state.url) + ? Value(state.url.toString()) + : const Value.absent(), + title: (previousState?.title != state.title) + ? Value(state.title) + : const Value.absent(), + ), + where: (t) => t.id.equals(state.id), + ); + } + } + }); + } + Future syncTabs({required List retainTabIds}) async { return db.transaction(() async { await (db.tab.delete()..where((t) => t.id.isNotIn(retainTabIds))).go(); @@ -125,4 +196,30 @@ class TabDao extends DatabaseAccessor with _$TabDaoMixin { ); }); } + + Selectable queryTabs({ + required String matchPrefix, + required String matchSuffix, + required String ellipsis, + required int snippetLength, + required String searchString, + }) { + final ftsQuery = db.buildFtsQuery(searchString); + + if (ftsQuery.isNotEmpty) { + return db.queryTabsFullContent( + query: db.buildFtsQuery(searchString), + snippetLength: snippetLength, + beforeMatch: matchPrefix, + afterMatch: matchSuffix, + ellipsis: ellipsis, + ); + } else { + return db.queryTabsBasic( + query: db.buildLikeQuery(searchString), + beforeMatch: matchPrefix, + afterMatch: matchSuffix, + ); + } + } } diff --git a/app/lib/features/geckoview/features/tabs/data/database/database.dart b/app/lib/features/geckoview/features/tabs/data/database/database.dart index 718fe419..b8a0a454 100644 --- a/app/lib/features/geckoview/features/tabs/data/database/database.dart +++ b/app/lib/features/geckoview/features/tabs/data/database/database.dart @@ -6,6 +6,10 @@ import 'package:lensai/data/database/converters/icon_data.dart'; import 'package:lensai/features/geckoview/features/tabs/data/database/daos/container.dart'; import 'package:lensai/features/geckoview/features/tabs/data/database/daos/tab.dart'; import 'package:lensai/features/geckoview/features/tabs/data/models/container_data.dart'; +import 'package:lensai/features/geckoview/features/tabs/data/models/tab_query_result.dart'; +import 'package:lensai/features/search/domain/entities/abstract/i_query_builder.dart'; +import 'package:lensai/features/search/domain/fts_tokenizer.dart'; +import 'package:lensai/features/search/domain/unix_tokenizer.dart'; part 'database.g.dart'; @@ -13,10 +17,40 @@ part 'database.g.dart'; include: {'database.drift'}, daos: [ContainerDao, TabDao], ) -class TabDatabase extends _$TabDatabase { +class TabDatabase extends _$TabDatabase implements IQueryBuilder { @override final int schemaVersion = 2; + @override + final int ftsTokenLimit = 10; + @override + final int ftsMinTokenLength = 3; + + @override + String buildFtsQuery(String input) { + final ftsQueryBuilder = TrigramQueryBuilder.tokenize( + input: input, + minTokenLength: ftsMinTokenLength, + tokenLimit: ftsTokenLimit, + ); + + if (ftsQueryBuilder.hasTokens) { + return ftsQueryBuilder.build(); + } + + return ''; + } + + String buildLikeQuery(String input) { + final likeQueryBuilder = UnixLikeQueryBuilder.tokenize( + input: input, + minTokenLength: 1, + tokenLimit: 5, + ); + + return likeQueryBuilder.build(); + } + @override MigrationStrategy get migration => MigrationStrategy( onUpgrade: (m, from, to) async { diff --git a/app/lib/features/geckoview/features/tabs/data/database/database.drift b/app/lib/features/geckoview/features/tabs/data/database/database.drift index 02263fd7..15c19f78 100644 --- a/app/lib/features/geckoview/features/tabs/data/database/database.drift +++ b/app/lib/features/geckoview/features/tabs/data/database/database.drift @@ -1,6 +1,7 @@ import 'package:lensai/data/database/converters/color.dart'; import 'package:lensai/data/database/converters/icon_data.dart'; import 'package:lensai/features/geckoview/features/tabs/data/models/container_data.dart'; +import 'package:lensai/features/geckoview/features/tabs/data/models/tab_query_result.dart'; CREATE TABLE container ( id TEXT PRIMARY KEY NOT NULL, @@ -14,9 +15,45 @@ CREATE TABLE tab ( id TEXT PRIMARY KEY NOT NULL, container_id TEXT REFERENCES container (id) ON DELETE CASCADE, order_key TEXT NOT NULL, + url TEXT, + title TEXT, + extracted_content_markdown TEXT, + extracted_content_plain TEXT, + full_content_markdown TEXT, + full_content_plain TEXT, timestamp DATETIME NOT NULL ); +CREATE VIRTUAL TABLE tab_fts + USING fts5( + title, + url, + extracted_content_plain, + full_content_plain, + content=tab, + tokenize="trigram" + ); + +-- Triggers to keep the FTS index up to date. +CREATE TRIGGER tab_after_insert AFTER INSERT ON tab BEGIN + INSERT INTO + tab_fts(rowid, title, url, extracted_content_plain, full_content_plain) + VALUES (new.rowid, new.title, new.url, new.extracted_content_plain, new.full_content_plain); +END; +CREATE TRIGGER tab_after_delete AFTER DELETE ON tab BEGIN + INSERT INTO + tab_fts(tab_fts, rowid, title, url, extracted_content_plain, full_content_plain) + VALUES('delete', old.rowid, old.title, old.url, old.extracted_content_plain, old.full_content_plain); +END; +CREATE TRIGGER tab_after_update AFTER UPDATE ON tab BEGIN + INSERT INTO + tab_fts(tab_fts, rowid, title, url, extracted_content_plain, full_content_plain) + VALUES('delete', old.rowid, old.title, old.url, old.extracted_content_plain, old.full_content_plain); + INSERT INTO + tab_fts(rowid, title, url, extracted_content_plain, full_content_plain) + VALUES (new.rowid, new.title, new.url, new.extracted_content_plain, new.full_content_plain); +END; + containersWithCount WITH ContainerDataWithCount: SELECT container.*, @@ -66,4 +103,53 @@ orderKeyAfterTab(:tab_id AS TEXT, :container_id AS TEXT OR NULL): ) SELECT lexo_rank_reorder_after(order_key, next_order_key) FROM ordered_table - WHERE id = :tab_id; \ No newline at end of file + WHERE id = :tab_id; + +queryTabsBasic WITH TabQueryResult: + WITH weights AS ( + SELECT + -- Customize these weights (higher = more important) + 10.0 as title_weight, -- Title matches are most important + 5.0 as url_weight -- URL matches are quite important + ) + SELECT + t.id, + highlight(tab_fts, 0, :beforeMatch, :afterMatch) AS title, + highlight(tab_fts, 1, :beforeMatch, :afterMatch) AS url, + bm25(tab_fts, weights.title_weight, weights.url_weight) AS weighted_rank + FROM tab_fts fts + INNER JOIN + tab t ON t.rowid = fts.rowid + CROSS JOIN weights + WHERE + fts.title LIKE :query OR + fts.url LIKE :query + ORDER BY + weighted_rank ASC, + t.timestamp DESC; + +queryTabsFullContent WITH TabQueryResult: + WITH weights AS ( + SELECT + -- Customize these weights (higher = more important) + 10.0 as title_weight, -- Title matches are most important + 5.0 as url_weight, -- URL matches are quite important + 3.0 as extracted_weight, -- Extracted content matches + 1.0 as full_weight -- Full content matches less important + ) + SELECT + highlight(tab_fts, 0, :beforeMatch, :afterMatch) AS title, + highlight(tab_fts, 1, :beforeMatch, :afterMatch) AS url, + snippet(tab_fts, 2, :beforeMatch, :afterMatch, :ellipsis, :snippetLength) AS extracted_content, + snippet(tab_fts, 3, :beforeMatch, :afterMatch, :ellipsis, :snippetLength) AS full_content, + ( + bm25(tab_fts, weights.title_weight, weights.url_weight, + weights.extracted_weight, weights.full_weight) + ) AS weighted_rank + FROM tab_fts(:query) fts + INNER JOIN + tab t ON t.rowid = fts.rowid + CROSS JOIN weights + ORDER BY + weighted_rank ASC, + t.timestamp DESC; \ No newline at end of file diff --git a/app/lib/features/geckoview/features/tabs/data/database/database.g.dart b/app/lib/features/geckoview/features/tabs/data/database/database.g.dart index 90611ece..d7418b35 100644 --- a/app/lib/features/geckoview/features/tabs/data/database/database.g.dart +++ b/app/lib/features/geckoview/features/tabs/data/database/database.g.dart @@ -195,13 +195,54 @@ class Tab extends Table with TableInfo { type: DriftSqlType.string, requiredDuringInsert: true, $customConstraints: 'NOT NULL'); + late final GeneratedColumn url = GeneratedColumn( + 'url', aliasedName, true, + type: DriftSqlType.string, + requiredDuringInsert: false, + $customConstraints: ''); + late final GeneratedColumn title = GeneratedColumn( + 'title', aliasedName, true, + type: DriftSqlType.string, + requiredDuringInsert: false, + $customConstraints: ''); + late final GeneratedColumn extractedContentMarkdown = + GeneratedColumn('extracted_content_markdown', aliasedName, true, + type: DriftSqlType.string, + requiredDuringInsert: false, + $customConstraints: ''); + late final GeneratedColumn extractedContentPlain = + GeneratedColumn('extracted_content_plain', aliasedName, true, + type: DriftSqlType.string, + requiredDuringInsert: false, + $customConstraints: ''); + late final GeneratedColumn fullContentMarkdown = + GeneratedColumn('full_content_markdown', aliasedName, true, + type: DriftSqlType.string, + requiredDuringInsert: false, + $customConstraints: ''); + late final GeneratedColumn fullContentPlain = GeneratedColumn( + 'full_content_plain', aliasedName, true, + type: DriftSqlType.string, + requiredDuringInsert: false, + $customConstraints: ''); late final GeneratedColumn timestamp = GeneratedColumn( 'timestamp', aliasedName, false, type: DriftSqlType.dateTime, requiredDuringInsert: true, $customConstraints: 'NOT NULL'); @override - List get $columns => [id, containerId, orderKey, timestamp]; + List get $columns => [ + id, + containerId, + orderKey, + url, + title, + extractedContentMarkdown, + extractedContentPlain, + fullContentMarkdown, + fullContentPlain, + timestamp + ]; @override String get aliasedName => _alias ?? actualTableName; @override @@ -219,6 +260,20 @@ class Tab extends Table with TableInfo { .read(DriftSqlType.string, data['${effectivePrefix}container_id']), orderKey: attachedDatabase.typeMapping .read(DriftSqlType.string, data['${effectivePrefix}order_key'])!, + url: attachedDatabase.typeMapping + .read(DriftSqlType.string, data['${effectivePrefix}url']), + title: attachedDatabase.typeMapping + .read(DriftSqlType.string, data['${effectivePrefix}title']), + extractedContentMarkdown: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}extracted_content_markdown']), + extractedContentPlain: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}extracted_content_plain']), + fullContentMarkdown: attachedDatabase.typeMapping.read( + DriftSqlType.string, data['${effectivePrefix}full_content_markdown']), + fullContentPlain: attachedDatabase.typeMapping.read( + DriftSqlType.string, data['${effectivePrefix}full_content_plain']), timestamp: attachedDatabase.typeMapping .read(DriftSqlType.dateTime, data['${effectivePrefix}timestamp'])!, ); @@ -237,11 +292,23 @@ class TabData extends DataClass implements Insertable { final String id; final String? containerId; final String orderKey; + final String? url; + final String? title; + final String? extractedContentMarkdown; + final String? extractedContentPlain; + final String? fullContentMarkdown; + final String? fullContentPlain; final DateTime timestamp; const TabData( {required this.id, this.containerId, required this.orderKey, + this.url, + this.title, + this.extractedContentMarkdown, + this.extractedContentPlain, + this.fullContentMarkdown, + this.fullContentPlain, required this.timestamp}); @override Map toColumns(bool nullToAbsent) { @@ -251,6 +318,25 @@ class TabData extends DataClass implements Insertable { map['container_id'] = Variable(containerId); } map['order_key'] = Variable(orderKey); + if (!nullToAbsent || url != null) { + map['url'] = Variable(url); + } + if (!nullToAbsent || title != null) { + map['title'] = Variable(title); + } + if (!nullToAbsent || extractedContentMarkdown != null) { + map['extracted_content_markdown'] = + Variable(extractedContentMarkdown); + } + if (!nullToAbsent || extractedContentPlain != null) { + map['extracted_content_plain'] = Variable(extractedContentPlain); + } + if (!nullToAbsent || fullContentMarkdown != null) { + map['full_content_markdown'] = Variable(fullContentMarkdown); + } + if (!nullToAbsent || fullContentPlain != null) { + map['full_content_plain'] = Variable(fullContentPlain); + } map['timestamp'] = Variable(timestamp); return map; } @@ -262,6 +348,16 @@ class TabData extends DataClass implements Insertable { id: serializer.fromJson(json['id']), containerId: serializer.fromJson(json['container_id']), orderKey: serializer.fromJson(json['order_key']), + url: serializer.fromJson(json['url']), + title: serializer.fromJson(json['title']), + extractedContentMarkdown: + serializer.fromJson(json['extracted_content_markdown']), + extractedContentPlain: + serializer.fromJson(json['extracted_content_plain']), + fullContentMarkdown: + serializer.fromJson(json['full_content_markdown']), + fullContentPlain: + serializer.fromJson(json['full_content_plain']), timestamp: serializer.fromJson(json['timestamp']), ); } @@ -272,6 +368,14 @@ class TabData extends DataClass implements Insertable { 'id': serializer.toJson(id), 'container_id': serializer.toJson(containerId), 'order_key': serializer.toJson(orderKey), + 'url': serializer.toJson(url), + 'title': serializer.toJson(title), + 'extracted_content_markdown': + serializer.toJson(extractedContentMarkdown), + 'extracted_content_plain': + serializer.toJson(extractedContentPlain), + 'full_content_markdown': serializer.toJson(fullContentMarkdown), + 'full_content_plain': serializer.toJson(fullContentPlain), 'timestamp': serializer.toJson(timestamp), }; } @@ -280,11 +384,31 @@ class TabData extends DataClass implements Insertable { {String? id, Value containerId = const Value.absent(), String? orderKey, + Value url = const Value.absent(), + Value title = const Value.absent(), + Value extractedContentMarkdown = const Value.absent(), + Value extractedContentPlain = const Value.absent(), + Value fullContentMarkdown = const Value.absent(), + Value fullContentPlain = const Value.absent(), DateTime? timestamp}) => TabData( id: id ?? this.id, containerId: containerId.present ? containerId.value : this.containerId, orderKey: orderKey ?? this.orderKey, + url: url.present ? url.value : this.url, + title: title.present ? title.value : this.title, + extractedContentMarkdown: extractedContentMarkdown.present + ? extractedContentMarkdown.value + : this.extractedContentMarkdown, + extractedContentPlain: extractedContentPlain.present + ? extractedContentPlain.value + : this.extractedContentPlain, + fullContentMarkdown: fullContentMarkdown.present + ? fullContentMarkdown.value + : this.fullContentMarkdown, + fullContentPlain: fullContentPlain.present + ? fullContentPlain.value + : this.fullContentPlain, timestamp: timestamp ?? this.timestamp, ); TabData copyWithCompanion(TabCompanion data) { @@ -293,6 +417,20 @@ class TabData extends DataClass implements Insertable { containerId: data.containerId.present ? data.containerId.value : this.containerId, orderKey: data.orderKey.present ? data.orderKey.value : this.orderKey, + url: data.url.present ? data.url.value : this.url, + title: data.title.present ? data.title.value : this.title, + extractedContentMarkdown: data.extractedContentMarkdown.present + ? data.extractedContentMarkdown.value + : this.extractedContentMarkdown, + extractedContentPlain: data.extractedContentPlain.present + ? data.extractedContentPlain.value + : this.extractedContentPlain, + fullContentMarkdown: data.fullContentMarkdown.present + ? data.fullContentMarkdown.value + : this.fullContentMarkdown, + fullContentPlain: data.fullContentPlain.present + ? data.fullContentPlain.value + : this.fullContentPlain, timestamp: data.timestamp.present ? data.timestamp.value : this.timestamp, ); } @@ -303,13 +441,29 @@ class TabData extends DataClass implements Insertable { ..write('id: $id, ') ..write('containerId: $containerId, ') ..write('orderKey: $orderKey, ') + ..write('url: $url, ') + ..write('title: $title, ') + ..write('extractedContentMarkdown: $extractedContentMarkdown, ') + ..write('extractedContentPlain: $extractedContentPlain, ') + ..write('fullContentMarkdown: $fullContentMarkdown, ') + ..write('fullContentPlain: $fullContentPlain, ') ..write('timestamp: $timestamp') ..write(')')) .toString(); } @override - int get hashCode => Object.hash(id, containerId, orderKey, timestamp); + int get hashCode => Object.hash( + id, + containerId, + orderKey, + url, + title, + extractedContentMarkdown, + extractedContentPlain, + fullContentMarkdown, + fullContentPlain, + timestamp); @override bool operator ==(Object other) => identical(this, other) || @@ -317,6 +471,12 @@ class TabData extends DataClass implements Insertable { other.id == this.id && other.containerId == this.containerId && other.orderKey == this.orderKey && + other.url == this.url && + other.title == this.title && + other.extractedContentMarkdown == this.extractedContentMarkdown && + other.extractedContentPlain == this.extractedContentPlain && + other.fullContentMarkdown == this.fullContentMarkdown && + other.fullContentPlain == this.fullContentPlain && other.timestamp == this.timestamp); } @@ -324,12 +484,24 @@ class TabCompanion extends UpdateCompanion { final Value id; final Value containerId; final Value orderKey; + final Value url; + final Value title; + final Value extractedContentMarkdown; + final Value extractedContentPlain; + final Value fullContentMarkdown; + final Value fullContentPlain; final Value timestamp; final Value rowid; const TabCompanion({ this.id = const Value.absent(), this.containerId = const Value.absent(), this.orderKey = const Value.absent(), + this.url = const Value.absent(), + this.title = const Value.absent(), + this.extractedContentMarkdown = const Value.absent(), + this.extractedContentPlain = const Value.absent(), + this.fullContentMarkdown = const Value.absent(), + this.fullContentPlain = const Value.absent(), this.timestamp = const Value.absent(), this.rowid = const Value.absent(), }); @@ -337,6 +509,12 @@ class TabCompanion extends UpdateCompanion { required String id, this.containerId = const Value.absent(), required String orderKey, + this.url = const Value.absent(), + this.title = const Value.absent(), + this.extractedContentMarkdown = const Value.absent(), + this.extractedContentPlain = const Value.absent(), + this.fullContentMarkdown = const Value.absent(), + this.fullContentPlain = const Value.absent(), required DateTime timestamp, this.rowid = const Value.absent(), }) : id = Value(id), @@ -346,6 +524,12 @@ class TabCompanion extends UpdateCompanion { Expression? id, Expression? containerId, Expression? orderKey, + Expression? url, + Expression? title, + Expression? extractedContentMarkdown, + Expression? extractedContentPlain, + Expression? fullContentMarkdown, + Expression? fullContentPlain, Expression? timestamp, Expression? rowid, }) { @@ -353,6 +537,15 @@ class TabCompanion extends UpdateCompanion { if (id != null) 'id': id, if (containerId != null) 'container_id': containerId, if (orderKey != null) 'order_key': orderKey, + if (url != null) 'url': url, + if (title != null) 'title': title, + if (extractedContentMarkdown != null) + 'extracted_content_markdown': extractedContentMarkdown, + if (extractedContentPlain != null) + 'extracted_content_plain': extractedContentPlain, + if (fullContentMarkdown != null) + 'full_content_markdown': fullContentMarkdown, + if (fullContentPlain != null) 'full_content_plain': fullContentPlain, if (timestamp != null) 'timestamp': timestamp, if (rowid != null) 'rowid': rowid, }); @@ -362,12 +555,26 @@ class TabCompanion extends UpdateCompanion { {Value? id, Value? containerId, Value? orderKey, + Value? url, + Value? title, + Value? extractedContentMarkdown, + Value? extractedContentPlain, + Value? fullContentMarkdown, + Value? fullContentPlain, Value? timestamp, Value? rowid}) { return TabCompanion( id: id ?? this.id, containerId: containerId ?? this.containerId, orderKey: orderKey ?? this.orderKey, + url: url ?? this.url, + title: title ?? this.title, + extractedContentMarkdown: + extractedContentMarkdown ?? this.extractedContentMarkdown, + extractedContentPlain: + extractedContentPlain ?? this.extractedContentPlain, + fullContentMarkdown: fullContentMarkdown ?? this.fullContentMarkdown, + fullContentPlain: fullContentPlain ?? this.fullContentPlain, timestamp: timestamp ?? this.timestamp, rowid: rowid ?? this.rowid, ); @@ -385,6 +592,27 @@ class TabCompanion extends UpdateCompanion { if (orderKey.present) { map['order_key'] = Variable(orderKey.value); } + if (url.present) { + map['url'] = Variable(url.value); + } + if (title.present) { + map['title'] = Variable(title.value); + } + if (extractedContentMarkdown.present) { + map['extracted_content_markdown'] = + Variable(extractedContentMarkdown.value); + } + if (extractedContentPlain.present) { + map['extracted_content_plain'] = + Variable(extractedContentPlain.value); + } + if (fullContentMarkdown.present) { + map['full_content_markdown'] = + Variable(fullContentMarkdown.value); + } + if (fullContentPlain.present) { + map['full_content_plain'] = Variable(fullContentPlain.value); + } if (timestamp.present) { map['timestamp'] = Variable(timestamp.value); } @@ -400,6 +628,12 @@ class TabCompanion extends UpdateCompanion { ..write('id: $id, ') ..write('containerId: $containerId, ') ..write('orderKey: $orderKey, ') + ..write('url: $url, ') + ..write('title: $title, ') + ..write('extractedContentMarkdown: $extractedContentMarkdown, ') + ..write('extractedContentPlain: $extractedContentPlain, ') + ..write('fullContentMarkdown: $fullContentMarkdown, ') + ..write('fullContentPlain: $fullContentPlain, ') ..write('timestamp: $timestamp, ') ..write('rowid: $rowid') ..write(')')) @@ -407,11 +641,268 @@ class TabCompanion extends UpdateCompanion { } } +class TabFts extends Table + with TableInfo, VirtualTableInfo { + @override + final GeneratedDatabase attachedDatabase; + final String? _alias; + TabFts(this.attachedDatabase, [this._alias]); + late final GeneratedColumn title = GeneratedColumn( + 'title', aliasedName, false, + type: DriftSqlType.string, + requiredDuringInsert: true, + $customConstraints: ''); + late final GeneratedColumn url = GeneratedColumn( + 'url', aliasedName, false, + type: DriftSqlType.string, + requiredDuringInsert: true, + $customConstraints: ''); + late final GeneratedColumn extractedContentPlain = + GeneratedColumn('extracted_content_plain', aliasedName, false, + type: DriftSqlType.string, + requiredDuringInsert: true, + $customConstraints: ''); + late final GeneratedColumn fullContentPlain = GeneratedColumn( + 'full_content_plain', aliasedName, false, + type: DriftSqlType.string, + requiredDuringInsert: true, + $customConstraints: ''); + @override + List get $columns => + [title, url, extractedContentPlain, fullContentPlain]; + @override + String get aliasedName => _alias ?? actualTableName; + @override + String get actualTableName => $name; + static const String $name = 'tab_fts'; + @override + Set get $primaryKey => const {}; + @override + TabFt map(Map data, {String? tablePrefix}) { + final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : ''; + return TabFt( + title: attachedDatabase.typeMapping + .read(DriftSqlType.string, data['${effectivePrefix}title'])!, + url: attachedDatabase.typeMapping + .read(DriftSqlType.string, data['${effectivePrefix}url'])!, + extractedContentPlain: attachedDatabase.typeMapping.read( + DriftSqlType.string, + data['${effectivePrefix}extracted_content_plain'])!, + fullContentPlain: attachedDatabase.typeMapping.read( + DriftSqlType.string, data['${effectivePrefix}full_content_plain'])!, + ); + } + + @override + TabFts createAlias(String alias) { + return TabFts(attachedDatabase, alias); + } + + @override + bool get dontWriteConstraints => true; + @override + String get moduleAndArgs => + 'fts5(title, url, extracted_content_plain, full_content_plain, content=tab, tokenize="trigram")'; +} + +class TabFt extends DataClass implements Insertable { + final String title; + final String url; + final String extractedContentPlain; + final String fullContentPlain; + const TabFt( + {required this.title, + required this.url, + required this.extractedContentPlain, + required this.fullContentPlain}); + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + map['title'] = Variable(title); + map['url'] = Variable(url); + map['extracted_content_plain'] = Variable(extractedContentPlain); + map['full_content_plain'] = Variable(fullContentPlain); + return map; + } + + factory TabFt.fromJson(Map json, + {ValueSerializer? serializer}) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return TabFt( + title: serializer.fromJson(json['title']), + url: serializer.fromJson(json['url']), + extractedContentPlain: + serializer.fromJson(json['extracted_content_plain']), + fullContentPlain: serializer.fromJson(json['full_content_plain']), + ); + } + @override + Map toJson({ValueSerializer? serializer}) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return { + 'title': serializer.toJson(title), + 'url': serializer.toJson(url), + 'extracted_content_plain': + serializer.toJson(extractedContentPlain), + 'full_content_plain': serializer.toJson(fullContentPlain), + }; + } + + TabFt copyWith( + {String? title, + String? url, + String? extractedContentPlain, + String? fullContentPlain}) => + TabFt( + title: title ?? this.title, + url: url ?? this.url, + extractedContentPlain: + extractedContentPlain ?? this.extractedContentPlain, + fullContentPlain: fullContentPlain ?? this.fullContentPlain, + ); + TabFt copyWithCompanion(TabFtsCompanion data) { + return TabFt( + title: data.title.present ? data.title.value : this.title, + url: data.url.present ? data.url.value : this.url, + extractedContentPlain: data.extractedContentPlain.present + ? data.extractedContentPlain.value + : this.extractedContentPlain, + fullContentPlain: data.fullContentPlain.present + ? data.fullContentPlain.value + : this.fullContentPlain, + ); + } + + @override + String toString() { + return (StringBuffer('TabFt(') + ..write('title: $title, ') + ..write('url: $url, ') + ..write('extractedContentPlain: $extractedContentPlain, ') + ..write('fullContentPlain: $fullContentPlain') + ..write(')')) + .toString(); + } + + @override + int get hashCode => + Object.hash(title, url, extractedContentPlain, fullContentPlain); + @override + bool operator ==(Object other) => + identical(this, other) || + (other is TabFt && + other.title == this.title && + other.url == this.url && + other.extractedContentPlain == this.extractedContentPlain && + other.fullContentPlain == this.fullContentPlain); +} + +class TabFtsCompanion extends UpdateCompanion { + final Value title; + final Value url; + final Value extractedContentPlain; + final Value fullContentPlain; + final Value rowid; + const TabFtsCompanion({ + this.title = const Value.absent(), + this.url = const Value.absent(), + this.extractedContentPlain = const Value.absent(), + this.fullContentPlain = const Value.absent(), + this.rowid = const Value.absent(), + }); + TabFtsCompanion.insert({ + required String title, + required String url, + required String extractedContentPlain, + required String fullContentPlain, + this.rowid = const Value.absent(), + }) : title = Value(title), + url = Value(url), + extractedContentPlain = Value(extractedContentPlain), + fullContentPlain = Value(fullContentPlain); + static Insertable custom({ + Expression? title, + Expression? url, + Expression? extractedContentPlain, + Expression? fullContentPlain, + Expression? rowid, + }) { + return RawValuesInsertable({ + if (title != null) 'title': title, + if (url != null) 'url': url, + if (extractedContentPlain != null) + 'extracted_content_plain': extractedContentPlain, + if (fullContentPlain != null) 'full_content_plain': fullContentPlain, + if (rowid != null) 'rowid': rowid, + }); + } + + TabFtsCompanion copyWith( + {Value? title, + Value? url, + Value? extractedContentPlain, + Value? fullContentPlain, + Value? rowid}) { + return TabFtsCompanion( + title: title ?? this.title, + url: url ?? this.url, + extractedContentPlain: + extractedContentPlain ?? this.extractedContentPlain, + fullContentPlain: fullContentPlain ?? this.fullContentPlain, + rowid: rowid ?? this.rowid, + ); + } + + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + if (title.present) { + map['title'] = Variable(title.value); + } + if (url.present) { + map['url'] = Variable(url.value); + } + if (extractedContentPlain.present) { + map['extracted_content_plain'] = + Variable(extractedContentPlain.value); + } + if (fullContentPlain.present) { + map['full_content_plain'] = Variable(fullContentPlain.value); + } + if (rowid.present) { + map['rowid'] = Variable(rowid.value); + } + return map; + } + + @override + String toString() { + return (StringBuffer('TabFtsCompanion(') + ..write('title: $title, ') + ..write('url: $url, ') + ..write('extractedContentPlain: $extractedContentPlain, ') + ..write('fullContentPlain: $fullContentPlain, ') + ..write('rowid: $rowid') + ..write(')')) + .toString(); + } +} + abstract class _$TabDatabase extends GeneratedDatabase { _$TabDatabase(QueryExecutor e) : super(e); $TabDatabaseManager get managers => $TabDatabaseManager(this); late final Container container = Container(this); late final Tab tab = Tab(this); + late final TabFts tabFts = TabFts(this); + late final Trigger tabAfterInsert = Trigger( + 'CREATE TRIGGER tab_after_insert AFTER INSERT ON tab BEGIN INSERT INTO tab_fts ("rowid", title, url, extracted_content_plain, full_content_plain) VALUES (new."rowid", new.title, new.url, new.extracted_content_plain, new.full_content_plain);END', + 'tab_after_insert'); + late final Trigger tabAfterDelete = Trigger( + 'CREATE TRIGGER tab_after_delete AFTER DELETE ON tab BEGIN INSERT INTO tab_fts (tab_fts, "rowid", title, url, extracted_content_plain, full_content_plain) VALUES (\'delete\', old."rowid", old.title, old.url, old.extracted_content_plain, old.full_content_plain);END', + 'tab_after_delete'); + late final Trigger tabAfterUpdate = Trigger( + 'CREATE TRIGGER tab_after_update AFTER UPDATE ON tab BEGIN INSERT INTO tab_fts (tab_fts, "rowid", title, url, extracted_content_plain, full_content_plain) VALUES (\'delete\', old."rowid", old.title, old.url, old.extracted_content_plain, old.full_content_plain);INSERT INTO tab_fts ("rowid", title, url, extracted_content_plain, full_content_plain) VALUES (new."rowid", new.title, new.url, new.extracted_content_plain, new.full_content_plain);END', + 'tab_after_update'); late final ContainerDao containerDao = ContainerDao(this as TabDatabase); late final TabDao tabDao = TabDao(this as TabDatabase); Selectable containersWithCount() { @@ -471,11 +962,60 @@ abstract class _$TabDatabase extends GeneratedDatabase { }).map((QueryRow row) => row.read('_c0')); } + Selectable queryTabsBasic( + {required String beforeMatch, + required String afterMatch, + required String query}) { + return customSelect( + 'WITH weights AS (SELECT 10.0 AS title_weight, 5.0 AS url_weight) SELECT t.id, highlight(tab_fts, 0, ?1, ?2) AS title, highlight(tab_fts, 1, ?1, ?2) AS url, bm25(tab_fts, weights.title_weight, weights.url_weight) AS weighted_rank FROM tab_fts AS fts INNER JOIN tab AS t ON t."rowid" = fts."rowid" CROSS JOIN weights WHERE fts.title LIKE ?3 OR fts.url LIKE ?3 ORDER BY weighted_rank ASC, t.timestamp DESC', + variables: [ + Variable(beforeMatch), + Variable(afterMatch), + Variable(query) + ], + readsFrom: { + tab, + tabFts, + }).map((QueryRow row) => TabQueryResult( + title: row.read('title'), + url: row.read('url'), + weightedRank: row.read('weighted_rank'), + )); + } + + Selectable queryTabsFullContent( + {required String beforeMatch, + required String afterMatch, + required String ellipsis, + required int snippetLength, + required String query}) { + return customSelect( + 'WITH weights AS (SELECT 10.0 AS title_weight, 5.0 AS url_weight, 3.0 AS extracted_weight, 1.0 AS full_weight) SELECT highlight(tab_fts, 0, ?1, ?2) AS title, highlight(tab_fts, 1, ?1, ?2) AS url, snippet(tab_fts, 2, ?1, ?2, ?3, ?4) AS extracted_content, snippet(tab_fts, 3, ?1, ?2, ?3, ?4) AS full_content,(bm25(tab_fts, weights.title_weight, weights.url_weight, weights.extracted_weight, weights.full_weight))AS weighted_rank FROM tab_fts(?5)AS fts INNER JOIN tab AS t ON t."rowid" = fts."rowid" CROSS JOIN weights ORDER BY weighted_rank ASC, t.timestamp DESC', + variables: [ + Variable(beforeMatch), + Variable(afterMatch), + Variable(ellipsis), + Variable(snippetLength), + Variable(query) + ], + readsFrom: { + tabFts, + tab, + }).map((QueryRow row) => TabQueryResult( + title: row.read('title'), + url: row.read('url'), + extractedContent: row.read('extracted_content'), + fullContent: row.read('full_content'), + weightedRank: row.read('weighted_rank'), + )); + } + @override Iterable> get allTables => allSchemaEntities.whereType>(); @override - List get allSchemaEntities => [container, tab]; + List get allSchemaEntities => + [container, tab, tabFts, tabAfterInsert, tabAfterDelete, tabAfterUpdate]; @override StreamQueryUpdateRules get streamUpdateRules => const StreamQueryUpdateRules( [ @@ -486,6 +1026,27 @@ abstract class _$TabDatabase extends GeneratedDatabase { TableUpdate('tab', kind: UpdateKind.delete), ], ), + WritePropagation( + on: TableUpdateQuery.onTableName('tab', + limitUpdateKind: UpdateKind.insert), + result: [ + TableUpdate('tab_fts', kind: UpdateKind.insert), + ], + ), + WritePropagation( + on: TableUpdateQuery.onTableName('tab', + limitUpdateKind: UpdateKind.delete), + result: [ + TableUpdate('tab_fts', kind: UpdateKind.insert), + ], + ), + WritePropagation( + on: TableUpdateQuery.onTableName('tab', + limitUpdateKind: UpdateKind.update), + result: [ + TableUpdate('tab_fts', kind: UpdateKind.insert), + ], + ), ], ); } @@ -743,6 +1304,12 @@ typedef $TabCreateCompanionBuilder = TabCompanion Function({ required String id, Value containerId, required String orderKey, + Value url, + Value title, + Value extractedContentMarkdown, + Value extractedContentPlain, + Value fullContentMarkdown, + Value fullContentPlain, required DateTime timestamp, Value rowid, }); @@ -750,6 +1317,12 @@ typedef $TabUpdateCompanionBuilder = TabCompanion Function({ Value id, Value containerId, Value orderKey, + Value url, + Value title, + Value extractedContentMarkdown, + Value extractedContentPlain, + Value fullContentMarkdown, + Value fullContentPlain, Value timestamp, Value rowid, }); @@ -785,6 +1358,28 @@ class $TabFilterComposer extends Composer<_$TabDatabase, Tab> { ColumnFilters get orderKey => $composableBuilder( column: $table.orderKey, builder: (column) => ColumnFilters(column)); + ColumnFilters get url => $composableBuilder( + column: $table.url, builder: (column) => ColumnFilters(column)); + + ColumnFilters get title => $composableBuilder( + column: $table.title, builder: (column) => ColumnFilters(column)); + + ColumnFilters get extractedContentMarkdown => $composableBuilder( + column: $table.extractedContentMarkdown, + builder: (column) => ColumnFilters(column)); + + ColumnFilters get extractedContentPlain => $composableBuilder( + column: $table.extractedContentPlain, + builder: (column) => ColumnFilters(column)); + + ColumnFilters get fullContentMarkdown => $composableBuilder( + column: $table.fullContentMarkdown, + builder: (column) => ColumnFilters(column)); + + ColumnFilters get fullContentPlain => $composableBuilder( + column: $table.fullContentPlain, + builder: (column) => ColumnFilters(column)); + ColumnFilters get timestamp => $composableBuilder( column: $table.timestamp, builder: (column) => ColumnFilters(column)); @@ -823,6 +1418,28 @@ class $TabOrderingComposer extends Composer<_$TabDatabase, Tab> { ColumnOrderings get orderKey => $composableBuilder( column: $table.orderKey, builder: (column) => ColumnOrderings(column)); + ColumnOrderings get url => $composableBuilder( + column: $table.url, builder: (column) => ColumnOrderings(column)); + + ColumnOrderings get title => $composableBuilder( + column: $table.title, builder: (column) => ColumnOrderings(column)); + + ColumnOrderings get extractedContentMarkdown => $composableBuilder( + column: $table.extractedContentMarkdown, + builder: (column) => ColumnOrderings(column)); + + ColumnOrderings get extractedContentPlain => $composableBuilder( + column: $table.extractedContentPlain, + builder: (column) => ColumnOrderings(column)); + + ColumnOrderings get fullContentMarkdown => $composableBuilder( + column: $table.fullContentMarkdown, + builder: (column) => ColumnOrderings(column)); + + ColumnOrderings get fullContentPlain => $composableBuilder( + column: $table.fullContentPlain, + builder: (column) => ColumnOrderings(column)); + ColumnOrderings get timestamp => $composableBuilder( column: $table.timestamp, builder: (column) => ColumnOrderings(column)); @@ -861,6 +1478,24 @@ class $TabAnnotationComposer extends Composer<_$TabDatabase, Tab> { GeneratedColumn get orderKey => $composableBuilder(column: $table.orderKey, builder: (column) => column); + GeneratedColumn get url => + $composableBuilder(column: $table.url, builder: (column) => column); + + GeneratedColumn get title => + $composableBuilder(column: $table.title, builder: (column) => column); + + GeneratedColumn get extractedContentMarkdown => $composableBuilder( + column: $table.extractedContentMarkdown, builder: (column) => column); + + GeneratedColumn get extractedContentPlain => $composableBuilder( + column: $table.extractedContentPlain, builder: (column) => column); + + GeneratedColumn get fullContentMarkdown => $composableBuilder( + column: $table.fullContentMarkdown, builder: (column) => column); + + GeneratedColumn get fullContentPlain => $composableBuilder( + column: $table.fullContentPlain, builder: (column) => column); + GeneratedColumn get timestamp => $composableBuilder(column: $table.timestamp, builder: (column) => column); @@ -911,6 +1546,12 @@ class $TabTableManager extends RootTableManager< Value id = const Value.absent(), Value containerId = const Value.absent(), Value orderKey = const Value.absent(), + Value url = const Value.absent(), + Value title = const Value.absent(), + Value extractedContentMarkdown = const Value.absent(), + Value extractedContentPlain = const Value.absent(), + Value fullContentMarkdown = const Value.absent(), + Value fullContentPlain = const Value.absent(), Value timestamp = const Value.absent(), Value rowid = const Value.absent(), }) => @@ -918,6 +1559,12 @@ class $TabTableManager extends RootTableManager< id: id, containerId: containerId, orderKey: orderKey, + url: url, + title: title, + extractedContentMarkdown: extractedContentMarkdown, + extractedContentPlain: extractedContentPlain, + fullContentMarkdown: fullContentMarkdown, + fullContentPlain: fullContentPlain, timestamp: timestamp, rowid: rowid, ), @@ -925,6 +1572,12 @@ class $TabTableManager extends RootTableManager< required String id, Value containerId = const Value.absent(), required String orderKey, + Value url = const Value.absent(), + Value title = const Value.absent(), + Value extractedContentMarkdown = const Value.absent(), + Value extractedContentPlain = const Value.absent(), + Value fullContentMarkdown = const Value.absent(), + Value fullContentPlain = const Value.absent(), required DateTime timestamp, Value rowid = const Value.absent(), }) => @@ -932,6 +1585,12 @@ class $TabTableManager extends RootTableManager< id: id, containerId: containerId, orderKey: orderKey, + url: url, + title: title, + extractedContentMarkdown: extractedContentMarkdown, + extractedContentPlain: extractedContentPlain, + fullContentMarkdown: fullContentMarkdown, + fullContentPlain: fullContentPlain, timestamp: timestamp, rowid: rowid, ), @@ -986,6 +1645,157 @@ typedef $TabProcessedTableManager = ProcessedTableManager< (TabData, $TabReferences), TabData, PrefetchHooks Function({bool containerId})>; +typedef $TabFtsCreateCompanionBuilder = TabFtsCompanion Function({ + required String title, + required String url, + required String extractedContentPlain, + required String fullContentPlain, + Value rowid, +}); +typedef $TabFtsUpdateCompanionBuilder = TabFtsCompanion Function({ + Value title, + Value url, + Value extractedContentPlain, + Value fullContentPlain, + Value rowid, +}); + +class $TabFtsFilterComposer extends Composer<_$TabDatabase, TabFts> { + $TabFtsFilterComposer({ + required super.$db, + required super.$table, + super.joinBuilder, + super.$addJoinBuilderToRootComposer, + super.$removeJoinBuilderFromRootComposer, + }); + ColumnFilters get title => $composableBuilder( + column: $table.title, builder: (column) => ColumnFilters(column)); + + ColumnFilters get url => $composableBuilder( + column: $table.url, builder: (column) => ColumnFilters(column)); + + ColumnFilters get extractedContentPlain => $composableBuilder( + column: $table.extractedContentPlain, + builder: (column) => ColumnFilters(column)); + + ColumnFilters get fullContentPlain => $composableBuilder( + column: $table.fullContentPlain, + builder: (column) => ColumnFilters(column)); +} + +class $TabFtsOrderingComposer extends Composer<_$TabDatabase, TabFts> { + $TabFtsOrderingComposer({ + required super.$db, + required super.$table, + super.joinBuilder, + super.$addJoinBuilderToRootComposer, + super.$removeJoinBuilderFromRootComposer, + }); + ColumnOrderings get title => $composableBuilder( + column: $table.title, builder: (column) => ColumnOrderings(column)); + + ColumnOrderings get url => $composableBuilder( + column: $table.url, builder: (column) => ColumnOrderings(column)); + + ColumnOrderings get extractedContentPlain => $composableBuilder( + column: $table.extractedContentPlain, + builder: (column) => ColumnOrderings(column)); + + ColumnOrderings get fullContentPlain => $composableBuilder( + column: $table.fullContentPlain, + builder: (column) => ColumnOrderings(column)); +} + +class $TabFtsAnnotationComposer extends Composer<_$TabDatabase, TabFts> { + $TabFtsAnnotationComposer({ + required super.$db, + required super.$table, + super.joinBuilder, + super.$addJoinBuilderToRootComposer, + super.$removeJoinBuilderFromRootComposer, + }); + GeneratedColumn get title => + $composableBuilder(column: $table.title, builder: (column) => column); + + GeneratedColumn get url => + $composableBuilder(column: $table.url, builder: (column) => column); + + GeneratedColumn get extractedContentPlain => $composableBuilder( + column: $table.extractedContentPlain, builder: (column) => column); + + GeneratedColumn get fullContentPlain => $composableBuilder( + column: $table.fullContentPlain, builder: (column) => column); +} + +class $TabFtsTableManager extends RootTableManager< + _$TabDatabase, + TabFts, + TabFt, + $TabFtsFilterComposer, + $TabFtsOrderingComposer, + $TabFtsAnnotationComposer, + $TabFtsCreateCompanionBuilder, + $TabFtsUpdateCompanionBuilder, + (TabFt, BaseReferences<_$TabDatabase, TabFts, TabFt>), + TabFt, + PrefetchHooks Function()> { + $TabFtsTableManager(_$TabDatabase db, TabFts table) + : super(TableManagerState( + db: db, + table: table, + createFilteringComposer: () => + $TabFtsFilterComposer($db: db, $table: table), + createOrderingComposer: () => + $TabFtsOrderingComposer($db: db, $table: table), + createComputedFieldComposer: () => + $TabFtsAnnotationComposer($db: db, $table: table), + updateCompanionCallback: ({ + Value title = const Value.absent(), + Value url = const Value.absent(), + Value extractedContentPlain = const Value.absent(), + Value fullContentPlain = const Value.absent(), + Value rowid = const Value.absent(), + }) => + TabFtsCompanion( + title: title, + url: url, + extractedContentPlain: extractedContentPlain, + fullContentPlain: fullContentPlain, + rowid: rowid, + ), + createCompanionCallback: ({ + required String title, + required String url, + required String extractedContentPlain, + required String fullContentPlain, + Value rowid = const Value.absent(), + }) => + TabFtsCompanion.insert( + title: title, + url: url, + extractedContentPlain: extractedContentPlain, + fullContentPlain: fullContentPlain, + rowid: rowid, + ), + withReferenceMapper: (p0) => p0 + .map((e) => (e.readTable(table), BaseReferences(db, table, e))) + .toList(), + prefetchHooksCallback: null, + )); +} + +typedef $TabFtsProcessedTableManager = ProcessedTableManager< + _$TabDatabase, + TabFts, + TabFt, + $TabFtsFilterComposer, + $TabFtsOrderingComposer, + $TabFtsAnnotationComposer, + $TabFtsCreateCompanionBuilder, + $TabFtsUpdateCompanionBuilder, + (TabFt, BaseReferences<_$TabDatabase, TabFts, TabFt>), + TabFt, + PrefetchHooks Function()>; class $TabDatabaseManager { final _$TabDatabase _db; @@ -993,4 +1803,5 @@ class $TabDatabaseManager { $ContainerTableManager get container => $ContainerTableManager(_db, _db.container); $TabTableManager get tab => $TabTableManager(_db, _db.tab); + $TabFtsTableManager get tabFts => $TabFtsTableManager(_db, _db.tabFts); } diff --git a/app/lib/features/geckoview/features/tabs/data/models/tab_query_result.dart b/app/lib/features/geckoview/features/tabs/data/models/tab_query_result.dart new file mode 100644 index 00000000..6ff663e1 --- /dev/null +++ b/app/lib/features/geckoview/features/tabs/data/models/tab_query_result.dart @@ -0,0 +1,17 @@ +class TabQueryResult { + final String title; + final String url; + + final String? extractedContent; + final String? fullContent; + + final double weightedRank; + + TabQueryResult({ + required this.title, + required this.url, + this.extractedContent, + this.fullContent, + required this.weightedRank, + }); +} diff --git a/app/lib/features/geckoview/features/tabs/domain/providers.dart b/app/lib/features/geckoview/features/tabs/domain/providers.dart index 686fe48d..dd7e9607 100644 --- a/app/lib/features/geckoview/features/tabs/domain/providers.dart +++ b/app/lib/features/geckoview/features/tabs/domain/providers.dart @@ -5,6 +5,7 @@ import 'package:lensai/features/geckoview/features/tabs/data/models/container_da import 'package:lensai/features/geckoview/features/tabs/data/providers.dart'; import 'package:lensai/features/geckoview/features/tabs/domain/repositories/container.dart'; import 'package:lensai/features/geckoview/features/tabs/utils/color_palette.dart'; +import 'package:lensai/features/search/util/tokenized_filter.dart'; import 'package:riverpod/riverpod.dart'; import 'package:riverpod_annotation/riverpod_annotation.dart'; @@ -35,6 +36,28 @@ Stream> containersWithCount( return db.containersWithCount().watch(); } +@Riverpod() +AsyncValue> filteredContainersWithCount( + Ref ref, + String? searchText, +) { + return ref.watch( + containersWithCountProvider.select((value) { + if (searchText?.isEmpty ?? true) { + return value; + } + + return value.whenData( + (cb) => TokenizedFilter( + items: cb, + toString: (item) => item.name, + query: searchText!, + ).filtered, + ); + }), + ); +} + @Riverpod() Stream tabContainerId(Ref ref, String tabId) { final db = ref.watch(tabDatabaseProvider); diff --git a/app/lib/features/geckoview/features/tabs/domain/providers.g.dart b/app/lib/features/geckoview/features/tabs/domain/providers.g.dart index cf8ea4aa..4ef3f4c8 100644 --- a/app/lib/features/geckoview/features/tabs/domain/providers.g.dart +++ b/app/lib/features/geckoview/features/tabs/domain/providers.g.dart @@ -45,7 +45,8 @@ final containersWithCountProvider = // ignore: unused_element typedef ContainersWithCountRef = AutoDisposeStreamProviderRef>; -String _$tabContainerIdHash() => r'726ddd000d23935a2c8ae39c7957412fab16016d'; +String _$filteredContainersWithCountHash() => + r'3a7284df29182a32f9b7831867a3a0b3e171b382'; /// Copied from Dart SDK class _SystemHash { @@ -68,6 +69,145 @@ class _SystemHash { } } +/// See also [filteredContainersWithCount]. +@ProviderFor(filteredContainersWithCount) +const filteredContainersWithCountProvider = FilteredContainersWithCountFamily(); + +/// See also [filteredContainersWithCount]. +class FilteredContainersWithCountFamily + extends Family>> { + /// See also [filteredContainersWithCount]. + const FilteredContainersWithCountFamily(); + + /// See also [filteredContainersWithCount]. + FilteredContainersWithCountProvider call( + String? searchText, + ) { + return FilteredContainersWithCountProvider( + searchText, + ); + } + + @override + FilteredContainersWithCountProvider getProviderOverride( + covariant FilteredContainersWithCountProvider provider, + ) { + return call( + provider.searchText, + ); + } + + static const Iterable? _dependencies = null; + + @override + Iterable? get dependencies => _dependencies; + + static const Iterable? _allTransitiveDependencies = null; + + @override + Iterable? get allTransitiveDependencies => + _allTransitiveDependencies; + + @override + String? get name => r'filteredContainersWithCountProvider'; +} + +/// See also [filteredContainersWithCount]. +class FilteredContainersWithCountProvider + extends AutoDisposeProvider>> { + /// See also [filteredContainersWithCount]. + FilteredContainersWithCountProvider( + String? searchText, + ) : this._internal( + (ref) => filteredContainersWithCount( + ref as FilteredContainersWithCountRef, + searchText, + ), + from: filteredContainersWithCountProvider, + name: r'filteredContainersWithCountProvider', + debugGetCreateSourceHash: + const bool.fromEnvironment('dart.vm.product') + ? null + : _$filteredContainersWithCountHash, + dependencies: FilteredContainersWithCountFamily._dependencies, + allTransitiveDependencies: + FilteredContainersWithCountFamily._allTransitiveDependencies, + searchText: searchText, + ); + + FilteredContainersWithCountProvider._internal( + super._createNotifier, { + required super.name, + required super.dependencies, + required super.allTransitiveDependencies, + required super.debugGetCreateSourceHash, + required super.from, + required this.searchText, + }) : super.internal(); + + final String? searchText; + + @override + Override overrideWith( + AsyncValue> Function( + FilteredContainersWithCountRef provider) + create, + ) { + return ProviderOverride( + origin: this, + override: FilteredContainersWithCountProvider._internal( + (ref) => create(ref as FilteredContainersWithCountRef), + from: from, + name: null, + dependencies: null, + allTransitiveDependencies: null, + debugGetCreateSourceHash: null, + searchText: searchText, + ), + ); + } + + @override + AutoDisposeProviderElement>> + createElement() { + return _FilteredContainersWithCountProviderElement(this); + } + + @override + bool operator ==(Object other) { + return other is FilteredContainersWithCountProvider && + other.searchText == searchText; + } + + @override + int get hashCode { + var hash = _SystemHash.combine(0, runtimeType.hashCode); + hash = _SystemHash.combine(hash, searchText.hashCode); + + return _SystemHash.finish(hash); + } +} + +@Deprecated('Will be removed in 3.0. Use Ref instead') +// ignore: unused_element +mixin FilteredContainersWithCountRef + on AutoDisposeProviderRef>> { + /// The parameter `searchText` of this provider. + String? get searchText; +} + +class _FilteredContainersWithCountProviderElement + extends AutoDisposeProviderElement>> + with FilteredContainersWithCountRef { + _FilteredContainersWithCountProviderElement(super.provider); + + @override + String? get searchText => + (origin as FilteredContainersWithCountProvider).searchText; +} + +String _$tabContainerIdHash() => r'726ddd000d23935a2c8ae39c7957412fab16016d'; + /// See also [tabContainerId]. @ProviderFor(tabContainerId) const tabContainerIdProvider = TabContainerIdFamily(); diff --git a/app/lib/features/geckoview/features/tabs/domain/repositories/tab_search.dart b/app/lib/features/geckoview/features/tabs/domain/repositories/tab_search.dart new file mode 100644 index 00000000..54c00f4b --- /dev/null +++ b/app/lib/features/geckoview/features/tabs/domain/repositories/tab_search.dart @@ -0,0 +1,42 @@ +import 'dart:async'; + +import 'package:lensai/features/geckoview/features/tabs/data/database/database.dart'; +import 'package:lensai/features/geckoview/features/tabs/data/models/tab_query_result.dart'; +import 'package:lensai/features/geckoview/features/tabs/data/providers.dart'; +import 'package:riverpod_annotation/riverpod_annotation.dart'; + +part 'tab_search.g.dart'; + +@Riverpod() +class TabSearchRepository extends _$TabSearchRepository { + late TabDatabase _db; + + Future addQuery( + String input, { + int snippetLength = 120, + String matchPrefix = '***', + String matchSuffix = '***', + String ellipsis = '…', + }) async { + if (input.isNotEmpty) { + state = await AsyncValue.guard( + () => _db.tabDao + .queryTabs( + matchPrefix: matchPrefix, + matchSuffix: matchSuffix, + ellipsis: ellipsis, + snippetLength: snippetLength, + searchString: input, + ) + .get(), + ); + } + } + + @override + Future> build() { + _db = ref.watch(tabDatabaseProvider); + + return Future.value([]); + } +} diff --git a/app/lib/features/kagi/domain/repositories/autosuggest.g.dart b/app/lib/features/geckoview/features/tabs/domain/repositories/tab_search.g.dart similarity index 53% rename from app/lib/features/kagi/domain/repositories/autosuggest.g.dart rename to app/lib/features/geckoview/features/tabs/domain/repositories/tab_search.g.dart index 64404555..c10cd957 100644 --- a/app/lib/features/kagi/domain/repositories/autosuggest.g.dart +++ b/app/lib/features/geckoview/features/tabs/domain/repositories/tab_search.g.dart @@ -1,27 +1,27 @@ // GENERATED CODE - DO NOT MODIFY BY HAND -part of 'autosuggest.dart'; +part of 'tab_search.dart'; // ************************************************************************** // RiverpodGenerator // ************************************************************************** -String _$autosuggestRepositoryHash() => - r'48d6bf45d648871f8570edfe1e0b394019084695'; +String _$tabSearchRepositoryHash() => + r'211ca4d7e9a744b5f8a32970ba3a6df721fc05e1'; -/// See also [AutosuggestRepository]. -@ProviderFor(AutosuggestRepository) -final autosuggestRepositoryProvider = - NotifierProvider>>>.internal( - AutosuggestRepository.new, - name: r'autosuggestRepositoryProvider', +/// See also [TabSearchRepository]. +@ProviderFor(TabSearchRepository) +final tabSearchRepositoryProvider = AutoDisposeAsyncNotifierProvider< + TabSearchRepository, List>.internal( + TabSearchRepository.new, + name: r'tabSearchRepositoryProvider', debugGetCreateSourceHash: const bool.fromEnvironment('dart.vm.product') ? null - : _$autosuggestRepositoryHash, + : _$tabSearchRepositoryHash, dependencies: null, allTransitiveDependencies: null, ); -typedef _$AutosuggestRepository = Notifier>>>; +typedef _$TabSearchRepository = AutoDisposeAsyncNotifier>; // ignore_for_file: type=lint // ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member, invalid_use_of_visible_for_testing_member, deprecated_member_use_from_same_package diff --git a/app/lib/features/geckoview/features/tabs/presentation/widgets/container_chips.dart b/app/lib/features/geckoview/features/tabs/presentation/widgets/container_chips.dart index 2c2729f1..b44ff931 100644 --- a/app/lib/features/geckoview/features/tabs/presentation/widgets/container_chips.dart +++ b/app/lib/features/geckoview/features/tabs/presentation/widgets/container_chips.dart @@ -1,25 +1,44 @@ import 'package:flutter/material.dart'; +import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:go_router/go_router.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:lensai/core/routing/routes.dart'; +import 'package:lensai/features/geckoview/features/tabs/data/models/container_data.dart'; import 'package:lensai/features/geckoview/features/tabs/domain/providers.dart'; -import 'package:lensai/features/geckoview/features/tabs/domain/providers/selected_container.dart'; import 'package:lensai/presentation/widgets/selectable_chips.dart'; class ContainerChips extends HookConsumerWidget { + final bool displayMenu; + + final ContainerData? selectedContainer; + final void Function(ContainerDataWithCount)? onSelected; + final void Function(ContainerDataWithCount)? onDeleted; + + final TextEditingController? searchTextController; + + const ContainerChips({ + required this.selectedContainer, + required this.onSelected, + required this.onDeleted, + this.searchTextController, + this.displayMenu = true, + }); + @override Widget build(BuildContext context, WidgetRef ref) { - final containersAsync = ref.watch(containersWithCountProvider); - final selectedContainer = ref.watch( - selectedContainerDataProvider.select((value) => value.valueOrNull), + final searchText = useListenableSelector( + searchTextController, + () => searchTextController?.text, ); + final containersAsync = + ref.watch(filteredContainersWithCountProvider(searchText)); + return containersAsync.when( data: (availableContainers) => SizedBox( height: 48, child: Row( children: [ - const SizedBox(width: 16), if (selectedContainer != null || availableContainers.isNotEmpty) Expanded( child: SelectableChips( @@ -38,34 +57,30 @@ class ContainerChips extends HookConsumerWidget { itemBadgeCount: (container) => container.tabCount, availableItems: availableContainers, selectedItem: selectedContainer, - onSelected: (container) { - ref - .read(selectedContainerProvider.notifier) - .setContainerId(container.id); - }, - onDeleted: (container) async { - ref - .read(selectedContainerProvider.notifier) - .clearContainer(); - }, + onSelected: onSelected, + onDeleted: onDeleted, ), ) else - Expanded( - child: Text( - "Press '>' to manage Containers.", - style: TextStyle( - color: Theme.of(context).hintColor, - fontStyle: FontStyle.italic, + Visibility( + visible: displayMenu, + child: Expanded( + child: Text( + "Press '>' to manage Containers.", + style: TextStyle( + color: Theme.of(context).hintColor, + fontStyle: FontStyle.italic, + ), ), ), ), - IconButton( - onPressed: () async { - await context.push(ContainerListRoute().location); - }, - icon: const Icon(Icons.chevron_right), - ), + if (displayMenu) + IconButton( + onPressed: () async { + await context.push(ContainerListRoute().location); + }, + icon: const Icon(Icons.chevron_right), + ), ], ), ), diff --git a/app/lib/features/kagi/data/services/autosuggest.dart b/app/lib/features/kagi/data/services/autosuggest.dart index e286698e..418c2875 100644 --- a/app/lib/features/kagi/data/services/autosuggest.dart +++ b/app/lib/features/kagi/data/services/autosuggest.dart @@ -3,12 +3,14 @@ import 'dart:convert'; import 'package:exceptions/exceptions.dart'; import 'package:http/http.dart' as http; import 'package:lensai/core/http_error_handler.dart'; +import 'package:lensai/features/search/domain/entities/abstract/i_search_suggestion_provider.dart'; import 'package:riverpod_annotation/riverpod_annotation.dart'; part 'autosuggest.g.dart'; @Riverpod(keepAlive: true) -class KagiAutosuggestService extends _$KagiAutosuggestService { +class KagiAutosuggestService extends _$KagiAutosuggestService + implements ISearchSuggestionProvider { static final _baseUrl = Uri.https('kagi.com', 'api/autosuggest'); late http.Client _client; @@ -18,6 +20,7 @@ class KagiAutosuggestService extends _$KagiAutosuggestService { _client = http.Client(); } + @override Future>> getSuggestions(String query) async { return Result.fromAsync( () async { diff --git a/app/lib/features/kagi/data/services/autosuggest.g.dart b/app/lib/features/kagi/data/services/autosuggest.g.dart index 38c6e48e..09b3fc93 100644 --- a/app/lib/features/kagi/data/services/autosuggest.g.dart +++ b/app/lib/features/kagi/data/services/autosuggest.g.dart @@ -7,7 +7,7 @@ part of 'autosuggest.dart'; // ************************************************************************** String _$kagiAutosuggestServiceHash() => - r'843b0d84b1dde2d903412a123c8c10d26e8036fd'; + r'e1cb4ef730bcf5c4bf4c77617bb12a22228af576'; /// See also [KagiAutosuggestService]. @ProviderFor(KagiAutosuggestService) diff --git a/app/lib/features/kagi/domain/repositories/autosuggest.dart b/app/lib/features/kagi/domain/repositories/search_suggestions.dart similarity index 75% rename from app/lib/features/kagi/domain/repositories/autosuggest.dart rename to app/lib/features/kagi/domain/repositories/search_suggestions.dart index b0e103eb..99ca3f3e 100644 --- a/app/lib/features/kagi/domain/repositories/autosuggest.dart +++ b/app/lib/features/kagi/domain/repositories/search_suggestions.dart @@ -1,26 +1,28 @@ import 'dart:async'; -import 'package:lensai/features/kagi/data/services/autosuggest.dart'; +import 'package:lensai/features/search/domain/entities/abstract/i_search_suggestion_provider.dart'; import 'package:lensai/utils/lru_cache.dart'; import 'package:riverpod_annotation/riverpod_annotation.dart'; import 'package:rxdart/rxdart.dart'; -part 'autosuggest.g.dart'; +part 'search_suggestions.g.dart'; @Riverpod(keepAlive: true) -class AutosuggestRepository extends _$AutosuggestRepository { +class SearchSuggestionsRepository extends _$SearchSuggestionsRepository { final LRUCache> _cache; late StreamController _queryStreamController; - AutosuggestRepository() : _cache = LRUCache(100); + SearchSuggestionsRepository() : _cache = LRUCache(100); void addQuery(String query) { _queryStreamController.add(query); } @override - Raw>> build() { + Raw>> build( + ISearchSuggestionProvider suggestionsProvider, + ) { _queryStreamController = StreamController(); ref.onDispose(() async { await _queryStreamController.close(); @@ -39,8 +41,7 @@ class AutosuggestRepository extends _$AutosuggestRepository { return Stream.value(cached); } - return ref - .read(kagiAutosuggestServiceProvider.notifier) + return suggestionsProvider // ignore: discarded_futures .getSuggestions(query) // ignore: discarded_futures diff --git a/app/lib/features/kagi/domain/repositories/search_suggestions.g.dart b/app/lib/features/kagi/domain/repositories/search_suggestions.g.dart new file mode 100644 index 00000000..aecec0b0 --- /dev/null +++ b/app/lib/features/kagi/domain/repositories/search_suggestions.g.dart @@ -0,0 +1,182 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'search_suggestions.dart'; + +// ************************************************************************** +// RiverpodGenerator +// ************************************************************************** + +String _$searchSuggestionsRepositoryHash() => + r'bc6dc862ae7d887b404972abbbee3c1b27a64d2e'; + +/// Copied from Dart SDK +class _SystemHash { + _SystemHash._(); + + static int combine(int hash, int value) { + // ignore: parameter_assignments + hash = 0x1fffffff & (hash + value); + // ignore: parameter_assignments + hash = 0x1fffffff & (hash + ((0x0007ffff & hash) << 10)); + return hash ^ (hash >> 6); + } + + static int finish(int hash) { + // ignore: parameter_assignments + hash = 0x1fffffff & (hash + ((0x03ffffff & hash) << 3)); + // ignore: parameter_assignments + hash = hash ^ (hash >> 11); + return 0x1fffffff & (hash + ((0x00003fff & hash) << 15)); + } +} + +abstract class _$SearchSuggestionsRepository + extends BuildlessNotifier>>> { + late final ISearchSuggestionProvider suggestionsProvider; + + Raw>> build( + ISearchSuggestionProvider suggestionsProvider, + ); +} + +/// See also [SearchSuggestionsRepository]. +@ProviderFor(SearchSuggestionsRepository) +const searchSuggestionsRepositoryProvider = SearchSuggestionsRepositoryFamily(); + +/// See also [SearchSuggestionsRepository]. +class SearchSuggestionsRepositoryFamily + extends Family>>> { + /// See also [SearchSuggestionsRepository]. + const SearchSuggestionsRepositoryFamily(); + + /// See also [SearchSuggestionsRepository]. + SearchSuggestionsRepositoryProvider call( + ISearchSuggestionProvider suggestionsProvider, + ) { + return SearchSuggestionsRepositoryProvider( + suggestionsProvider, + ); + } + + @override + SearchSuggestionsRepositoryProvider getProviderOverride( + covariant SearchSuggestionsRepositoryProvider provider, + ) { + return call( + provider.suggestionsProvider, + ); + } + + static const Iterable? _dependencies = null; + + @override + Iterable? get dependencies => _dependencies; + + static const Iterable? _allTransitiveDependencies = null; + + @override + Iterable? get allTransitiveDependencies => + _allTransitiveDependencies; + + @override + String? get name => r'searchSuggestionsRepositoryProvider'; +} + +/// See also [SearchSuggestionsRepository]. +class SearchSuggestionsRepositoryProvider extends NotifierProviderImpl< + SearchSuggestionsRepository, Raw>>> { + /// See also [SearchSuggestionsRepository]. + SearchSuggestionsRepositoryProvider( + ISearchSuggestionProvider suggestionsProvider, + ) : this._internal( + () => SearchSuggestionsRepository() + ..suggestionsProvider = suggestionsProvider, + from: searchSuggestionsRepositoryProvider, + name: r'searchSuggestionsRepositoryProvider', + debugGetCreateSourceHash: + const bool.fromEnvironment('dart.vm.product') + ? null + : _$searchSuggestionsRepositoryHash, + dependencies: SearchSuggestionsRepositoryFamily._dependencies, + allTransitiveDependencies: + SearchSuggestionsRepositoryFamily._allTransitiveDependencies, + suggestionsProvider: suggestionsProvider, + ); + + SearchSuggestionsRepositoryProvider._internal( + super._createNotifier, { + required super.name, + required super.dependencies, + required super.allTransitiveDependencies, + required super.debugGetCreateSourceHash, + required super.from, + required this.suggestionsProvider, + }) : super.internal(); + + final ISearchSuggestionProvider suggestionsProvider; + + @override + Raw>> runNotifierBuild( + covariant SearchSuggestionsRepository notifier, + ) { + return notifier.build( + suggestionsProvider, + ); + } + + @override + Override overrideWith(SearchSuggestionsRepository Function() create) { + return ProviderOverride( + origin: this, + override: SearchSuggestionsRepositoryProvider._internal( + () => create()..suggestionsProvider = suggestionsProvider, + from: from, + name: null, + dependencies: null, + allTransitiveDependencies: null, + debugGetCreateSourceHash: null, + suggestionsProvider: suggestionsProvider, + ), + ); + } + + @override + NotifierProviderElement>>> createElement() { + return _SearchSuggestionsRepositoryProviderElement(this); + } + + @override + bool operator ==(Object other) { + return other is SearchSuggestionsRepositoryProvider && + other.suggestionsProvider == suggestionsProvider; + } + + @override + int get hashCode { + var hash = _SystemHash.combine(0, runtimeType.hashCode); + hash = _SystemHash.combine(hash, suggestionsProvider.hashCode); + + return _SystemHash.finish(hash); + } +} + +@Deprecated('Will be removed in 3.0. Use Ref instead') +// ignore: unused_element +mixin SearchSuggestionsRepositoryRef + on NotifierProviderRef>>> { + /// The parameter `suggestionsProvider` of this provider. + ISearchSuggestionProvider get suggestionsProvider; +} + +class _SearchSuggestionsRepositoryProviderElement + extends NotifierProviderElement>>> with SearchSuggestionsRepositoryRef { + _SearchSuggestionsRepositoryProviderElement(super.provider); + + @override + ISearchSuggestionProvider get suggestionsProvider => + (origin as SearchSuggestionsRepositoryProvider).suggestionsProvider; +} +// ignore_for_file: type=lint +// ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member, invalid_use_of_visible_for_testing_member, deprecated_member_use_from_same_package diff --git a/app/lib/features/kagi/presentation/tabs/search_tab.dart b/app/lib/features/kagi/presentation/tabs/search_tab.dart index 716605da..8f0346f8 100644 --- a/app/lib/features/kagi/presentation/tabs/search_tab.dart +++ b/app/lib/features/kagi/presentation/tabs/search_tab.dart @@ -4,7 +4,7 @@ import 'package:flutter_material_design_icons/flutter_material_design_icons.dart import 'package:go_router/go_router.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:lensai/core/routing/routes.dart'; -import 'package:lensai/features/bangs/domain/providers.dart'; +import 'package:lensai/features/bangs/domain/providers/bangs.dart'; import 'package:lensai/features/bangs/domain/repositories/data.dart'; import 'package:lensai/features/bangs/presentation/widgets/bang_icon.dart'; import 'package:lensai/features/bangs/presentation/widgets/search_field.dart'; @@ -32,8 +32,8 @@ class SearchTab extends HookConsumerWidget { final selectedBang = ref .watch(selectedBangDataProvider().select((value) => value.valueOrNull)); - final defaultSearchBang = ref - .watch(kagiSearchBangDataProvider.select((value) => value.valueOrNull)); + final defaultSearchBang = ref.watch( + defaultSearchBangDataProvider.select((value) => value.valueOrNull)); final activeBang = selectedBang ?? defaultSearchBang; diff --git a/app/lib/features/query/domain/entities/abstract/i_query_builder.dart b/app/lib/features/search/domain/entities/abstract/i_query_builder.dart similarity index 72% rename from app/lib/features/query/domain/entities/abstract/i_query_builder.dart rename to app/lib/features/search/domain/entities/abstract/i_query_builder.dart index 080f704e..a3a16f22 100644 --- a/app/lib/features/query/domain/entities/abstract/i_query_builder.dart +++ b/app/lib/features/search/domain/entities/abstract/i_query_builder.dart @@ -2,5 +2,5 @@ abstract interface class IQueryBuilder { int get ftsTokenLimit; int get ftsMinTokenLength; - String buildQuery(String input); + String buildFtsQuery(String input); } diff --git a/app/lib/features/search/domain/entities/abstract/i_search_suggestion_provider.dart b/app/lib/features/search/domain/entities/abstract/i_search_suggestion_provider.dart new file mode 100644 index 00000000..03a8aeeb --- /dev/null +++ b/app/lib/features/search/domain/entities/abstract/i_search_suggestion_provider.dart @@ -0,0 +1,5 @@ +import 'package:exceptions/exceptions.dart'; + +abstract interface class ISearchSuggestionProvider { + Future>> getSuggestions(String query); +} diff --git a/app/lib/features/query/domain/entities/bareword.dart b/app/lib/features/search/domain/entities/bareword.dart similarity index 100% rename from app/lib/features/query/domain/entities/bareword.dart rename to app/lib/features/search/domain/entities/bareword.dart diff --git a/app/lib/features/query/domain/tokenizer.dart b/app/lib/features/search/domain/fts_tokenizer.dart similarity index 92% rename from app/lib/features/query/domain/tokenizer.dart rename to app/lib/features/search/domain/fts_tokenizer.dart index eb93e4a6..9ba99ba4 100644 --- a/app/lib/features/query/domain/tokenizer.dart +++ b/app/lib/features/search/domain/fts_tokenizer.dart @@ -1,12 +1,12 @@ import 'dart:math' as math; import 'package:collection/collection.dart'; -import 'package:lensai/features/query/domain/entities/abstract/i_query_builder.dart'; -import 'package:lensai/features/query/domain/entities/bareword.dart'; +import 'package:lensai/features/search/domain/entities/abstract/i_query_builder.dart'; +import 'package:lensai/features/search/domain/entities/bareword.dart'; typedef _Phrase = List; -sealed class QueryBuilder { +sealed class FtsQueryBuilder { ///Matching quoted strings like "xda bda" (group 1), as well as strings delimetered by ///a whitespace (group 2) static final _tokenizePattern = RegExp('"([^"]+)"|([^ ]+)'); @@ -26,7 +26,9 @@ sealed class QueryBuilder { late final _Phrase _tokens; - QueryBuilder.tokenize({ + bool get hasTokens => _tokens.isNotEmpty; + + FtsQueryBuilder.tokenize({ required String input, required int minTokenLength, required int tokenLimit, @@ -174,7 +176,7 @@ sealed class QueryBuilder { String build(); } -final class PrefixQueryBuilder extends QueryBuilder { +final class PrefixQueryBuilder extends FtsQueryBuilder { PrefixQueryBuilder.tokenize({ required super.input, required super.minTokenLength, @@ -197,7 +199,7 @@ final class PrefixQueryBuilder extends QueryBuilder { } } -final class TrigramQueryBuilder extends QueryBuilder { +final class TrigramQueryBuilder extends FtsQueryBuilder { TrigramQueryBuilder.tokenize({ required super.input, required super.minTokenLength, @@ -216,7 +218,7 @@ final class TrigramQueryBuilder extends QueryBuilder { mixin PrefixQueryBuilderMixin implements IQueryBuilder { @override - String buildQuery(String input) { + String buildFtsQuery(String input) { final queryBuilder = PrefixQueryBuilder.tokenize( input: input, minTokenLength: ftsMinTokenLength, @@ -229,7 +231,7 @@ mixin PrefixQueryBuilderMixin implements IQueryBuilder { mixin TrigramQueryBuilderMixin implements IQueryBuilder { @override - String buildQuery(String input) { + String buildFtsQuery(String input) { final queryBuilder = TrigramQueryBuilder.tokenize( input: input, minTokenLength: ftsMinTokenLength, diff --git a/app/lib/features/search/domain/providers/search_suggestions.dart b/app/lib/features/search/domain/providers/search_suggestions.dart new file mode 100644 index 00000000..bf95d52a --- /dev/null +++ b/app/lib/features/search/domain/providers/search_suggestions.dart @@ -0,0 +1,35 @@ +import 'package:lensai/features/kagi/data/services/autosuggest.dart'; +import 'package:lensai/features/kagi/domain/repositories/search_suggestions.dart'; +import 'package:lensai/features/search/domain/entities/abstract/i_search_suggestion_provider.dart'; +import 'package:riverpod/riverpod.dart'; +import 'package:riverpod_annotation/riverpod_annotation.dart'; + +part 'search_suggestions.g.dart'; + +@Riverpod(keepAlive: true) +ISearchSuggestionProvider defaultSearchSuggestions(Ref ref) { + return ref.watch(kagiAutosuggestServiceProvider.notifier); +} + +@Riverpod(keepAlive: true) +class SearchSuggestions extends _$SearchSuggestions { + late void Function(String query) _addQueryBinding; + + void addQuery(String query) => _addQueryBinding(query); + + @override + Raw>> build({ + ISearchSuggestionProvider? suggestionsProvider, + }) { + final defaultProvider = ref.watch(defaultSearchSuggestionsProvider); + final resolvedProvider = suggestionsProvider ?? defaultProvider; + + _addQueryBinding = ref + .watch(searchSuggestionsRepositoryProvider(resolvedProvider).notifier) + .addQuery; + + return ref.watch( + searchSuggestionsRepositoryProvider(resolvedProvider), + ); + } +} diff --git a/app/lib/features/search/domain/providers/search_suggestions.g.dart b/app/lib/features/search/domain/providers/search_suggestions.g.dart new file mode 100644 index 00000000..cce5552a --- /dev/null +++ b/app/lib/features/search/domain/providers/search_suggestions.g.dart @@ -0,0 +1,196 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'search_suggestions.dart'; + +// ************************************************************************** +// RiverpodGenerator +// ************************************************************************** + +String _$defaultSearchSuggestionsHash() => + r'56514064baa64acf0a28ec34cfad957dd863538b'; + +/// See also [defaultSearchSuggestions]. +@ProviderFor(defaultSearchSuggestions) +final defaultSearchSuggestionsProvider = + Provider.internal( + defaultSearchSuggestions, + name: r'defaultSearchSuggestionsProvider', + debugGetCreateSourceHash: const bool.fromEnvironment('dart.vm.product') + ? null + : _$defaultSearchSuggestionsHash, + dependencies: null, + allTransitiveDependencies: null, +); + +@Deprecated('Will be removed in 3.0. Use Ref instead') +// ignore: unused_element +typedef DefaultSearchSuggestionsRef = ProviderRef; +String _$searchSuggestionsHash() => r'ecc378aca325cc6759292a06d8d4d5ace910eb7f'; + +/// Copied from Dart SDK +class _SystemHash { + _SystemHash._(); + + static int combine(int hash, int value) { + // ignore: parameter_assignments + hash = 0x1fffffff & (hash + value); + // ignore: parameter_assignments + hash = 0x1fffffff & (hash + ((0x0007ffff & hash) << 10)); + return hash ^ (hash >> 6); + } + + static int finish(int hash) { + // ignore: parameter_assignments + hash = 0x1fffffff & (hash + ((0x03ffffff & hash) << 3)); + // ignore: parameter_assignments + hash = hash ^ (hash >> 11); + return 0x1fffffff & (hash + ((0x00003fff & hash) << 15)); + } +} + +abstract class _$SearchSuggestions + extends BuildlessNotifier>>> { + late final ISearchSuggestionProvider? suggestionsProvider; + + Raw>> build({ + ISearchSuggestionProvider? suggestionsProvider, + }); +} + +/// See also [SearchSuggestions]. +@ProviderFor(SearchSuggestions) +const searchSuggestionsProvider = SearchSuggestionsFamily(); + +/// See also [SearchSuggestions]. +class SearchSuggestionsFamily extends Family>>> { + /// See also [SearchSuggestions]. + const SearchSuggestionsFamily(); + + /// See also [SearchSuggestions]. + SearchSuggestionsProvider call({ + ISearchSuggestionProvider? suggestionsProvider, + }) { + return SearchSuggestionsProvider( + suggestionsProvider: suggestionsProvider, + ); + } + + @override + SearchSuggestionsProvider getProviderOverride( + covariant SearchSuggestionsProvider provider, + ) { + return call( + suggestionsProvider: provider.suggestionsProvider, + ); + } + + static const Iterable? _dependencies = null; + + @override + Iterable? get dependencies => _dependencies; + + static const Iterable? _allTransitiveDependencies = null; + + @override + Iterable? get allTransitiveDependencies => + _allTransitiveDependencies; + + @override + String? get name => r'searchSuggestionsProvider'; +} + +/// See also [SearchSuggestions]. +class SearchSuggestionsProvider + extends NotifierProviderImpl>>> { + /// See also [SearchSuggestions]. + SearchSuggestionsProvider({ + ISearchSuggestionProvider? suggestionsProvider, + }) : this._internal( + () => SearchSuggestions()..suggestionsProvider = suggestionsProvider, + from: searchSuggestionsProvider, + name: r'searchSuggestionsProvider', + debugGetCreateSourceHash: + const bool.fromEnvironment('dart.vm.product') + ? null + : _$searchSuggestionsHash, + dependencies: SearchSuggestionsFamily._dependencies, + allTransitiveDependencies: + SearchSuggestionsFamily._allTransitiveDependencies, + suggestionsProvider: suggestionsProvider, + ); + + SearchSuggestionsProvider._internal( + super._createNotifier, { + required super.name, + required super.dependencies, + required super.allTransitiveDependencies, + required super.debugGetCreateSourceHash, + required super.from, + required this.suggestionsProvider, + }) : super.internal(); + + final ISearchSuggestionProvider? suggestionsProvider; + + @override + Raw>> runNotifierBuild( + covariant SearchSuggestions notifier, + ) { + return notifier.build( + suggestionsProvider: suggestionsProvider, + ); + } + + @override + Override overrideWith(SearchSuggestions Function() create) { + return ProviderOverride( + origin: this, + override: SearchSuggestionsProvider._internal( + () => create()..suggestionsProvider = suggestionsProvider, + from: from, + name: null, + dependencies: null, + allTransitiveDependencies: null, + debugGetCreateSourceHash: null, + suggestionsProvider: suggestionsProvider, + ), + ); + } + + @override + NotifierProviderElement>>> + createElement() { + return _SearchSuggestionsProviderElement(this); + } + + @override + bool operator ==(Object other) { + return other is SearchSuggestionsProvider && + other.suggestionsProvider == suggestionsProvider; + } + + @override + int get hashCode { + var hash = _SystemHash.combine(0, runtimeType.hashCode); + hash = _SystemHash.combine(hash, suggestionsProvider.hashCode); + + return _SystemHash.finish(hash); + } +} + +@Deprecated('Will be removed in 3.0. Use Ref instead') +// ignore: unused_element +mixin SearchSuggestionsRef on NotifierProviderRef>>> { + /// The parameter `suggestionsProvider` of this provider. + ISearchSuggestionProvider? get suggestionsProvider; +} + +class _SearchSuggestionsProviderElement extends NotifierProviderElement< + SearchSuggestions, Raw>>> with SearchSuggestionsRef { + _SearchSuggestionsProviderElement(super.provider); + + @override + ISearchSuggestionProvider? get suggestionsProvider => + (origin as SearchSuggestionsProvider).suggestionsProvider; +} +// ignore_for_file: type=lint +// ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member, invalid_use_of_visible_for_testing_member, deprecated_member_use_from_same_package diff --git a/app/lib/features/search/domain/unix_tokenizer.dart b/app/lib/features/search/domain/unix_tokenizer.dart new file mode 100644 index 00000000..1c5b4d30 --- /dev/null +++ b/app/lib/features/search/domain/unix_tokenizer.dart @@ -0,0 +1,68 @@ +import 'package:lensai/features/search/domain/entities/bareword.dart'; + +typedef _Phrase = List; + +sealed class UnixTokenizer { + ///Matching quoted strings like "xda bda" (group 1), as well as strings delimetered by + ///a whitespace (group 2) + static final _tokenizePattern = RegExp('"([^"]+)"|([^ ]+)'); + + late final _Phrase _tokens; + + bool get hasTokens => _tokens.isNotEmpty; + + static void _mergeShortBarewords( + List barewords, + int minTokenLength, + ) { + for (var i = 0; i < barewords.length; i++) { + final bareword = barewords[i]; + + if (i != 0) { + if (bareword.word.length < minTokenLength) { + barewords[i] = barewords[i - 1].join(bareword); + } + } + } + } + + UnixTokenizer.tokenize({ + required String input, + required int minTokenLength, + required int tokenLimit, + }) { + final matches = _tokenizePattern.allMatches(input); + + final barewords = matches + .map((match) { + if (match.group(1) != null) { + return EnclosedBareword(match.group(1)!); + } else { + return SimpleBareword(match.group(2)!); + } + }) + .where((token) => token.word.isNotEmpty) + .toList(); + + //Merge short tokens + _mergeShortBarewords(barewords, minTokenLength); + + _tokens = barewords.take(tokenLimit).toList(); + } + + String build({bool wildcard}); +} + +final class UnixLikeQueryBuilder extends UnixTokenizer { + UnixLikeQueryBuilder.tokenize({ + required super.input, + required super.minTokenLength, + required super.tokenLimit, + }) : super.tokenize(); + + @override + String build({bool wildcard = true}) { + final joined = _tokens.join('%'); + return wildcard ? '%$joined%' : joined; + } +} diff --git a/app/lib/features/search/presentation/screens/search.dart b/app/lib/features/search/presentation/screens/search.dart new file mode 100644 index 00000000..c25035c4 --- /dev/null +++ b/app/lib/features/search/presentation/screens/search.dart @@ -0,0 +1,262 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_hooks/flutter_hooks.dart'; +import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:lensai/data/models/equatable_iterable.dart'; +import 'package:lensai/features/bangs/data/models/bang_data.dart'; +import 'package:lensai/features/bangs/domain/providers/bangs.dart'; +import 'package:lensai/features/bangs/domain/repositories/data.dart'; +import 'package:lensai/features/geckoview/domain/providers/tab_state.dart'; +import 'package:lensai/features/geckoview/features/browser/domain/providers.dart'; +import 'package:lensai/features/geckoview/features/tabs/data/models/container_data.dart'; +import 'package:lensai/features/geckoview/features/tabs/domain/providers/selected_container.dart'; +import 'package:lensai/features/geckoview/features/tabs/domain/repositories/tab_search.dart'; +import 'package:lensai/features/geckoview/features/tabs/presentation/widgets/container_chips.dart'; +import 'package:lensai/features/search/domain/providers/search_suggestions.dart'; +import 'package:lensai/features/search/presentation/widgets/bang_chips.dart'; +import 'package:lensai/features/search/presentation/widgets/search_field.dart'; +import 'package:lensai/presentation/hooks/listenable_callback.dart'; +import 'package:skeletonizer/skeletonizer.dart'; + +class SearchScreen extends HookConsumerWidget { + final String? initialSearchText; + + const SearchScreen({required this.initialSearchText}); + + @override + Widget build(BuildContext context, WidgetRef ref) { + final formKey = useMemoized(() => GlobalKey()); + + final searchTextController = + useTextEditingController(text: initialSearchText); + + useListenableCallback( + searchTextController, + () async { + ref + .read(searchSuggestionsProvider().notifier) + .addQuery(searchTextController.text); + + await ref + .read(tabSearchRepositoryProvider.notifier) + .addQuery(searchTextController.text); + }, + ); + + final globalSelectedContainer = ref.watch( + selectedContainerDataProvider.select((value) => value.valueOrNull), + ); + + final defaultSearchBang = ref.watch( + defaultSearchBangDataProvider.select((value) => value.valueOrNull), + ); + + final selectedBang = useState(null); + final activeBang = selectedBang.value ?? defaultSearchBang; + final showBangIcon = useState(false); + + ref.listen( + selectedBangDataProvider(), + (previous, next) { + if (next.hasValue) { + if ((previous?.hasValue ?? false) && previous!.value != next.value) { + showBangIcon.value = true; + } + + selectedBang.value = next.value; + } + }, + ); + + final selectedContainer = useState(globalSelectedContainer); + + final availableTabs = ref + .watch( + availableTabIdsProvider(selectedContainer.value?.id).select( + (value) => EquatableCollection(value, immutable: true), + ), + ) + .collection; + + return Scaffold( + body: Form( + key: formKey, + child: CustomScrollView( + slivers: [ + SliverAppBar( + floating: true, + pinned: true, + automaticallyImplyLeading: false, + title: SearchField( + showBangIcon: showBangIcon.value, + textEditingController: searchTextController, + onFieldSubmitted: (text) {}, + activeBang: activeBang, + ), + ), + const SliverToBoxAdapter( + child: Divider(), + ), + SliverToBoxAdapter( + child: Padding( + padding: const EdgeInsets.only(left: 16.0), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + 'Site Search', + style: Theme.of(context).textTheme.labelSmall, + ), + BangChips( + activeBang: activeBang, + onSelected: (bang) { + ref + .read(selectedBangTriggerProvider().notifier) + .setTrigger(bang.trigger); + }, + onDeleted: (bang) async { + if (ref.read(selectedBangTriggerProvider()) == + bang.trigger) { + ref + .read( + selectedBangTriggerProvider().notifier, + ) + .clearTrigger(); + } else { + final dialogResult = await BangChips.resetBangDialog( + context, + bang.trigger, + ); + + if (dialogResult == true) { + await ref + .read(bangDataRepositoryProvider.notifier) + .resetFrequency(bang.trigger); + } + } + }, + searchTextController: searchTextController, + ), + ], + ), + ), + ), + HookConsumer( + builder: (context, ref, child) { + final hasSearchText = useListenableSelector( + searchTextController, + () => searchTextController.text.isNotEmpty, + ); + + final suggestions = + useStream(ref.watch(searchSuggestionsProvider())); + + return (!hasSearchText || !suggestions.hasData) + ? SliverList.builder( + itemCount: 5, + itemBuilder: (context, index) { + return ListTile( + leading: const Icon(Icons.history), + title: Text('Search History $index'), + ); + }, + ) + : SliverList.builder( + itemCount: suggestions.data!.length, + itemBuilder: (context, index) { + final suggestion = suggestions.data![index]; + + return ListTile( + leading: const Icon(Icons.search), + title: Text(suggestion), + onLongPress: () { + searchTextController.text = suggestion; + }, + ); + }, + ); + }, + ), + const SliverToBoxAdapter( + child: Divider(), + ), + SliverToBoxAdapter( + child: Padding( + padding: const EdgeInsets.only(left: 16.0), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + 'Tabs', + style: Theme.of(context).textTheme.labelSmall, + ), + ContainerChips( + displayMenu: false, + selectedContainer: selectedContainer.value, + onSelected: (container) { + selectedContainer.value = container; + }, + onDeleted: (container) { + selectedContainer.value = null; + }, + searchTextController: searchTextController, + ), + ], + ), + ), + ), + Consumer( + builder: (context, ref, child) { + final tabs = ref.watch(tabSearchRepositoryProvider); + + return SliverSkeletonizer( + enabled: tabs.isLoading, + child: tabs.when( + data: (data) { + return SliverList.builder(itemBuilder: itemBuilder); + }, + error: error, + loading: () => SliverList.builder( + itemCount: tabs.valueOrNull?.length ?? 3, + itemBuilder: (context, index) { + return ListTile() + },), + ), + ); + }, + ), + SliverList.builder( + itemCount: availableTabs.length, + itemBuilder: (context, index) { + return Consumer( + key: ValueKey(availableTabs[index]), + builder: (context, ref, child) { + final tab = + ref.watch(tabStateProvider(availableTabs[index])); + + if (tab == null) { + return const SizedBox.shrink(); + } + + return ListTile( + leading: RawImage( + image: tab.icon?.value, + height: 24, + width: 24, + ), + title: Text(tab.title), + subtitle: Text( + tab.url.toString(), + softWrap: false, + overflow: TextOverflow.fade, + ), + ); + }, + ); + }, + ), + ], + ), + ), + ); + } +} diff --git a/app/lib/features/search/presentation/widgets/bang_chips.dart b/app/lib/features/search/presentation/widgets/bang_chips.dart new file mode 100644 index 00000000..b5680ff2 --- /dev/null +++ b/app/lib/features/search/presentation/widgets/bang_chips.dart @@ -0,0 +1,123 @@ +import 'package:flutter/material.dart'; +import 'package:go_router/go_router.dart'; +import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:lensai/core/routing/routes.dart'; +import 'package:lensai/features/bangs/data/models/bang_data.dart'; +import 'package:lensai/features/bangs/domain/repositories/search.dart'; +import 'package:lensai/features/bangs/presentation/widgets/bang_icon.dart'; +import 'package:lensai/presentation/hooks/listenable_callback.dart'; +import 'package:lensai/presentation/widgets/selectable_chips.dart'; + +class BangChips extends HookConsumerWidget { + final bool displayMenu; + + final BangData? activeBang; + final void Function(BangData)? onSelected; + final void Function(BangData)? onDeleted; + + final TextEditingController? searchTextController; + + const BangChips({ + required this.activeBang, + required this.onSelected, + required this.onDeleted, + this.searchTextController, + this.displayMenu = true, + }); + + static Future resetBangDialog( + BuildContext context, + String triggerName, + ) { + return showDialog( + context: context, + builder: (context) => AlertDialog( + title: Text( + 'Reset usage frequency of $triggerName?', + ), + content: const Text( + 'This will remove the Bang from quick select.', + ), + actions: [ + TextButton( + onPressed: () => Navigator.pop(context, false), + child: const Text('Cancel'), + ), + TextButton( + onPressed: () => Navigator.pop(context, true), + child: const Text('Reset'), + ), + ], + ), + ); + } + + @override + Widget build(BuildContext context, WidgetRef ref) { + final availableBangs = ref.watch(seamlessBangProviderProvider); + + useListenableCallback( + searchTextController, + () { + ref + .read(seamlessBangProviderProvider.notifier) + .search(searchTextController!.text); + }, + ); + + return availableBangs.when( + data: (availableBangs) => SizedBox( + height: 48, + child: Row( + children: [ + if (activeBang != null || availableBangs.isNotEmpty) + Expanded( + child: SelectableChips( + itemId: (bang) => bang.trigger, + itemAvatar: (bang) => BangIcon(bang, iconSize: 20), + itemLabel: (bang) => Text(bang.websiteName), + availableItems: availableBangs, + selectedItem: activeBang, + onSelected: onSelected, + onDeleted: onDeleted, + ), + ) + else + Visibility( + visible: displayMenu, + child: Expanded( + child: Text( + "Press '>' to search Bangs.", + style: TextStyle( + color: Theme.of(context).hintColor, + fontStyle: FontStyle.italic, + ), + ), + ), + ), + if (displayMenu) + IconButton( + onPressed: () async { + final searchText = searchTextController?.text.trim(); + + await context.push( + BangSearchRoute( + searchText: (searchText?.isEmpty ?? true) + ? BangSearchRoute.emptySearchText + : searchText!, + ).location, + ); + }, + icon: const Icon(Icons.chevron_right), + ), + ], + ), + ), + error: (error, stackTrace) => const SizedBox.shrink(), + loading: () => const SizedBox( + height: 48, + width: double.infinity, + ), + ); + } +} diff --git a/app/lib/features/search/presentation/widgets/search_field.dart b/app/lib/features/search/presentation/widgets/search_field.dart new file mode 100644 index 00000000..36523c81 --- /dev/null +++ b/app/lib/features/search/presentation/widgets/search_field.dart @@ -0,0 +1,84 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_hooks/flutter_hooks.dart'; +import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:lensai/features/bangs/data/models/bang_data.dart'; +import 'package:lensai/features/bangs/presentation/widgets/bang_icon.dart'; +import 'package:lensai/features/geckoview/features/browser/presentation/widgets/speech_to_text_button.dart'; +import 'package:lensai/features/settings/data/models/settings.dart'; +import 'package:lensai/features/settings/data/repositories/settings_repository.dart'; + +class SearchField extends HookConsumerWidget { + final TextEditingController textEditingController; + final FocusNode? focusNode; + final void Function(String)? onFieldSubmitted; + + final BangData? activeBang; + final bool showBangIcon; + + const SearchField({ + super.key, + required this.textEditingController, + required this.onFieldSubmitted, + required this.activeBang, + this.focusNode, + this.showBangIcon = true, + }); + + @override + Widget build(BuildContext context, WidgetRef ref) { + final incognitoEnabled = ref.watch( + settingsRepositoryProvider.select( + (value) => (value.valueOrNull ?? Settings.withDefaults()).incognitoMode, + ), + ); + + final hasText = useListenableSelector( + textEditingController, + () => textEditingController.text.isNotEmpty, + ); + + return TextFormField( + controller: textEditingController, + enableIMEPersonalizedLearning: !incognitoEnabled, + focusNode: focusNode, + decoration: InputDecoration( + border: InputBorder.none, + prefixIcon: (showBangIcon && activeBang != null) + ? Padding( + padding: const EdgeInsetsDirectional.all(12.0), + child: BangIcon(activeBang!, iconSize: 24.0), + ) + : null, + label: const Text('Search'), + hintText: 'Ask anything...', + floatingLabelBehavior: FloatingLabelBehavior.always, + suffixIcon: hasText + ? IconButton( + onPressed: () { + textEditingController.clear(); + }, + icon: const Icon(Icons.clear), + ) + : SpeechToTextButton( + onTextReceived: (data) { + textEditingController.text = data.toString(); + }, + ), + ), + // autovalidateMode: AutovalidateMode.onUserInteraction, + // validator: (value) { + // if (value?.isEmpty ?? true) { + // return ''; + // } + + // return null; + // }, + onTapOutside: (focusNode != null) + ? (event) { + focusNode!.unfocus(); + } + : null, + onFieldSubmitted: onFieldSubmitted, + ); + } +} diff --git a/app/lib/features/search/util/tokenized_filter.dart b/app/lib/features/search/util/tokenized_filter.dart new file mode 100644 index 00000000..bdbd1e1e --- /dev/null +++ b/app/lib/features/search/util/tokenized_filter.dart @@ -0,0 +1,48 @@ +typedef ToString = String? Function(T); + +class TokenizedFilter { + final Iterable original; + final List filtered; + + static List _tokenize(String input) { + return input + .trim() + .toLowerCase() + .replaceAll(RegExp(r'[^\w\s]'), '') // Remove punctuation + .split(RegExp(r'\s+')) // Split on whitespace + .where((word) => word.isNotEmpty) + .toList(); + } + + static bool _matchTokens( + List queryTokens, + List targetTokens, + ) { + return queryTokens.every( + (queryToken) => + targetTokens.any((targetToken) => targetToken.contains(queryToken)), + ); + } + + factory TokenizedFilter({ + required Iterable items, + required ToString toString, + required String query, + }) { + final queryTokens = _tokenize(query); + + final filtered = items.where((item) { + final itemString = toString(item); + if (itemString == null || itemString.isEmpty) { + return false; + } + + final itemTokens = _tokenize(itemString); + return _matchTokens(queryTokens, itemTokens); + }).toList(); + + return TokenizedFilter._(items, filtered); + } + + const TokenizedFilter._(this.original, this.filtered); +} diff --git a/app/lib/features/settings/presentation/screens/settings.dart b/app/lib/features/settings/presentation/screens/settings.dart index 0df8a3b7..60adee19 100644 --- a/app/lib/features/settings/presentation/screens/settings.dart +++ b/app/lib/features/settings/presentation/screens/settings.dart @@ -5,7 +5,7 @@ import 'package:flutter_markdown/flutter_markdown.dart'; import 'package:google_fonts/google_fonts.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:lensai/features/bangs/data/models/bang.dart'; -import 'package:lensai/features/bangs/domain/providers.dart'; +import 'package:lensai/features/bangs/domain/providers/bangs.dart'; import 'package:lensai/features/bangs/domain/repositories/data.dart'; import 'package:lensai/features/kagi/data/entities/modes.dart'; import 'package:lensai/features/settings/data/models/settings.dart'; diff --git a/app/lib/features/settings/presentation/widgets/bang_group_list_tile.dart b/app/lib/features/settings/presentation/widgets/bang_group_list_tile.dart index 9c19181f..8d8d0db3 100644 --- a/app/lib/features/settings/presentation/widgets/bang_group_list_tile.dart +++ b/app/lib/features/settings/presentation/widgets/bang_group_list_tile.dart @@ -1,7 +1,7 @@ import 'package:flutter/material.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:lensai/features/bangs/data/models/bang.dart'; -import 'package:lensai/features/bangs/domain/providers.dart'; +import 'package:lensai/features/bangs/domain/providers/bangs.dart'; import 'package:lensai/features/bangs/domain/repositories/sync.dart'; import 'package:lensai/features/settings/presentation/widgets/custom_list_tile.dart'; import 'package:lensai/features/settings/presentation/widgets/sync_details_table.dart'; diff --git a/app/lib/presentation/hooks/listenable_callback.dart b/app/lib/presentation/hooks/listenable_callback.dart index f3067a2b..d82a7a6f 100644 --- a/app/lib/presentation/hooks/listenable_callback.dart +++ b/app/lib/presentation/hooks/listenable_callback.dart @@ -1,12 +1,13 @@ import 'package:flutter/foundation.dart'; import 'package:flutter_hooks/flutter_hooks.dart'; -void useListenableCallback(Listenable? listenable, void Function() callback) { +void useListenableCallback(Listenable? listenable, void Function() callback, + [List? keys]) { useEffect( () { listenable?.addListener(callback); return () => listenable?.removeListener(callback); }, - [listenable], + keys ?? [listenable], ); } diff --git a/app/lib/utils/debouncer.dart b/app/lib/utils/debouncer.dart new file mode 100644 index 00000000..0c6ae20d --- /dev/null +++ b/app/lib/utils/debouncer.dart @@ -0,0 +1,21 @@ +import 'dart:async'; + +class Debouncer { + final Duration debounce; + + Timer? _timer; + + Debouncer(this.debounce); + + bool get isDebouncing => _timer?.isActive ?? false; + + void eventOccured(void Function() callback) { + _timer?.cancel(); + _timer = Timer(debounce, callback); + } + + void dispose() { + _timer?.cancel(); + _timer = null; + } +} diff --git a/app/lib/utils/lru_cache.dart b/app/lib/utils/lru_cache.dart index e1bfb88d..f2e7fa87 100644 --- a/app/lib/utils/lru_cache.dart +++ b/app/lib/utils/lru_cache.dart @@ -34,7 +34,7 @@ class LRUCache { return value; } - void set(K key, V value) { + V set(K key, V value) { if (_cache.containsKey(key)) { _cache.remove(key); // Remove the existing item before updating. } else if (_cache.length == _capacity) { @@ -43,6 +43,6 @@ class LRUCache { ); // Explicitly remove the least recently used item if at capacity. } - _cache[key] = value; // Inserting or updating the item. + return _cache[key] = value; // Inserting or updating the item. } } diff --git a/app/pubspec.lock b/app/pubspec.lock index 9c8c0f32..d9907890 100644 --- a/app/pubspec.lock +++ b/app/pubspec.lock @@ -162,10 +162,10 @@ packages: dependency: transitive description: name: cli_util - sha256: c05b7406fdabc7a49a3929d4af76bcaccbbffcbcdcf185b082e1ae07da323d19 + sha256: ff6785f7e9e3c38ac98b2fb035701789de90154024a75b6cb926445e83197d1c url: "https://pub.dev" source: hosted - version: "0.4.1" + version: "0.4.2" clock: dependency: transitive description: @@ -178,10 +178,10 @@ packages: dependency: transitive description: name: code_builder - sha256: f692079e25e7869c14132d39f223f8eec9830eb76131925143b2129c4bb01b37 + sha256: "0ec10bf4a89e4c613960bf1e8b42c64127021740fb21640c29c909826a5eea3e" url: "https://pub.dev" source: hosted - version: "4.10.0" + version: "4.10.1" collection: dependency: "direct main" description: @@ -234,10 +234,10 @@ packages: dependency: transitive description: name: csslib - sha256: "706b5707578e0c1b4b7550f64078f0a0f19dec3f50a178ffae7006b0a9ca58fb" + sha256: "09bad715f418841f976c77db72d5398dc1253c21fb9c0c7f0b0b985860b2d58e" url: "https://pub.dev" source: hosted - version: "1.0.0" + version: "1.0.2" custom_lint: dependency: "direct dev" description: @@ -290,10 +290,10 @@ packages: dependency: "direct dev" description: name: drift_dev - sha256: "4592cea370f1dcd8afc67987c28402797d9ddb4aa3ae372cb675497c0741816c" + sha256: "623649abe932fc17bd32e578e7e05f7ac5e7dd0b33e6c8669a0634105d1389bf" url: "https://pub.dev" source: hosted - version: "2.21.1" + version: "2.21.2" dynamic_color: dependency: "direct main" description: @@ -544,10 +544,10 @@ packages: dependency: "direct main" description: name: go_router - sha256: "6f1b756f6e863259a99135ff3c95026c3cdca17d10ebef2bba2261a25ddc8bbc" + sha256: ce89c5a993ca5eea74535f798478502c30a625ecb10a1de4d7fef5cd1bcac2a4 url: "https://pub.dev" source: hosted - version: "14.3.0" + version: "14.4.1" go_router_builder: dependency: "direct dev" description: @@ -600,10 +600,10 @@ packages: dependency: "direct main" description: name: html - sha256: "3a7812d5bcd2894edf53dfaf8cd640876cf6cef50a8f238745c8b8120ea74d3a" + sha256: "1fc58edeaec4307368c60d59b7e15b9d658b57d7f3125098b6294153c75337ec" url: "https://pub.dev" source: hosted - version: "0.15.4" + version: "0.15.5" http: dependency: "direct main" description: @@ -817,10 +817,10 @@ packages: dependency: "direct main" description: name: path_provider - sha256: fec0d61223fba3154d87759e3cc27fe2c8dc498f6386c6d6fc80d1afdd1bf378 + sha256: "50c5dd5b6e1aaf6fb3a78b33f6aa3afca52bf903a8a5298f53101fdaee55bbcd" url: "https://pub.dev" source: hosted - version: "2.1.4" + version: "2.1.5" path_provider_android: dependency: transitive description: @@ -1260,10 +1260,10 @@ packages: dependency: transitive description: name: url_launcher_android - sha256: "0dea215895a4d254401730ca0ba8204b29109a34a99fb06ae559a2b60988d2de" + sha256: "6fc2f56536ee873eeb867ad176ae15f304ccccc357848b351f6f0d8d4a40d193" url: "https://pub.dev" source: hosted - version: "6.3.13" + version: "6.3.14" url_launcher_ios: dependency: transitive description: @@ -1372,10 +1372,10 @@ packages: dependency: transitive description: name: win32 - sha256: e1d0cc62e65dc2561f5071fcbccecf58ff20c344f8f3dc7d4922df372a11df1f + sha256: "84ba388638ed7a8cb3445a320c8273136ab2631cd5f2c57888335504ddab1bc2" url: "https://pub.dev" source: hosted - version: "5.7.1" + version: "5.8.0" xdg_directories: dependency: transitive description: diff --git a/app/pubspec.yaml b/app/pubspec.yaml index 52d753fc..e99f153c 100644 --- a/app/pubspec.yaml +++ b/app/pubspec.yaml @@ -26,11 +26,11 @@ dependencies: flutter_pdf_text: ^0.7.0 flutter_secure_storage: ^9.2.2 flutter_sharing_intent: ^1.1.1 - go_router: ^14.3.0 + go_router: ^14.4.1 google_fonts: ^6.2.1 home_widget: ^0.7.0 hooks_riverpod: ^2.6.1 - html: ^0.15.4 + html: ^0.15.5 http: ^1.2.2 json_annotation: ^4.9.0 lexo_rank: @@ -41,7 +41,7 @@ dependencies: mime: ^2.0.0 package_info_plus: ^8.1.0 path: ^1.9.0 - path_provider: ^2.1.4 + path_provider: ^2.1.5 reorderable_grid: ^1.0.10 riverpod: ^2.6.1 riverpod_annotation: ^2.6.1 @@ -69,7 +69,7 @@ dev_dependencies: copy_with_extension_gen: ^5.0.4 custom_lint: ^0.6.8 dependency_validator: ^4.1.1 - drift_dev: ^2.21.1 + drift_dev: ^2.21.2 fast_equatable_lint: ^0.3.0 flutter_launcher_icons: ^0.14.1 go_router_builder: ^2.7.1 diff --git a/packages/flutter_mozilla_components/android/build.gradle b/packages/flutter_mozilla_components/android/build.gradle index 554e7fc1..670a5d64 100644 --- a/packages/flutter_mozilla_components/android/build.gradle +++ b/packages/flutter_mozilla_components/android/build.gradle @@ -3,7 +3,7 @@ version = "1.0-SNAPSHOT" buildscript { ext.kotlin_version = "1.9.22" - ext.mozillaComponentsVersion = '133.0.20241024211615' + ext.mozillaComponentsVersion = '134.0.20241030214633' repositories { google() @@ -74,48 +74,6 @@ android { viewBinding true } - dependencies { - implementation "org.mozilla.components:support-utils:$mozillaComponentsVersion" - implementation "org.mozilla.components:support-ktx:$mozillaComponentsVersion" - implementation "org.mozilla.components:support-webextensions:$mozillaComponentsVersion" - implementation "org.mozilla.components:support-locale:$mozillaComponentsVersion" - implementation "org.mozilla.components:lib-fetch-httpurlconnection:$mozillaComponentsVersion" - implementation "org.mozilla.components:lib-crash:$mozillaComponentsVersion" - implementation "org.mozilla.components:lib-publicsuffixlist:$mozillaComponentsVersion" - implementation "org.mozilla.components:lib-dataprotect:$mozillaComponentsVersion" - implementation "org.mozilla.components:concept-engine:$mozillaComponentsVersion" - implementation "org.mozilla.components:concept-fetch:$mozillaComponentsVersion" - implementation "org.mozilla.components:browser-engine-gecko:$mozillaComponentsVersion" - implementation "org.mozilla.components:browser-state:$mozillaComponentsVersion" - implementation "org.mozilla.components:browser-session-storage:$mozillaComponentsVersion" - implementation "org.mozilla.components:browser-icons:$mozillaComponentsVersion" - implementation "org.mozilla.components:browser-thumbnails:$mozillaComponentsVersion" - implementation "org.mozilla.components:feature-addons:$mozillaComponentsVersion" - implementation "org.mozilla.components:feature-app-links:$mozillaComponentsVersion" - implementation "org.mozilla.components:feature-autofill:$mozillaComponentsVersion" - implementation "org.mozilla.components:feature-downloads:$mozillaComponentsVersion" - implementation "org.mozilla.components:feature-media:$mozillaComponentsVersion" - implementation "org.mozilla.components:feature-tabs:$mozillaComponentsVersion" - implementation "org.mozilla.components:feature-prompts:$mozillaComponentsVersion" - implementation "org.mozilla.components:feature-session:$mozillaComponentsVersion" - implementation "org.mozilla.components:feature-readerview:$mozillaComponentsVersion" - implementation "org.mozilla.components:feature-privatemode:$mozillaComponentsVersion" - implementation "org.mozilla.components:feature-sitepermissions:$mozillaComponentsVersion" - implementation "org.mozilla.components:feature-webcompat:$mozillaComponentsVersion" - implementation "org.mozilla.components:feature-webnotifications:$mozillaComponentsVersion" - implementation "org.mozilla.components:service-digitalassetlinks:$mozillaComponentsVersion" - implementation "org.mozilla.components:ui-widgets:$mozillaComponentsVersion" - - implementation 'androidx.coordinatorlayout:coordinatorlayout:1.2.0' - implementation 'androidx.swiperefreshlayout:swiperefreshlayout:1.1.0' - implementation 'com.google.android.material:material:1.12.0' - //https://stackoverflow.com/questions/73782320/onbackinvokedcallback-is-not-enabled-for-the-application-in-set-androidenableo - implementation 'androidx.activity:activity:1.9.3' - - testImplementation("org.jetbrains.kotlin:kotlin-test") - testImplementation("org.mockito:mockito-core:5.1.0") - } - testOptions { unitTests.all { useJUnitPlatform() @@ -129,6 +87,66 @@ android { } } -dependencies { - implementation 'androidx.preference:preference-ktx:1.2.1' +configurations.configureEach { + exclude group: "org.mozilla.telemetry", module: "glean-native" +} + +// Select the Glean from GeckoView. +// `service-sync-logins` requires Glean, which pulls in glean-native, +// but that's also provided by geckoview-omni, so now we need to select which one to use. +project.configurations.configureEach { + resolutionStrategy.capabilitiesResolution.withCapability("org.mozilla.telemetry:glean-native") { + def toBeSelected = candidates.find { it.id instanceof ModuleComponentIdentifier && it.id.module.contains('geckoview') } + if (toBeSelected != null) { + select(toBeSelected) + } + because 'use GeckoView Glean instead of standalone Glean' + } +} + +dependencies { + implementation "org.mozilla.components:support-utils:$mozillaComponentsVersion" + implementation "org.mozilla.components:support-ktx:$mozillaComponentsVersion" + implementation "org.mozilla.components:support-webextensions:$mozillaComponentsVersion" + implementation "org.mozilla.components:support-locale:$mozillaComponentsVersion" + implementation "org.mozilla.components:lib-fetch-httpurlconnection:$mozillaComponentsVersion" + implementation "org.mozilla.components:lib-crash:$mozillaComponentsVersion" + implementation "org.mozilla.components:lib-publicsuffixlist:$mozillaComponentsVersion" + implementation "org.mozilla.components:lib-dataprotect:$mozillaComponentsVersion" + implementation "org.mozilla.components:concept-engine:$mozillaComponentsVersion" + implementation "org.mozilla.components:concept-fetch:$mozillaComponentsVersion" + implementation "org.mozilla.components:concept-toolbar:$mozillaComponentsVersion" + implementation "org.mozilla.components:concept-awesomebar:$mozillaComponentsVersion" + implementation "org.mozilla.components:browser-engine-gecko:$mozillaComponentsVersion" + implementation "org.mozilla.components:browser-state:$mozillaComponentsVersion" + implementation "org.mozilla.components:browser-session-storage:$mozillaComponentsVersion" + implementation "org.mozilla.components:browser-storage-sync:$mozillaComponentsVersion" + implementation "org.mozilla.components:browser-icons:$mozillaComponentsVersion" + implementation "org.mozilla.components:browser-thumbnails:$mozillaComponentsVersion" + implementation "org.mozilla.components:feature-addons:$mozillaComponentsVersion" + implementation "org.mozilla.components:feature-app-links:$mozillaComponentsVersion" + implementation "org.mozilla.components:feature-autofill:$mozillaComponentsVersion" + implementation "org.mozilla.components:feature-awesomebar:$mozillaComponentsVersion" + implementation "org.mozilla.components:feature-downloads:$mozillaComponentsVersion" + implementation "org.mozilla.components:feature-media:$mozillaComponentsVersion" + implementation "org.mozilla.components:feature-tabs:$mozillaComponentsVersion" + implementation "org.mozilla.components:feature-prompts:$mozillaComponentsVersion" + implementation "org.mozilla.components:feature-session:$mozillaComponentsVersion" + implementation "org.mozilla.components:feature-readerview:$mozillaComponentsVersion" + implementation "org.mozilla.components:feature-privatemode:$mozillaComponentsVersion" + implementation "org.mozilla.components:feature-sitepermissions:$mozillaComponentsVersion" + implementation "org.mozilla.components:feature-webcompat:$mozillaComponentsVersion" + implementation "org.mozilla.components:feature-webnotifications:$mozillaComponentsVersion" + implementation "org.mozilla.components:service-digitalassetlinks:$mozillaComponentsVersion" + implementation "org.mozilla.components:ui-widgets:$mozillaComponentsVersion" + + implementation 'androidx.coordinatorlayout:coordinatorlayout:1.2.0' + implementation 'androidx.swiperefreshlayout:swiperefreshlayout:1.1.0' + implementation 'androidx.preference:preference-ktx:1.2.1' + implementation 'com.google.android.material:material:1.12.0' + //https://stackoverflow.com/questions/73782320/onbackinvokedcallback-is-not-enabled-for-the-application-in-set-androidenableo + implementation 'androidx.activity:activity-ktx:1.9.3' + + testImplementation("org.jetbrains.kotlin:kotlin-test") + testImplementation("org.mockito:mockito-core:5.2.0") } diff --git a/packages/flutter_mozilla_components/android/src/main/assets/extensions/readability_extract/content.js b/packages/flutter_mozilla_components/android/src/main/assets/extensions/readability_extract/content.js new file mode 100644 index 00000000..57b85b24 --- /dev/null +++ b/packages/flutter_mozilla_components/android/src/main/assets/extensions/readability_extract/content.js @@ -0,0 +1,47 @@ +const port = browser.runtime.connectNative("mozacReaderExtract"); + +let domChanged = false; +let lastContent = ''; + +function parseContent() { + const article = window.parseReaderable(document); + + if (article && lastContent !== article.textContent) { + port.postMessage(article); + + lastContent = article.textContent; + } + + domChanged = false; +} + +port.onMessage.addListener((message) => { + if (message.action === "parseContent") { + if (domChanged) { + parseContent(); + } + } +}); + +const observer = new MutationObserver(() => { + domChanged = true; +}); + +const observerConfig = { + childList: true, + subtree: true, + characterData: true, + attributes: false +}; + +// Wait for page to be fully loaded +if (document.readyState === 'complete') { + parseContent(); + observer.observe(document.body, observerConfig); +} else { + window.addEventListener('load', parseContent); +} + +window.addEventListener('unload', () => { + observer.disconnect(); +}); diff --git a/packages/flutter_mozilla_components/android/src/main/assets/extensions/readability_extract/manifest.json b/packages/flutter_mozilla_components/android/src/main/assets/extensions/readability_extract/manifest.json new file mode 100644 index 00000000..bb85955e --- /dev/null +++ b/packages/flutter_mozilla_components/android/src/main/assets/extensions/readability_extract/manifest.json @@ -0,0 +1,29 @@ +{ + "manifest_version": 2, + "browser_specific_settings": { + "gecko": { + "id": "readability-extract@movenext.me" + } + }, + "name": "Extract text of Websites", + "version": "1.0", + "content_scripts": [ + { + "matches": [""], + "js": [ + "readability.min.js", + "content.js" + ] + } + ], + "permissions": [ + "mozillaAddons", + "geckoViewAddons", + "nativeMessaging", + "nativeMessagingFromContent", + "storage", + "tabs", + "webNavigation", + "" + ] +} diff --git a/packages/flutter_mozilla_components/android/src/main/assets/extensions/readability_extract/readability.min.js b/packages/flutter_mozilla_components/android/src/main/assets/extensions/readability_extract/readability.min.js new file mode 120000 index 00000000..1eada1aa --- /dev/null +++ b/packages/flutter_mozilla_components/android/src/main/assets/extensions/readability_extract/readability.min.js @@ -0,0 +1 @@ +../../../../../../javascript/readability/dist/readability.min.js \ No newline at end of file diff --git a/packages/flutter_mozilla_components/android/src/main/kotlin/eu/lensai/flutter_mozilla_components/BaseBrowserFragment.kt b/packages/flutter_mozilla_components/android/src/main/kotlin/eu/lensai/flutter_mozilla_components/BaseBrowserFragment.kt index 7ac2c2e7..d7ee1bc3 100644 --- a/packages/flutter_mozilla_components/android/src/main/kotlin/eu/lensai/flutter_mozilla_components/BaseBrowserFragment.kt +++ b/packages/flutter_mozilla_components/android/src/main/kotlin/eu/lensai/flutter_mozilla_components/BaseBrowserFragment.kt @@ -15,7 +15,9 @@ import androidx.fragment.app.Fragment import eu.lensai.flutter_mozilla_components.addons.WebExtensionPromptFeature import eu.lensai.flutter_mozilla_components.databinding.FragmentBrowserBinding import eu.lensai.flutter_mozilla_components.ext.getPreferenceKey +import eu.lensai.flutter_mozilla_components.pip.PictureInPictureIntegration import eu.lensai.flutter_mozilla_components.services.DownloadService +import mozilla.components.browser.state.selector.selectedTab import mozilla.components.concept.engine.EngineView import mozilla.components.feature.app.links.AppLinksFeature import mozilla.components.feature.downloads.DownloadsFeature @@ -51,6 +53,7 @@ abstract class BaseBrowserFragment : Fragment(), UserInteractionHandler, Activit private val appLinksFeature = ViewBoundFeatureWrapper() private val promptFeature = ViewBoundFeatureWrapper() private val webExtensionPromptFeature = ViewBoundFeatureWrapper() + private val pictureInPictureIntegration = ViewBoundFeatureWrapper() private val sitePermissionsFeature = ViewBoundFeatureWrapper() private val swipeRefreshFeature = ViewBoundFeatureWrapper() private val secureWindowFeature = ViewBoundFeatureWrapper() @@ -251,16 +254,11 @@ abstract class BaseBrowserFragment : Fragment(), UserInteractionHandler, Activit fullScreenFeature.set( feature = FullScreenFeature( - components.core.store, - components.useCases.sessionUseCases, - sessionId, - ) { inFullScreen -> - if (inFullScreen) { - activity?.enterImmersiveMode() - } else { - activity?.exitImmersiveMode() - } - }, + store = components.core.store, + sessionUseCases = components.useCases.sessionUseCases, + tabId = sessionId, + fullScreenChanged = ::fullScreenChanged, + ), owner = this, view = binding.root, ) @@ -275,6 +273,16 @@ abstract class BaseBrowserFragment : Fragment(), UserInteractionHandler, Activit view = binding.root, ) + pictureInPictureIntegration.set( + feature = PictureInPictureIntegration( + components.core.store, + requireActivity(), + sessionId, + ), + owner = this, + view = view, + ) + secureWindowFeature.set( feature = SecureWindowFeature( window = requireActivity().window, @@ -312,11 +320,34 @@ abstract class BaseBrowserFragment : Fragment(), UserInteractionHandler, Activit return binding.root } + private fun fullScreenChanged(enabled: Boolean) { + if (enabled) { + activity?.enterImmersiveMode() + } else { + activity?.exitImmersiveMode() + } + } + @CallSuper override fun onBackPressed(): Boolean { return backButtonHandler.any { it.onBackPressed() } } + final override fun onPause() { + pictureInPictureIntegration.get()?.onHomePressed() ?: false + super.onPause() + } + + final override fun onPictureInPictureModeChanged(enabled: Boolean) { + val session = components.core.store.state.selectedTab + val fullScreenMode = session?.content?.fullScreen ?: false + // If we're exiting PIP mode and we're in fullscreen mode, then we should exit fullscreen mode as well. + if (!enabled && fullScreenMode) { + onBackPressed() + fullScreenChanged(false) + } + } + @CallSuper override fun onActivityResult(requestCode: Int, data: Intent?, resultCode: Int): Boolean { return activityResultHandler.any { it.onActivityResult(requestCode, data, resultCode) } diff --git a/packages/flutter_mozilla_components/android/src/main/kotlin/eu/lensai/flutter_mozilla_components/BrowserFragment.kt b/packages/flutter_mozilla_components/android/src/main/kotlin/eu/lensai/flutter_mozilla_components/BrowserFragment.kt index daa5550c..c804ec2d 100644 --- a/packages/flutter_mozilla_components/android/src/main/kotlin/eu/lensai/flutter_mozilla_components/BrowserFragment.kt +++ b/packages/flutter_mozilla_components/android/src/main/kotlin/eu/lensai/flutter_mozilla_components/BrowserFragment.kt @@ -6,6 +6,7 @@ import android.content.Intent import android.os.Bundle import android.view.View import eu.lensai.flutter_mozilla_components.addons.WebExtensionActionPopupActivity +import eu.lensai.flutter_mozilla_components.feature.ReadabilityExtractFeature import eu.lensai.flutter_mozilla_components.feature.WebExtensionToolbarFeature import eu.lensai.flutter_mozilla_components.integration.ReaderViewIntegration import mozilla.components.browser.state.state.WebExtensionState @@ -19,15 +20,16 @@ import mozilla.components.support.webextensions.WebExtensionPopupObserver /** * Fragment used for browsing the web within the main app. */ -class BrowserFragment(private val context: Context) : BaseBrowserFragment(), UserInteractionHandler { +class BrowserFragment() : BaseBrowserFragment(), UserInteractionHandler { private val windowFeature = ViewBoundFeatureWrapper() private val thumbnailsFeature = ViewBoundFeatureWrapper() private val readerViewFeature = ViewBoundFeatureWrapper() + private val readabilityExtractFeature = ViewBoundFeatureWrapper() private val webExtensionPopupObserver = ViewBoundFeatureWrapper() private val webExtToolbarFeature = ViewBoundFeatureWrapper() override fun createEngine(components: Components): EngineView { - return components.core.engine.createView(context).apply { + return components.core.engine.createView(requireContext()).apply { selectionActionDelegate = components.selectionAction } } @@ -49,6 +51,12 @@ class BrowserFragment(private val context: Context) : BaseBrowserFragment(), Use view = view, ) + readabilityExtractFeature.set( + feature = components.features.readabilityExtractFeature, + owner = this, + view = view, + ) + windowFeature.set( feature = WindowFeature(components.core.store, components.useCases.tabsUseCases), owner = this, @@ -72,6 +80,8 @@ class BrowserFragment(private val context: Context) : BaseBrowserFragment(), Use owner = this, view = view, ) + + components.core.historyStorage.registerStorageMaintenanceWorker() } private fun openPopup(webExtensionState: WebExtensionState) { @@ -86,7 +96,7 @@ class BrowserFragment(private val context: Context) : BaseBrowserFragment(), Use readerViewFeature.onBackPressed() || super.onBackPressed() companion object { - fun create(context: Context, sessionId: String? = null) = BrowserFragment(context).apply { + fun create(sessionId: String? = null) = BrowserFragment().apply { arguments = Bundle().apply { putSessionId(sessionId) } diff --git a/packages/flutter_mozilla_components/android/src/main/kotlin/eu/lensai/flutter_mozilla_components/Components.kt b/packages/flutter_mozilla_components/android/src/main/kotlin/eu/lensai/flutter_mozilla_components/Components.kt index ae9cc6a5..17a56123 100644 --- a/packages/flutter_mozilla_components/android/src/main/kotlin/eu/lensai/flutter_mozilla_components/Components.kt +++ b/packages/flutter_mozilla_components/android/src/main/kotlin/eu/lensai/flutter_mozilla_components/Components.kt @@ -5,10 +5,13 @@ import androidx.core.app.NotificationManagerCompat import eu.lensai.flutter_mozilla_components.components.Core import eu.lensai.flutter_mozilla_components.components.Events import eu.lensai.flutter_mozilla_components.components.Features +import eu.lensai.flutter_mozilla_components.components.Search import eu.lensai.flutter_mozilla_components.components.Services import eu.lensai.flutter_mozilla_components.components.UseCases import eu.lensai.flutter_mozilla_components.pigeons.GeckoAddonEvents import eu.lensai.flutter_mozilla_components.pigeons.GeckoStateEvents +import eu.lensai.flutter_mozilla_components.pigeons.GeckoSuggestionEvents +import eu.lensai.flutter_mozilla_components.pigeons.GeckoTabContentEvents import eu.lensai.flutter_mozilla_components.pigeons.ReaderViewController import mozilla.components.concept.engine.EngineView import mozilla.components.concept.engine.selection.SelectionActionDelegate @@ -18,13 +21,15 @@ class Components(private val context: Context, val flutterEvents: GeckoStateEvents, val readerViewController: ReaderViewController, val selectionAction: SelectionActionDelegate, - val addonEvents: GeckoAddonEvents + val addonEvents: GeckoAddonEvents, + val tabContentEvents: GeckoTabContentEvents ) { val core by lazy { Core(context, this, flutterEvents) } val events by lazy { Events(flutterEvents) } val useCases by lazy { UseCases(context, core.engine, core.store) } val services by lazy { Services(context, useCases.tabsUseCases) } - val features by lazy { Features(core.store, addonEvents) } + val features by lazy { Features(core.engine, core.store, addonEvents, tabContentEvents) } + val search by lazy { Search(context, core, useCases) } var engineView: EngineView? = null var engineReportedInitialized = false diff --git a/packages/flutter_mozilla_components/android/src/main/kotlin/eu/lensai/flutter_mozilla_components/EngineProvider.kt b/packages/flutter_mozilla_components/android/src/main/kotlin/eu/lensai/flutter_mozilla_components/EngineProvider.kt index c13823e4..338d5597 100644 --- a/packages/flutter_mozilla_components/android/src/main/kotlin/eu/lensai/flutter_mozilla_components/EngineProvider.kt +++ b/packages/flutter_mozilla_components/android/src/main/kotlin/eu/lensai/flutter_mozilla_components/EngineProvider.kt @@ -32,6 +32,8 @@ object EngineProvider { // About config it's no longer enabled by default builder.aboutConfigEnabled(true) builder.extensionsWebAPIEnabled(true) + builder.consoleOutput(true) + runtime = GeckoRuntime.create(context, builder.build()) } diff --git a/packages/flutter_mozilla_components/android/src/main/kotlin/eu/lensai/flutter_mozilla_components/FlutterMozillaComponentsPlugin.kt b/packages/flutter_mozilla_components/android/src/main/kotlin/eu/lensai/flutter_mozilla_components/FlutterMozillaComponentsPlugin.kt index 5cd09b20..04e33df2 100644 --- a/packages/flutter_mozilla_components/android/src/main/kotlin/eu/lensai/flutter_mozilla_components/FlutterMozillaComponentsPlugin.kt +++ b/packages/flutter_mozilla_components/android/src/main/kotlin/eu/lensai/flutter_mozilla_components/FlutterMozillaComponentsPlugin.kt @@ -12,6 +12,7 @@ import eu.lensai.flutter_mozilla_components.api.GeckoFindApiImpl import eu.lensai.flutter_mozilla_components.api.GeckoIconsApiImpl import eu.lensai.flutter_mozilla_components.api.GeckoSelectionActionControllerImpl import eu.lensai.flutter_mozilla_components.api.GeckoSessionApiImpl +import eu.lensai.flutter_mozilla_components.api.GeckoSuggestionApiImpl import eu.lensai.flutter_mozilla_components.api.GeckoTabsApiImpl import eu.lensai.flutter_mozilla_components.feature.DefaultSelectionActionDelegate import eu.lensai.flutter_mozilla_components.pigeons.GeckoAddonEvents @@ -25,6 +26,9 @@ import eu.lensai.flutter_mozilla_components.pigeons.GeckoSelectionActionControll import eu.lensai.flutter_mozilla_components.pigeons.GeckoSelectionActionEvents import eu.lensai.flutter_mozilla_components.pigeons.GeckoSessionApi import eu.lensai.flutter_mozilla_components.pigeons.GeckoStateEvents +import eu.lensai.flutter_mozilla_components.pigeons.GeckoSuggestionApi +import eu.lensai.flutter_mozilla_components.pigeons.GeckoSuggestionEvents +import eu.lensai.flutter_mozilla_components.pigeons.GeckoTabContentEvents import eu.lensai.flutter_mozilla_components.pigeons.GeckoTabsApi import eu.lensai.flutter_mozilla_components.pigeons.ReaderViewController import eu.lensai.flutter_mozilla_components.pigeons.ReaderViewEvents @@ -63,13 +67,18 @@ class FlutterMozillaComponentsPlugin: FlutterPlugin, ActivityAware { ReaderViewController(_flutterPluginBinding.binaryMessenger) val addonEvents = GeckoAddonEvents(_flutterPluginBinding.binaryMessenger) + val tabContentEvents = GeckoTabContentEvents(_flutterPluginBinding.binaryMessenger) + + val suggestionEvents = GeckoSuggestionEvents(_flutterPluginBinding.binaryMessenger) + GeckoSuggestionApi.setUp(_flutterPluginBinding.binaryMessenger, GeckoSuggestionApiImpl(suggestionEvents)) GlobalComponents.setUp( flutterPluginBinding.applicationContext, _flutterEvents, readerViewController, selectionActionDelegate, - addonEvents + addonEvents, + tabContentEvents, ) GeckoBrowserApi.setUp(_flutterPluginBinding.binaryMessenger, GeckoBrowserApiImpl { @@ -104,7 +113,7 @@ class FlutterMozillaComponentsPlugin: FlutterPlugin, ActivityAware { } // Replace this with your actual Fragment - val nativeFragment = BrowserFragment.create(activity!!) + val nativeFragment = BrowserFragment.create() val fm = (activity as FragmentActivity).supportFragmentManager fm.beginTransaction() diff --git a/packages/flutter_mozilla_components/android/src/main/kotlin/eu/lensai/flutter_mozilla_components/GlobalComponents.kt b/packages/flutter_mozilla_components/android/src/main/kotlin/eu/lensai/flutter_mozilla_components/GlobalComponents.kt index 63b0f7d3..580d92fe 100644 --- a/packages/flutter_mozilla_components/android/src/main/kotlin/eu/lensai/flutter_mozilla_components/GlobalComponents.kt +++ b/packages/flutter_mozilla_components/android/src/main/kotlin/eu/lensai/flutter_mozilla_components/GlobalComponents.kt @@ -3,11 +3,14 @@ package eu.lensai.flutter_mozilla_components import android.content.Context import eu.lensai.flutter_mozilla_components.pigeons.GeckoAddonEvents import eu.lensai.flutter_mozilla_components.pigeons.GeckoStateEvents +import eu.lensai.flutter_mozilla_components.pigeons.GeckoSuggestionEvents +import eu.lensai.flutter_mozilla_components.pigeons.GeckoTabContentEvents import eu.lensai.flutter_mozilla_components.pigeons.ReaderViewController import kotlinx.coroutines.DelicateCoroutinesApi import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.GlobalScope import kotlinx.coroutines.launch +import mozilla.components.browser.storage.sync.GlobalPlacesDependencyProvider import mozilla.components.concept.engine.selection.SelectionActionDelegate import mozilla.components.feature.addons.update.GlobalAddonDependencyProvider import mozilla.components.support.base.facts.Facts @@ -40,7 +43,8 @@ object GlobalComponents { flutterEvents: GeckoStateEvents, readerViewController: ReaderViewController, selectionAction: SelectionActionDelegate, - addonEvents: GeckoAddonEvents + addonEvents: GeckoAddonEvents, + tabContentEvents: GeckoTabContentEvents ) { Logger.debug("Creating new components") @@ -50,6 +54,7 @@ object GlobalComponents { readerViewController, selectionAction, addonEvents, + tabContentEvents ) //newComponents.crashReporter.install(applicationContext) @@ -65,6 +70,8 @@ object GlobalComponents { //newComponents.useCases.downloadsUseCases.restoreDownloads() try { + GlobalPlacesDependencyProvider.initialize(newComponents.core.historyStorage) + GlobalAddonDependencyProvider.initialize( newComponents.core.addonManager, newComponents.core.addonUpdater, diff --git a/packages/flutter_mozilla_components/android/src/main/kotlin/eu/lensai/flutter_mozilla_components/api/GeckoSessionApiImpl.kt b/packages/flutter_mozilla_components/android/src/main/kotlin/eu/lensai/flutter_mozilla_components/api/GeckoSessionApiImpl.kt index a47000dd..288ff76a 100644 --- a/packages/flutter_mozilla_components/android/src/main/kotlin/eu/lensai/flutter_mozilla_components/api/GeckoSessionApiImpl.kt +++ b/packages/flutter_mozilla_components/android/src/main/kotlin/eu/lensai/flutter_mozilla_components/api/GeckoSessionApiImpl.kt @@ -22,7 +22,6 @@ import eu.lensai.flutter_mozilla_components.pigeons.TranslationOptions as Pigeon class GeckoSessionApiImpl : GeckoSessionApi { companion object { private const val TAG = "GeckoSessionApi" - private val coroutineScope = CoroutineScope(Dispatchers.Main + SupervisorJob()) } private val components by lazy { diff --git a/packages/flutter_mozilla_components/android/src/main/kotlin/eu/lensai/flutter_mozilla_components/api/GeckoSuggestionApiImpl.kt b/packages/flutter_mozilla_components/android/src/main/kotlin/eu/lensai/flutter_mozilla_components/api/GeckoSuggestionApiImpl.kt new file mode 100644 index 00000000..7ebb544a --- /dev/null +++ b/packages/flutter_mozilla_components/android/src/main/kotlin/eu/lensai/flutter_mozilla_components/api/GeckoSuggestionApiImpl.kt @@ -0,0 +1,57 @@ +package eu.lensai.flutter_mozilla_components.api + +import eu.lensai.flutter_mozilla_components.GlobalComponents +import eu.lensai.flutter_mozilla_components.ext.toWebPBytes +import eu.lensai.flutter_mozilla_components.pigeons.GeckoSuggestion +import eu.lensai.flutter_mozilla_components.pigeons.GeckoSuggestionApi +import eu.lensai.flutter_mozilla_components.pigeons.GeckoSuggestionEvents +import eu.lensai.flutter_mozilla_components.pigeons.GeckoSuggestionType +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.SupervisorJob +import kotlinx.coroutines.launch +import org.mozilla.gecko.util.ThreadUtils.runOnUiThread + +class GeckoSuggestionApiImpl( + private val suggestionEvents: GeckoSuggestionEvents +) : GeckoSuggestionApi { + companion object { + private val coroutineScope = CoroutineScope(Dispatchers.Main + SupervisorJob()) + } + + private val components by lazy { + requireNotNull(GlobalComponents.components) { "Components not initialized" } + } + + override fun onInputChanged(text: String, providers: List) { + for(provider in providers) { + coroutineScope.launch { + val results = when(provider) { + GeckoSuggestionType.SESSION -> components.search.sessionSuggestions.onInputChanged(text) + GeckoSuggestionType.CLIPBOARD -> components.search.clipboardSuggestions.onInputChanged(text) + GeckoSuggestionType.HISTORY -> components.search.historySuggestions.onInputChanged(text) + } + + val mappedResults = results.map { result -> + GeckoSuggestion( + id = result.id, + title = result.title, + score = result.score.toLong(), + description = result.description, + type = provider, + editSuggestion = result.editSuggestion, + icon = result.icon?.toWebPBytes() + ) + } + + runOnUiThread { + suggestionEvents.onSuggestionResult( + System.currentTimeMillis(), + provider, + mappedResults + ) { } + } + } + } + } +} \ No newline at end of file diff --git a/packages/flutter_mozilla_components/android/src/main/kotlin/eu/lensai/flutter_mozilla_components/components/Core.kt b/packages/flutter_mozilla_components/android/src/main/kotlin/eu/lensai/flutter_mozilla_components/components/Core.kt index bf70382e..591a1986 100644 --- a/packages/flutter_mozilla_components/android/src/main/kotlin/eu/lensai/flutter_mozilla_components/components/Core.kt +++ b/packages/flutter_mozilla_components/android/src/main/kotlin/eu/lensai/flutter_mozilla_components/components/Core.kt @@ -20,6 +20,7 @@ import mozilla.components.browser.session.storage.SessionStorage import mozilla.components.browser.state.engine.EngineMiddleware import mozilla.components.browser.state.engine.middleware.SessionPrioritizationMiddleware import mozilla.components.browser.state.store.BrowserStore +import mozilla.components.browser.storage.sync.PlacesHistoryStorage import mozilla.components.browser.thumbnails.ThumbnailsMiddleware import mozilla.components.browser.thumbnails.storage.ThumbnailStorage import mozilla.components.concept.engine.DefaultSettings @@ -35,6 +36,7 @@ import mozilla.components.feature.media.MediaSessionFeature import mozilla.components.feature.media.middleware.RecordingDevicesMiddleware import mozilla.components.feature.prompts.file.FileUploadsDirCleaner import mozilla.components.feature.readerview.ReaderViewMiddleware +import mozilla.components.feature.session.HistoryDelegate import mozilla.components.feature.session.middleware.LastAccessMiddleware import mozilla.components.feature.sitepermissions.OnDiskSitePermissionsStorage import mozilla.components.feature.webnotifications.WebNotificationFeature @@ -51,12 +53,13 @@ class Core(private val context: Context, PreferenceManager.getDefaultSharedPreferences(context) } - val engineSettings by lazy { + private val engineSettings by lazy { DefaultSettings().apply { //historyTrackingDelegate = HistoryDelegate(lazyHistoryStorage) requestInterceptor = AppRequestInterceptor(context) remoteDebuggingEnabled = prefs.getBoolean(context.getPreferenceKey(R.string.pref_key_remote_debugging), false) testingModeEnabled = prefs.getBoolean(context.getPreferenceKey(R.string.pref_key_testing_mode), false) + historyTrackingDelegate = HistoryDelegate(lazyHistoryStorage) trackingProtectionPolicy = createTrackingProtectionPolicy(prefs) httpsOnlyMode = Engine.HttpsOnlyMode.ENABLED globalPrivacyControlEnabled = prefs.getBoolean( @@ -159,6 +162,17 @@ class Core(private val context: Context, SessionStorage(context, engine) } + /** + * The storage component to persist browsing history (with the exception of + * private sessions). + */ + val lazyHistoryStorage = lazy { PlacesHistoryStorage(context) } + + /** + * A convenience accessor to the [PlacesHistoryStorage]. + */ + val historyStorage by lazy { lazyHistoryStorage.value } + /** * Constructs a [TrackingProtectionPolicy] based on current preferences. * diff --git a/packages/flutter_mozilla_components/android/src/main/kotlin/eu/lensai/flutter_mozilla_components/components/Features.kt b/packages/flutter_mozilla_components/android/src/main/kotlin/eu/lensai/flutter_mozilla_components/components/Features.kt index 2d362ade..469a133e 100644 --- a/packages/flutter_mozilla_components/android/src/main/kotlin/eu/lensai/flutter_mozilla_components/components/Features.kt +++ b/packages/flutter_mozilla_components/android/src/main/kotlin/eu/lensai/flutter_mozilla_components/components/Features.kt @@ -1,12 +1,17 @@ package eu.lensai.flutter_mozilla_components.components +import eu.lensai.flutter_mozilla_components.feature.ReadabilityExtractFeature import eu.lensai.flutter_mozilla_components.feature.WebExtensionToolbarFeature import eu.lensai.flutter_mozilla_components.pigeons.GeckoAddonEvents +import eu.lensai.flutter_mozilla_components.pigeons.GeckoTabContentEvents import mozilla.components.browser.state.store.BrowserStore +import mozilla.components.concept.engine.Engine class Features( + private val engine: Engine, private val store: BrowserStore, - private val addonEvents: GeckoAddonEvents + private val addonEvents: GeckoAddonEvents, + private var tabContentEvents: GeckoTabContentEvents ) { val webExtensionToolbarFeature by lazy { WebExtensionToolbarFeature( @@ -14,4 +19,12 @@ class Features( addonEvents ) } + + val readabilityExtractFeature by lazy { + ReadabilityExtractFeature( + engine, + store, + tabContentEvents + ) + } } \ No newline at end of file diff --git a/packages/flutter_mozilla_components/android/src/main/kotlin/eu/lensai/flutter_mozilla_components/components/Search.kt b/packages/flutter_mozilla_components/android/src/main/kotlin/eu/lensai/flutter_mozilla_components/components/Search.kt new file mode 100644 index 00000000..f1426326 --- /dev/null +++ b/packages/flutter_mozilla_components/android/src/main/kotlin/eu/lensai/flutter_mozilla_components/components/Search.kt @@ -0,0 +1,36 @@ +package eu.lensai.flutter_mozilla_components.components + +import android.content.Context +import mozilla.components.feature.awesomebar.provider.ClipboardSuggestionProvider +import mozilla.components.feature.awesomebar.provider.HistoryStorageSuggestionProvider +import mozilla.components.feature.awesomebar.provider.SessionSuggestionProvider + +class Search( + private val context: Context, + private val core: Core, + private val useCases: UseCases, +) { + val sessionSuggestions by lazy { + SessionSuggestionProvider( + context.resources, + core.store, + useCases.tabsUseCases.selectTab, + ) + } + + val clipboardSuggestions by lazy { + ClipboardSuggestionProvider( + context, + useCases.sessionUseCases.loadUrl, + ) + } + + val historySuggestions by lazy { + HistoryStorageSuggestionProvider( + core.historyStorage, + useCases.sessionUseCases.loadUrl, + core.icons, + core.engine, + ) + } +} \ No newline at end of file diff --git a/packages/flutter_mozilla_components/android/src/main/kotlin/eu/lensai/flutter_mozilla_components/feature/ReadabilityExtractFeature.kt b/packages/flutter_mozilla_components/android/src/main/kotlin/eu/lensai/flutter_mozilla_components/feature/ReadabilityExtractFeature.kt new file mode 100644 index 00000000..a284aeab --- /dev/null +++ b/packages/flutter_mozilla_components/android/src/main/kotlin/eu/lensai/flutter_mozilla_components/feature/ReadabilityExtractFeature.kt @@ -0,0 +1,123 @@ +package eu.lensai.flutter_mozilla_components.feature + +import eu.lensai.flutter_mozilla_components.pigeons.GeckoTabContentEvents +import eu.lensai.flutter_mozilla_components.pigeons.TabContent +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.cancel +import kotlinx.coroutines.flow.map +import mozilla.components.browser.state.store.BrowserStore +import mozilla.components.concept.engine.Engine +import mozilla.components.concept.engine.webextension.MessageHandler +import mozilla.components.concept.engine.webextension.Port +import mozilla.components.lib.state.ext.flowScoped +import mozilla.components.support.base.feature.LifecycleAwareFeature +import mozilla.components.support.base.log.logger.Logger +import mozilla.components.support.ktx.android.org.json.tryGetString +import mozilla.components.support.ktx.kotlinx.coroutines.flow.filterChanged +import mozilla.components.support.ktx.kotlinx.coroutines.flow.ifAnyChanged +import mozilla.components.support.webextensions.WebExtensionController +import org.json.JSONObject + +class ReadabilityExtractFeature( + private var engine: Engine, + private var store: BrowserStore, + private var tabContentEvents: GeckoTabContentEvents +): LifecycleAwareFeature { + companion object { + private val logger = Logger("ReadabilityExtract") + + internal const val READER_EXTRACT_EXTENSION_ID = "readability-extract@movenext.me" + internal const val READER_EXTRACT_CONTENT_PORT = "mozacReaderExtract" + internal const val READER_EXTRACT_EXTENSION_URL = + "resource://android/assets/extensions/readability_extract/" + } + + private class ContentMessageHandler( + private var tabContentEvents: GeckoTabContentEvents, + private var tabId: String + ) : MessageHandler { + override fun onPortConnected(port: Port) { + logger.debug("Port connected: ${port.name()}") + } + + override fun onPortMessage(message: Any, port: Port) { + if (message is JSONObject) { + tabContentEvents.onContentUpdate( + System.currentTimeMillis(), + contentArg = TabContent( + tabId = tabId, + fullContentMarkdown = message.tryGetString("fullContentMarkdown"), + fullContentPlain = message.tryGetString("fullContentPlain"), + extractedContentMarkdown = message.tryGetString("extractedContentMarkdown"), + extractedContentPlain = message.tryGetString("extractedContentPlain") + ) + ) {} + } + } + } + + private var sessionScope: CoroutineScope? = null + private var historyScope: CoroutineScope? = null + + private var extensionController = WebExtensionController( + READER_EXTRACT_EXTENSION_ID, + READER_EXTRACT_EXTENSION_URL, + READER_EXTRACT_CONTENT_PORT, + ) + + override fun start() { + ensureExtensionInstalled() + } + + override fun stop() { + sessionScope?.cancel() + historyScope?.cancel() + } + + private fun ensureExtensionInstalled() { + extensionController.install( + engine, + onSuccess = { extension -> + sessionScope = store.flowScoped { flow -> + flow.map { it.tabs } + .filterChanged { it.engineState.engineSession } + .collect { state -> + val engineSession = state.engineState.engineSession ?: return@collect + + if (extension.hasContentMessageHandler(engineSession, READER_EXTRACT_CONTENT_PORT)) { + return@collect + } + + val handler = ContentMessageHandler(tabContentEvents, state.id) + extension.registerContentMessageHandler(engineSession, READER_EXTRACT_CONTENT_PORT, handler) + } + } + + historyScope = store.flowScoped { flow -> + flow.map { it.tabs } + .filterChanged { it.content.history } + .ifAnyChanged { arrayOf(it.content.history.currentIndex) } + .collect { state -> + val engineSession = state.engineState.engineSession ?: return@collect + + if(state.content.loading) { + return@collect + } + + if (extension.hasContentMessageHandler(engineSession, READER_EXTRACT_CONTENT_PORT)) { + if(extensionController.portConnected(engineSession)) { + extensionController.sendContentMessage( + JSONObject().put("action", "parseContent"), + engineSession + ) + } + } + } + } + }, + onError = { throwable -> + Logger.error("Could not install $READER_EXTRACT_EXTENSION_ID extension", throwable) + }, + ) + } +} \ No newline at end of file diff --git a/packages/flutter_mozilla_components/android/src/main/kotlin/eu/lensai/flutter_mozilla_components/feature/WebExtensionToolbarFeature.kt b/packages/flutter_mozilla_components/android/src/main/kotlin/eu/lensai/flutter_mozilla_components/feature/WebExtensionToolbarFeature.kt index 20cbde48..c26db0d1 100644 --- a/packages/flutter_mozilla_components/android/src/main/kotlin/eu/lensai/flutter_mozilla_components/feature/WebExtensionToolbarFeature.kt +++ b/packages/flutter_mozilla_components/android/src/main/kotlin/eu/lensai/flutter_mozilla_components/feature/WebExtensionToolbarFeature.kt @@ -119,7 +119,7 @@ class WebExtensionToolbarFeature( extension.browserAction?.let { browserAction -> addOrUpdateAction( extension = extension, - defaultAction = browserAction, + globalAction = browserAction, tabAction = tab?.extensionState?.get(extension.id)?.browserAction, ) } @@ -132,7 +132,7 @@ class WebExtensionToolbarFeature( if (pageAction.copyWithOverride(tabPageAction).enabled == true) { addOrUpdateAction( extension = extension, - defaultAction = pageAction, + globalAction = pageAction, tabAction = tabPageAction, isPageAction = true, ) @@ -156,62 +156,60 @@ class WebExtensionToolbarFeature( private fun addOrUpdateAction( extension: WebExtensionState, - defaultAction: Action, + globalAction: Action, tabAction: Action?, isPageAction: Boolean = false, ) { - var action = defaultAction + val actionMap = if (isPageAction) webExtensionPageActions else webExtensionBrowserActions + // Add the global page/browser action if it doesn't exist + var toolbarAction = actionMap.getOrPut(extension.id) { + CoroutineScope(iconJobDispatcher).launch { + try { + //TODO: make variable size + val icon = globalAction.loadIcon?.invoke(128) + icon?.let { + val imageBytes = icon.toWebPBytes() + runOnUiThread { + addonEvents.onUpdateWebExtensionIcon( + timestampArg = System.currentTimeMillis(), + extensionIdArg = extension.id, + actionTypeArg = if (isPageAction) WebExtensionActionType.PAGE else WebExtensionActionType.BROWSER, + iconArg = imageBytes + ) { } + } + } + } catch (throwable: Throwable) { + Log.log( + Log.Priority.ERROR, + "mozac-webextensions", + throwable, + "Failed to load browser action icon, falling back to default.", + ) + } + } + + globalAction + } // Apply tab-specific override of browser/page action tabAction?.let { - action = action.copyWithOverride(it) + toolbarAction = toolbarAction.copyWithOverride(it) } - CoroutineScope(iconJobDispatcher).launch { - try { - //TODO: make variable size - val icon = action.loadIcon?.invoke(128) - icon?.let { - val imageBytes = icon.toWebPBytes() - runOnUiThread { - addonEvents.onUpdateWebExtensionIcon( - timestampArg = System.currentTimeMillis(), - extensionIdArg = extension.id, - actionTypeArg = if (isPageAction) WebExtensionActionType.PAGE else WebExtensionActionType.BROWSER, - iconArg = imageBytes - ) { } - } - } - } catch (throwable: Throwable) { - Log.log( - Log.Priority.ERROR, - "mozac-webextensions", - throwable, - "Failed to load browser action icon, falling back to default.", - ) - } - } + val data = WebExtensionData( + extensionId = extension.id, + title = toolbarAction.title, + enabled = toolbarAction.enabled, + badgeText = toolbarAction.badgeText, + badgeTextColor = toolbarAction.badgeTextColor?.toLong(), + badgeBackgroundColor = toolbarAction.badgeBackgroundColor?.toLong(), + ) - val actionMap = if (isPageAction) webExtensionPageActions else webExtensionBrowserActions - // Add the global page/browser action if it doesn't exist - val toolbarAction = actionMap.getOrPut(extension.id) { - val toolbarAction = WebExtensionData( - extensionId = extension.id, - title = action.title, - enabled = action.enabled, - badgeText = action.badgeText, - badgeTextColor = action.badgeTextColor?.toLong(), - badgeBackgroundColor = action.badgeBackgroundColor?.toLong(), - ) - - addonEvents.onUpsertWebExtensionAction( - timestampArg = System.currentTimeMillis(), - extensionIdArg = extension.id, - actionTypeArg = if (isPageAction) WebExtensionActionType.PAGE else WebExtensionActionType.BROWSER, - extensionDataArg = toolbarAction - ) { } - - action - } + addonEvents.onUpsertWebExtensionAction( + timestampArg = System.currentTimeMillis(), + extensionIdArg = extension.id, + actionTypeArg = if (isPageAction) WebExtensionActionType.PAGE else WebExtensionActionType.BROWSER, + extensionDataArg = data + ) { } } } diff --git a/packages/flutter_mozilla_components/android/src/main/kotlin/eu/lensai/flutter_mozilla_components/integration/ReaderViewIntegration.kt b/packages/flutter_mozilla_components/android/src/main/kotlin/eu/lensai/flutter_mozilla_components/integration/ReaderViewIntegration.kt index cfeec442..ec6348c2 100644 --- a/packages/flutter_mozilla_components/android/src/main/kotlin/eu/lensai/flutter_mozilla_components/integration/ReaderViewIntegration.kt +++ b/packages/flutter_mozilla_components/android/src/main/kotlin/eu/lensai/flutter_mozilla_components/integration/ReaderViewIntegration.kt @@ -30,12 +30,12 @@ class ReaderViewIntegration( if (enabled) { feature.showReaderView() - readerViewController.appearanceButtonVisibility(true) { _ -> }; + readerViewController.appearanceButtonVisibility(System.currentTimeMillis(),true) { _ -> }; } else { feature.hideReaderView() feature.hideControls() - readerViewController.appearanceButtonVisibility(false) { _ -> }; + readerViewController.appearanceButtonVisibility(System.currentTimeMillis(),false) { _ -> }; } } diff --git a/packages/flutter_mozilla_components/android/src/main/kotlin/eu/lensai/flutter_mozilla_components/pigeons/Gecko.g.kt b/packages/flutter_mozilla_components/android/src/main/kotlin/eu/lensai/flutter_mozilla_components/pigeons/Gecko.g.kt index e2ba20d0..e51d06d6 100644 --- a/packages/flutter_mozilla_components/android/src/main/kotlin/eu/lensai/flutter_mozilla_components/pigeons/Gecko.g.kt +++ b/packages/flutter_mozilla_components/android/src/main/kotlin/eu/lensai/flutter_mozilla_components/pigeons/Gecko.g.kt @@ -154,6 +154,18 @@ enum class WebExtensionActionType(val raw: Int) { } } +enum class GeckoSuggestionType(val raw: Int) { + SESSION(0), + CLIPBOARD(1), + HISTORY(2); + + companion object { + fun ofRaw(raw: Int): GeckoSuggestionType? { + return values().firstOrNull { it.raw == raw } + } + } +} + /** * Translation options that map to the Gecko Translations Options. * @@ -968,6 +980,72 @@ data class WebExtensionData ( ) } } + +/** Generated class from Pigeon that represents data sent in messages. */ +data class GeckoSuggestion ( + val id: String, + val type: GeckoSuggestionType, + val score: Long, + val title: String? = null, + val description: String? = null, + val editSuggestion: String? = null, + val icon: ByteArray? = null +) + { + companion object { + fun fromList(pigeonVar_list: List): GeckoSuggestion { + val id = pigeonVar_list[0] as String + val type = pigeonVar_list[1] as GeckoSuggestionType + val score = pigeonVar_list[2] as Long + val title = pigeonVar_list[3] as String? + val description = pigeonVar_list[4] as String? + val editSuggestion = pigeonVar_list[5] as String? + val icon = pigeonVar_list[6] as ByteArray? + return GeckoSuggestion(id, type, score, title, description, editSuggestion, icon) + } + } + fun toList(): List { + return listOf( + id, + type, + score, + title, + description, + editSuggestion, + icon, + ) + } +} + +/** Generated class from Pigeon that represents data sent in messages. */ +data class TabContent ( + val tabId: String, + val fullContentMarkdown: String? = null, + val fullContentPlain: String? = null, + val extractedContentMarkdown: String? = null, + val extractedContentPlain: String? = null +) + { + companion object { + fun fromList(pigeonVar_list: List): TabContent { + val tabId = pigeonVar_list[0] as String + val fullContentMarkdown = pigeonVar_list[1] as String? + val fullContentPlain = pigeonVar_list[2] as String? + val extractedContentMarkdown = pigeonVar_list[3] as String? + val extractedContentPlain = pigeonVar_list[4] as String? + return TabContent(tabId, fullContentMarkdown, fullContentPlain, extractedContentMarkdown, extractedContentPlain) + } + } + fun toList(): List { + return listOf( + tabId, + fullContentMarkdown, + fullContentPlain, + extractedContentMarkdown, + extractedContentPlain, + ) + } +} private open class GeckoPigeonCodec : StandardMessageCodec() { override fun readValueOfType(type: Byte, buffer: ByteBuffer): Any? { return when (type) { @@ -1007,130 +1085,145 @@ private open class GeckoPigeonCodec : StandardMessageCodec() { } } 136.toByte() -> { - return (readValue(buffer) as? List)?.let { - TranslationOptions.fromList(it) + return (readValue(buffer) as Long?)?.let { + GeckoSuggestionType.ofRaw(it.toInt()) } } 137.toByte() -> { return (readValue(buffer) as? List)?.let { - ReaderState.fromList(it) + TranslationOptions.fromList(it) } } 138.toByte() -> { return (readValue(buffer) as? List)?.let { - LastMediaAccessState.fromList(it) + ReaderState.fromList(it) } } 139.toByte() -> { return (readValue(buffer) as? List)?.let { - HistoryMetadataKey.fromList(it) + LastMediaAccessState.fromList(it) } } 140.toByte() -> { return (readValue(buffer) as? List)?.let { - PackageCategoryValue.fromList(it) + HistoryMetadataKey.fromList(it) } } 141.toByte() -> { return (readValue(buffer) as? List)?.let { - ExternalPackage.fromList(it) + PackageCategoryValue.fromList(it) } } 142.toByte() -> { return (readValue(buffer) as? List)?.let { - LoadUrlFlagsValue.fromList(it) + ExternalPackage.fromList(it) } } 143.toByte() -> { return (readValue(buffer) as? List)?.let { - SourceValue.fromList(it) + LoadUrlFlagsValue.fromList(it) } } 144.toByte() -> { return (readValue(buffer) as? List)?.let { - TabState.fromList(it) + SourceValue.fromList(it) } } 145.toByte() -> { return (readValue(buffer) as? List)?.let { - RecoverableTab.fromList(it) + TabState.fromList(it) } } 146.toByte() -> { return (readValue(buffer) as? List)?.let { - RecoverableBrowserState.fromList(it) + RecoverableTab.fromList(it) } } 147.toByte() -> { return (readValue(buffer) as? List)?.let { - IconRequest.fromList(it) + RecoverableBrowserState.fromList(it) } } 148.toByte() -> { return (readValue(buffer) as? List)?.let { - ResourceSize.fromList(it) + IconRequest.fromList(it) } } 149.toByte() -> { return (readValue(buffer) as? List)?.let { - Resource.fromList(it) + ResourceSize.fromList(it) } } 150.toByte() -> { return (readValue(buffer) as? List)?.let { - IconResult.fromList(it) + Resource.fromList(it) } } 151.toByte() -> { return (readValue(buffer) as? List)?.let { - CookiePartitionKey.fromList(it) + IconResult.fromList(it) } } 152.toByte() -> { return (readValue(buffer) as? List)?.let { - Cookie.fromList(it) + CookiePartitionKey.fromList(it) } } 153.toByte() -> { return (readValue(buffer) as? List)?.let { - HistoryItem.fromList(it) + Cookie.fromList(it) } } 154.toByte() -> { return (readValue(buffer) as? List)?.let { - HistoryState.fromList(it) + HistoryItem.fromList(it) } } 155.toByte() -> { return (readValue(buffer) as? List)?.let { - ReaderableState.fromList(it) + HistoryState.fromList(it) } } 156.toByte() -> { return (readValue(buffer) as? List)?.let { - SecurityInfoState.fromList(it) + ReaderableState.fromList(it) } } 157.toByte() -> { return (readValue(buffer) as? List)?.let { - TabContentState.fromList(it) + SecurityInfoState.fromList(it) } } 158.toByte() -> { return (readValue(buffer) as? List)?.let { - FindResultState.fromList(it) + TabContentState.fromList(it) } } 159.toByte() -> { return (readValue(buffer) as? List)?.let { - CustomSelectionAction.fromList(it) + FindResultState.fromList(it) } } 160.toByte() -> { + return (readValue(buffer) as? List)?.let { + CustomSelectionAction.fromList(it) + } + } + 161.toByte() -> { return (readValue(buffer) as? List)?.let { WebExtensionData.fromList(it) } } + 162.toByte() -> { + return (readValue(buffer) as? List)?.let { + GeckoSuggestion.fromList(it) + } + } + 163.toByte() -> { + return (readValue(buffer) as? List)?.let { + TabContent.fromList(it) + } + } else -> super.readValueOfType(type, buffer) } } @@ -1164,106 +1257,118 @@ private open class GeckoPigeonCodec : StandardMessageCodec() { stream.write(135) writeValue(stream, value.raw) } - is TranslationOptions -> { + is GeckoSuggestionType -> { stream.write(136) - writeValue(stream, value.toList()) + writeValue(stream, value.raw) } - is ReaderState -> { + is TranslationOptions -> { stream.write(137) writeValue(stream, value.toList()) } - is LastMediaAccessState -> { + is ReaderState -> { stream.write(138) writeValue(stream, value.toList()) } - is HistoryMetadataKey -> { + is LastMediaAccessState -> { stream.write(139) writeValue(stream, value.toList()) } - is PackageCategoryValue -> { + is HistoryMetadataKey -> { stream.write(140) writeValue(stream, value.toList()) } - is ExternalPackage -> { + is PackageCategoryValue -> { stream.write(141) writeValue(stream, value.toList()) } - is LoadUrlFlagsValue -> { + is ExternalPackage -> { stream.write(142) writeValue(stream, value.toList()) } - is SourceValue -> { + is LoadUrlFlagsValue -> { stream.write(143) writeValue(stream, value.toList()) } - is TabState -> { + is SourceValue -> { stream.write(144) writeValue(stream, value.toList()) } - is RecoverableTab -> { + is TabState -> { stream.write(145) writeValue(stream, value.toList()) } - is RecoverableBrowserState -> { + is RecoverableTab -> { stream.write(146) writeValue(stream, value.toList()) } - is IconRequest -> { + is RecoverableBrowserState -> { stream.write(147) writeValue(stream, value.toList()) } - is ResourceSize -> { + is IconRequest -> { stream.write(148) writeValue(stream, value.toList()) } - is Resource -> { + is ResourceSize -> { stream.write(149) writeValue(stream, value.toList()) } - is IconResult -> { + is Resource -> { stream.write(150) writeValue(stream, value.toList()) } - is CookiePartitionKey -> { + is IconResult -> { stream.write(151) writeValue(stream, value.toList()) } - is Cookie -> { + is CookiePartitionKey -> { stream.write(152) writeValue(stream, value.toList()) } - is HistoryItem -> { + is Cookie -> { stream.write(153) writeValue(stream, value.toList()) } - is HistoryState -> { + is HistoryItem -> { stream.write(154) writeValue(stream, value.toList()) } - is ReaderableState -> { + is HistoryState -> { stream.write(155) writeValue(stream, value.toList()) } - is SecurityInfoState -> { + is ReaderableState -> { stream.write(156) writeValue(stream, value.toList()) } - is TabContentState -> { + is SecurityInfoState -> { stream.write(157) writeValue(stream, value.toList()) } - is FindResultState -> { + is TabContentState -> { stream.write(158) writeValue(stream, value.toList()) } - is CustomSelectionAction -> { + is FindResultState -> { stream.write(159) writeValue(stream, value.toList()) } - is WebExtensionData -> { + is CustomSelectionAction -> { stream.write(160) writeValue(stream, value.toList()) } + is WebExtensionData -> { + stream.write(161) + writeValue(stream, value.toList()) + } + is GeckoSuggestion -> { + stream.write(162) + writeValue(stream, value.toList()) + } + is TabContent -> { + stream.write(163) + writeValue(stream, value.toList()) + } else -> super.writeValue(stream, value) } } @@ -2553,12 +2658,12 @@ class ReaderViewController(private val binaryMessenger: BinaryMessenger, private GeckoPigeonCodec() } } - fun appearanceButtonVisibility(visibleArg: Boolean, callback: (Result) -> Unit) + fun appearanceButtonVisibility(timestampArg: Long, visibleArg: Boolean, callback: (Result) -> Unit) { val separatedMessageChannelSuffix = if (messageChannelSuffix.isNotEmpty()) ".$messageChannelSuffix" else "" val channelName = "dev.flutter.pigeon.flutter_mozilla_components.ReaderViewController.appearanceButtonVisibility$separatedMessageChannelSuffix" val channel = BasicMessageChannel(binaryMessenger, channelName, codec) - channel.send(listOf(visibleArg)) { + channel.send(listOf(timestampArg, visibleArg)) { if (it is List<*>) { if (it.size > 1) { callback(Result.failure(FlutterError(it[0] as String, it[1] as String, it[2] as String?))) @@ -2743,3 +2848,90 @@ class GeckoAddonEvents(private val binaryMessenger: BinaryMessenger, private val } } } +/** Generated interface from Pigeon that represents a handler of messages from Flutter. */ +interface GeckoSuggestionApi { + fun onInputChanged(text: String, providers: List) + + companion object { + /** The codec used by GeckoSuggestionApi. */ + val codec: MessageCodec by lazy { + GeckoPigeonCodec() + } + /** Sets up an instance of `GeckoSuggestionApi` to handle messages through the `binaryMessenger`. */ + @JvmOverloads + fun setUp(binaryMessenger: BinaryMessenger, api: GeckoSuggestionApi?, messageChannelSuffix: String = "") { + val separatedMessageChannelSuffix = if (messageChannelSuffix.isNotEmpty()) ".$messageChannelSuffix" else "" + run { + val channel = BasicMessageChannel(binaryMessenger, "dev.flutter.pigeon.flutter_mozilla_components.GeckoSuggestionApi.onInputChanged$separatedMessageChannelSuffix", codec) + if (api != null) { + channel.setMessageHandler { message, reply -> + val args = message as List + val textArg = args[0] as String + val providersArg = args[1] as List + val wrapped: List = try { + api.onInputChanged(textArg, providersArg) + listOf(null) + } catch (exception: Throwable) { + wrapError(exception) + } + reply.reply(wrapped) + } + } else { + channel.setMessageHandler(null) + } + } + } + } +} +/** Generated class from Pigeon that represents Flutter messages that can be called from Kotlin. */ +class GeckoSuggestionEvents(private val binaryMessenger: BinaryMessenger, private val messageChannelSuffix: String = "") { + companion object { + /** The codec used by GeckoSuggestionEvents. */ + val codec: MessageCodec by lazy { + GeckoPigeonCodec() + } + } + fun onSuggestionResult(timestampArg: Long, suggestionTypeArg: GeckoSuggestionType, suggestionsArg: List, callback: (Result) -> Unit) +{ + val separatedMessageChannelSuffix = if (messageChannelSuffix.isNotEmpty()) ".$messageChannelSuffix" else "" + val channelName = "dev.flutter.pigeon.flutter_mozilla_components.GeckoSuggestionEvents.onSuggestionResult$separatedMessageChannelSuffix" + val channel = BasicMessageChannel(binaryMessenger, channelName, codec) + channel.send(listOf(timestampArg, suggestionTypeArg, suggestionsArg)) { + if (it is List<*>) { + if (it.size > 1) { + callback(Result.failure(FlutterError(it[0] as String, it[1] as String, it[2] as String?))) + } else { + callback(Result.success(Unit)) + } + } else { + callback(Result.failure(createConnectionError(channelName))) + } + } + } +} +/** Generated class from Pigeon that represents Flutter messages that can be called from Kotlin. */ +class GeckoTabContentEvents(private val binaryMessenger: BinaryMessenger, private val messageChannelSuffix: String = "") { + companion object { + /** The codec used by GeckoTabContentEvents. */ + val codec: MessageCodec by lazy { + GeckoPigeonCodec() + } + } + fun onContentUpdate(timestampArg: Long, contentArg: TabContent, callback: (Result) -> Unit) +{ + val separatedMessageChannelSuffix = if (messageChannelSuffix.isNotEmpty()) ".$messageChannelSuffix" else "" + val channelName = "dev.flutter.pigeon.flutter_mozilla_components.GeckoTabContentEvents.onContentUpdate$separatedMessageChannelSuffix" + val channel = BasicMessageChannel(binaryMessenger, channelName, codec) + channel.send(listOf(timestampArg, contentArg)) { + if (it is List<*>) { + if (it.size > 1) { + callback(Result.failure(FlutterError(it[0] as String, it[1] as String, it[2] as String?))) + } else { + callback(Result.success(Unit)) + } + } else { + callback(Result.failure(createConnectionError(channelName))) + } + } + } +} diff --git a/packages/flutter_mozilla_components/android/src/main/kotlin/eu/lensai/flutter_mozilla_components/pip/PictureInPictureIntegration.kt b/packages/flutter_mozilla_components/android/src/main/kotlin/eu/lensai/flutter_mozilla_components/pip/PictureInPictureIntegration.kt new file mode 100644 index 00000000..e1ae5cc7 --- /dev/null +++ b/packages/flutter_mozilla_components/android/src/main/kotlin/eu/lensai/flutter_mozilla_components/pip/PictureInPictureIntegration.kt @@ -0,0 +1,50 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +package eu.lensai.flutter_mozilla_components.pip + +import android.app.Activity +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.cancel +import kotlinx.coroutines.flow.distinctUntilChangedBy +import kotlinx.coroutines.flow.mapNotNull +import mozilla.components.browser.state.selector.findTabOrCustomTabOrSelectedTab +import mozilla.components.browser.state.store.BrowserStore +import mozilla.components.feature.session.PictureInPictureFeature +import mozilla.components.lib.state.ext.flowScoped +import mozilla.components.support.base.feature.LifecycleAwareFeature + +class PictureInPictureIntegration( + private val store: BrowserStore, + activity: Activity, + private val customTabId: String?, + private val whiteList: List = listOf("youtube.com/tv"), +) : LifecycleAwareFeature { + private var scope: CoroutineScope? = null + private val pictureFeature = PictureInPictureFeature(store, activity) + private var whiteListed = false + + override fun start() { + scope = store.flowScoped { flow -> + flow.mapNotNull { state -> state.findTabOrCustomTabOrSelectedTab(customTabId) } + .distinctUntilChangedBy { it.content.url } + .collect { whiteListed = isWhitelisted(it.content.url) } + } + } + + override fun stop() { + scope?.cancel() + } + + fun onHomePressed() = if (whiteListed) { + pictureFeature.enterPipModeCompat() + } else { + pictureFeature.onHomePressed() + } + + private fun isWhitelisted(url: String): Boolean { + val exists = whiteList.firstOrNull { url.contains(it) } + return exists != null + } +} diff --git a/packages/flutter_mozilla_components/example/android/app/src/main/AndroidManifest.xml b/packages/flutter_mozilla_components/example/android/app/src/main/AndroidManifest.xml index 4e5b5361..67aab865 100644 --- a/packages/flutter_mozilla_components/example/android/app/src/main/AndroidManifest.xml +++ b/packages/flutter_mozilla_components/example/android/app/src/main/AndroidManifest.xml @@ -48,6 +48,7 @@ android:launchMode="singleTop" android:taskAffinity="" android:theme="@style/LaunchTheme" + android:supportsPictureInPicture="true" android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode" android:hardwareAccelerated="true" android:windowSoftInputMode="adjustResize"> diff --git a/app/js/.gitignore b/packages/flutter_mozilla_components/javascript/.gitignore similarity index 100% rename from app/js/.gitignore rename to packages/flutter_mozilla_components/javascript/.gitignore diff --git a/packages/flutter_mozilla_components/javascript/readability/dist/readability.min.js b/packages/flutter_mozilla_components/javascript/readability/dist/readability.min.js new file mode 100644 index 00000000..f88eec38 --- /dev/null +++ b/packages/flutter_mozilla_components/javascript/readability/dist/readability.min.js @@ -0,0 +1 @@ +!function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t():"function"==typeof define&&define.amd?define([],t):"object"==typeof exports?exports.ReadabilityBundle=t():e.ReadabilityBundle=t()}(this,(()=>(()=>{var e={804:e=>{var t={unlikelyCandidates:/-ad-|ai2html|banner|breadcrumbs|combx|comment|community|cover-wrap|disqus|extra|footer|gdpr|header|legends|menu|related|remark|replies|rss|shoutbox|sidebar|skyscraper|social|sponsor|supplemental|ad-break|agegate|pagination|pager|popup|yom-remote/i,okMaybeItsACandidate:/and|article|body|column|content|main|shadow/i};function i(e){return(!e.style||"none"!=e.style.display)&&!e.hasAttribute("hidden")&&(!e.hasAttribute("aria-hidden")||"true"!=e.getAttribute("aria-hidden")||e.className&&e.className.indexOf&&-1!==e.className.indexOf("fallback-image"))}e.exports=function(e,n={}){"function"==typeof n&&(n={visibilityChecker:n});var r={minScore:20,minContentLength:140,visibilityChecker:i};n=Object.assign(r,n);var a=e.querySelectorAll("p, pre, article"),s=e.querySelectorAll("div > br");if(s.length){var o=new Set(a);[].forEach.call(s,(function(e){o.add(e.parentNode)})),a=Array.from(o)}var l=0;return[].some.call(a,(function(e){if(!n.visibilityChecker(e))return!1;var i=e.className+" "+e.id;if(t.unlikelyCandidates.test(i)&&!t.okMaybeItsACandidate.test(i))return!1;if(e.matches("li p"))return!1;var r=e.textContent.trim().length;return!(rn.minScore}))}},238:e=>{function t(e,t){if(t&&t.documentElement)e=t,t=arguments[2];else if(!e||!e.documentElement)throw new Error("First argument to Readability constructor should be a document object.");if(t=t||{},this._doc=e,this._docJSDOMParser=this._doc.firstChild.__JSDOMParser__,this._articleTitle=null,this._articleByline=null,this._articleDir=null,this._articleSiteName=null,this._attempts=[],this._debug=!!t.debug,this._maxElemsToParse=t.maxElemsToParse||this.DEFAULT_MAX_ELEMS_TO_PARSE,this._nbTopCandidates=t.nbTopCandidates||this.DEFAULT_N_TOP_CANDIDATES,this._charThreshold=t.charThreshold||this.DEFAULT_CHAR_THRESHOLD,this._classesToPreserve=this.CLASSES_TO_PRESERVE.concat(t.classesToPreserve||[]),this._keepClasses=!!t.keepClasses,this._serializer=t.serializer||function(e){return e.innerHTML},this._disableJSONLD=!!t.disableJSONLD,this._allowedVideoRegex=t.allowedVideoRegex||this.REGEXPS.videos,this._flags=this.FLAG_STRIP_UNLIKELYS|this.FLAG_WEIGHT_CLASSES|this.FLAG_CLEAN_CONDITIONALLY,this._debug){let e=function(e){if(e.nodeType==e.TEXT_NODE)return`${e.nodeName} ("${e.textContent}")`;let t=Array.from(e.attributes||[],(function(e){return`${e.name}="${e.value}"`})).join(" ");return`<${e.localName} ${t}>`};this.log=function(){if("undefined"!=typeof console){let t=Array.from(arguments,(t=>t&&t.nodeType==this.ELEMENT_NODE?e(t):t));t.unshift("Reader: (Readability)"),console.log.apply(console,t)}else if("undefined"!=typeof dump){var t=Array.prototype.map.call(arguments,(function(t){return t&&t.nodeName?e(t):t})).join(" ");dump("Reader: (Readability) "+t+"\n")}}}else this.log=function(){}}t.prototype={FLAG_STRIP_UNLIKELYS:1,FLAG_WEIGHT_CLASSES:2,FLAG_CLEAN_CONDITIONALLY:4,ELEMENT_NODE:1,TEXT_NODE:3,DEFAULT_MAX_ELEMS_TO_PARSE:0,DEFAULT_N_TOP_CANDIDATES:5,DEFAULT_TAGS_TO_SCORE:"section,h2,h3,h4,h5,h6,p,td,pre".toUpperCase().split(","),DEFAULT_CHAR_THRESHOLD:500,REGEXPS:{unlikelyCandidates:/-ad-|ai2html|banner|breadcrumbs|combx|comment|community|cover-wrap|disqus|extra|footer|gdpr|header|legends|menu|related|remark|replies|rss|shoutbox|sidebar|skyscraper|social|sponsor|supplemental|ad-break|agegate|pagination|pager|popup|yom-remote/i,okMaybeItsACandidate:/and|article|body|column|content|main|shadow/i,positive:/article|body|content|entry|hentry|h-entry|main|page|pagination|post|text|blog|story/i,negative:/-ad-|hidden|^hid$| hid$| hid |^hid |banner|combx|comment|com-|contact|foot|footer|footnote|gdpr|masthead|media|meta|outbrain|promo|related|scroll|share|shoutbox|sidebar|skyscraper|sponsor|shopping|tags|tool|widget/i,extraneous:/print|archive|comment|discuss|e[\-]?mail|share|reply|all|login|sign|single|utility/i,byline:/byline|author|dateline|writtenby|p-author/i,replaceFonts:/<(\/?)font[^>]*>/gi,normalize:/\s{2,}/g,videos:/\/\/(www\.)?((dailymotion|youtube|youtube-nocookie|player\.vimeo|v\.qq)\.com|(archive|upload\.wikimedia)\.org|player\.twitch\.tv)/i,shareElements:/(\b|_)(share|sharedaddy)(\b|_)/i,nextLink:/(next|weiter|continue|>([^\|]|$)|»([^\|]|$))/i,prevLink:/(prev|earl|old|new|<|«)/i,tokenize:/\W+/g,whitespace:/^\s*$/,hasContent:/\S$/,hashUrl:/^#.+/,srcsetUrl:/(\S+)(\s+[\d.]+[xw])?(\s*(?:,|$))/g,b64DataUrl:/^data:\s*([^\s;,]+)\s*;\s*base64\s*,/i,commas:/\u002C|\u060C|\uFE50|\uFE10|\uFE11|\u2E41|\u2E34|\u2E32|\uFF0C/g,jsonLdArticleTypes:/^Article|AdvertiserContentArticle|NewsArticle|AnalysisNewsArticle|AskPublicNewsArticle|BackgroundNewsArticle|OpinionNewsArticle|ReportageNewsArticle|ReviewNewsArticle|Report|SatiricalArticle|ScholarlyArticle|MedicalScholarlyArticle|SocialMediaPosting|BlogPosting|LiveBlogPosting|DiscussionForumPosting|TechArticle|APIReference$/},UNLIKELY_ROLES:["menu","menubar","complementary","navigation","alert","alertdialog","dialog"],DIV_TO_P_ELEMS:new Set(["BLOCKQUOTE","DL","DIV","IMG","OL","P","PRE","TABLE","UL"]),ALTER_TO_DIV_EXCEPTIONS:["DIV","ARTICLE","SECTION","P"],PRESENTATIONAL_ATTRIBUTES:["align","background","bgcolor","border","cellpadding","cellspacing","frame","hspace","rules","style","valign","vspace"],DEPRECATED_SIZE_ATTRIBUTE_ELEMS:["TABLE","TH","TD","HR","PRE"],PHRASING_ELEMS:["ABBR","AUDIO","B","BDO","BR","BUTTON","CITE","CODE","DATA","DATALIST","DFN","EM","EMBED","I","IMG","INPUT","KBD","LABEL","MARK","MATH","METER","NOSCRIPT","OBJECT","OUTPUT","PROGRESS","Q","RUBY","SAMP","SCRIPT","SELECT","SMALL","SPAN","STRONG","SUB","SUP","TEXTAREA","TIME","VAR","WBR"],CLASSES_TO_PRESERVE:["page"],HTML_ESCAPE_MAP:{lt:"<",gt:">",amp:"&",quot:'"',apos:"'"},_postProcessContent:function(e){this._fixRelativeUris(e),this._simplifyNestedElements(e),this._keepClasses||this._cleanClasses(e)},_removeNodes:function(e,t){if(this._docJSDOMParser&&e._isLiveNodeList)throw new Error("Do not pass live node lists to _removeNodes");for(var i=e.length-1;i>=0;i--){var n=e[i],r=n.parentNode;r&&(t&&!t.call(this,n,i,e)||r.removeChild(n))}},_replaceNodeTags:function(e,t){if(this._docJSDOMParser&&e._isLiveNodeList)throw new Error("Do not pass live node lists to _replaceNodeTags");for(const i of e)this._setNodeTag(i,t)},_forEachNode:function(e,t){Array.prototype.forEach.call(e,t,this)},_findNode:function(e,t){return Array.prototype.find.call(e,t,this)},_someNode:function(e,t){return Array.prototype.some.call(e,t,this)},_everyNode:function(e,t){return Array.prototype.every.call(e,t,this)},_concatNodeLists:function(){var e=Array.prototype.slice,t=e.call(arguments).map((function(t){return e.call(t)}));return Array.prototype.concat.apply([],t)},_getAllNodesWithTag:function(e,t){return e.querySelectorAll?e.querySelectorAll(t.join(",")):[].concat.apply([],t.map((function(t){var i=e.getElementsByTagName(t);return Array.isArray(i)?i:Array.from(i)})))},_cleanClasses:function(e){var t=this._classesToPreserve,i=(e.getAttribute("class")||"").split(/\s+/).filter((function(e){return-1!=t.indexOf(e)})).join(" ");for(i?e.setAttribute("class",i):e.removeAttribute("class"),e=e.firstElementChild;e;e=e.nextElementSibling)this._cleanClasses(e)},_fixRelativeUris:function(e){var t=this._doc.baseURI,i=this._doc.documentURI;function n(e){if(t==i&&"#"==e.charAt(0))return e;try{return new URL(e,t).href}catch(e){}return e}var r=this._getAllNodesWithTag(e,["a"]);this._forEachNode(r,(function(e){var t=e.getAttribute("href");if(t)if(0===t.indexOf("javascript:"))if(1===e.childNodes.length&&e.childNodes[0].nodeType===this.TEXT_NODE){var i=this._doc.createTextNode(e.textContent);e.parentNode.replaceChild(i,e)}else{for(var r=this._doc.createElement("span");e.firstChild;)r.appendChild(e.firstChild);e.parentNode.replaceChild(r,e)}else e.setAttribute("href",n(t))}));var a=this._getAllNodesWithTag(e,["img","picture","figure","video","audio","source"]);this._forEachNode(a,(function(e){var t=e.getAttribute("src"),i=e.getAttribute("poster"),r=e.getAttribute("srcset");if(t&&e.setAttribute("src",n(t)),i&&e.setAttribute("poster",n(i)),r){var a=r.replace(this.REGEXPS.srcsetUrl,(function(e,t,i,r){return n(t)+(i||"")+r}));e.setAttribute("srcset",a)}}))},_simplifyNestedElements:function(e){for(var t=e;t;){if(t.parentNode&&["DIV","SECTION"].includes(t.tagName)&&(!t.id||!t.id.startsWith("readability"))){if(this._isElementWithoutContent(t)){t=this._removeAndGetNext(t);continue}if(this._hasSingleTagInsideElement(t,"DIV")||this._hasSingleTagInsideElement(t,"SECTION")){for(var i=t.children[0],n=0;n»] /.test(t))n=/ [\\\/>»] /.test(t),r(t=i.replace(/(.*)[\|\-\\\/>»] .*/gi,"$1"))<3&&(t=i.replace(/[^\|\-\\\/>»]*[\|\-\\\/>»](.*)/gi,"$1"));else if(-1!==t.indexOf(": ")){var a=this._concatNodeLists(e.getElementsByTagName("h1"),e.getElementsByTagName("h2")),s=t.trim();this._someNode(a,(function(e){return e.textContent.trim()===s}))||(r(t=i.substring(i.lastIndexOf(":")+1))<3?t=i.substring(i.indexOf(":")+1):r(i.substr(0,i.indexOf(":")))>5&&(t=i))}else if(t.length>150||t.length<15){var o=e.getElementsByTagName("h1");1===o.length&&(t=this._getInnerText(o[0]))}var l=r(t=t.trim().replace(this.REGEXPS.normalize," "));return l<=4&&(!n||l!=r(i.replace(/[\|\-\\\/>»]+/g,""))-1)&&(t=i),t},_prepDocument:function(){var e=this._doc;this._removeNodes(this._getAllNodesWithTag(e,["style"])),e.body&&this._replaceBrs(e.body),this._replaceNodeTags(this._getAllNodesWithTag(e,["font"]),"SPAN")},_nextNode:function(e){for(var t=e;t&&t.nodeType!=this.ELEMENT_NODE&&this.REGEXPS.whitespace.test(t.textContent);)t=t.nextSibling;return t},_replaceBrs:function(e){this._forEachNode(this._getAllNodesWithTag(e,["br"]),(function(e){for(var t=e.nextSibling,i=!1;(t=this._nextNode(t))&&"BR"==t.tagName;){i=!0;var n=t.nextSibling;t.parentNode.removeChild(t),t=n}if(i){var r=this._doc.createElement("p");for(e.parentNode.replaceChild(r,e),t=r.nextSibling;t;){if("BR"==t.tagName){var a=this._nextNode(t.nextSibling);if(a&&"BR"==a.tagName)break}if(!this._isPhrasingContent(t))break;var s=t.nextSibling;r.appendChild(t),t=s}for(;r.lastChild&&this._isWhitespace(r.lastChild);)r.removeChild(r.lastChild);"P"===r.parentNode.tagName&&this._setNodeTag(r.parentNode,"DIV")}}))},_setNodeTag:function(e,t){if(this.log("_setNodeTag",e,t),this._docJSDOMParser)return e.localName=t.toLowerCase(),e.tagName=t.toUpperCase(),e;for(var i=e.ownerDocument.createElement(t);e.firstChild;)i.appendChild(e.firstChild);e.parentNode.replaceChild(i,e),e.readability&&(i.readability=e.readability);for(var n=0;n!i.includes(e))).join(" ").length/n.join(" ").length:0},_checkByline:function(e,t){if(this._articleByline)return!1;if(void 0!==e.getAttribute)var i=e.getAttribute("rel"),n=e.getAttribute("itemprop");return!(!("author"===i||n&&-1!==n.indexOf("author")||this.REGEXPS.byline.test(t))||!this._isValidByline(e.textContent))&&(this._articleByline=e.textContent.trim(),!0)},_getNodeAncestors:function(e,t){t=t||0;for(var i=0,n=[];e.parentNode&&(n.push(e.parentNode),!t||++i!==t);)e=e.parentNode;return n},_grabArticle:function(e){this.log("**** grabArticle ****");var t=this._doc,i=null!==e;if(!(e=e||this._doc.body))return this.log("No body found in document. Abort."),null;for(var n=e.innerHTML;;){this.log("Starting grabArticle loop");var r=this._flagIsActive(this.FLAG_STRIP_UNLIKELYS),a=[],s=this._doc.documentElement;let V=!0;for(;s;){"HTML"===s.tagName&&(this._articleLang=s.getAttribute("lang"));var o=s.className+" "+s.id;if(this._isProbablyVisible(s))if("true"!=s.getAttribute("aria-modal")||"dialog"!=s.getAttribute("role"))if(this._checkByline(s,o))s=this._removeAndGetNext(s);else if(V&&this._headerDuplicatesTitle(s))this.log("Removing header: ",s.textContent.trim(),this._articleTitle.trim()),V=!1,s=this._removeAndGetNext(s);else{if(r){if(this.REGEXPS.unlikelyCandidates.test(o)&&!this.REGEXPS.okMaybeItsACandidate.test(o)&&!this._hasAncestorTag(s,"table")&&!this._hasAncestorTag(s,"code")&&"BODY"!==s.tagName&&"A"!==s.tagName){this.log("Removing unlikely candidate - "+o),s=this._removeAndGetNext(s);continue}if(this.UNLIKELY_ROLES.includes(s.getAttribute("role"))){this.log("Removing content with role "+s.getAttribute("role")+" - "+o),s=this._removeAndGetNext(s);continue}}if("DIV"!==s.tagName&&"SECTION"!==s.tagName&&"HEADER"!==s.tagName&&"H1"!==s.tagName&&"H2"!==s.tagName&&"H3"!==s.tagName&&"H4"!==s.tagName&&"H5"!==s.tagName&&"H6"!==s.tagName||!this._isElementWithoutContent(s)){if(-1!==this.DEFAULT_TAGS_TO_SCORE.indexOf(s.tagName)&&a.push(s),"DIV"===s.tagName){for(var l=null,c=s.firstChild;c;){var h=c.nextSibling;if(this._isPhrasingContent(c))null!==l?l.appendChild(c):this._isWhitespace(c)||(l=t.createElement("p"),s.replaceChild(l,c),l.appendChild(c));else if(null!==l){for(;l.lastChild&&this._isWhitespace(l.lastChild);)l.removeChild(l.lastChild);l=null}c=h}if(this._hasSingleTagInsideElement(s,"P")&&this._getLinkDensity(s)<.25){var d=s.children[0];s.parentNode.replaceChild(d,s),s=d,a.push(s)}else this._hasChildBlockElement(s)||(s=this._setNodeTag(s,"P"),a.push(s))}s=this._getNextNode(s)}else s=this._removeAndGetNext(s)}else s=this._removeAndGetNext(s);else this.log("Removing hidden node - "+o),s=this._removeAndGetNext(s)}var u=[];this._forEachNode(a,(function(e){if(e.parentNode&&void 0!==e.parentNode.tagName){var t=this._getInnerText(e);if(!(t.length<25)){var i=this._getNodeAncestors(e,5);if(0!==i.length){var n=0;n+=1,n+=t.split(this.REGEXPS.commas).length,n+=Math.min(Math.floor(t.length/100),3),this._forEachNode(i,(function(e,t){if(e.tagName&&e.parentNode&&void 0!==e.parentNode.tagName){if(void 0===e.readability&&(this._initializeNode(e),u.push(e)),0===t)var i=1;else i=1===t?2:3*t;e.readability.contentScore+=n/i}}))}}}}));for(var g=[],f=0,p=u.length;fb.readability.contentScore){g.splice(N,0,m),g.length>this._nbTopCandidates&&g.pop();break}}}var E,y=g[0]||null,T=!1;if(null===y||"BODY"===y.tagName){for(y=t.createElement("DIV"),T=!0;e.firstChild;)this.log("Moving child out:",e.firstChild),y.appendChild(e.firstChild);e.appendChild(y),this._initializeNode(y)}else if(y){for(var v=[],A=1;A=.75&&v.push(this._getNodeAncestors(g[A]));if(v.length>=3)for(E=y.parentNode;"BODY"!==E.tagName;){for(var S=0,C=0;C=3){y=E;break}E=E.parentNode}y.readability||this._initializeNode(y),E=y.parentNode;for(var L=y.readability.contentScore,x=L/3;"BODY"!==E.tagName;)if(E.readability){var O=E.readability.contentScore;if(OL){y=E;break}L=E.readability.contentScore,E=E.parentNode}else E=E.parentNode;for(E=y.parentNode;"BODY"!=E.tagName&&1==E.children.length;)E=(y=E).parentNode;y.readability||this._initializeNode(y)}var R=t.createElement("DIV");i&&(R.id="readability-content");for(var D=Math.max(10,.2*y.readability.contentScore),I=(E=y.parentNode).children,w=0,P=I.length;w=D)B=!0;else if("P"===k.nodeName){var H=this._getLinkDensity(k),G=this._getInnerText(k),U=G.length;(U>80&&H<.25||U<80&&U>0&&0===H&&-1!==G.search(/\.( |$)/))&&(B=!0)}}B&&(this.log("Appending node:",k),-1===this.ALTER_TO_DIV_EXCEPTIONS.indexOf(k.nodeName)&&(this.log("Altering sibling:",k,"to div."),k=this._setNodeTag(k,"DIV")),R.appendChild(k),I=E.children,w-=1,P-=1)}if(this._debug&&this.log("Article content pre-prep: "+R.innerHTML),this._prepArticle(R),this._debug&&this.log("Article content post-prep: "+R.innerHTML),T)y.id="readability-page-1",y.className="page";else{var $=t.createElement("DIV");for($.id="readability-page-1",$.className="page";R.firstChild;)$.appendChild(R.firstChild);R.appendChild($)}this._debug&&this.log("Article content after paging: "+R.innerHTML);var j=!0,F=this._getInnerText(R,!0).length;if(F0&&e.length<100)},_unescapeHtmlEntities:function(e){if(!e)return e;var t=this.HTML_ESCAPE_MAP;return e.replace(/&(quot|amp|apos|lt|gt);/g,(function(e,i){return t[i]})).replace(/&#(?:x([0-9a-z]{1,4})|([0-9]{1,4}));/gi,(function(e,t,i){var n=parseInt(t||i,t?16:10);return String.fromCharCode(n)}))},_getJSONLD:function(e){var t,i=this._getAllNodesWithTag(e,["script"]);return this._forEachNode(i,(function(e){if(!t&&"application/ld+json"===e.getAttribute("type"))try{var i=e.textContent.replace(/^\s*\s*$/g,""),n=JSON.parse(i);if(!n["@context"]||!n["@context"].match(/^https?\:\/\/schema\.org$/))return;if(!n["@type"]&&Array.isArray(n["@graph"])&&(n=n["@graph"].find((function(e){return(e["@type"]||"").match(this.REGEXPS.jsonLdArticleTypes)}))),!n||!n["@type"]||!n["@type"].match(this.REGEXPS.jsonLdArticleTypes))return;if(t={},"string"==typeof n.name&&"string"==typeof n.headline&&n.name!==n.headline){var r=this._getArticleTitle(),a=this._textSimilarity(n.name,r)>.75,s=this._textSimilarity(n.headline,r)>.75;t.title=s&&!a?n.headline:n.name}else"string"==typeof n.name?t.title=n.name.trim():"string"==typeof n.headline&&(t.title=n.headline.trim());return n.author&&("string"==typeof n.author.name?t.byline=n.author.name.trim():Array.isArray(n.author)&&n.author[0]&&"string"==typeof n.author[0].name&&(t.byline=n.author.filter((function(e){return e&&"string"==typeof e.name})).map((function(e){return e.name.trim()})).join(", "))),"string"==typeof n.description&&(t.excerpt=n.description.trim()),n.publisher&&"string"==typeof n.publisher.name&&(t.siteName=n.publisher.name.trim()),void("string"==typeof n.datePublished&&(t.datePublished=n.datePublished.trim()))}catch(e){this.log(e.message)}})),t||{}},_getArticleMetadata:function(e){var t={},i={},n=this._doc.getElementsByTagName("meta"),r=/\s*(article|dc|dcterm|og|twitter)\s*:\s*(author|creator|description|published_time|title|site_name)\s*/gi,a=/^\s*(?:(dc|dcterm|og|twitter|weibo:(article|webpage))\s*[\.:]\s*)?(author|creator|description|title|site_name)\s*$/i;return this._forEachNode(n,(function(e){var t=e.getAttribute("name"),n=e.getAttribute("property"),s=e.getAttribute("content");if(s){var o=null,l=null;n&&(o=n.match(r))&&(l=o[0].toLowerCase().replace(/\s/g,""),i[l]=s.trim()),!o&&t&&a.test(t)&&(l=t,s&&(l=l.toLowerCase().replace(/\s/g,"").replace(/\./g,":"),i[l]=s.trim()))}})),t.title=e.title||i["dc:title"]||i["dcterm:title"]||i["og:title"]||i["weibo:article:title"]||i["weibo:webpage:title"]||i.title||i["twitter:title"],t.title||(t.title=this._getArticleTitle()),t.byline=e.byline||i["dc:creator"]||i["dcterm:creator"]||i.author,t.excerpt=e.excerpt||i["dc:description"]||i["dcterm:description"]||i["og:description"]||i["weibo:article:description"]||i["weibo:webpage:description"]||i.description||i["twitter:description"],t.siteName=e.siteName||i["og:site_name"],t.publishedTime=e.datePublished||i["article:published_time"]||null,t.title=this._unescapeHtmlEntities(t.title),t.byline=this._unescapeHtmlEntities(t.byline),t.excerpt=this._unescapeHtmlEntities(t.excerpt),t.siteName=this._unescapeHtmlEntities(t.siteName),t.publishedTime=this._unescapeHtmlEntities(t.publishedTime),t},_isSingleImage:function(e){return"IMG"===e.tagName||1===e.children.length&&""===e.textContent.trim()&&this._isSingleImage(e.children[0])},_unwrapNoscriptImages:function(e){var t=Array.from(e.getElementsByTagName("img"));this._forEachNode(t,(function(e){for(var t=0;t0&&r>i)return!1;if(e.parentNode.tagName===t&&(!n||n(e.parentNode)))return!0;e=e.parentNode,r++}return!1},_getRowAndColumnCount:function(e){for(var t=0,i=0,n=e.getElementsByTagName("tr"),r=0;r0)n._readabilityDataTable=!0;else{if(["col","colgroup","tfoot","thead","th"].some((function(e){return!!n.getElementsByTagName(e)[0]})))this.log("Data table because found data-y descendant"),n._readabilityDataTable=!0;else if(n.getElementsByTagName("table")[0])n._readabilityDataTable=!1;else{var a=this._getRowAndColumnCount(n);a.rows>=10||a.columns>4?n._readabilityDataTable=!0:n._readabilityDataTable=a.rows*a.columns>10}}}else n._readabilityDataTable=!1;else n._readabilityDataTable=!1}},_fixLazyImages:function(e){this._forEachNode(this._getAllNodesWithTag(e,["img","picture","figure"]),(function(e){if(e.src&&this.REGEXPS.b64DataUrl.test(e.src)){if("image/svg+xml"===this.REGEXPS.b64DataUrl.exec(e.src)[1])return;for(var t=!1,i=0;in+=this._getInnerText(e,!0).length)),n/i},_cleanConditionally:function(e,t){this._flagIsActive(this.FLAG_CLEAN_CONDITIONALLY)&&this._removeNodes(this._getAllNodesWithTag(e,[t]),(function(e){var i=function(e){return e._readabilityDataTable},n="ul"===t||"ol"===t;if(!n){var r=0,a=this._getAllNodesWithTag(e,["ul","ol"]);this._forEachNode(a,(e=>r+=this._getInnerText(e).length)),n=r/this._getInnerText(e).length>.9}if("table"===t&&i(e))return!1;if(this._hasAncestorTag(e,"table",-1,i))return!1;if(this._hasAncestorTag(e,"code"))return!1;var s=this._getClassWeight(e);this.log("Cleaning Conditionally",e);if(s+0<0)return!0;if(this._getCharCount(e,",")<10){for(var o=e.getElementsByTagName("p").length,l=e.getElementsByTagName("img").length,c=e.getElementsByTagName("li").length-100,h=e.getElementsByTagName("input").length,d=this._getTextDensity(e,["h1","h2","h3","h4","h5","h6"]),u=0,g=this._getAllNodesWithTag(e,["object","embed","iframe"]),f=0;f1&&o/l<.5&&!this._hasAncestorTag(e,"figure")||!n&&c>o||h>Math.floor(o/3)||!n&&d<.9&&_<25&&(0===l||l>2)&&!this._hasAncestorTag(e,"figure")||!n&&s<25&&m>.2||s>=25&&m>.5||1===u&&_<75||u>1;if(n&&N){for(var b=0;b1)return N}if(l==e.getElementsByTagName("li").length)return!1}return N}return!1}))},_cleanMatchedNodes:function(e,t){for(var i=this._getNextNode(e,!0),n=this._getNextNode(e);n&&n!=i;)n=t.call(this,n,n.className+" "+n.id)?this._removeAndGetNext(n):this._getNextNode(n)},_cleanHeaders:function(e){let t=this._getAllNodesWithTag(e,["h1","h2"]);this._removeNodes(t,(function(e){let t=this._getClassWeight(e)<0;return t&&this.log("Removing header with low class weight:",e),t}))},_headerDuplicatesTitle:function(e){if("H1"!=e.tagName&&"H2"!=e.tagName)return!1;var t=this._getInnerText(e,!1);return this.log("Evaluating similarity of header:",t,this._articleTitle),this._textSimilarity(this._articleTitle,t)>.75},_flagIsActive:function(e){return(this._flags&e)>0},_removeFlag:function(e){this._flags=this._flags&~e},_isProbablyVisible:function(e){return(!e.style||"none"!=e.style.display)&&(!e.style||"hidden"!=e.style.visibility)&&!e.hasAttribute("hidden")&&(!e.hasAttribute("aria-hidden")||"true"!=e.getAttribute("aria-hidden")||e.className&&e.className.indexOf&&-1!==e.className.indexOf("fallback-image"))},parse:function(){if(this._maxElemsToParse>0){var e=this._doc.getElementsByTagName("*").length;if(e>this._maxElemsToParse)throw new Error("Aborting parsing document; "+e+" elements found")}this._unwrapNoscriptImages(this._doc);var t=this._disableJSONLD?{}:this._getJSONLD(this._doc);this._removeScripts(this._doc),this._prepDocument();var i=this._getArticleMetadata(t);this._articleTitle=i.title;var n=this._grabArticle();if(!n)return null;if(this.log("Grabbed: "+n.innerHTML),this._postProcessContent(n),!i.excerpt){var r=n.getElementsByTagName("p");r.length>0&&(i.excerpt=r[0].textContent.trim())}var a=n.textContent;return{title:this._articleTitle,byline:i.byline||this._articleByline,dir:this._articleDir,lang:this._articleLang,content:this._serializer(n),textContent:a,length:a.length,excerpt:i.excerpt,siteName:i.siteName||this._articleSiteName,publishedTime:i.publishedTime}}},e.exports=t},396:(e,t,i)=>{var n=i(238),r=i(804);e.exports={Readability:n,isProbablyReaderable:r}},481:e=>{e.exports=function(e,t){(t=t||{}).listUnicodeChar=!!t.hasOwnProperty("listUnicodeChar")&&t.listUnicodeChar,t.stripListLeaders=!t.hasOwnProperty("stripListLeaders")||t.stripListLeaders,t.gfm=!t.hasOwnProperty("gfm")||t.gfm,t.useImgAltText=!t.hasOwnProperty("useImgAltText")||t.useImgAltText,t.abbr=!!t.hasOwnProperty("abbr")&&t.abbr,t.replaceLinksWithURL=!!t.hasOwnProperty("replaceLinksWithURL")&&t.replaceLinksWithURL,t.htmlTagsToSkip=t.hasOwnProperty("htmlTagsToSkip")?t.htmlTagsToSkip:[],t.throwError=!!t.hasOwnProperty("throwError")&&t.throwError;var i=e||"";i=i.replace(/^(-\s*?|\*\s*?|_\s*?){3,}\s*/gm,"");try{t.stripListLeaders&&(i=t.listUnicodeChar?i.replace(/^([\s\t]*)([\*\-\+]|\d+\.)\s+/gm,t.listUnicodeChar+" $1"):i.replace(/^([\s\t]*)([\*\-\+]|\d+\.)\s+/gm,"$1")),t.gfm&&(i=i.replace(/\n={2,}/g,"\n").replace(/~{3}.*\n/g,"").replace(/~~/g,"").replace(/`{3}.*\n/g,"")),t.abbr&&(i=i.replace(/\*\[.*\]:.*\n/,"")),i=i.replace(/<[^>]*>/g,"");var n=new RegExp("<[^>]*>","g");if(t.htmlTagsToSkip.length>0){var r="(?!"+t.htmlTagsToSkip.join("|")+")";n=new RegExp("<"+r+"[^>]*>","ig")}i=i.replace(n,"").replace(/^[=\-]{2,}\s*$/g,"").replace(/\[\^.+?\](\: .*?$)?/g,"").replace(/\s{0,2}\[.*?\]: .*?$/g,"").replace(/\!\[(.*?)\][\[\(].*?[\]\)]/g,t.useImgAltText?"$1":"").replace(/\[([^\]]*?)\][\[\(].*?[\]\)]/g,t.replaceLinksWithURL?"$2":"$1").replace(/^(\n)?\s{0,3}>\s?/gm,"$1").replace(/^\s{1,2}\[(.*?)\]: (\S+)( ".*?")?\s*$/g,"").replace(/^(\n)?\s{0,}#{1,6}\s*( (.+))? +#+$|^(\n)?\s{0,}#{1,6}\s*( (.+))?$/gm,"$1$3$4$6").replace(/([\*]+)(\S)(.*?\S)??\1/g,"$2$3").replace(/(^|\W)([_]+)(\S)(.*?\S)??\2($|\W)/g,"$1$3$4$5").replace(/(`{3,})(.*?)\1/gm,"$2").replace(/`(.+?)`/g,"$1").replace(/~(.*?)~/g,"$1")}catch(i){if(t.throwError)throw i;return console.error("remove-markdown encountered error: %s",i),e}return i}}},t={};function i(n){var r=t[n];if(void 0!==r)return r.exports;var a=t[n]={exports:{}};return e[n](a,a.exports,i),a.exports}i.d=(e,t)=>{for(var n in t)i.o(t,n)&&!i.o(e,n)&&Object.defineProperty(e,n,{enumerable:!0,get:t[n]})},i.o=(e,t)=>Object.prototype.hasOwnProperty.call(e,t),i.r=e=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})};var n={};return(()=>{"use strict";i.r(n),i.d(n,{parseReaderable:()=>U});var e=i(396);function t(e,t){return Array(t+1).join(e)}var r=["ADDRESS","ARTICLE","ASIDE","AUDIO","BLOCKQUOTE","BODY","CANVAS","CENTER","DD","DIR","DIV","DL","DT","FIELDSET","FIGCAPTION","FIGURE","FOOTER","FORM","FRAMESET","H1","H2","H3","H4","H5","H6","HEADER","HGROUP","HR","HTML","ISINDEX","LI","MAIN","MENU","NAV","NOFRAMES","NOSCRIPT","OL","OUTPUT","P","PRE","SECTION","TABLE","TBODY","TD","TFOOT","TH","THEAD","TR","UL"];function a(e){return c(e,r)}var s=["AREA","BASE","BR","COL","COMMAND","EMBED","HR","IMG","INPUT","KEYGEN","LINK","META","PARAM","SOURCE","TRACK","WBR"];function o(e){return c(e,s)}var l=["A","TABLE","THEAD","TBODY","TFOOT","TH","TD","IFRAME","SCRIPT","AUDIO","VIDEO"];function c(e,t){return t.indexOf(e.nodeName)>=0}function h(e,t){return e.getElementsByTagName&&t.some((function(t){return e.getElementsByTagName(t).length}))}var d={};function u(e){return e?e.replace(/(\n+\s*)+/g,"\n"):""}function g(e){for(var t in this.options=e,this._keep=[],this._remove=[],this.blankRule={replacement:e.blankReplacement},this.keepReplacement=e.keepReplacement,this.defaultRule={replacement:e.defaultReplacement},this.array=[],e.rules)this.array.push(e.rules[t])}function f(e,t,i){for(var n=0;n-1)return!0}else{if("function"!=typeof n)throw new TypeError("`filter` needs to be a string, array, or function");if(n.call(e,t,i))return!0}}function m(e){var t=e.nextSibling||e.parentNode;return e.parentNode.removeChild(e),t}function _(e,t,i){return e&&e.parentNode===t||i(t)?t.nextSibling||t.parentNode:t.firstChild||t.nextSibling||t.parentNode}d.paragraph={filter:"p",replacement:function(e){return"\n\n"+e+"\n\n"}},d.lineBreak={filter:"br",replacement:function(e,t,i){return i.br+"\n"}},d.heading={filter:["h1","h2","h3","h4","h5","h6"],replacement:function(e,i,n){var r=Number(i.nodeName.charAt(1));return"setext"===n.headingStyle&&r<3?"\n\n"+e+"\n"+t(1===r?"=":"-",e.length)+"\n\n":"\n\n"+t("#",r)+" "+e+"\n\n"}},d.blockquote={filter:"blockquote",replacement:function(e){return"\n\n"+(e=(e=e.replace(/^\n+|\n+$/g,"")).replace(/^/gm,"> "))+"\n\n"}},d.list={filter:["ul","ol"],replacement:function(e,t){var i=t.parentNode;return"LI"===i.nodeName&&i.lastElementChild===t?"\n"+e:"\n\n"+e+"\n\n"}},d.listItem={filter:"li",replacement:function(e,t,i){e=e.replace(/^\n+/,"").replace(/\n+$/,"\n").replace(/\n/gm,"\n ");var n=i.bulletListMarker+" ",r=t.parentNode;if("OL"===r.nodeName){var a=r.getAttribute("start"),s=Array.prototype.indexOf.call(r.children,t);n=(a?Number(a)+s:s+1)+". "}return n+e+(t.nextSibling&&!/\n$/.test(e)?"\n":"")}},d.indentedCodeBlock={filter:function(e,t){return"indented"===t.codeBlockStyle&&"PRE"===e.nodeName&&e.firstChild&&"CODE"===e.firstChild.nodeName},replacement:function(e,t,i){return"\n\n "+t.firstChild.textContent.replace(/\n/g,"\n ")+"\n\n"}},d.fencedCodeBlock={filter:function(e,t){return"fenced"===t.codeBlockStyle&&"PRE"===e.nodeName&&e.firstChild&&"CODE"===e.firstChild.nodeName},replacement:function(e,i,n){for(var r,a=((i.firstChild.getAttribute("class")||"").match(/language-(\S+)/)||[null,""])[1],s=i.firstChild.textContent,o=n.fence.charAt(0),l=3,c=new RegExp("^"+o+"{3,}","gm");r=c.exec(s);)r[0].length>=l&&(l=r[0].length+1);var h=t(o,l);return"\n\n"+h+a+"\n"+s.replace(/\n$/,"")+"\n"+h+"\n\n"}},d.horizontalRule={filter:"hr",replacement:function(e,t,i){return"\n\n"+i.hr+"\n\n"}},d.inlineLink={filter:function(e,t){return"inlined"===t.linkStyle&&"A"===e.nodeName&&e.getAttribute("href")},replacement:function(e,t){var i=t.getAttribute("href");i&&(i=i.replace(/([()])/g,"\\$1"));var n=u(t.getAttribute("title"));return n&&(n=' "'+n.replace(/"/g,'\\"')+'"'),"["+e+"]("+i+n+")"}},d.referenceLink={filter:function(e,t){return"referenced"===t.linkStyle&&"A"===e.nodeName&&e.getAttribute("href")},replacement:function(e,t,i){var n,r,a=t.getAttribute("href"),s=u(t.getAttribute("title"));switch(s&&(s=' "'+s+'"'),i.linkReferenceStyle){case"collapsed":n="["+e+"][]",r="["+e+"]: "+a+s;break;case"shortcut":n="["+e+"]",r="["+e+"]: "+a+s;break;default:var o=this.references.length+1;n="["+e+"]["+o+"]",r="["+o+"]: "+a+s}return this.references.push(r),n},references:[],append:function(e){var t="";return this.references.length&&(t="\n\n"+this.references.join("\n")+"\n\n",this.references=[]),t}},d.emphasis={filter:["em","i"],replacement:function(e,t,i){return e.trim()?i.emDelimiter+e+i.emDelimiter:""}},d.strong={filter:["strong","b"],replacement:function(e,t,i){return e.trim()?i.strongDelimiter+e+i.strongDelimiter:""}},d.code={filter:function(e){var t=e.previousSibling||e.nextSibling,i="PRE"===e.parentNode.nodeName&&!t;return"CODE"===e.nodeName&&!i},replacement:function(e){if(!e)return"";e=e.replace(/\r?\n|\r/g," ");for(var t=/^`|^ .*?[^ ].* $|`$/.test(e)?" ":"",i="`",n=e.match(/`+/gm)||[];-1!==n.indexOf(i);)i+="`";return i+t+e+t+i}},d.image={filter:"img",replacement:function(e,t){var i=u(t.getAttribute("alt")),n=t.getAttribute("src")||"",r=u(t.getAttribute("title"));return n?"!["+i+"]("+n+(r?' "'+r+'"':"")+")":""}},g.prototype={add:function(e,t){this.array.unshift(t)},keep:function(e){this._keep.unshift({filter:e,replacement:this.keepReplacement})},remove:function(e){this._remove.unshift({filter:e,replacement:function(){return""}})},forNode:function(e){return e.isBlank?this.blankRule:(t=f(this.array,e,this.options))||(t=f(this._keep,e,this.options))||(t=f(this._remove,e,this.options))?t:this.defaultRule;var t},forEach:function(e){for(var t=0;t'+e+"","text/html").getElementById("turndown-root"):i=e.cloneNode(!0);return function(e){var t=e.element,i=e.isBlock,n=e.isVoid,r=e.isPre||function(e){return"PRE"===e.nodeName};if(t.firstChild&&!r(t)){for(var a=null,s=!1,o=null,l=_(o,t,r);l!==t;){if(3===l.nodeType||4===l.nodeType){var c=l.data.replace(/[ \r\n\t]+/g," ");if(a&&!/ $/.test(a.data)||s||" "!==c[0]||(c=c.substr(1)),!c){l=m(l);continue}l.data=c,a=l}else{if(1!==l.nodeType){l=m(l);continue}i(l)||"BR"===l.nodeName?(a&&(a.data=a.data.replace(/ $/,"")),a=null,s=!1):n(l)||r(l)?(a=null,s=!0):a&&(s=!1)}var h=_(o,l,r);o=l,l=h}a&&(a.data=a.data.replace(/ $/,""),a.data||m(a))}}({element:i,isBlock:a,isVoid:o,isPre:t.preformattedCode?v:null}),i}function v(e){return"PRE"===e.nodeName||"CODE"===e.nodeName}function A(e,t){return e.isBlock=a(e),e.isCode="CODE"===e.nodeName||e.parentNode.isCode,e.isBlank=function(e){return!o(e)&&!function(e){return c(e,l)}(e)&&/^\s*$/i.test(e.textContent)&&!function(e){return h(e,s)}(e)&&!function(e){return h(e,l)}(e)}(e),e.flankingWhitespace=function(e,t){if(e.isBlock||t.preformattedCode&&e.isCode)return{leading:"",trailing:""};var i=(n=e.textContent,r=n.match(/^(([ \t\r\n]*)(\s*))(?:(?=\S)[\s\S]*\S)?((\s*?)([ \t\r\n]*))$/),{leading:r[1],leadingAscii:r[2],leadingNonAscii:r[3],trailing:r[4],trailingNonAscii:r[5],trailingAscii:r[6]});var n,r;i.leadingAscii&&S("left",e,t)&&(i.leading=i.leadingNonAscii);i.trailingAscii&&S("right",e,t)&&(i.trailing=i.trailingNonAscii);return{leading:i.leading,trailing:i.trailing}}(e,t),e}function S(e,t,i){var n,r,s;return"left"===e?(n=t.previousSibling,r=/ $/):(n=t.nextSibling,r=/^ /),n&&(3===n.nodeType?s=r.test(n.nodeValue):i.preformattedCode&&"CODE"===n.nodeName?s=!1:1!==n.nodeType||a(n)||(s=r.test(n.textContent))),s}var C=Array.prototype.reduce,L=[[/\\/g,"\\\\"],[/\*/g,"\\*"],[/^-/g,"\\-"],[/^\+ /g,"\\+ "],[/^(=+)/g,"\\$1"],[/^(#{1,6}) /g,"\\$1 "],[/`/g,"\\`"],[/^~~~/g,"\\~~~"],[/\[/g,"\\["],[/\]/g,"\\]"],[/^>/g,"\\>"],[/_/g,"\\_"],[/^(\d+)\. /g,"$1\\. "]];function x(e){if(!(this instanceof x))return new x(e);var t={rules:d,headingStyle:"setext",hr:"* * *",bulletListMarker:"*",codeBlockStyle:"indented",fence:"```",emDelimiter:"_",strongDelimiter:"**",linkStyle:"inlined",linkReferenceStyle:"full",br:" ",preformattedCode:!1,blankReplacement:function(e,t){return t.isBlock?"\n\n":""},keepReplacement:function(e,t){return t.isBlock?"\n\n"+t.outerHTML+"\n\n":t.outerHTML},defaultReplacement:function(e,t){return t.isBlock?"\n\n"+e+"\n\n":e}};this.options=function(e){for(var t=1;t0&&"\n"===e[t-1];)t--;return e.substring(0,t)}(e),n=t.replace(/^\n*/,""),r=Math.max(e.length-i.length,t.length-n.length);return i+"\n\n".substring(0,r)+n}x.prototype={turndown:function(e){if(!function(e){return null!=e&&("string"==typeof e||e.nodeType&&(1===e.nodeType||9===e.nodeType||11===e.nodeType))}(e))throw new TypeError(e+" is not a string, or an element/document/fragment node.");if(""===e)return"";var t=O.call(this,new T(e,this.options));return R.call(this,t)},use:function(e){if(Array.isArray(e))for(var t=0;t - readability [9 Jul 2024 at 10:42] + readability [6 Nov 2024 at 17:38] diff --git a/app/js/readability/dist/stats.json b/packages/flutter_mozilla_components/javascript/readability/dist/stats.json similarity index 51% rename from app/js/readability/dist/stats.json rename to packages/flutter_mozilla_components/javascript/readability/dist/stats.json index 3feaf288..691c5f88 100644 --- a/app/js/readability/dist/stats.json +++ b/packages/flutter_mozilla_components/javascript/readability/dist/stats.json @@ -1,10 +1,10 @@ { - "hash": "8d23fa454595d8aa7895", - "version": "5.92.1", - "time": 1715, - "builtAt": 1720514525488, + "hash": "e972bd2742adaf1dd89a", + "version": "5.96.1", + "time": 1769, + "builtAt": 1730911086642, "publicPath": "auto", - "outputPath": "/home/fafre/Repos/kagi_bang_bang/app/js/readability/dist", + "outputPath": "/home/fafre/Repos/kagi_bang_bang/packages/flutter_mozilla_components/javascript/readability/dist", "assetsByChunkName": { "main": [ "readability.min.js" @@ -14,17 +14,14 @@ { "type": "asset", "name": "readability.min.js", - "size": 55954, + "size": 48006, "emitted": true, "comparedForEmit": false, "cached": false, "info": { "javascriptModule": false, "minimized": true, - "related": { - "gzipped": "readability.min.js.gz" - }, - "size": 55954 + "size": 48006 }, "chunkNames": [ "main" @@ -32,29 +29,7 @@ "chunkIdHints": [], "auxiliaryChunkNames": [], "auxiliaryChunkIdHints": [], - "filteredRelated": 0, - "related": [ - { - "type": "gzipped", - "name": "readability.min.js.gz", - "size": 18947, - "emitted": true, - "comparedForEmit": false, - "cached": false, - "info": { - "compressed": true, - "size": 18947 - }, - "chunkNames": [], - "chunkIdHints": [], - "auxiliaryChunkNames": [], - "auxiliaryChunkIdHints": [], - "related": {}, - "chunks": [], - "auxiliaryChunks": [], - "isOverSizeLimit": false - } - ], + "related": [], "chunks": [ 792 ], @@ -68,10 +43,10 @@ "initial": true, "entry": true, "recorded": false, - "size": 157907, + "size": 120760, "sizes": { - "javascript": 156970, - "runtime": 937 + "javascript": 120090, + "runtime": 670 }, "names": [ "main" @@ -84,7 +59,7 @@ "readability.min.js" ], "auxiliaryFiles": [], - "hash": "55ea9d503085bb5260ad", + "hash": "e213d94771310f354882", "childrenByOrder": {}, "id": 792, "siblings": [], @@ -103,9 +78,9 @@ "codeGenerated": true, "buildTimeExecuted": false, "cached": false, - "identifier": "/home/fafre/Repos/kagi_bang_bang/app/js/readability/node_modules/@mozilla/readability/Readability-readerable.js", + "identifier": "/home/fafre/Repos/kagi_bang_bang/packages/flutter_mozilla_components/javascript/readability/node_modules/@mozilla/readability/Readability-readerable.js", "name": "./node_modules/@mozilla/readability/Readability-readerable.js", - "nameForCondition": "/home/fafre/Repos/kagi_bang_bang/app/js/readability/node_modules/@mozilla/readability/Readability-readerable.js", + "nameForCondition": "/home/fafre/Repos/kagi_bang_bang/packages/flutter_mozilla_components/javascript/readability/node_modules/@mozilla/readability/Readability-readerable.js", "index": 3, "preOrderIndex": 3, "index2": 1, @@ -114,16 +89,16 @@ "optional": false, "orphan": false, "dependent": true, - "issuer": "/home/fafre/Repos/kagi_bang_bang/app/js/readability/node_modules/@mozilla/readability/index.js", + "issuer": "/home/fafre/Repos/kagi_bang_bang/packages/flutter_mozilla_components/javascript/readability/node_modules/@mozilla/readability/index.js", "issuerName": "./node_modules/@mozilla/readability/index.js", "issuerPath": [ { - "identifier": "/home/fafre/Repos/kagi_bang_bang/app/js/readability/node_modules/babel-loader/lib/index.js??ruleSet[1].rules[0].use!/home/fafre/Repos/kagi_bang_bang/app/js/readability/src/index.js", + "identifier": "/home/fafre/Repos/kagi_bang_bang/packages/flutter_mozilla_components/javascript/readability/node_modules/babel-loader/lib/index.js??ruleSet[1].rules[0].use!/home/fafre/Repos/kagi_bang_bang/packages/flutter_mozilla_components/javascript/readability/src/index.js", "name": "./src/index.js", - "id": 954 + "id": null }, { - "identifier": "/home/fafre/Repos/kagi_bang_bang/app/js/readability/node_modules/@mozilla/readability/index.js", + "identifier": "/home/fafre/Repos/kagi_bang_bang/packages/flutter_mozilla_components/javascript/readability/node_modules/@mozilla/readability/index.js", "name": "./node_modules/@mozilla/readability/index.js", "id": 396 } @@ -139,10 +114,10 @@ "assets": [], "reasons": [ { - "moduleIdentifier": "/home/fafre/Repos/kagi_bang_bang/app/js/readability/node_modules/@mozilla/readability/Readability-readerable.js", + "moduleIdentifier": "/home/fafre/Repos/kagi_bang_bang/packages/flutter_mozilla_components/javascript/readability/node_modules/@mozilla/readability/Readability-readerable.js", "module": "./node_modules/@mozilla/readability/Readability-readerable.js", "moduleName": "./node_modules/@mozilla/readability/Readability-readerable.js", - "resolvedModuleIdentifier": "/home/fafre/Repos/kagi_bang_bang/app/js/readability/node_modules/@mozilla/readability/Readability-readerable.js", + "resolvedModuleIdentifier": "/home/fafre/Repos/kagi_bang_bang/packages/flutter_mozilla_components/javascript/readability/node_modules/@mozilla/readability/Readability-readerable.js", "resolvedModule": "./node_modules/@mozilla/readability/Readability-readerable.js", "type": "cjs self exports reference", "active": true, @@ -153,10 +128,10 @@ "resolvedModuleId": 804 }, { - "moduleIdentifier": "/home/fafre/Repos/kagi_bang_bang/app/js/readability/node_modules/@mozilla/readability/index.js", + "moduleIdentifier": "/home/fafre/Repos/kagi_bang_bang/packages/flutter_mozilla_components/javascript/readability/node_modules/@mozilla/readability/index.js", "module": "./node_modules/@mozilla/readability/index.js", "moduleName": "./node_modules/@mozilla/readability/index.js", - "resolvedModuleIdentifier": "/home/fafre/Repos/kagi_bang_bang/app/js/readability/node_modules/@mozilla/readability/index.js", + "resolvedModuleIdentifier": "/home/fafre/Repos/kagi_bang_bang/packages/flutter_mozilla_components/javascript/readability/node_modules/@mozilla/readability/index.js", "resolvedModule": "./node_modules/@mozilla/readability/index.js", "type": "cjs require", "active": true, @@ -188,9 +163,9 @@ "codeGenerated": true, "buildTimeExecuted": false, "cached": false, - "identifier": "/home/fafre/Repos/kagi_bang_bang/app/js/readability/node_modules/@mozilla/readability/Readability.js", + "identifier": "/home/fafre/Repos/kagi_bang_bang/packages/flutter_mozilla_components/javascript/readability/node_modules/@mozilla/readability/Readability.js", "name": "./node_modules/@mozilla/readability/Readability.js", - "nameForCondition": "/home/fafre/Repos/kagi_bang_bang/app/js/readability/node_modules/@mozilla/readability/Readability.js", + "nameForCondition": "/home/fafre/Repos/kagi_bang_bang/packages/flutter_mozilla_components/javascript/readability/node_modules/@mozilla/readability/Readability.js", "index": 2, "preOrderIndex": 2, "index2": 0, @@ -199,16 +174,16 @@ "optional": false, "orphan": false, "dependent": true, - "issuer": "/home/fafre/Repos/kagi_bang_bang/app/js/readability/node_modules/@mozilla/readability/index.js", + "issuer": "/home/fafre/Repos/kagi_bang_bang/packages/flutter_mozilla_components/javascript/readability/node_modules/@mozilla/readability/index.js", "issuerName": "./node_modules/@mozilla/readability/index.js", "issuerPath": [ { - "identifier": "/home/fafre/Repos/kagi_bang_bang/app/js/readability/node_modules/babel-loader/lib/index.js??ruleSet[1].rules[0].use!/home/fafre/Repos/kagi_bang_bang/app/js/readability/src/index.js", + "identifier": "/home/fafre/Repos/kagi_bang_bang/packages/flutter_mozilla_components/javascript/readability/node_modules/babel-loader/lib/index.js??ruleSet[1].rules[0].use!/home/fafre/Repos/kagi_bang_bang/packages/flutter_mozilla_components/javascript/readability/src/index.js", "name": "./src/index.js", - "id": 954 + "id": null }, { - "identifier": "/home/fafre/Repos/kagi_bang_bang/app/js/readability/node_modules/@mozilla/readability/index.js", + "identifier": "/home/fafre/Repos/kagi_bang_bang/packages/flutter_mozilla_components/javascript/readability/node_modules/@mozilla/readability/index.js", "name": "./node_modules/@mozilla/readability/index.js", "id": 396 } @@ -224,10 +199,10 @@ "assets": [], "reasons": [ { - "moduleIdentifier": "/home/fafre/Repos/kagi_bang_bang/app/js/readability/node_modules/@mozilla/readability/Readability.js", + "moduleIdentifier": "/home/fafre/Repos/kagi_bang_bang/packages/flutter_mozilla_components/javascript/readability/node_modules/@mozilla/readability/Readability.js", "module": "./node_modules/@mozilla/readability/Readability.js", "moduleName": "./node_modules/@mozilla/readability/Readability.js", - "resolvedModuleIdentifier": "/home/fafre/Repos/kagi_bang_bang/app/js/readability/node_modules/@mozilla/readability/Readability.js", + "resolvedModuleIdentifier": "/home/fafre/Repos/kagi_bang_bang/packages/flutter_mozilla_components/javascript/readability/node_modules/@mozilla/readability/Readability.js", "resolvedModule": "./node_modules/@mozilla/readability/Readability.js", "type": "cjs self exports reference", "active": true, @@ -238,10 +213,10 @@ "resolvedModuleId": 238 }, { - "moduleIdentifier": "/home/fafre/Repos/kagi_bang_bang/app/js/readability/node_modules/@mozilla/readability/index.js", + "moduleIdentifier": "/home/fafre/Repos/kagi_bang_bang/packages/flutter_mozilla_components/javascript/readability/node_modules/@mozilla/readability/index.js", "module": "./node_modules/@mozilla/readability/index.js", "moduleName": "./node_modules/@mozilla/readability/index.js", - "resolvedModuleIdentifier": "/home/fafre/Repos/kagi_bang_bang/app/js/readability/node_modules/@mozilla/readability/index.js", + "resolvedModuleIdentifier": "/home/fafre/Repos/kagi_bang_bang/packages/flutter_mozilla_components/javascript/readability/node_modules/@mozilla/readability/index.js", "resolvedModule": "./node_modules/@mozilla/readability/index.js", "type": "cjs require", "active": true, @@ -273,9 +248,9 @@ "codeGenerated": true, "buildTimeExecuted": false, "cached": false, - "identifier": "/home/fafre/Repos/kagi_bang_bang/app/js/readability/node_modules/@mozilla/readability/index.js", + "identifier": "/home/fafre/Repos/kagi_bang_bang/packages/flutter_mozilla_components/javascript/readability/node_modules/@mozilla/readability/index.js", "name": "./node_modules/@mozilla/readability/index.js", - "nameForCondition": "/home/fafre/Repos/kagi_bang_bang/app/js/readability/node_modules/@mozilla/readability/index.js", + "nameForCondition": "/home/fafre/Repos/kagi_bang_bang/packages/flutter_mozilla_components/javascript/readability/node_modules/@mozilla/readability/index.js", "index": 1, "preOrderIndex": 1, "index2": 2, @@ -284,30 +259,30 @@ "optional": false, "orphan": false, "dependent": true, - "issuer": "/home/fafre/Repos/kagi_bang_bang/app/js/readability/node_modules/babel-loader/lib/index.js??ruleSet[1].rules[0].use!/home/fafre/Repos/kagi_bang_bang/app/js/readability/src/index.js", + "issuer": "/home/fafre/Repos/kagi_bang_bang/packages/flutter_mozilla_components/javascript/readability/node_modules/babel-loader/lib/index.js??ruleSet[1].rules[0].use!/home/fafre/Repos/kagi_bang_bang/packages/flutter_mozilla_components/javascript/readability/src/index.js", "issuerName": "./src/index.js", "issuerPath": [ { - "identifier": "/home/fafre/Repos/kagi_bang_bang/app/js/readability/node_modules/babel-loader/lib/index.js??ruleSet[1].rules[0].use!/home/fafre/Repos/kagi_bang_bang/app/js/readability/src/index.js", + "identifier": "/home/fafre/Repos/kagi_bang_bang/packages/flutter_mozilla_components/javascript/readability/node_modules/babel-loader/lib/index.js??ruleSet[1].rules[0].use!/home/fafre/Repos/kagi_bang_bang/packages/flutter_mozilla_components/javascript/readability/src/index.js", "name": "./src/index.js", - "id": 954 + "id": null } ], "failed": false, "errors": 0, "warnings": 0, "id": 396, - "issuerId": 954, + "issuerId": null, "chunks": [ 792 ], "assets": [], "reasons": [ { - "moduleIdentifier": "/home/fafre/Repos/kagi_bang_bang/app/js/readability/node_modules/@mozilla/readability/index.js", + "moduleIdentifier": "/home/fafre/Repos/kagi_bang_bang/packages/flutter_mozilla_components/javascript/readability/node_modules/@mozilla/readability/index.js", "module": "./node_modules/@mozilla/readability/index.js", "moduleName": "./node_modules/@mozilla/readability/index.js", - "resolvedModuleIdentifier": "/home/fafre/Repos/kagi_bang_bang/app/js/readability/node_modules/@mozilla/readability/index.js", + "resolvedModuleIdentifier": "/home/fafre/Repos/kagi_bang_bang/packages/flutter_mozilla_components/javascript/readability/node_modules/@mozilla/readability/index.js", "resolvedModule": "./node_modules/@mozilla/readability/index.js", "type": "cjs self exports reference", "active": true, @@ -318,46 +293,32 @@ "resolvedModuleId": 396 }, { - "moduleIdentifier": "/home/fafre/Repos/kagi_bang_bang/app/js/readability/node_modules/babel-loader/lib/index.js??ruleSet[1].rules[0].use!/home/fafre/Repos/kagi_bang_bang/app/js/readability/src/index.js", - "module": "./src/index.js", - "moduleName": "./src/index.js", - "resolvedModuleIdentifier": "/home/fafre/Repos/kagi_bang_bang/app/js/readability/node_modules/babel-loader/lib/index.js??ruleSet[1].rules[0].use!/home/fafre/Repos/kagi_bang_bang/app/js/readability/src/index.js", + "moduleIdentifier": "/home/fafre/Repos/kagi_bang_bang/packages/flutter_mozilla_components/javascript/readability/node_modules/babel-loader/lib/index.js??ruleSet[1].rules[0].use!/home/fafre/Repos/kagi_bang_bang/packages/flutter_mozilla_components/javascript/readability/src/index.js|b30ecb37559a8d7773ad4932c7b03100", + "module": "./src/index.js + 1 modules", + "moduleName": "./src/index.js + 1 modules", + "resolvedModuleIdentifier": "/home/fafre/Repos/kagi_bang_bang/packages/flutter_mozilla_components/javascript/readability/node_modules/babel-loader/lib/index.js??ruleSet[1].rules[0].use!/home/fafre/Repos/kagi_bang_bang/packages/flutter_mozilla_components/javascript/readability/src/index.js", "resolvedModule": "./src/index.js", "type": "harmony side effect evaluation", "active": true, "explanation": "", "userRequest": "@mozilla/readability", - "loc": "1:0-73", - "moduleId": 954, - "resolvedModuleId": 954 + "loc": "7:0-51", + "moduleId": 922, + "resolvedModuleId": null }, { - "moduleIdentifier": "/home/fafre/Repos/kagi_bang_bang/app/js/readability/node_modules/babel-loader/lib/index.js??ruleSet[1].rules[0].use!/home/fafre/Repos/kagi_bang_bang/app/js/readability/src/index.js", - "module": "./src/index.js", - "moduleName": "./src/index.js", - "resolvedModuleIdentifier": "/home/fafre/Repos/kagi_bang_bang/app/js/readability/node_modules/babel-loader/lib/index.js??ruleSet[1].rules[0].use!/home/fafre/Repos/kagi_bang_bang/app/js/readability/src/index.js", + "moduleIdentifier": "/home/fafre/Repos/kagi_bang_bang/packages/flutter_mozilla_components/javascript/readability/node_modules/babel-loader/lib/index.js??ruleSet[1].rules[0].use!/home/fafre/Repos/kagi_bang_bang/packages/flutter_mozilla_components/javascript/readability/src/index.js|b30ecb37559a8d7773ad4932c7b03100", + "module": "./src/index.js + 1 modules", + "moduleName": "./src/index.js + 1 modules", + "resolvedModuleIdentifier": "/home/fafre/Repos/kagi_bang_bang/packages/flutter_mozilla_components/javascript/readability/node_modules/babel-loader/lib/index.js??ruleSet[1].rules[0].use!/home/fafre/Repos/kagi_bang_bang/packages/flutter_mozilla_components/javascript/readability/src/index.js", "resolvedModule": "./src/index.js", "type": "harmony import specifier", "active": true, "explanation": "", "userRequest": "@mozilla/readability", - "loc": "4:9-29", - "moduleId": 954, - "resolvedModuleId": 954 - }, - { - "moduleIdentifier": "/home/fafre/Repos/kagi_bang_bang/app/js/readability/node_modules/babel-loader/lib/index.js??ruleSet[1].rules[0].use!/home/fafre/Repos/kagi_bang_bang/app/js/readability/src/index.js", - "module": "./src/index.js", - "moduleName": "./src/index.js", - "resolvedModuleIdentifier": "/home/fafre/Repos/kagi_bang_bang/app/js/readability/node_modules/babel-loader/lib/index.js??ruleSet[1].rules[0].use!/home/fafre/Repos/kagi_bang_bang/app/js/readability/src/index.js", - "resolvedModule": "./src/index.js", - "type": "harmony import specifier", - "active": true, - "explanation": "", - "userRequest": "@mozilla/readability", - "loc": "7:19-30", - "moduleId": 954, - "resolvedModuleId": 954 + "loc": "18:19-30", + "moduleId": 922, + "resolvedModuleId": null } ], "usedExports": null, @@ -373,142 +334,109 @@ "type": "module", "moduleType": "javascript/auto", "layer": null, - "size": 67137, + "size": 4061, "sizes": { - "javascript": 67137 + "javascript": 4061 }, "built": true, "codeGenerated": true, "buildTimeExecuted": false, "cached": false, - "identifier": "/home/fafre/Repos/kagi_bang_bang/app/js/readability/node_modules/dompurify/dist/purify.js", - "name": "./node_modules/dompurify/dist/purify.js", - "nameForCondition": "/home/fafre/Repos/kagi_bang_bang/app/js/readability/node_modules/dompurify/dist/purify.js", - "index": 4, - "preOrderIndex": 4, - "index2": 3, - "postOrderIndex": 3, + "identifier": "/home/fafre/Repos/kagi_bang_bang/packages/flutter_mozilla_components/javascript/readability/node_modules/remove-markdown/index.js", + "name": "./node_modules/remove-markdown/index.js", + "nameForCondition": "/home/fafre/Repos/kagi_bang_bang/packages/flutter_mozilla_components/javascript/readability/node_modules/remove-markdown/index.js", + "index": 5, + "preOrderIndex": 5, + "index2": 4, + "postOrderIndex": 4, "cacheable": true, "optional": false, "orphan": false, "dependent": true, - "issuer": "/home/fafre/Repos/kagi_bang_bang/app/js/readability/node_modules/babel-loader/lib/index.js??ruleSet[1].rules[0].use!/home/fafre/Repos/kagi_bang_bang/app/js/readability/src/index.js", + "issuer": "/home/fafre/Repos/kagi_bang_bang/packages/flutter_mozilla_components/javascript/readability/node_modules/babel-loader/lib/index.js??ruleSet[1].rules[0].use!/home/fafre/Repos/kagi_bang_bang/packages/flutter_mozilla_components/javascript/readability/src/index.js", "issuerName": "./src/index.js", "issuerPath": [ { - "identifier": "/home/fafre/Repos/kagi_bang_bang/app/js/readability/node_modules/babel-loader/lib/index.js??ruleSet[1].rules[0].use!/home/fafre/Repos/kagi_bang_bang/app/js/readability/src/index.js", + "identifier": "/home/fafre/Repos/kagi_bang_bang/packages/flutter_mozilla_components/javascript/readability/node_modules/babel-loader/lib/index.js??ruleSet[1].rules[0].use!/home/fafre/Repos/kagi_bang_bang/packages/flutter_mozilla_components/javascript/readability/src/index.js", "name": "./src/index.js", - "id": 954 + "id": null } ], "failed": false, "errors": 0, "warnings": 0, - "id": 838, - "issuerId": 954, + "id": 481, + "issuerId": null, "chunks": [ 792 ], "assets": [], "reasons": [ { - "moduleIdentifier": "/home/fafre/Repos/kagi_bang_bang/app/js/readability/node_modules/babel-loader/lib/index.js??ruleSet[1].rules[0].use!/home/fafre/Repos/kagi_bang_bang/app/js/readability/src/index.js", - "module": "./src/index.js", - "moduleName": "./src/index.js", - "resolvedModuleIdentifier": "/home/fafre/Repos/kagi_bang_bang/app/js/readability/node_modules/babel-loader/lib/index.js??ruleSet[1].rules[0].use!/home/fafre/Repos/kagi_bang_bang/app/js/readability/src/index.js", + "moduleIdentifier": "/home/fafre/Repos/kagi_bang_bang/packages/flutter_mozilla_components/javascript/readability/node_modules/babel-loader/lib/index.js??ruleSet[1].rules[0].use!/home/fafre/Repos/kagi_bang_bang/packages/flutter_mozilla_components/javascript/readability/src/index.js|b30ecb37559a8d7773ad4932c7b03100", + "module": "./src/index.js + 1 modules", + "moduleName": "./src/index.js + 1 modules", + "resolvedModuleIdentifier": "/home/fafre/Repos/kagi_bang_bang/packages/flutter_mozilla_components/javascript/readability/node_modules/babel-loader/lib/index.js??ruleSet[1].rules[0].use!/home/fafre/Repos/kagi_bang_bang/packages/flutter_mozilla_components/javascript/readability/src/index.js", "resolvedModule": "./src/index.js", - "type": "harmony side effect evaluation", + "type": "cjs require", "active": true, "explanation": "", - "userRequest": "dompurify", - "loc": "2:0-34", - "moduleId": 954, - "resolvedModuleId": 954 + "userRequest": "remove-markdown", + "loc": "9:21-47", + "moduleId": 922, + "resolvedModuleId": null }, { - "moduleIdentifier": "/home/fafre/Repos/kagi_bang_bang/app/js/readability/node_modules/babel-loader/lib/index.js??ruleSet[1].rules[0].use!/home/fafre/Repos/kagi_bang_bang/app/js/readability/src/index.js", - "module": "./src/index.js", - "moduleName": "./src/index.js", - "resolvedModuleIdentifier": "/home/fafre/Repos/kagi_bang_bang/app/js/readability/node_modules/babel-loader/lib/index.js??ruleSet[1].rules[0].use!/home/fafre/Repos/kagi_bang_bang/app/js/readability/src/index.js", - "resolvedModule": "./src/index.js", - "type": "harmony import specifier", - "active": true, - "explanation": "", - "userRequest": "dompurify", - "loc": "14:15-33", - "moduleId": 954, - "resolvedModuleId": 954 - }, - { - "moduleIdentifier": "/home/fafre/Repos/kagi_bang_bang/app/js/readability/node_modules/dompurify/dist/purify.js", - "module": "./node_modules/dompurify/dist/purify.js", - "moduleName": "./node_modules/dompurify/dist/purify.js", - "resolvedModuleIdentifier": "/home/fafre/Repos/kagi_bang_bang/app/js/readability/node_modules/dompurify/dist/purify.js", - "resolvedModule": "./node_modules/dompurify/dist/purify.js", + "moduleIdentifier": "/home/fafre/Repos/kagi_bang_bang/packages/flutter_mozilla_components/javascript/readability/node_modules/remove-markdown/index.js", + "module": "./node_modules/remove-markdown/index.js", + "moduleName": "./node_modules/remove-markdown/index.js", + "resolvedModuleIdentifier": "/home/fafre/Repos/kagi_bang_bang/packages/flutter_mozilla_components/javascript/readability/node_modules/remove-markdown/index.js", + "resolvedModule": "./node_modules/remove-markdown/index.js", "type": "cjs self exports reference", "active": true, "explanation": "", "userRequest": null, - "loc": "4:65-79", - "moduleId": 838, - "resolvedModuleId": 838 - }, - { - "moduleIdentifier": "/home/fafre/Repos/kagi_bang_bang/app/js/readability/node_modules/dompurify/dist/purify.js", - "module": "./node_modules/dompurify/dist/purify.js", - "moduleName": "./node_modules/dompurify/dist/purify.js", - "resolvedModuleIdentifier": "/home/fafre/Repos/kagi_bang_bang/app/js/readability/node_modules/dompurify/dist/purify.js", - "resolvedModule": "./node_modules/dompurify/dist/purify.js", - "type": "cjs self exports reference", - "active": true, - "explanation": "", - "userRequest": null, - "loc": "7:3-7", - "moduleId": 838, - "resolvedModuleId": 838 + "loc": "1:0-14", + "moduleId": 481, + "resolvedModuleId": 481 } ], "usedExports": null, "providedExports": null, "optimizationBailout": [ - "CommonJS bailout: this is used directly at 7:3-7", - "CommonJS bailout: module.exports is used directly at 4:65-79", - "Statement (ExpressionStatement) with side effects in source code at 3:0-1561:4", + "CommonJS bailout: module.exports is used directly at 1:0-14", + "Statement (ExpressionStatement) with side effects in source code at 1:0-99:2", "ModuleConcatenation bailout: Module is not an ECMAScript module" ], "depth": 1 }, { "type": "module", - "moduleType": "javascript/auto", + "moduleType": "javascript/esm", "layer": null, - "size": 1412, + "size": 27608, "sizes": { - "javascript": 1412 + "javascript": 27608 }, "built": true, "codeGenerated": true, "buildTimeExecuted": false, "cached": false, - "identifier": "/home/fafre/Repos/kagi_bang_bang/app/js/readability/node_modules/babel-loader/lib/index.js??ruleSet[1].rules[0].use!/home/fafre/Repos/kagi_bang_bang/app/js/readability/src/index.js", - "name": "./src/index.js", - "nameForCondition": "/home/fafre/Repos/kagi_bang_bang/app/js/readability/src/index.js", + "identifier": "/home/fafre/Repos/kagi_bang_bang/packages/flutter_mozilla_components/javascript/readability/node_modules/babel-loader/lib/index.js??ruleSet[1].rules[0].use!/home/fafre/Repos/kagi_bang_bang/packages/flutter_mozilla_components/javascript/readability/src/index.js|b30ecb37559a8d7773ad4932c7b03100", + "name": "./src/index.js + 1 modules", + "nameForCondition": "/home/fafre/Repos/kagi_bang_bang/packages/flutter_mozilla_components/javascript/readability/src/index.js", "index": 0, "preOrderIndex": 0, - "index2": 4, - "postOrderIndex": 4, + "index2": 5, + "postOrderIndex": 5, "cacheable": true, "optional": false, "orphan": false, "dependent": false, - "issuer": null, - "issuerName": null, - "issuerPath": null, "failed": false, "errors": 0, "warnings": 0, - "id": 954, - "issuerId": null, + "id": 922, "chunks": [ 792 ], @@ -544,51 +472,137 @@ ], "usedExports": true, "providedExports": [ - "applyReaderable", - "isReaderable" + "parseReaderable" ], "optimizationBailout": [ - "Statement (ExpressionStatement) with side effects in source code at 33:0-35", - "ModuleConcatenation bailout: Cannot concat with ./node_modules/@mozilla/readability/index.js: Module is not an ECMAScript module", - "ModuleConcatenation bailout: Cannot concat with ./node_modules/dompurify/dist/purify.js: Module is not an ECMAScript module" + "ModuleConcatenation bailout: Cannot concat with ./node_modules/@mozilla/readability/index.js: Module is not an ECMAScript module" ], - "depth": 0 - }, - { - "type": "module", - "moduleType": "runtime", - "layer": null, - "size": 267, - "sizes": { - "runtime": 267 - }, - "built": false, - "codeGenerated": true, - "buildTimeExecuted": false, - "cached": false, - "identifier": "webpack/runtime/compat get default export", - "name": "webpack/runtime/compat get default export", - "nameForCondition": null, - "index": null, - "preOrderIndex": null, - "index2": null, - "postOrderIndex": null, - "optional": false, - "orphan": false, - "dependent": false, - "failed": false, - "errors": 0, - "warnings": 0, - "id": "", - "chunks": [ - 792 - ], - "assets": [], - "reasons": [], - "usedExports": null, - "providedExports": [], - "optimizationBailout": [], - "depth": null + "depth": 0, + "modules": [ + { + "type": "module", + "moduleType": "javascript/auto", + "layer": null, + "size": 2546, + "sizes": { + "javascript": 2546 + }, + "built": true, + "codeGenerated": false, + "buildTimeExecuted": false, + "cached": false, + "identifier": "/home/fafre/Repos/kagi_bang_bang/packages/flutter_mozilla_components/javascript/readability/node_modules/babel-loader/lib/index.js??ruleSet[1].rules[0].use!/home/fafre/Repos/kagi_bang_bang/packages/flutter_mozilla_components/javascript/readability/src/index.js", + "name": "./src/index.js", + "nameForCondition": "/home/fafre/Repos/kagi_bang_bang/packages/flutter_mozilla_components/javascript/readability/src/index.js", + "index": 0, + "preOrderIndex": 0, + "index2": 5, + "postOrderIndex": 5, + "cacheable": true, + "optional": false, + "orphan": false, + "dependent": true, + "issuer": null, + "issuerName": null, + "issuerPath": null, + "failed": false, + "errors": 0, + "warnings": 0, + "id": null, + "issuerId": null, + "chunks": [], + "assets": [], + "reasons": [], + "usedExports": true, + "providedExports": [ + "parseReaderable" + ], + "optimizationBailout": [ + "Statement (VariableDeclaration) with side effects in source code at 9:0-48" + ], + "depth": 0 + }, + { + "type": "module", + "moduleType": "javascript/auto", + "layer": null, + "size": 25062, + "sizes": { + "javascript": 25062 + }, + "built": true, + "codeGenerated": false, + "buildTimeExecuted": false, + "cached": false, + "identifier": "/home/fafre/Repos/kagi_bang_bang/packages/flutter_mozilla_components/javascript/readability/node_modules/turndown/lib/turndown.browser.es.js", + "name": "./node_modules/turndown/lib/turndown.browser.es.js", + "nameForCondition": "/home/fafre/Repos/kagi_bang_bang/packages/flutter_mozilla_components/javascript/readability/node_modules/turndown/lib/turndown.browser.es.js", + "index": 4, + "preOrderIndex": 4, + "index2": 3, + "postOrderIndex": 3, + "cacheable": true, + "optional": false, + "orphan": false, + "dependent": true, + "issuer": "/home/fafre/Repos/kagi_bang_bang/packages/flutter_mozilla_components/javascript/readability/node_modules/babel-loader/lib/index.js??ruleSet[1].rules[0].use!/home/fafre/Repos/kagi_bang_bang/packages/flutter_mozilla_components/javascript/readability/src/index.js", + "issuerName": "./src/index.js", + "issuerPath": [ + { + "identifier": "/home/fafre/Repos/kagi_bang_bang/packages/flutter_mozilla_components/javascript/readability/node_modules/babel-loader/lib/index.js??ruleSet[1].rules[0].use!/home/fafre/Repos/kagi_bang_bang/packages/flutter_mozilla_components/javascript/readability/src/index.js", + "name": "./src/index.js", + "id": null + } + ], + "failed": false, + "errors": 0, + "warnings": 0, + "id": null, + "issuerId": null, + "chunks": [], + "assets": [], + "reasons": [ + { + "moduleIdentifier": "/home/fafre/Repos/kagi_bang_bang/packages/flutter_mozilla_components/javascript/readability/node_modules/babel-loader/lib/index.js??ruleSet[1].rules[0].use!/home/fafre/Repos/kagi_bang_bang/packages/flutter_mozilla_components/javascript/readability/src/index.js", + "module": "./src/index.js", + "moduleName": "./src/index.js", + "resolvedModuleIdentifier": "/home/fafre/Repos/kagi_bang_bang/packages/flutter_mozilla_components/javascript/readability/node_modules/babel-loader/lib/index.js??ruleSet[1].rules[0].use!/home/fafre/Repos/kagi_bang_bang/packages/flutter_mozilla_components/javascript/readability/src/index.js", + "resolvedModule": "./src/index.js", + "type": "harmony side effect evaluation", + "active": true, + "explanation": "", + "userRequest": "turndown", + "loc": "8:0-39", + "moduleId": null, + "resolvedModuleId": null + }, + { + "moduleIdentifier": "/home/fafre/Repos/kagi_bang_bang/packages/flutter_mozilla_components/javascript/readability/node_modules/babel-loader/lib/index.js??ruleSet[1].rules[0].use!/home/fafre/Repos/kagi_bang_bang/packages/flutter_mozilla_components/javascript/readability/src/index.js", + "module": "./src/index.js", + "moduleName": "./src/index.js", + "resolvedModuleIdentifier": "/home/fafre/Repos/kagi_bang_bang/packages/flutter_mozilla_components/javascript/readability/node_modules/babel-loader/lib/index.js??ruleSet[1].rules[0].use!/home/fafre/Repos/kagi_bang_bang/packages/flutter_mozilla_components/javascript/readability/src/index.js", + "resolvedModule": "./src/index.js", + "type": "harmony import specifier", + "active": true, + "explanation": "", + "userRequest": "turndown", + "loc": "10:26-41", + "moduleId": null, + "resolvedModuleId": null + } + ], + "usedExports": [ + "default" + ], + "providedExports": [ + "default" + ], + "optimizationBailout": [ + "Statement (VariableDeclaration) with side effects in source code at 78:0-15" + ], + "depth": 1 + } + ] }, { "type": "module", @@ -713,34 +727,30 @@ "modules": [ { "type": "module", - "moduleType": "javascript/auto", + "moduleType": "javascript/esm", "layer": null, - "size": 1412, + "size": 27608, "sizes": { - "javascript": 1412 + "javascript": 27608 }, "built": true, "codeGenerated": true, "buildTimeExecuted": false, "cached": false, - "identifier": "/home/fafre/Repos/kagi_bang_bang/app/js/readability/node_modules/babel-loader/lib/index.js??ruleSet[1].rules[0].use!/home/fafre/Repos/kagi_bang_bang/app/js/readability/src/index.js", - "name": "./src/index.js", - "nameForCondition": "/home/fafre/Repos/kagi_bang_bang/app/js/readability/src/index.js", + "identifier": "/home/fafre/Repos/kagi_bang_bang/packages/flutter_mozilla_components/javascript/readability/node_modules/babel-loader/lib/index.js??ruleSet[1].rules[0].use!/home/fafre/Repos/kagi_bang_bang/packages/flutter_mozilla_components/javascript/readability/src/index.js|b30ecb37559a8d7773ad4932c7b03100", + "name": "./src/index.js + 1 modules", + "nameForCondition": "/home/fafre/Repos/kagi_bang_bang/packages/flutter_mozilla_components/javascript/readability/src/index.js", "index": 0, "preOrderIndex": 0, - "index2": 4, - "postOrderIndex": 4, + "index2": 5, + "postOrderIndex": 5, "cacheable": true, "optional": false, "orphan": false, - "issuer": null, - "issuerName": null, - "issuerPath": null, "failed": false, "errors": 0, "warnings": 0, - "id": 954, - "issuerId": null, + "id": 922, "chunks": [ 792 ], @@ -776,15 +786,135 @@ ], "usedExports": true, "providedExports": [ - "applyReaderable", - "isReaderable" + "parseReaderable" ], "optimizationBailout": [ - "Statement (ExpressionStatement) with side effects in source code at 33:0-35", - "ModuleConcatenation bailout: Cannot concat with ./node_modules/@mozilla/readability/index.js: Module is not an ECMAScript module", - "ModuleConcatenation bailout: Cannot concat with ./node_modules/dompurify/dist/purify.js: Module is not an ECMAScript module" + "ModuleConcatenation bailout: Cannot concat with ./node_modules/@mozilla/readability/index.js: Module is not an ECMAScript module" ], - "depth": 0 + "depth": 0, + "modules": [ + { + "type": "module", + "moduleType": "javascript/auto", + "layer": null, + "size": 2546, + "sizes": { + "javascript": 2546 + }, + "built": true, + "codeGenerated": false, + "buildTimeExecuted": false, + "cached": false, + "identifier": "/home/fafre/Repos/kagi_bang_bang/packages/flutter_mozilla_components/javascript/readability/node_modules/babel-loader/lib/index.js??ruleSet[1].rules[0].use!/home/fafre/Repos/kagi_bang_bang/packages/flutter_mozilla_components/javascript/readability/src/index.js", + "name": "./src/index.js", + "nameForCondition": "/home/fafre/Repos/kagi_bang_bang/packages/flutter_mozilla_components/javascript/readability/src/index.js", + "index": 0, + "preOrderIndex": 0, + "index2": 5, + "postOrderIndex": 5, + "cacheable": true, + "optional": false, + "orphan": false, + "issuer": null, + "issuerName": null, + "issuerPath": null, + "failed": false, + "errors": 0, + "warnings": 0, + "id": null, + "issuerId": null, + "chunks": [], + "assets": [], + "reasons": [], + "usedExports": true, + "providedExports": [ + "parseReaderable" + ], + "optimizationBailout": [ + "Statement (VariableDeclaration) with side effects in source code at 9:0-48" + ], + "depth": 0 + }, + { + "type": "module", + "moduleType": "javascript/auto", + "layer": null, + "size": 25062, + "sizes": { + "javascript": 25062 + }, + "built": true, + "codeGenerated": false, + "buildTimeExecuted": false, + "cached": false, + "identifier": "/home/fafre/Repos/kagi_bang_bang/packages/flutter_mozilla_components/javascript/readability/node_modules/turndown/lib/turndown.browser.es.js", + "name": "./node_modules/turndown/lib/turndown.browser.es.js", + "nameForCondition": "/home/fafre/Repos/kagi_bang_bang/packages/flutter_mozilla_components/javascript/readability/node_modules/turndown/lib/turndown.browser.es.js", + "index": 4, + "preOrderIndex": 4, + "index2": 3, + "postOrderIndex": 3, + "cacheable": true, + "optional": false, + "orphan": false, + "issuer": "/home/fafre/Repos/kagi_bang_bang/packages/flutter_mozilla_components/javascript/readability/node_modules/babel-loader/lib/index.js??ruleSet[1].rules[0].use!/home/fafre/Repos/kagi_bang_bang/packages/flutter_mozilla_components/javascript/readability/src/index.js", + "issuerName": "./src/index.js", + "issuerPath": [ + { + "identifier": "/home/fafre/Repos/kagi_bang_bang/packages/flutter_mozilla_components/javascript/readability/node_modules/babel-loader/lib/index.js??ruleSet[1].rules[0].use!/home/fafre/Repos/kagi_bang_bang/packages/flutter_mozilla_components/javascript/readability/src/index.js", + "name": "./src/index.js", + "id": null + } + ], + "failed": false, + "errors": 0, + "warnings": 0, + "id": null, + "issuerId": null, + "chunks": [], + "assets": [], + "reasons": [ + { + "moduleIdentifier": "/home/fafre/Repos/kagi_bang_bang/packages/flutter_mozilla_components/javascript/readability/node_modules/babel-loader/lib/index.js??ruleSet[1].rules[0].use!/home/fafre/Repos/kagi_bang_bang/packages/flutter_mozilla_components/javascript/readability/src/index.js", + "module": "./src/index.js", + "moduleName": "./src/index.js", + "resolvedModuleIdentifier": "/home/fafre/Repos/kagi_bang_bang/packages/flutter_mozilla_components/javascript/readability/node_modules/babel-loader/lib/index.js??ruleSet[1].rules[0].use!/home/fafre/Repos/kagi_bang_bang/packages/flutter_mozilla_components/javascript/readability/src/index.js", + "resolvedModule": "./src/index.js", + "type": "harmony side effect evaluation", + "active": true, + "explanation": "", + "userRequest": "turndown", + "loc": "8:0-39", + "moduleId": null, + "resolvedModuleId": null + }, + { + "moduleIdentifier": "/home/fafre/Repos/kagi_bang_bang/packages/flutter_mozilla_components/javascript/readability/node_modules/babel-loader/lib/index.js??ruleSet[1].rules[0].use!/home/fafre/Repos/kagi_bang_bang/packages/flutter_mozilla_components/javascript/readability/src/index.js", + "module": "./src/index.js", + "moduleName": "./src/index.js", + "resolvedModuleIdentifier": "/home/fafre/Repos/kagi_bang_bang/packages/flutter_mozilla_components/javascript/readability/node_modules/babel-loader/lib/index.js??ruleSet[1].rules[0].use!/home/fafre/Repos/kagi_bang_bang/packages/flutter_mozilla_components/javascript/readability/src/index.js", + "resolvedModule": "./src/index.js", + "type": "harmony import specifier", + "active": true, + "explanation": "", + "userRequest": "turndown", + "loc": "10:26-41", + "moduleId": null, + "resolvedModuleId": null + } + ], + "usedExports": [ + "default" + ], + "providedExports": [ + "default" + ], + "optimizationBailout": [ + "Statement (VariableDeclaration) with side effects in source code at 78:0-15" + ], + "depth": 1 + } + ] }, { "type": "module", @@ -798,9 +928,9 @@ "codeGenerated": true, "buildTimeExecuted": false, "cached": false, - "identifier": "/home/fafre/Repos/kagi_bang_bang/app/js/readability/node_modules/@mozilla/readability/index.js", + "identifier": "/home/fafre/Repos/kagi_bang_bang/packages/flutter_mozilla_components/javascript/readability/node_modules/@mozilla/readability/index.js", "name": "./node_modules/@mozilla/readability/index.js", - "nameForCondition": "/home/fafre/Repos/kagi_bang_bang/app/js/readability/node_modules/@mozilla/readability/index.js", + "nameForCondition": "/home/fafre/Repos/kagi_bang_bang/packages/flutter_mozilla_components/javascript/readability/node_modules/@mozilla/readability/index.js", "index": 1, "preOrderIndex": 1, "index2": 2, @@ -808,30 +938,30 @@ "cacheable": true, "optional": false, "orphan": false, - "issuer": "/home/fafre/Repos/kagi_bang_bang/app/js/readability/node_modules/babel-loader/lib/index.js??ruleSet[1].rules[0].use!/home/fafre/Repos/kagi_bang_bang/app/js/readability/src/index.js", + "issuer": "/home/fafre/Repos/kagi_bang_bang/packages/flutter_mozilla_components/javascript/readability/node_modules/babel-loader/lib/index.js??ruleSet[1].rules[0].use!/home/fafre/Repos/kagi_bang_bang/packages/flutter_mozilla_components/javascript/readability/src/index.js", "issuerName": "./src/index.js", "issuerPath": [ { - "identifier": "/home/fafre/Repos/kagi_bang_bang/app/js/readability/node_modules/babel-loader/lib/index.js??ruleSet[1].rules[0].use!/home/fafre/Repos/kagi_bang_bang/app/js/readability/src/index.js", + "identifier": "/home/fafre/Repos/kagi_bang_bang/packages/flutter_mozilla_components/javascript/readability/node_modules/babel-loader/lib/index.js??ruleSet[1].rules[0].use!/home/fafre/Repos/kagi_bang_bang/packages/flutter_mozilla_components/javascript/readability/src/index.js", "name": "./src/index.js", - "id": 954 + "id": null } ], "failed": false, "errors": 0, "warnings": 0, "id": 396, - "issuerId": 954, + "issuerId": null, "chunks": [ 792 ], "assets": [], "reasons": [ { - "moduleIdentifier": "/home/fafre/Repos/kagi_bang_bang/app/js/readability/node_modules/@mozilla/readability/index.js", + "moduleIdentifier": "/home/fafre/Repos/kagi_bang_bang/packages/flutter_mozilla_components/javascript/readability/node_modules/@mozilla/readability/index.js", "module": "./node_modules/@mozilla/readability/index.js", "moduleName": "./node_modules/@mozilla/readability/index.js", - "resolvedModuleIdentifier": "/home/fafre/Repos/kagi_bang_bang/app/js/readability/node_modules/@mozilla/readability/index.js", + "resolvedModuleIdentifier": "/home/fafre/Repos/kagi_bang_bang/packages/flutter_mozilla_components/javascript/readability/node_modules/@mozilla/readability/index.js", "resolvedModule": "./node_modules/@mozilla/readability/index.js", "type": "cjs self exports reference", "active": true, @@ -842,46 +972,32 @@ "resolvedModuleId": 396 }, { - "moduleIdentifier": "/home/fafre/Repos/kagi_bang_bang/app/js/readability/node_modules/babel-loader/lib/index.js??ruleSet[1].rules[0].use!/home/fafre/Repos/kagi_bang_bang/app/js/readability/src/index.js", - "module": "./src/index.js", - "moduleName": "./src/index.js", - "resolvedModuleIdentifier": "/home/fafre/Repos/kagi_bang_bang/app/js/readability/node_modules/babel-loader/lib/index.js??ruleSet[1].rules[0].use!/home/fafre/Repos/kagi_bang_bang/app/js/readability/src/index.js", + "moduleIdentifier": "/home/fafre/Repos/kagi_bang_bang/packages/flutter_mozilla_components/javascript/readability/node_modules/babel-loader/lib/index.js??ruleSet[1].rules[0].use!/home/fafre/Repos/kagi_bang_bang/packages/flutter_mozilla_components/javascript/readability/src/index.js|b30ecb37559a8d7773ad4932c7b03100", + "module": "./src/index.js + 1 modules", + "moduleName": "./src/index.js + 1 modules", + "resolvedModuleIdentifier": "/home/fafre/Repos/kagi_bang_bang/packages/flutter_mozilla_components/javascript/readability/node_modules/babel-loader/lib/index.js??ruleSet[1].rules[0].use!/home/fafre/Repos/kagi_bang_bang/packages/flutter_mozilla_components/javascript/readability/src/index.js", "resolvedModule": "./src/index.js", "type": "harmony side effect evaluation", "active": true, "explanation": "", "userRequest": "@mozilla/readability", - "loc": "1:0-73", - "moduleId": 954, - "resolvedModuleId": 954 + "loc": "7:0-51", + "moduleId": 922, + "resolvedModuleId": null }, { - "moduleIdentifier": "/home/fafre/Repos/kagi_bang_bang/app/js/readability/node_modules/babel-loader/lib/index.js??ruleSet[1].rules[0].use!/home/fafre/Repos/kagi_bang_bang/app/js/readability/src/index.js", - "module": "./src/index.js", - "moduleName": "./src/index.js", - "resolvedModuleIdentifier": "/home/fafre/Repos/kagi_bang_bang/app/js/readability/node_modules/babel-loader/lib/index.js??ruleSet[1].rules[0].use!/home/fafre/Repos/kagi_bang_bang/app/js/readability/src/index.js", + "moduleIdentifier": "/home/fafre/Repos/kagi_bang_bang/packages/flutter_mozilla_components/javascript/readability/node_modules/babel-loader/lib/index.js??ruleSet[1].rules[0].use!/home/fafre/Repos/kagi_bang_bang/packages/flutter_mozilla_components/javascript/readability/src/index.js|b30ecb37559a8d7773ad4932c7b03100", + "module": "./src/index.js + 1 modules", + "moduleName": "./src/index.js + 1 modules", + "resolvedModuleIdentifier": "/home/fafre/Repos/kagi_bang_bang/packages/flutter_mozilla_components/javascript/readability/node_modules/babel-loader/lib/index.js??ruleSet[1].rules[0].use!/home/fafre/Repos/kagi_bang_bang/packages/flutter_mozilla_components/javascript/readability/src/index.js", "resolvedModule": "./src/index.js", "type": "harmony import specifier", "active": true, "explanation": "", "userRequest": "@mozilla/readability", - "loc": "4:9-29", - "moduleId": 954, - "resolvedModuleId": 954 - }, - { - "moduleIdentifier": "/home/fafre/Repos/kagi_bang_bang/app/js/readability/node_modules/babel-loader/lib/index.js??ruleSet[1].rules[0].use!/home/fafre/Repos/kagi_bang_bang/app/js/readability/src/index.js", - "module": "./src/index.js", - "moduleName": "./src/index.js", - "resolvedModuleIdentifier": "/home/fafre/Repos/kagi_bang_bang/app/js/readability/node_modules/babel-loader/lib/index.js??ruleSet[1].rules[0].use!/home/fafre/Repos/kagi_bang_bang/app/js/readability/src/index.js", - "resolvedModule": "./src/index.js", - "type": "harmony import specifier", - "active": true, - "explanation": "", - "userRequest": "@mozilla/readability", - "loc": "7:19-30", - "moduleId": 954, - "resolvedModuleId": 954 + "loc": "18:19-30", + "moduleId": 922, + "resolvedModuleId": null } ], "usedExports": null, @@ -897,106 +1013,156 @@ "type": "module", "moduleType": "javascript/auto", "layer": null, - "size": 67137, + "size": 25062, "sizes": { - "javascript": 67137 + "javascript": 25062 }, "built": true, - "codeGenerated": true, + "codeGenerated": false, "buildTimeExecuted": false, "cached": false, - "identifier": "/home/fafre/Repos/kagi_bang_bang/app/js/readability/node_modules/dompurify/dist/purify.js", - "name": "./node_modules/dompurify/dist/purify.js", - "nameForCondition": "/home/fafre/Repos/kagi_bang_bang/app/js/readability/node_modules/dompurify/dist/purify.js", + "identifier": "/home/fafre/Repos/kagi_bang_bang/packages/flutter_mozilla_components/javascript/readability/node_modules/turndown/lib/turndown.browser.es.js", + "name": "./node_modules/turndown/lib/turndown.browser.es.js", + "nameForCondition": "/home/fafre/Repos/kagi_bang_bang/packages/flutter_mozilla_components/javascript/readability/node_modules/turndown/lib/turndown.browser.es.js", "index": 4, "preOrderIndex": 4, "index2": 3, "postOrderIndex": 3, "cacheable": true, "optional": false, - "orphan": false, - "issuer": "/home/fafre/Repos/kagi_bang_bang/app/js/readability/node_modules/babel-loader/lib/index.js??ruleSet[1].rules[0].use!/home/fafre/Repos/kagi_bang_bang/app/js/readability/src/index.js", + "orphan": true, + "issuer": "/home/fafre/Repos/kagi_bang_bang/packages/flutter_mozilla_components/javascript/readability/node_modules/babel-loader/lib/index.js??ruleSet[1].rules[0].use!/home/fafre/Repos/kagi_bang_bang/packages/flutter_mozilla_components/javascript/readability/src/index.js", "issuerName": "./src/index.js", "issuerPath": [ { - "identifier": "/home/fafre/Repos/kagi_bang_bang/app/js/readability/node_modules/babel-loader/lib/index.js??ruleSet[1].rules[0].use!/home/fafre/Repos/kagi_bang_bang/app/js/readability/src/index.js", + "identifier": "/home/fafre/Repos/kagi_bang_bang/packages/flutter_mozilla_components/javascript/readability/node_modules/babel-loader/lib/index.js??ruleSet[1].rules[0].use!/home/fafre/Repos/kagi_bang_bang/packages/flutter_mozilla_components/javascript/readability/src/index.js", "name": "./src/index.js", - "id": 954 + "id": null } ], "failed": false, "errors": 0, "warnings": 0, - "id": 838, - "issuerId": 954, + "id": null, + "issuerId": null, + "chunks": [], + "assets": [], + "reasons": [ + { + "moduleIdentifier": "/home/fafre/Repos/kagi_bang_bang/packages/flutter_mozilla_components/javascript/readability/node_modules/babel-loader/lib/index.js??ruleSet[1].rules[0].use!/home/fafre/Repos/kagi_bang_bang/packages/flutter_mozilla_components/javascript/readability/src/index.js", + "module": "./src/index.js", + "moduleName": "./src/index.js", + "resolvedModuleIdentifier": "/home/fafre/Repos/kagi_bang_bang/packages/flutter_mozilla_components/javascript/readability/node_modules/babel-loader/lib/index.js??ruleSet[1].rules[0].use!/home/fafre/Repos/kagi_bang_bang/packages/flutter_mozilla_components/javascript/readability/src/index.js", + "resolvedModule": "./src/index.js", + "type": "harmony side effect evaluation", + "active": true, + "explanation": "", + "userRequest": "turndown", + "loc": "8:0-39", + "moduleId": null, + "resolvedModuleId": null + }, + { + "moduleIdentifier": "/home/fafre/Repos/kagi_bang_bang/packages/flutter_mozilla_components/javascript/readability/node_modules/babel-loader/lib/index.js??ruleSet[1].rules[0].use!/home/fafre/Repos/kagi_bang_bang/packages/flutter_mozilla_components/javascript/readability/src/index.js", + "module": "./src/index.js", + "moduleName": "./src/index.js", + "resolvedModuleIdentifier": "/home/fafre/Repos/kagi_bang_bang/packages/flutter_mozilla_components/javascript/readability/node_modules/babel-loader/lib/index.js??ruleSet[1].rules[0].use!/home/fafre/Repos/kagi_bang_bang/packages/flutter_mozilla_components/javascript/readability/src/index.js", + "resolvedModule": "./src/index.js", + "type": "harmony import specifier", + "active": true, + "explanation": "", + "userRequest": "turndown", + "loc": "10:26-41", + "moduleId": null, + "resolvedModuleId": null + } + ], + "usedExports": [ + "default" + ], + "providedExports": [ + "default" + ], + "optimizationBailout": [ + "Statement (VariableDeclaration) with side effects in source code at 78:0-15" + ], + "depth": 1 + }, + { + "type": "module", + "moduleType": "javascript/auto", + "layer": null, + "size": 4061, + "sizes": { + "javascript": 4061 + }, + "built": true, + "codeGenerated": true, + "buildTimeExecuted": false, + "cached": false, + "identifier": "/home/fafre/Repos/kagi_bang_bang/packages/flutter_mozilla_components/javascript/readability/node_modules/remove-markdown/index.js", + "name": "./node_modules/remove-markdown/index.js", + "nameForCondition": "/home/fafre/Repos/kagi_bang_bang/packages/flutter_mozilla_components/javascript/readability/node_modules/remove-markdown/index.js", + "index": 5, + "preOrderIndex": 5, + "index2": 4, + "postOrderIndex": 4, + "cacheable": true, + "optional": false, + "orphan": false, + "issuer": "/home/fafre/Repos/kagi_bang_bang/packages/flutter_mozilla_components/javascript/readability/node_modules/babel-loader/lib/index.js??ruleSet[1].rules[0].use!/home/fafre/Repos/kagi_bang_bang/packages/flutter_mozilla_components/javascript/readability/src/index.js", + "issuerName": "./src/index.js", + "issuerPath": [ + { + "identifier": "/home/fafre/Repos/kagi_bang_bang/packages/flutter_mozilla_components/javascript/readability/node_modules/babel-loader/lib/index.js??ruleSet[1].rules[0].use!/home/fafre/Repos/kagi_bang_bang/packages/flutter_mozilla_components/javascript/readability/src/index.js", + "name": "./src/index.js", + "id": null + } + ], + "failed": false, + "errors": 0, + "warnings": 0, + "id": 481, + "issuerId": null, "chunks": [ 792 ], "assets": [], "reasons": [ { - "moduleIdentifier": "/home/fafre/Repos/kagi_bang_bang/app/js/readability/node_modules/babel-loader/lib/index.js??ruleSet[1].rules[0].use!/home/fafre/Repos/kagi_bang_bang/app/js/readability/src/index.js", - "module": "./src/index.js", - "moduleName": "./src/index.js", - "resolvedModuleIdentifier": "/home/fafre/Repos/kagi_bang_bang/app/js/readability/node_modules/babel-loader/lib/index.js??ruleSet[1].rules[0].use!/home/fafre/Repos/kagi_bang_bang/app/js/readability/src/index.js", + "moduleIdentifier": "/home/fafre/Repos/kagi_bang_bang/packages/flutter_mozilla_components/javascript/readability/node_modules/babel-loader/lib/index.js??ruleSet[1].rules[0].use!/home/fafre/Repos/kagi_bang_bang/packages/flutter_mozilla_components/javascript/readability/src/index.js|b30ecb37559a8d7773ad4932c7b03100", + "module": "./src/index.js + 1 modules", + "moduleName": "./src/index.js + 1 modules", + "resolvedModuleIdentifier": "/home/fafre/Repos/kagi_bang_bang/packages/flutter_mozilla_components/javascript/readability/node_modules/babel-loader/lib/index.js??ruleSet[1].rules[0].use!/home/fafre/Repos/kagi_bang_bang/packages/flutter_mozilla_components/javascript/readability/src/index.js", "resolvedModule": "./src/index.js", - "type": "harmony side effect evaluation", + "type": "cjs require", "active": true, "explanation": "", - "userRequest": "dompurify", - "loc": "2:0-34", - "moduleId": 954, - "resolvedModuleId": 954 + "userRequest": "remove-markdown", + "loc": "9:21-47", + "moduleId": 922, + "resolvedModuleId": null }, { - "moduleIdentifier": "/home/fafre/Repos/kagi_bang_bang/app/js/readability/node_modules/babel-loader/lib/index.js??ruleSet[1].rules[0].use!/home/fafre/Repos/kagi_bang_bang/app/js/readability/src/index.js", - "module": "./src/index.js", - "moduleName": "./src/index.js", - "resolvedModuleIdentifier": "/home/fafre/Repos/kagi_bang_bang/app/js/readability/node_modules/babel-loader/lib/index.js??ruleSet[1].rules[0].use!/home/fafre/Repos/kagi_bang_bang/app/js/readability/src/index.js", - "resolvedModule": "./src/index.js", - "type": "harmony import specifier", - "active": true, - "explanation": "", - "userRequest": "dompurify", - "loc": "14:15-33", - "moduleId": 954, - "resolvedModuleId": 954 - }, - { - "moduleIdentifier": "/home/fafre/Repos/kagi_bang_bang/app/js/readability/node_modules/dompurify/dist/purify.js", - "module": "./node_modules/dompurify/dist/purify.js", - "moduleName": "./node_modules/dompurify/dist/purify.js", - "resolvedModuleIdentifier": "/home/fafre/Repos/kagi_bang_bang/app/js/readability/node_modules/dompurify/dist/purify.js", - "resolvedModule": "./node_modules/dompurify/dist/purify.js", + "moduleIdentifier": "/home/fafre/Repos/kagi_bang_bang/packages/flutter_mozilla_components/javascript/readability/node_modules/remove-markdown/index.js", + "module": "./node_modules/remove-markdown/index.js", + "moduleName": "./node_modules/remove-markdown/index.js", + "resolvedModuleIdentifier": "/home/fafre/Repos/kagi_bang_bang/packages/flutter_mozilla_components/javascript/readability/node_modules/remove-markdown/index.js", + "resolvedModule": "./node_modules/remove-markdown/index.js", "type": "cjs self exports reference", "active": true, "explanation": "", "userRequest": null, - "loc": "4:65-79", - "moduleId": 838, - "resolvedModuleId": 838 - }, - { - "moduleIdentifier": "/home/fafre/Repos/kagi_bang_bang/app/js/readability/node_modules/dompurify/dist/purify.js", - "module": "./node_modules/dompurify/dist/purify.js", - "moduleName": "./node_modules/dompurify/dist/purify.js", - "resolvedModuleIdentifier": "/home/fafre/Repos/kagi_bang_bang/app/js/readability/node_modules/dompurify/dist/purify.js", - "resolvedModule": "./node_modules/dompurify/dist/purify.js", - "type": "cjs self exports reference", - "active": true, - "explanation": "", - "userRequest": null, - "loc": "7:3-7", - "moduleId": 838, - "resolvedModuleId": 838 + "loc": "1:0-14", + "moduleId": 481, + "resolvedModuleId": 481 } ], "usedExports": null, "providedExports": null, "optimizationBailout": [ - "CommonJS bailout: this is used directly at 7:3-7", - "CommonJS bailout: module.exports is used directly at 4:65-79", - "Statement (ExpressionStatement) with side effects in source code at 3:0-1561:4", + "CommonJS bailout: module.exports is used directly at 1:0-14", + "Statement (ExpressionStatement) with side effects in source code at 1:0-99:2", "ModuleConcatenation bailout: Module is not an ECMAScript module" ], "depth": 1 @@ -1013,9 +1179,9 @@ "codeGenerated": true, "buildTimeExecuted": false, "cached": false, - "identifier": "/home/fafre/Repos/kagi_bang_bang/app/js/readability/node_modules/@mozilla/readability/Readability.js", + "identifier": "/home/fafre/Repos/kagi_bang_bang/packages/flutter_mozilla_components/javascript/readability/node_modules/@mozilla/readability/Readability.js", "name": "./node_modules/@mozilla/readability/Readability.js", - "nameForCondition": "/home/fafre/Repos/kagi_bang_bang/app/js/readability/node_modules/@mozilla/readability/Readability.js", + "nameForCondition": "/home/fafre/Repos/kagi_bang_bang/packages/flutter_mozilla_components/javascript/readability/node_modules/@mozilla/readability/Readability.js", "index": 2, "preOrderIndex": 2, "index2": 0, @@ -1023,16 +1189,16 @@ "cacheable": true, "optional": false, "orphan": false, - "issuer": "/home/fafre/Repos/kagi_bang_bang/app/js/readability/node_modules/@mozilla/readability/index.js", + "issuer": "/home/fafre/Repos/kagi_bang_bang/packages/flutter_mozilla_components/javascript/readability/node_modules/@mozilla/readability/index.js", "issuerName": "./node_modules/@mozilla/readability/index.js", "issuerPath": [ { - "identifier": "/home/fafre/Repos/kagi_bang_bang/app/js/readability/node_modules/babel-loader/lib/index.js??ruleSet[1].rules[0].use!/home/fafre/Repos/kagi_bang_bang/app/js/readability/src/index.js", + "identifier": "/home/fafre/Repos/kagi_bang_bang/packages/flutter_mozilla_components/javascript/readability/node_modules/babel-loader/lib/index.js??ruleSet[1].rules[0].use!/home/fafre/Repos/kagi_bang_bang/packages/flutter_mozilla_components/javascript/readability/src/index.js", "name": "./src/index.js", - "id": 954 + "id": null }, { - "identifier": "/home/fafre/Repos/kagi_bang_bang/app/js/readability/node_modules/@mozilla/readability/index.js", + "identifier": "/home/fafre/Repos/kagi_bang_bang/packages/flutter_mozilla_components/javascript/readability/node_modules/@mozilla/readability/index.js", "name": "./node_modules/@mozilla/readability/index.js", "id": 396 } @@ -1048,10 +1214,10 @@ "assets": [], "reasons": [ { - "moduleIdentifier": "/home/fafre/Repos/kagi_bang_bang/app/js/readability/node_modules/@mozilla/readability/Readability.js", + "moduleIdentifier": "/home/fafre/Repos/kagi_bang_bang/packages/flutter_mozilla_components/javascript/readability/node_modules/@mozilla/readability/Readability.js", "module": "./node_modules/@mozilla/readability/Readability.js", "moduleName": "./node_modules/@mozilla/readability/Readability.js", - "resolvedModuleIdentifier": "/home/fafre/Repos/kagi_bang_bang/app/js/readability/node_modules/@mozilla/readability/Readability.js", + "resolvedModuleIdentifier": "/home/fafre/Repos/kagi_bang_bang/packages/flutter_mozilla_components/javascript/readability/node_modules/@mozilla/readability/Readability.js", "resolvedModule": "./node_modules/@mozilla/readability/Readability.js", "type": "cjs self exports reference", "active": true, @@ -1062,10 +1228,10 @@ "resolvedModuleId": 238 }, { - "moduleIdentifier": "/home/fafre/Repos/kagi_bang_bang/app/js/readability/node_modules/@mozilla/readability/index.js", + "moduleIdentifier": "/home/fafre/Repos/kagi_bang_bang/packages/flutter_mozilla_components/javascript/readability/node_modules/@mozilla/readability/index.js", "module": "./node_modules/@mozilla/readability/index.js", "moduleName": "./node_modules/@mozilla/readability/index.js", - "resolvedModuleIdentifier": "/home/fafre/Repos/kagi_bang_bang/app/js/readability/node_modules/@mozilla/readability/index.js", + "resolvedModuleIdentifier": "/home/fafre/Repos/kagi_bang_bang/packages/flutter_mozilla_components/javascript/readability/node_modules/@mozilla/readability/index.js", "resolvedModule": "./node_modules/@mozilla/readability/index.js", "type": "cjs require", "active": true, @@ -1097,9 +1263,9 @@ "codeGenerated": true, "buildTimeExecuted": false, "cached": false, - "identifier": "/home/fafre/Repos/kagi_bang_bang/app/js/readability/node_modules/@mozilla/readability/Readability-readerable.js", + "identifier": "/home/fafre/Repos/kagi_bang_bang/packages/flutter_mozilla_components/javascript/readability/node_modules/@mozilla/readability/Readability-readerable.js", "name": "./node_modules/@mozilla/readability/Readability-readerable.js", - "nameForCondition": "/home/fafre/Repos/kagi_bang_bang/app/js/readability/node_modules/@mozilla/readability/Readability-readerable.js", + "nameForCondition": "/home/fafre/Repos/kagi_bang_bang/packages/flutter_mozilla_components/javascript/readability/node_modules/@mozilla/readability/Readability-readerable.js", "index": 3, "preOrderIndex": 3, "index2": 1, @@ -1107,16 +1273,16 @@ "cacheable": true, "optional": false, "orphan": false, - "issuer": "/home/fafre/Repos/kagi_bang_bang/app/js/readability/node_modules/@mozilla/readability/index.js", + "issuer": "/home/fafre/Repos/kagi_bang_bang/packages/flutter_mozilla_components/javascript/readability/node_modules/@mozilla/readability/index.js", "issuerName": "./node_modules/@mozilla/readability/index.js", "issuerPath": [ { - "identifier": "/home/fafre/Repos/kagi_bang_bang/app/js/readability/node_modules/babel-loader/lib/index.js??ruleSet[1].rules[0].use!/home/fafre/Repos/kagi_bang_bang/app/js/readability/src/index.js", + "identifier": "/home/fafre/Repos/kagi_bang_bang/packages/flutter_mozilla_components/javascript/readability/node_modules/babel-loader/lib/index.js??ruleSet[1].rules[0].use!/home/fafre/Repos/kagi_bang_bang/packages/flutter_mozilla_components/javascript/readability/src/index.js", "name": "./src/index.js", - "id": 954 + "id": null }, { - "identifier": "/home/fafre/Repos/kagi_bang_bang/app/js/readability/node_modules/@mozilla/readability/index.js", + "identifier": "/home/fafre/Repos/kagi_bang_bang/packages/flutter_mozilla_components/javascript/readability/node_modules/@mozilla/readability/index.js", "name": "./node_modules/@mozilla/readability/index.js", "id": 396 } @@ -1132,10 +1298,10 @@ "assets": [], "reasons": [ { - "moduleIdentifier": "/home/fafre/Repos/kagi_bang_bang/app/js/readability/node_modules/@mozilla/readability/Readability-readerable.js", + "moduleIdentifier": "/home/fafre/Repos/kagi_bang_bang/packages/flutter_mozilla_components/javascript/readability/node_modules/@mozilla/readability/Readability-readerable.js", "module": "./node_modules/@mozilla/readability/Readability-readerable.js", "moduleName": "./node_modules/@mozilla/readability/Readability-readerable.js", - "resolvedModuleIdentifier": "/home/fafre/Repos/kagi_bang_bang/app/js/readability/node_modules/@mozilla/readability/Readability-readerable.js", + "resolvedModuleIdentifier": "/home/fafre/Repos/kagi_bang_bang/packages/flutter_mozilla_components/javascript/readability/node_modules/@mozilla/readability/Readability-readerable.js", "resolvedModule": "./node_modules/@mozilla/readability/Readability-readerable.js", "type": "cjs self exports reference", "active": true, @@ -1146,10 +1312,10 @@ "resolvedModuleId": 804 }, { - "moduleIdentifier": "/home/fafre/Repos/kagi_bang_bang/app/js/readability/node_modules/@mozilla/readability/index.js", + "moduleIdentifier": "/home/fafre/Repos/kagi_bang_bang/packages/flutter_mozilla_components/javascript/readability/node_modules/@mozilla/readability/index.js", "module": "./node_modules/@mozilla/readability/index.js", "moduleName": "./node_modules/@mozilla/readability/index.js", - "resolvedModuleIdentifier": "/home/fafre/Repos/kagi_bang_bang/app/js/readability/node_modules/@mozilla/readability/index.js", + "resolvedModuleIdentifier": "/home/fafre/Repos/kagi_bang_bang/packages/flutter_mozilla_components/javascript/readability/node_modules/@mozilla/readability/index.js", "resolvedModule": "./node_modules/@mozilla/readability/index.js", "type": "cjs require", "active": true, @@ -1169,41 +1335,6 @@ ], "depth": 2 }, - { - "type": "module", - "moduleType": "runtime", - "layer": null, - "size": 267, - "sizes": { - "runtime": 267 - }, - "built": false, - "codeGenerated": true, - "buildTimeExecuted": false, - "cached": false, - "identifier": "webpack/runtime/compat get default export", - "name": "webpack/runtime/compat get default export", - "nameForCondition": null, - "index": null, - "preOrderIndex": null, - "index2": null, - "postOrderIndex": null, - "optional": false, - "orphan": false, - "failed": false, - "errors": 0, - "warnings": 0, - "id": "", - "chunks": [ - 792 - ], - "assets": [], - "reasons": [], - "usedExports": null, - "providedExports": [], - "optimizationBailout": [], - "depth": null - }, { "type": "module", "moduleType": "runtime", @@ -1319,11 +1450,11 @@ "assets": [ { "name": "readability.min.js", - "size": 55954 + "size": 48006 } ], "filteredAssets": 0, - "assetsSize": 55954, + "assetsSize": 48006, "auxiliaryAssets": [], "filteredAuxiliaryAssets": 0, "auxiliaryAssetsSize": 0, @@ -1341,11 +1472,11 @@ "assets": [ { "name": "readability.min.js", - "size": 55954 + "size": 48006 } ], "filteredAssets": 0, - "assetsSize": 55954, + "assetsSize": 48006, "auxiliaryAssets": [], "filteredAuxiliaryAssets": 0, "auxiliaryAssetsSize": 0, diff --git a/app/js/readability/package-lock.json b/packages/flutter_mozilla_components/javascript/readability/package-lock.json similarity index 69% rename from app/js/readability/package-lock.json rename to packages/flutter_mozilla_components/javascript/readability/package-lock.json index b8cf6af2..535bdc55 100644 --- a/app/js/readability/package-lock.json +++ b/packages/flutter_mozilla_components/javascript/readability/package-lock.json @@ -10,16 +10,16 @@ "license": "ISC", "dependencies": { "@mozilla/readability": "^0.5.0", - "dompurify": "^3.1.6" + "remove-markdown": "^0.5.5", + "turndown": "^7.2.0" }, "devDependencies": { - "@babel/core": "^7.24.7", - "@babel/preset-env": "^7.24.7", - "babel-loader": "^9.1.3", + "@babel/core": "^7.26.0", + "@babel/preset-env": "^7.26.0", + "babel-loader": "^9.2.1", "clean-webpack-plugin": "^4.0.0", - "compression-webpack-plugin": "^11.1.0", "terser-webpack-plugin": "^5.3.10", - "webpack": "^5.92.1", + "webpack": "^5.96.1", "webpack-bundle-analyzer": "^4.10.2", "webpack-cli": "^5.1.4" } @@ -39,13 +39,14 @@ } }, "node_modules/@babel/code-frame": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.24.7.tgz", - "integrity": "sha512-BcYH1CVJBO9tvyIZ2jVeXgSIMvGZ2FDRvDdOIVQyuklNKSsx+eppDEBq/g47Ayw+RqNFE+URvOShmf+f/qwAlA==", + "version": "7.26.2", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.26.2.tgz", + "integrity": "sha512-RJlIHRueQgwWitWgF8OdFYGZX328Ax5BCemNGlqHfplnRT9ESi8JkFlvaVYbS+UubVY6dpv87Fs2u5M29iNFVQ==", "dev": true, "license": "MIT", "dependencies": { - "@babel/highlight": "^7.24.7", + "@babel/helper-validator-identifier": "^7.25.9", + "js-tokens": "^4.0.0", "picocolors": "^1.0.0" }, "engines": { @@ -53,9 +54,9 @@ } }, "node_modules/@babel/compat-data": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.24.7.tgz", - "integrity": "sha512-qJzAIcv03PyaWqxRgO4mSU3lihncDT296vnyuE2O8uA4w3UHWI4S3hgeZd1L8W1Bft40w9JxJ2b412iDUFFRhw==", + "version": "7.26.2", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.26.2.tgz", + "integrity": "sha512-Z0WgzSEa+aUcdiJuCIqgujCshpMWgUpgOxXotrYPSA53hA3qopNaqcJpyr0hVb1FeWdnqFA35/fUtXgBK8srQg==", "dev": true, "license": "MIT", "engines": { @@ -63,22 +64,22 @@ } }, "node_modules/@babel/core": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.24.7.tgz", - "integrity": "sha512-nykK+LEK86ahTkX/3TgauT0ikKoNCfKHEaZYTUVupJdTLzGNvrblu4u6fa7DhZONAltdf8e662t/abY8idrd/g==", + "version": "7.26.0", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.26.0.tgz", + "integrity": "sha512-i1SLeK+DzNnQ3LL/CswPCa/E5u4lh1k6IAEphON8F+cXt0t9euTshDru0q7/IqMa1PMPz5RnHuHscF8/ZJsStg==", "dev": true, "license": "MIT", "dependencies": { "@ampproject/remapping": "^2.2.0", - "@babel/code-frame": "^7.24.7", - "@babel/generator": "^7.24.7", - "@babel/helper-compilation-targets": "^7.24.7", - "@babel/helper-module-transforms": "^7.24.7", - "@babel/helpers": "^7.24.7", - "@babel/parser": "^7.24.7", - "@babel/template": "^7.24.7", - "@babel/traverse": "^7.24.7", - "@babel/types": "^7.24.7", + "@babel/code-frame": "^7.26.0", + "@babel/generator": "^7.26.0", + "@babel/helper-compilation-targets": "^7.25.9", + "@babel/helper-module-transforms": "^7.26.0", + "@babel/helpers": "^7.26.0", + "@babel/parser": "^7.26.0", + "@babel/template": "^7.25.9", + "@babel/traverse": "^7.25.9", + "@babel/types": "^7.26.0", "convert-source-map": "^2.0.0", "debug": "^4.1.0", "gensync": "^1.0.0-beta.2", @@ -94,58 +95,59 @@ } }, "node_modules/@babel/generator": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.24.7.tgz", - "integrity": "sha512-oipXieGC3i45Y1A41t4tAqpnEZWgB/lC6Ehh6+rOviR5XWpTtMmLN+fGjz9vOiNRt0p6RtO6DtD0pdU3vpqdSA==", + "version": "7.26.2", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.26.2.tgz", + "integrity": "sha512-zevQbhbau95nkoxSq3f/DC/SC+EEOUZd3DYqfSkMhY2/wfSeaHV1Ew4vk8e+x8lja31IbyuUa2uQ3JONqKbysw==", "dev": true, "license": "MIT", "dependencies": { - "@babel/types": "^7.24.7", + "@babel/parser": "^7.26.2", + "@babel/types": "^7.26.0", "@jridgewell/gen-mapping": "^0.3.5", "@jridgewell/trace-mapping": "^0.3.25", - "jsesc": "^2.5.1" + "jsesc": "^3.0.2" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-annotate-as-pure": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.24.7.tgz", - "integrity": "sha512-BaDeOonYvhdKw+JoMVkAixAAJzG2jVPIwWoKBPdYuY9b452e2rPuI9QPYh3KpofZ3pW2akOmwZLOiOsHMiqRAg==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.25.9.tgz", + "integrity": "sha512-gv7320KBUFJz1RnylIg5WWYPRXKZ884AGkYpgpWW02TH66Dl+HaC1t1CKd0z3R4b6hdYEcmrNZHUmfCP+1u3/g==", "dev": true, "license": "MIT", "dependencies": { - "@babel/types": "^7.24.7" + "@babel/types": "^7.25.9" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-builder-binary-assignment-operator-visitor": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.24.7.tgz", - "integrity": "sha512-xZeCVVdwb4MsDBkkyZ64tReWYrLRHlMN72vP7Bdm3OUOuyFZExhsHUUnuWnm2/XOlAJzR0LfPpB56WXZn0X/lA==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.25.9.tgz", + "integrity": "sha512-C47lC7LIDCnz0h4vai/tpNOI95tCd5ZT3iBt/DBH5lXKHZsyNQv18yf1wIIg2ntiQNgmAvA+DgZ82iW8Qdym8g==", "dev": true, "license": "MIT", "dependencies": { - "@babel/traverse": "^7.24.7", - "@babel/types": "^7.24.7" + "@babel/traverse": "^7.25.9", + "@babel/types": "^7.25.9" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-compilation-targets": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.24.7.tgz", - "integrity": "sha512-ctSdRHBi20qWOfy27RUb4Fhp07KSJ3sXcuSvTrXrc4aG8NSYDo1ici3Vhg9bg69y5bj0Mr1lh0aeEgTvc12rMg==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.25.9.tgz", + "integrity": "sha512-j9Db8Suy6yV/VHa4qzrj9yZfZxhLWQdVnRlXxmKLYlhWUVB1sB2G5sxuWYXk/whHD9iW76PmNzxZ4UCnTQTVEQ==", "dev": true, "license": "MIT", "dependencies": { - "@babel/compat-data": "^7.24.7", - "@babel/helper-validator-option": "^7.24.7", - "browserslist": "^4.22.2", + "@babel/compat-data": "^7.25.9", + "@babel/helper-validator-option": "^7.25.9", + "browserslist": "^4.24.0", "lru-cache": "^5.1.1", "semver": "^6.3.1" }, @@ -154,20 +156,18 @@ } }, "node_modules/@babel/helper-create-class-features-plugin": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.24.7.tgz", - "integrity": "sha512-kTkaDl7c9vO80zeX1rJxnuRpEsD5tA81yh11X1gQo+PhSti3JS+7qeZo9U4RHobKRiFPKaGK3svUAeb8D0Q7eg==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.25.9.tgz", + "integrity": "sha512-UTZQMvt0d/rSz6KI+qdu7GQze5TIajwTS++GUozlw8VBJDEOAqSXwm1WvmYEZwqdqSGQshRocPDqrt4HBZB3fQ==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-annotate-as-pure": "^7.24.7", - "@babel/helper-environment-visitor": "^7.24.7", - "@babel/helper-function-name": "^7.24.7", - "@babel/helper-member-expression-to-functions": "^7.24.7", - "@babel/helper-optimise-call-expression": "^7.24.7", - "@babel/helper-replace-supers": "^7.24.7", - "@babel/helper-skip-transparent-expression-wrappers": "^7.24.7", - "@babel/helper-split-export-declaration": "^7.24.7", + "@babel/helper-annotate-as-pure": "^7.25.9", + "@babel/helper-member-expression-to-functions": "^7.25.9", + "@babel/helper-optimise-call-expression": "^7.25.9", + "@babel/helper-replace-supers": "^7.25.9", + "@babel/helper-skip-transparent-expression-wrappers": "^7.25.9", + "@babel/traverse": "^7.25.9", "semver": "^6.3.1" }, "engines": { @@ -178,14 +178,14 @@ } }, "node_modules/@babel/helper-create-regexp-features-plugin": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.24.7.tgz", - "integrity": "sha512-03TCmXy2FtXJEZfbXDTSqq1fRJArk7lX9DOFC/47VthYcxyIOx+eXQmdo6DOQvrbpIix+KfXwvuXdFDZHxt+rA==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.25.9.tgz", + "integrity": "sha512-ORPNZ3h6ZRkOyAa/SaHU+XsLZr0UQzRwuDQ0cczIA17nAzZ+85G5cVkOJIj7QavLZGSe8QXUmNFxSZzjcZF9bw==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-annotate-as-pure": "^7.24.7", - "regexpu-core": "^5.3.1", + "@babel/helper-annotate-as-pure": "^7.25.9", + "regexpu-core": "^6.1.1", "semver": "^6.3.1" }, "engines": { @@ -212,86 +212,44 @@ "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" } }, - "node_modules/@babel/helper-environment-visitor": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.24.7.tgz", - "integrity": "sha512-DoiN84+4Gnd0ncbBOM9AZENV4a5ZiL39HYMyZJGZ/AZEykHYdJw0wW3kdcsh9/Kn+BRXHLkkklZ51ecPKmI1CQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/types": "^7.24.7" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-function-name": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.24.7.tgz", - "integrity": "sha512-FyoJTsj/PEUWu1/TYRiXTIHc8lbw+TDYkZuoE43opPS5TrI7MyONBE1oNvfguEXAD9yhQRrVBnXdXzSLQl9XnA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/template": "^7.24.7", - "@babel/types": "^7.24.7" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-hoist-variables": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.24.7.tgz", - "integrity": "sha512-MJJwhkoGy5c4ehfoRyrJ/owKeMl19U54h27YYftT0o2teQ3FJ3nQUf/I3LlJsX4l3qlw7WRXUmiyajvHXoTubQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/types": "^7.24.7" - }, - "engines": { - "node": ">=6.9.0" - } - }, "node_modules/@babel/helper-member-expression-to-functions": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.24.7.tgz", - "integrity": "sha512-LGeMaf5JN4hAT471eJdBs/GK1DoYIJ5GCtZN/EsL6KUiiDZOvO/eKE11AMZJa2zP4zk4qe9V2O/hxAmkRc8p6w==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.25.9.tgz", + "integrity": "sha512-wbfdZ9w5vk0C0oyHqAJbc62+vet5prjj01jjJ8sKn3j9h3MQQlflEdXYvuqRWjHnM12coDEqiC1IRCi0U/EKwQ==", "dev": true, "license": "MIT", "dependencies": { - "@babel/traverse": "^7.24.7", - "@babel/types": "^7.24.7" + "@babel/traverse": "^7.25.9", + "@babel/types": "^7.25.9" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-module-imports": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.24.7.tgz", - "integrity": "sha512-8AyH3C+74cgCVVXow/myrynrAGv+nTVg5vKu2nZph9x7RcRwzmh0VFallJuFTZ9mx6u4eSdXZfcOzSqTUm0HCA==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.25.9.tgz", + "integrity": "sha512-tnUA4RsrmflIM6W6RFTLFSXITtl0wKjgpnLgXyowocVPrbYrLUXSBXDgTs8BlbmIzIdlBySRQjINYs2BAkiLtw==", "dev": true, "license": "MIT", "dependencies": { - "@babel/traverse": "^7.24.7", - "@babel/types": "^7.24.7" + "@babel/traverse": "^7.25.9", + "@babel/types": "^7.25.9" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-module-transforms": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.24.7.tgz", - "integrity": "sha512-1fuJEwIrp+97rM4RWdO+qrRsZlAeL1lQJoPqtCYWv0NL115XM93hIH4CSRln2w52SqvmY5hqdtauB6QFCDiZNQ==", + "version": "7.26.0", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.26.0.tgz", + "integrity": "sha512-xO+xu6B5K2czEnQye6BHA7DolFFmS3LB7stHZFaOLb1pAwO1HWLS8fXA+eh0A2yIvltPVmx3eNNDBJA2SLHXFw==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-environment-visitor": "^7.24.7", - "@babel/helper-module-imports": "^7.24.7", - "@babel/helper-simple-access": "^7.24.7", - "@babel/helper-split-export-declaration": "^7.24.7", - "@babel/helper-validator-identifier": "^7.24.7" + "@babel/helper-module-imports": "^7.25.9", + "@babel/helper-validator-identifier": "^7.25.9", + "@babel/traverse": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -301,22 +259,22 @@ } }, "node_modules/@babel/helper-optimise-call-expression": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.24.7.tgz", - "integrity": "sha512-jKiTsW2xmWwxT1ixIdfXUZp+P5yURx2suzLZr5Hi64rURpDYdMW0pv+Uf17EYk2Rd428Lx4tLsnjGJzYKDM/6A==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.25.9.tgz", + "integrity": "sha512-FIpuNaz5ow8VyrYcnXQTDRGvV6tTjkNtCK/RYNDXGSLlUD6cBuQTSw43CShGxjvfBTfcUA/r6UhUCbtYqkhcuQ==", "dev": true, "license": "MIT", "dependencies": { - "@babel/types": "^7.24.7" + "@babel/types": "^7.25.9" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-plugin-utils": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.24.7.tgz", - "integrity": "sha512-Rq76wjt7yz9AAc1KnlRKNAi/dMSVWgDRx43FHoJEbcYU6xOWaE2dVPwcdTukJrjxS65GITyfbvEYHvkirZ6uEg==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.25.9.tgz", + "integrity": "sha512-kSMlyUVdWe25rEsRGviIgOWnoT/nfABVWlqt9N19/dIPWViAOW2s9wznP5tURbs/IDuNk4gPy3YdYRgH3uxhBw==", "dev": true, "license": "MIT", "engines": { @@ -324,15 +282,15 @@ } }, "node_modules/@babel/helper-remap-async-to-generator": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.24.7.tgz", - "integrity": "sha512-9pKLcTlZ92hNZMQfGCHImUpDOlAgkkpqalWEeftW5FBya75k8Li2ilerxkM/uBEj01iBZXcCIB/bwvDYgWyibA==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.25.9.tgz", + "integrity": "sha512-IZtukuUeBbhgOcaW2s06OXTzVNJR0ybm4W5xC1opWFFJMZbwRj5LCk+ByYH7WdZPZTt8KnFwA8pvjN2yqcPlgw==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-annotate-as-pure": "^7.24.7", - "@babel/helper-environment-visitor": "^7.24.7", - "@babel/helper-wrap-function": "^7.24.7" + "@babel/helper-annotate-as-pure": "^7.25.9", + "@babel/helper-wrap-function": "^7.25.9", + "@babel/traverse": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -342,15 +300,15 @@ } }, "node_modules/@babel/helper-replace-supers": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.24.7.tgz", - "integrity": "sha512-qTAxxBM81VEyoAY0TtLrx1oAEJc09ZK67Q9ljQToqCnA+55eNwCORaxlKyu+rNfX86o8OXRUSNUnrtsAZXM9sg==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.25.9.tgz", + "integrity": "sha512-IiDqTOTBQy0sWyeXyGSC5TBJpGFXBkRynjBeXsvbhQFKj2viwJC76Epz35YLU1fpe/Am6Vppb7W7zM4fPQzLsQ==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-environment-visitor": "^7.24.7", - "@babel/helper-member-expression-to-functions": "^7.24.7", - "@babel/helper-optimise-call-expression": "^7.24.7" + "@babel/helper-member-expression-to-functions": "^7.25.9", + "@babel/helper-optimise-call-expression": "^7.25.9", + "@babel/traverse": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -360,50 +318,37 @@ } }, "node_modules/@babel/helper-simple-access": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.24.7.tgz", - "integrity": "sha512-zBAIvbCMh5Ts+b86r/CjU+4XGYIs+R1j951gxI3KmmxBMhCg4oQMsv6ZXQ64XOm/cvzfU1FmoCyt6+owc5QMYg==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.25.9.tgz", + "integrity": "sha512-c6WHXuiaRsJTyHYLJV75t9IqsmTbItYfdj99PnzYGQZkYKvan5/2jKJ7gu31J3/BJ/A18grImSPModuyG/Eo0Q==", "dev": true, "license": "MIT", "dependencies": { - "@babel/traverse": "^7.24.7", - "@babel/types": "^7.24.7" + "@babel/traverse": "^7.25.9", + "@babel/types": "^7.25.9" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-skip-transparent-expression-wrappers": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.24.7.tgz", - "integrity": "sha512-IO+DLT3LQUElMbpzlatRASEyQtfhSE0+m465v++3jyyXeBTBUjtVZg28/gHeV5mrTJqvEKhKroBGAvhW+qPHiQ==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.25.9.tgz", + "integrity": "sha512-K4Du3BFa3gvyhzgPcntrkDgZzQaq6uozzcpGbOO1OEJaI+EJdqWIMTLgFgQf6lrfiDFo5FU+BxKepI9RmZqahA==", "dev": true, "license": "MIT", "dependencies": { - "@babel/traverse": "^7.24.7", - "@babel/types": "^7.24.7" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-split-export-declaration": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.24.7.tgz", - "integrity": "sha512-oy5V7pD+UvfkEATUKvIjvIAH/xCzfsFVw7ygW2SI6NClZzquT+mwdTfgfdbUiceh6iQO0CHtCPsyze/MZ2YbAA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/types": "^7.24.7" + "@babel/traverse": "^7.25.9", + "@babel/types": "^7.25.9" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-string-parser": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.24.7.tgz", - "integrity": "sha512-7MbVt6xrwFQbunH2DNQsAP5sTGxfqQtErvBIvIMi6EQnbgUOuVYanvREcmFrOPhoXBrTtjhhP+lW+o5UfK+tDg==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.25.9.tgz", + "integrity": "sha512-4A/SCr/2KLd5jrtOMFzaKjVtAei3+2r/NChoBNoZ3EyP/+GlhoaEGoWOZUmFmoITP7zOJyHIMm+DYRd8o3PvHA==", "dev": true, "license": "MIT", "engines": { @@ -411,9 +356,9 @@ } }, "node_modules/@babel/helper-validator-identifier": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.24.7.tgz", - "integrity": "sha512-rR+PBcQ1SMQDDyF6X0wxtG8QyLCgUB0eRAGguqRLfkCA87l7yAP7ehq8SNj96OOGTO8OBV70KhuFYcIkHXOg0w==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.25.9.tgz", + "integrity": "sha512-Ed61U6XJc3CVRfkERJWDz4dJwKe7iLmmJsbOGu9wSloNSFttHV0I8g6UAgb7qnK5ly5bGLPd4oXZlxCdANBOWQ==", "dev": true, "license": "MIT", "engines": { @@ -421,9 +366,9 @@ } }, "node_modules/@babel/helper-validator-option": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.24.7.tgz", - "integrity": "sha512-yy1/KvjhV/ZCL+SM7hBrvnZJ3ZuT9OuZgIJAGpPEToANvc3iM6iDvBnRjtElWibHU6n8/LPR/EjX9EtIEYO3pw==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.25.9.tgz", + "integrity": "sha512-e/zv1co8pp55dNdEcCynfj9X7nyUKUXoUEwfXqaZt0omVOmDe9oOTdKStH4GmAw6zxMFs50ZayuMfHDKlO7Tfw==", "dev": true, "license": "MIT", "engines": { @@ -431,57 +376,43 @@ } }, "node_modules/@babel/helper-wrap-function": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.24.7.tgz", - "integrity": "sha512-N9JIYk3TD+1vq/wn77YnJOqMtfWhNewNE+DJV4puD2X7Ew9J4JvrzrFDfTfyv5EgEXVy9/Wt8QiOErzEmv5Ifw==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.25.9.tgz", + "integrity": "sha512-ETzz9UTjQSTmw39GboatdymDq4XIQbR8ySgVrylRhPOFpsd+JrKHIuF0de7GCWmem+T4uC5z7EZguod7Wj4A4g==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-function-name": "^7.24.7", - "@babel/template": "^7.24.7", - "@babel/traverse": "^7.24.7", - "@babel/types": "^7.24.7" + "@babel/template": "^7.25.9", + "@babel/traverse": "^7.25.9", + "@babel/types": "^7.25.9" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helpers": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.24.7.tgz", - "integrity": "sha512-NlmJJtvcw72yRJRcnCmGvSi+3jDEg8qFu3z0AFoymmzLx5ERVWyzd9kVXr7Th9/8yIJi2Zc6av4Tqz3wFs8QWg==", + "version": "7.26.0", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.26.0.tgz", + "integrity": "sha512-tbhNuIxNcVb21pInl3ZSjksLCvgdZy9KwJ8brv993QtIVKJBBkYXz4q4ZbAv31GdnC+R90np23L5FbEBlthAEw==", "dev": true, "license": "MIT", "dependencies": { - "@babel/template": "^7.24.7", - "@babel/types": "^7.24.7" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/highlight": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.24.7.tgz", - "integrity": "sha512-EStJpq4OuY8xYfhGVXngigBJRWxftKX9ksiGDnmlY3o7B/V7KIAc9X4oiK87uPJSc/vs5L869bem5fhZa8caZw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-validator-identifier": "^7.24.7", - "chalk": "^2.4.2", - "js-tokens": "^4.0.0", - "picocolors": "^1.0.0" + "@babel/template": "^7.25.9", + "@babel/types": "^7.26.0" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/parser": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.24.7.tgz", - "integrity": "sha512-9uUYRm6OqQrCqQdG1iCBwBPZgN8ciDBro2nIOFaiRz1/BCxaI7CNvQbDHvsArAC7Tw9Hda/B3U+6ui9u4HWXPw==", + "version": "7.26.2", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.26.2.tgz", + "integrity": "sha512-DWMCZH9WA4Maitz2q21SRKHo9QXZxkDsbNZoVD62gusNtNBBqDg9i7uOhASfTfIGNzW+O+r7+jAlM8dwphcJKQ==", "dev": true, "license": "MIT", + "dependencies": { + "@babel/types": "^7.26.0" + }, "bin": { "parser": "bin/babel-parser.js" }, @@ -490,14 +421,30 @@ } }, "node_modules/@babel/plugin-bugfix-firefox-class-in-computed-class-key": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-firefox-class-in-computed-class-key/-/plugin-bugfix-firefox-class-in-computed-class-key-7.24.7.tgz", - "integrity": "sha512-TiT1ss81W80eQsN+722OaeQMY/G4yTb4G9JrqeiDADs3N8lbPMGldWi9x8tyqCW5NLx1Jh2AvkE6r6QvEltMMQ==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-firefox-class-in-computed-class-key/-/plugin-bugfix-firefox-class-in-computed-class-key-7.25.9.tgz", + "integrity": "sha512-ZkRyVkThtxQ/J6nv3JFYv1RYY+JT5BvU0y3k5bWrmuG4woXypRa4PXmm9RhOwodRkYFWqC0C0cqcJ4OqR7kW+g==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-environment-visitor": "^7.24.7", - "@babel/helper-plugin-utils": "^7.24.7" + "@babel/helper-plugin-utils": "^7.25.9", + "@babel/traverse": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-bugfix-safari-class-field-initializer-scope": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-class-field-initializer-scope/-/plugin-bugfix-safari-class-field-initializer-scope-7.25.9.tgz", + "integrity": "sha512-MrGRLZxLD/Zjj0gdU15dfs+HH/OXvnw/U4jJD8vpcP2CJQapPEv1IWwjc/qMg7ItBlPwSv1hRBbb7LeuANdcnw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -507,13 +454,13 @@ } }, "node_modules/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.24.7.tgz", - "integrity": "sha512-unaQgZ/iRu/By6tsjMZzpeBZjChYfLYry6HrEXPoz3KmfF0sVBQ1l8zKMQ4xRGLWVsjuvB8nQfjNP/DcfEOCsg==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.25.9.tgz", + "integrity": "sha512-2qUwwfAFpJLZqxd02YW9btUCZHl+RFvdDkNfZwaIJrvB8Tesjsk8pEQkTvGwZXLqXUx/2oyY3ySRhm6HOXuCug==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7" + "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -523,15 +470,15 @@ } }, "node_modules/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.24.7.tgz", - "integrity": "sha512-+izXIbke1T33mY4MSNnrqhPXDz01WYhEf3yF5NbnUtkiNnm+XBZJl3kNfoK6NKmYlz/D07+l2GWVK/QfDkNCuQ==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.25.9.tgz", + "integrity": "sha512-6xWgLZTJXwilVjlnV7ospI3xi+sl8lN8rXXbBD6vYn3UYDlGsag8wrZkKcSI8G6KgqKP7vNFaDgeDnfAABq61g==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7", - "@babel/helper-skip-transparent-expression-wrappers": "^7.24.7", - "@babel/plugin-transform-optional-chaining": "^7.24.7" + "@babel/helper-plugin-utils": "^7.25.9", + "@babel/helper-skip-transparent-expression-wrappers": "^7.25.9", + "@babel/plugin-transform-optional-chaining": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -541,14 +488,14 @@ } }, "node_modules/@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly/-/plugin-bugfix-v8-static-class-fields-redefine-readonly-7.24.7.tgz", - "integrity": "sha512-utA4HuR6F4Vvcr+o4DnjL8fCOlgRFGbeeBEGNg3ZTrLFw6VWG5XmUrvcQ0FjIYMU2ST4XcR2Wsp7t9qOAPnxMg==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly/-/plugin-bugfix-v8-static-class-fields-redefine-readonly-7.25.9.tgz", + "integrity": "sha512-aLnMXYPnzwwqhYSCyXfKkIkYgJ8zv9RK+roo9DkTXz38ynIhd9XCbN08s3MGvqL2MYGVUGdRQLL/JqBIeJhJBg==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-environment-visitor": "^7.24.7", - "@babel/helper-plugin-utils": "^7.24.7" + "@babel/helper-plugin-utils": "^7.25.9", + "@babel/traverse": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -570,82 +517,14 @@ "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-syntax-async-generators": { - "version": "7.8.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz", - "integrity": "sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-class-properties": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz", - "integrity": "sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.12.13" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-class-static-block": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-static-block/-/plugin-syntax-class-static-block-7.14.5.tgz", - "integrity": "sha512-b+YyPmr6ldyNnM6sqYeMWE+bgJcJpO6yS4QD7ymxgH34GBPNDM/THBh8iunyvKIZztiwLH4CJZ0RxTk9emgpjw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.14.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-dynamic-import": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-dynamic-import/-/plugin-syntax-dynamic-import-7.8.3.tgz", - "integrity": "sha512-5gdGbFon+PszYzqs83S3E5mpi7/y/8M9eC90MRTZfduQOYW76ig6SOSPNe41IG5LoP3FGBn2N0RjVDSQiS94kQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-export-namespace-from": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-export-namespace-from/-/plugin-syntax-export-namespace-from-7.8.3.tgz", - "integrity": "sha512-MXf5laXo6c1IbEbegDmzGPwGNTsHZmEy6QGznu5Sh2UCWvueywb2ee+CCE4zQiZstxU9BMoQO9i6zUFSY0Kj0Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.3" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, "node_modules/@babel/plugin-syntax-import-assertions": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-assertions/-/plugin-syntax-import-assertions-7.24.7.tgz", - "integrity": "sha512-Ec3NRUMoi8gskrkBe3fNmEQfxDvY8bgfQpz6jlk/41kX9eUjvpyqWU7PBP/pLAvMaSQjbMNKJmvX57jP+M6bPg==", + "version": "7.26.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-assertions/-/plugin-syntax-import-assertions-7.26.0.tgz", + "integrity": "sha512-QCWT5Hh830hK5EQa7XzuqIkQU9tT/whqbDz7kuaZMHFl1inRRg7JnuAEOQ0Ur0QUl0NufCk1msK2BeY79Aj/eg==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7" + "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -655,149 +534,13 @@ } }, "node_modules/@babel/plugin-syntax-import-attributes": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.24.7.tgz", - "integrity": "sha512-hbX+lKKeUMGihnK8nvKqmXBInriT3GVjzXKFriV3YC6APGxMbP8RZNFwy91+hocLXq90Mta+HshoB31802bb8A==", + "version": "7.26.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.26.0.tgz", + "integrity": "sha512-e2dttdsJ1ZTpi3B9UYGLw41hifAubg19AtCu/2I/F1QNVclOBr1dYpTdmdyZ84Xiz43BS/tCUkMAZNLv12Pi+A==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-import-meta": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz", - "integrity": "sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.10.4" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-json-strings": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz", - "integrity": "sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-logical-assignment-operators": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz", - "integrity": "sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.10.4" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-nullish-coalescing-operator": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz", - "integrity": "sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-numeric-separator": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz", - "integrity": "sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.10.4" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-object-rest-spread": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz", - "integrity": "sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-optional-catch-binding": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz", - "integrity": "sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-optional-chaining": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz", - "integrity": "sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-private-property-in-object": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-private-property-in-object/-/plugin-syntax-private-property-in-object-7.14.5.tgz", - "integrity": "sha512-0wVnp9dxJ72ZUJDV27ZfbSj6iHLoytYZmh3rFcxNnvsJF3ktkzLDZPy/mA17HGsaQT3/DQsWYX1f1QGWkCoVUg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.14.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-top-level-await": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz", - "integrity": "sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.14.5" + "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -824,13 +567,13 @@ } }, "node_modules/@babel/plugin-transform-arrow-functions": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.24.7.tgz", - "integrity": "sha512-Dt9LQs6iEY++gXUwY03DNFat5C2NbO48jj+j/bSAz6b3HgPs39qcPiYt77fDObIcFwj3/C2ICX9YMwGflUoSHQ==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.25.9.tgz", + "integrity": "sha512-6jmooXYIwn9ca5/RylZADJ+EnSxVUS5sjeJ9UPk6RWRzXCmOJCy6dqItPJFpw2cuCangPK4OYr5uhGKcmrm5Qg==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7" + "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -840,16 +583,15 @@ } }, "node_modules/@babel/plugin-transform-async-generator-functions": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-generator-functions/-/plugin-transform-async-generator-functions-7.24.7.tgz", - "integrity": "sha512-o+iF77e3u7ZS4AoAuJvapz9Fm001PuD2V3Lp6OSE4FYQke+cSewYtnek+THqGRWyQloRCyvWL1OkyfNEl9vr/g==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-generator-functions/-/plugin-transform-async-generator-functions-7.25.9.tgz", + "integrity": "sha512-RXV6QAzTBbhDMO9fWwOmwwTuYaiPbggWQ9INdZqAYeSHyG7FzQ+nOZaUUjNwKv9pV3aE4WFqFm1Hnbci5tBCAw==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-environment-visitor": "^7.24.7", - "@babel/helper-plugin-utils": "^7.24.7", - "@babel/helper-remap-async-to-generator": "^7.24.7", - "@babel/plugin-syntax-async-generators": "^7.8.4" + "@babel/helper-plugin-utils": "^7.25.9", + "@babel/helper-remap-async-to-generator": "^7.25.9", + "@babel/traverse": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -859,15 +601,15 @@ } }, "node_modules/@babel/plugin-transform-async-to-generator": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.24.7.tgz", - "integrity": "sha512-SQY01PcJfmQ+4Ash7NE+rpbLFbmqA2GPIgqzxfFTL4t1FKRq4zTms/7htKpoCUI9OcFYgzqfmCdH53s6/jn5fA==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.25.9.tgz", + "integrity": "sha512-NT7Ejn7Z/LjUH0Gv5KsBCxh7BH3fbLTV0ptHvpeMvrt3cPThHfJfst9Wrb7S8EvJ7vRTFI7z+VAvFVEQn/m5zQ==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-module-imports": "^7.24.7", - "@babel/helper-plugin-utils": "^7.24.7", - "@babel/helper-remap-async-to-generator": "^7.24.7" + "@babel/helper-module-imports": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9", + "@babel/helper-remap-async-to-generator": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -877,13 +619,13 @@ } }, "node_modules/@babel/plugin-transform-block-scoped-functions": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.24.7.tgz", - "integrity": "sha512-yO7RAz6EsVQDaBH18IDJcMB1HnrUn2FJ/Jslc/WtPPWcjhpUJXU/rjbwmluzp7v/ZzWcEhTMXELnnsz8djWDwQ==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.25.9.tgz", + "integrity": "sha512-toHc9fzab0ZfenFpsyYinOX0J/5dgJVA2fm64xPewu7CoYHWEivIWKxkK2rMi4r3yQqLnVmheMXRdG+k239CgA==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7" + "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -893,13 +635,13 @@ } }, "node_modules/@babel/plugin-transform-block-scoping": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.24.7.tgz", - "integrity": "sha512-Nd5CvgMbWc+oWzBsuaMcbwjJWAcp5qzrbg69SZdHSP7AMY0AbWFqFO0WTFCA1jxhMCwodRwvRec8k0QUbZk7RQ==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.25.9.tgz", + "integrity": "sha512-1F05O7AYjymAtqbsFETboN1NvBdcnzMerO+zlMyJBEz6WkMdejvGWw9p05iTSjC85RLlBseHHQpYaM4gzJkBGg==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7" + "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -909,14 +651,14 @@ } }, "node_modules/@babel/plugin-transform-class-properties": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-properties/-/plugin-transform-class-properties-7.24.7.tgz", - "integrity": "sha512-vKbfawVYayKcSeSR5YYzzyXvsDFWU2mD8U5TFeXtbCPLFUqe7GyCgvO6XDHzje862ODrOwy6WCPmKeWHbCFJ4w==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-properties/-/plugin-transform-class-properties-7.25.9.tgz", + "integrity": "sha512-bbMAII8GRSkcd0h0b4X+36GksxuheLFjP65ul9w6C3KgAamI3JqErNgSrosX6ZPj+Mpim5VvEbawXxJCyEUV3Q==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-create-class-features-plugin": "^7.24.7", - "@babel/helper-plugin-utils": "^7.24.7" + "@babel/helper-create-class-features-plugin": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -926,15 +668,14 @@ } }, "node_modules/@babel/plugin-transform-class-static-block": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-static-block/-/plugin-transform-class-static-block-7.24.7.tgz", - "integrity": "sha512-HMXK3WbBPpZQufbMG4B46A90PkuuhN9vBCb5T8+VAHqvAqvcLi+2cKoukcpmUYkszLhScU3l1iudhrks3DggRQ==", + "version": "7.26.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-static-block/-/plugin-transform-class-static-block-7.26.0.tgz", + "integrity": "sha512-6J2APTs7BDDm+UMqP1useWqhcRAXo0WIoVj26N7kPFB6S73Lgvyka4KTZYIxtgYXiN5HTyRObA72N2iu628iTQ==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-create-class-features-plugin": "^7.24.7", - "@babel/helper-plugin-utils": "^7.24.7", - "@babel/plugin-syntax-class-static-block": "^7.14.5" + "@babel/helper-create-class-features-plugin": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -944,19 +685,17 @@ } }, "node_modules/@babel/plugin-transform-classes": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.24.7.tgz", - "integrity": "sha512-CFbbBigp8ln4FU6Bpy6g7sE8B/WmCmzvivzUC6xDAdWVsjYTXijpuuGJmYkAaoWAzcItGKT3IOAbxRItZ5HTjw==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.25.9.tgz", + "integrity": "sha512-mD8APIXmseE7oZvZgGABDyM34GUmK45Um2TXiBUt7PnuAxrgoSVf123qUzPxEr/+/BHrRn5NMZCdE2m/1F8DGg==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-annotate-as-pure": "^7.24.7", - "@babel/helper-compilation-targets": "^7.24.7", - "@babel/helper-environment-visitor": "^7.24.7", - "@babel/helper-function-name": "^7.24.7", - "@babel/helper-plugin-utils": "^7.24.7", - "@babel/helper-replace-supers": "^7.24.7", - "@babel/helper-split-export-declaration": "^7.24.7", + "@babel/helper-annotate-as-pure": "^7.25.9", + "@babel/helper-compilation-targets": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9", + "@babel/helper-replace-supers": "^7.25.9", + "@babel/traverse": "^7.25.9", "globals": "^11.1.0" }, "engines": { @@ -967,14 +706,14 @@ } }, "node_modules/@babel/plugin-transform-computed-properties": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.24.7.tgz", - "integrity": "sha512-25cS7v+707Gu6Ds2oY6tCkUwsJ9YIDbggd9+cu9jzzDgiNq7hR/8dkzxWfKWnTic26vsI3EsCXNd4iEB6e8esQ==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.25.9.tgz", + "integrity": "sha512-HnBegGqXZR12xbcTHlJ9HGxw1OniltT26J5YpfruGqtUHlz/xKf/G2ak9e+t0rVqrjXa9WOhvYPz1ERfMj23AA==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7", - "@babel/template": "^7.24.7" + "@babel/helper-plugin-utils": "^7.25.9", + "@babel/template": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -984,13 +723,13 @@ } }, "node_modules/@babel/plugin-transform-destructuring": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.24.7.tgz", - "integrity": "sha512-19eJO/8kdCQ9zISOf+SEUJM/bAUIsvY3YDnXZTupUCQ8LgrWnsG/gFB9dvXqdXnRXMAM8fvt7b0CBKQHNGy1mw==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.25.9.tgz", + "integrity": "sha512-WkCGb/3ZxXepmMiX101nnGiU+1CAdut8oHyEOHxkKuS1qKpU2SMXE2uSvfz8PBuLd49V6LEsbtyPhWC7fnkgvQ==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7" + "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -1000,14 +739,14 @@ } }, "node_modules/@babel/plugin-transform-dotall-regex": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.24.7.tgz", - "integrity": "sha512-ZOA3W+1RRTSWvyqcMJDLqbchh7U4NRGqwRfFSVbOLS/ePIP4vHB5e8T8eXcuqyN1QkgKyj5wuW0lcS85v4CrSw==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.25.9.tgz", + "integrity": "sha512-t7ZQ7g5trIgSRYhI9pIJtRl64KHotutUJsh4Eze5l7olJv+mRSg4/MmbZ0tv1eeqRbdvo/+trvJD/Oc5DmW2cA==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.24.7", - "@babel/helper-plugin-utils": "^7.24.7" + "@babel/helper-create-regexp-features-plugin": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -1017,13 +756,13 @@ } }, "node_modules/@babel/plugin-transform-duplicate-keys": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.24.7.tgz", - "integrity": "sha512-JdYfXyCRihAe46jUIliuL2/s0x0wObgwwiGxw/UbgJBr20gQBThrokO4nYKgWkD7uBaqM7+9x5TU7NkExZJyzw==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.25.9.tgz", + "integrity": "sha512-LZxhJ6dvBb/f3x8xwWIuyiAHy56nrRG3PeYTpBkkzkYRRQ6tJLu68lEF5VIqMUZiAV7a8+Tb78nEoMCMcqjXBw==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7" + "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -1032,15 +771,31 @@ "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-transform-dynamic-import": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dynamic-import/-/plugin-transform-dynamic-import-7.24.7.tgz", - "integrity": "sha512-sc3X26PhZQDb3JhORmakcbvkeInvxz+A8oda99lj7J60QRuPZvNAk9wQlTBS1ZynelDrDmTU4pw1tyc5d5ZMUg==", + "node_modules/@babel/plugin-transform-duplicate-named-capturing-groups-regex": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-named-capturing-groups-regex/-/plugin-transform-duplicate-named-capturing-groups-regex-7.25.9.tgz", + "integrity": "sha512-0UfuJS0EsXbRvKnwcLjFtJy/Sxc5J5jhLHnFhy7u4zih97Hz6tJkLU+O+FMMrNZrosUPxDi6sYxJ/EA8jDiAog==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7", - "@babel/plugin-syntax-dynamic-import": "^7.8.3" + "@babel/helper-create-regexp-features-plugin": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-transform-dynamic-import": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dynamic-import/-/plugin-transform-dynamic-import-7.25.9.tgz", + "integrity": "sha512-GCggjexbmSLaFhqsojeugBpeaRIgWNTcgKVq/0qIteFEqY2A+b9QidYadrWlnbWQUrW5fn+mCvf3tr7OeBFTyg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -1050,14 +805,14 @@ } }, "node_modules/@babel/plugin-transform-exponentiation-operator": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.24.7.tgz", - "integrity": "sha512-Rqe/vSc9OYgDajNIK35u7ot+KeCoetqQYFXM4Epf7M7ez3lWlOjrDjrwMei6caCVhfdw+mIKD4cgdGNy5JQotQ==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.25.9.tgz", + "integrity": "sha512-KRhdhlVk2nObA5AYa7QMgTMTVJdfHprfpAk4DjZVtllqRg9qarilstTKEhpVjyt+Npi8ThRyiV8176Am3CodPA==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-builder-binary-assignment-operator-visitor": "^7.24.7", - "@babel/helper-plugin-utils": "^7.24.7" + "@babel/helper-builder-binary-assignment-operator-visitor": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -1067,14 +822,13 @@ } }, "node_modules/@babel/plugin-transform-export-namespace-from": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-export-namespace-from/-/plugin-transform-export-namespace-from-7.24.7.tgz", - "integrity": "sha512-v0K9uNYsPL3oXZ/7F9NNIbAj2jv1whUEtyA6aujhekLs56R++JDQuzRcP2/z4WX5Vg/c5lE9uWZA0/iUoFhLTA==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-export-namespace-from/-/plugin-transform-export-namespace-from-7.25.9.tgz", + "integrity": "sha512-2NsEz+CxzJIVOPx2o9UsW1rXLqtChtLoVnwYHHiB04wS5sgn7mrV45fWMBX0Kk+ub9uXytVYfNP2HjbVbCB3Ww==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7", - "@babel/plugin-syntax-export-namespace-from": "^7.8.3" + "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -1084,14 +838,14 @@ } }, "node_modules/@babel/plugin-transform-for-of": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.24.7.tgz", - "integrity": "sha512-wo9ogrDG1ITTTBsy46oGiN1dS9A7MROBTcYsfS8DtsImMkHk9JXJ3EWQM6X2SUw4x80uGPlwj0o00Uoc6nEE3g==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.25.9.tgz", + "integrity": "sha512-LqHxduHoaGELJl2uhImHwRQudhCM50pT46rIBNvtT/Oql3nqiS3wOwP+5ten7NpYSXrrVLgtZU3DZmPtWZo16A==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7", - "@babel/helper-skip-transparent-expression-wrappers": "^7.24.7" + "@babel/helper-plugin-utils": "^7.25.9", + "@babel/helper-skip-transparent-expression-wrappers": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -1101,15 +855,15 @@ } }, "node_modules/@babel/plugin-transform-function-name": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.24.7.tgz", - "integrity": "sha512-U9FcnA821YoILngSmYkW6FjyQe2TyZD5pHt4EVIhmcTkrJw/3KqcrRSxuOo5tFZJi7TE19iDyI1u+weTI7bn2w==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.25.9.tgz", + "integrity": "sha512-8lP+Yxjv14Vc5MuWBpJsoUCd3hD6V9DgBon2FVYL4jJgbnVQ9fTgYmonchzZJOVNgzEgbxp4OwAf6xz6M/14XA==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-compilation-targets": "^7.24.7", - "@babel/helper-function-name": "^7.24.7", - "@babel/helper-plugin-utils": "^7.24.7" + "@babel/helper-compilation-targets": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9", + "@babel/traverse": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -1119,14 +873,13 @@ } }, "node_modules/@babel/plugin-transform-json-strings": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-json-strings/-/plugin-transform-json-strings-7.24.7.tgz", - "integrity": "sha512-2yFnBGDvRuxAaE/f0vfBKvtnvvqU8tGpMHqMNpTN2oWMKIR3NqFkjaAgGwawhqK/pIN2T3XdjGPdaG0vDhOBGw==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-json-strings/-/plugin-transform-json-strings-7.25.9.tgz", + "integrity": "sha512-xoTMk0WXceiiIvsaquQQUaLLXSW1KJ159KP87VilruQm0LNNGxWzahxSS6T6i4Zg3ezp4vA4zuwiNUR53qmQAw==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7", - "@babel/plugin-syntax-json-strings": "^7.8.3" + "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -1136,13 +889,13 @@ } }, "node_modules/@babel/plugin-transform-literals": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.24.7.tgz", - "integrity": "sha512-vcwCbb4HDH+hWi8Pqenwnjy+UiklO4Kt1vfspcQYFhJdpthSnW8XvWGyDZWKNVrVbVViI/S7K9PDJZiUmP2fYQ==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.25.9.tgz", + "integrity": "sha512-9N7+2lFziW8W9pBl2TzaNht3+pgMIRP74zizeCSrtnSKVdUl8mAjjOP2OOVQAfZ881P2cNjDj1uAMEdeD50nuQ==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7" + "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -1152,14 +905,13 @@ } }, "node_modules/@babel/plugin-transform-logical-assignment-operators": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-logical-assignment-operators/-/plugin-transform-logical-assignment-operators-7.24.7.tgz", - "integrity": "sha512-4D2tpwlQ1odXmTEIFWy9ELJcZHqrStlzK/dAOWYyxX3zT0iXQB6banjgeOJQXzEc4S0E0a5A+hahxPaEFYftsw==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-logical-assignment-operators/-/plugin-transform-logical-assignment-operators-7.25.9.tgz", + "integrity": "sha512-wI4wRAzGko551Y8eVf6iOY9EouIDTtPb0ByZx+ktDGHwv6bHFimrgJM/2T021txPZ2s4c7bqvHbd+vXG6K948Q==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7", - "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4" + "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -1169,13 +921,13 @@ } }, "node_modules/@babel/plugin-transform-member-expression-literals": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.24.7.tgz", - "integrity": "sha512-T/hRC1uqrzXMKLQ6UCwMT85S3EvqaBXDGf0FaMf4446Qx9vKwlghvee0+uuZcDUCZU5RuNi4781UQ7R308zzBw==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.25.9.tgz", + "integrity": "sha512-PYazBVfofCQkkMzh2P6IdIUaCEWni3iYEerAsRWuVd8+jlM1S9S9cz1dF9hIzyoZ8IA3+OwVYIp9v9e+GbgZhA==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7" + "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -1185,14 +937,14 @@ } }, "node_modules/@babel/plugin-transform-modules-amd": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.24.7.tgz", - "integrity": "sha512-9+pB1qxV3vs/8Hdmz/CulFB8w2tuu6EB94JZFsjdqxQokwGa9Unap7Bo2gGBGIvPmDIVvQrom7r5m/TCDMURhg==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.25.9.tgz", + "integrity": "sha512-g5T11tnI36jVClQlMlt4qKDLlWnG5pP9CSM4GhdRciTNMRgkfpo5cR6b4rGIOYPgRRuFAvwjPQ/Yk+ql4dyhbw==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-module-transforms": "^7.24.7", - "@babel/helper-plugin-utils": "^7.24.7" + "@babel/helper-module-transforms": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -1202,15 +954,15 @@ } }, "node_modules/@babel/plugin-transform-modules-commonjs": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.24.7.tgz", - "integrity": "sha512-iFI8GDxtevHJ/Z22J5xQpVqFLlMNstcLXh994xifFwxxGslr2ZXXLWgtBeLctOD63UFDArdvN6Tg8RFw+aEmjQ==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.25.9.tgz", + "integrity": "sha512-dwh2Ol1jWwL2MgkCzUSOvfmKElqQcuswAZypBSUsScMXvgdT8Ekq5YA6TtqpTVWH+4903NmboMuH1o9i8Rxlyg==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-module-transforms": "^7.24.7", - "@babel/helper-plugin-utils": "^7.24.7", - "@babel/helper-simple-access": "^7.24.7" + "@babel/helper-module-transforms": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9", + "@babel/helper-simple-access": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -1220,16 +972,16 @@ } }, "node_modules/@babel/plugin-transform-modules-systemjs": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.24.7.tgz", - "integrity": "sha512-GYQE0tW7YoaN13qFh3O1NCY4MPkUiAH3fiF7UcV/I3ajmDKEdG3l+UOcbAm4zUE3gnvUU+Eni7XrVKo9eO9auw==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.25.9.tgz", + "integrity": "sha512-hyss7iIlH/zLHaehT+xwiymtPOpsiwIIRlCAOwBB04ta5Tt+lNItADdlXw3jAWZ96VJ2jlhl/c+PNIQPKNfvcA==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-hoist-variables": "^7.24.7", - "@babel/helper-module-transforms": "^7.24.7", - "@babel/helper-plugin-utils": "^7.24.7", - "@babel/helper-validator-identifier": "^7.24.7" + "@babel/helper-module-transforms": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9", + "@babel/helper-validator-identifier": "^7.25.9", + "@babel/traverse": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -1239,14 +991,14 @@ } }, "node_modules/@babel/plugin-transform-modules-umd": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.24.7.tgz", - "integrity": "sha512-3aytQvqJ/h9z4g8AsKPLvD4Zqi2qT+L3j7XoFFu1XBlZWEl2/1kWnhmAbxpLgPrHSY0M6UA02jyTiwUVtiKR6A==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.25.9.tgz", + "integrity": "sha512-bS9MVObUgE7ww36HEfwe6g9WakQ0KF07mQF74uuXdkoziUPfKyu/nIm663kz//e5O1nPInPFx36z7WJmJ4yNEw==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-module-transforms": "^7.24.7", - "@babel/helper-plugin-utils": "^7.24.7" + "@babel/helper-module-transforms": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -1256,14 +1008,14 @@ } }, "node_modules/@babel/plugin-transform-named-capturing-groups-regex": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.24.7.tgz", - "integrity": "sha512-/jr7h/EWeJtk1U/uz2jlsCioHkZk1JJZVcc8oQsJ1dUlaJD83f4/6Zeh2aHt9BIFokHIsSeDfhUmju0+1GPd6g==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.25.9.tgz", + "integrity": "sha512-oqB6WHdKTGl3q/ItQhpLSnWWOpjUJLsOCLVyeFgeTktkBSCiurvPOsyt93gibI9CmuKvTUEtWmG5VhZD+5T/KA==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.24.7", - "@babel/helper-plugin-utils": "^7.24.7" + "@babel/helper-create-regexp-features-plugin": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -1273,13 +1025,13 @@ } }, "node_modules/@babel/plugin-transform-new-target": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.24.7.tgz", - "integrity": "sha512-RNKwfRIXg4Ls/8mMTza5oPF5RkOW8Wy/WgMAp1/F1yZ8mMbtwXW+HDoJiOsagWrAhI5f57Vncrmr9XeT4CVapA==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.25.9.tgz", + "integrity": "sha512-U/3p8X1yCSoKyUj2eOBIx3FOn6pElFOKvAAGf8HTtItuPyB+ZeOqfn+mvTtg9ZlOAjsPdK3ayQEjqHjU/yLeVQ==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7" + "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -1289,14 +1041,13 @@ } }, "node_modules/@babel/plugin-transform-nullish-coalescing-operator": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-nullish-coalescing-operator/-/plugin-transform-nullish-coalescing-operator-7.24.7.tgz", - "integrity": "sha512-Ts7xQVk1OEocqzm8rHMXHlxvsfZ0cEF2yomUqpKENHWMF4zKk175Y4q8H5knJes6PgYad50uuRmt3UJuhBw8pQ==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-nullish-coalescing-operator/-/plugin-transform-nullish-coalescing-operator-7.25.9.tgz", + "integrity": "sha512-ENfftpLZw5EItALAD4WsY/KUWvhUlZndm5GC7G3evUsVeSJB6p0pBeLQUnRnBCBx7zV0RKQjR9kCuwrsIrjWog==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7", - "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3" + "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -1306,14 +1057,13 @@ } }, "node_modules/@babel/plugin-transform-numeric-separator": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-numeric-separator/-/plugin-transform-numeric-separator-7.24.7.tgz", - "integrity": "sha512-e6q1TiVUzvH9KRvicuxdBTUj4AdKSRwzIyFFnfnezpCfP2/7Qmbb8qbU2j7GODbl4JMkblitCQjKYUaX/qkkwA==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-numeric-separator/-/plugin-transform-numeric-separator-7.25.9.tgz", + "integrity": "sha512-TlprrJ1GBZ3r6s96Yq8gEQv82s8/5HnCVHtEJScUj90thHQbwe+E5MLhi2bbNHBEJuzrvltXSru+BUxHDoog7Q==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7", - "@babel/plugin-syntax-numeric-separator": "^7.10.4" + "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -1323,16 +1073,15 @@ } }, "node_modules/@babel/plugin-transform-object-rest-spread": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-rest-spread/-/plugin-transform-object-rest-spread-7.24.7.tgz", - "integrity": "sha512-4QrHAr0aXQCEFni2q4DqKLD31n2DL+RxcwnNjDFkSG0eNQ/xCavnRkfCUjsyqGC2OviNJvZOF/mQqZBw7i2C5Q==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-rest-spread/-/plugin-transform-object-rest-spread-7.25.9.tgz", + "integrity": "sha512-fSaXafEE9CVHPweLYw4J0emp1t8zYTXyzN3UuG+lylqkvYd7RMrsOQ8TYx5RF231be0vqtFC6jnx3UmpJmKBYg==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-compilation-targets": "^7.24.7", - "@babel/helper-plugin-utils": "^7.24.7", - "@babel/plugin-syntax-object-rest-spread": "^7.8.3", - "@babel/plugin-transform-parameters": "^7.24.7" + "@babel/helper-compilation-targets": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9", + "@babel/plugin-transform-parameters": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -1342,14 +1091,14 @@ } }, "node_modules/@babel/plugin-transform-object-super": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.24.7.tgz", - "integrity": "sha512-A/vVLwN6lBrMFmMDmPPz0jnE6ZGx7Jq7d6sT/Ev4H65RER6pZ+kczlf1DthF5N0qaPHBsI7UXiE8Zy66nmAovg==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.25.9.tgz", + "integrity": "sha512-Kj/Gh+Rw2RNLbCK1VAWj2U48yxxqL2x0k10nPtSdRa0O2xnHXalD0s+o1A6a0W43gJ00ANo38jxkQreckOzv5A==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7", - "@babel/helper-replace-supers": "^7.24.7" + "@babel/helper-plugin-utils": "^7.25.9", + "@babel/helper-replace-supers": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -1359,14 +1108,13 @@ } }, "node_modules/@babel/plugin-transform-optional-catch-binding": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-catch-binding/-/plugin-transform-optional-catch-binding-7.24.7.tgz", - "integrity": "sha512-uLEndKqP5BfBbC/5jTwPxLh9kqPWWgzN/f8w6UwAIirAEqiIVJWWY312X72Eub09g5KF9+Zn7+hT7sDxmhRuKA==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-catch-binding/-/plugin-transform-optional-catch-binding-7.25.9.tgz", + "integrity": "sha512-qM/6m6hQZzDcZF3onzIhZeDHDO43bkNNlOX0i8n3lR6zLbu0GN2d8qfM/IERJZYauhAHSLHy39NF0Ctdvcid7g==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7", - "@babel/plugin-syntax-optional-catch-binding": "^7.8.3" + "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -1376,15 +1124,14 @@ } }, "node_modules/@babel/plugin-transform-optional-chaining": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-chaining/-/plugin-transform-optional-chaining-7.24.7.tgz", - "integrity": "sha512-tK+0N9yd4j+x/4hxF3F0e0fu/VdcxU18y5SevtyM/PCFlQvXbR0Zmlo2eBrKtVipGNFzpq56o8WsIIKcJFUCRQ==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-chaining/-/plugin-transform-optional-chaining-7.25.9.tgz", + "integrity": "sha512-6AvV0FsLULbpnXeBjrY4dmWF8F7gf8QnvTEoO/wX/5xm/xE1Xo8oPuD3MPS+KS9f9XBEAWN7X1aWr4z9HdOr7A==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7", - "@babel/helper-skip-transparent-expression-wrappers": "^7.24.7", - "@babel/plugin-syntax-optional-chaining": "^7.8.3" + "@babel/helper-plugin-utils": "^7.25.9", + "@babel/helper-skip-transparent-expression-wrappers": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -1394,13 +1141,13 @@ } }, "node_modules/@babel/plugin-transform-parameters": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.24.7.tgz", - "integrity": "sha512-yGWW5Rr+sQOhK0Ot8hjDJuxU3XLRQGflvT4lhlSY0DFvdb3TwKaY26CJzHtYllU0vT9j58hc37ndFPsqT1SrzA==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.25.9.tgz", + "integrity": "sha512-wzz6MKwpnshBAiRmn4jR8LYz/g8Ksg0o80XmwZDlordjwEk9SxBzTWC7F5ef1jhbrbOW2DJ5J6ayRukrJmnr0g==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7" + "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -1410,14 +1157,14 @@ } }, "node_modules/@babel/plugin-transform-private-methods": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-methods/-/plugin-transform-private-methods-7.24.7.tgz", - "integrity": "sha512-COTCOkG2hn4JKGEKBADkA8WNb35TGkkRbI5iT845dB+NyqgO8Hn+ajPbSnIQznneJTa3d30scb6iz/DhH8GsJQ==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-methods/-/plugin-transform-private-methods-7.25.9.tgz", + "integrity": "sha512-D/JUozNpQLAPUVusvqMxyvjzllRaF8/nSrP1s2YGQT/W4LHK4xxsMcHjhOGTS01mp9Hda8nswb+FblLdJornQw==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-create-class-features-plugin": "^7.24.7", - "@babel/helper-plugin-utils": "^7.24.7" + "@babel/helper-create-class-features-plugin": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -1427,16 +1174,15 @@ } }, "node_modules/@babel/plugin-transform-private-property-in-object": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-property-in-object/-/plugin-transform-private-property-in-object-7.24.7.tgz", - "integrity": "sha512-9z76mxwnwFxMyxZWEgdgECQglF2Q7cFLm0kMf8pGwt+GSJsY0cONKj/UuO4bOH0w/uAel3ekS4ra5CEAyJRmDA==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-property-in-object/-/plugin-transform-private-property-in-object-7.25.9.tgz", + "integrity": "sha512-Evf3kcMqzXA3xfYJmZ9Pg1OvKdtqsDMSWBDzZOPLvHiTt36E75jLDQo5w1gtRU95Q4E5PDttrTf25Fw8d/uWLw==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-annotate-as-pure": "^7.24.7", - "@babel/helper-create-class-features-plugin": "^7.24.7", - "@babel/helper-plugin-utils": "^7.24.7", - "@babel/plugin-syntax-private-property-in-object": "^7.14.5" + "@babel/helper-annotate-as-pure": "^7.25.9", + "@babel/helper-create-class-features-plugin": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -1446,13 +1192,13 @@ } }, "node_modules/@babel/plugin-transform-property-literals": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.24.7.tgz", - "integrity": "sha512-EMi4MLQSHfd2nrCqQEWxFdha2gBCqU4ZcCng4WBGZ5CJL4bBRW0ptdqqDdeirGZcpALazVVNJqRmsO8/+oNCBA==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.25.9.tgz", + "integrity": "sha512-IvIUeV5KrS/VPavfSM/Iu+RE6llrHrYIKY1yfCzyO/lMXHQ+p7uGhonmGVisv6tSBSVgWzMBohTcvkC9vQcQFA==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7" + "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -1462,13 +1208,13 @@ } }, "node_modules/@babel/plugin-transform-regenerator": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.24.7.tgz", - "integrity": "sha512-lq3fvXPdimDrlg6LWBoqj+r/DEWgONuwjuOuQCSYgRroXDH/IdM1C0IZf59fL5cHLpjEH/O6opIRBbqv7ELnuA==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.25.9.tgz", + "integrity": "sha512-vwDcDNsgMPDGP0nMqzahDWE5/MLcX8sv96+wfX7as7LoF/kr97Bo/7fI00lXY4wUXYfVmwIIyG80fGZ1uvt2qg==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7", + "@babel/helper-plugin-utils": "^7.25.9", "regenerator-transform": "^0.15.2" }, "engines": { @@ -1478,14 +1224,31 @@ "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/plugin-transform-reserved-words": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.24.7.tgz", - "integrity": "sha512-0DUq0pHcPKbjFZCfTss/pGkYMfy3vFWydkUBd9r0GHpIyfs2eCDENvqadMycRS9wZCXR41wucAfJHJmwA0UmoQ==", + "node_modules/@babel/plugin-transform-regexp-modifiers": { + "version": "7.26.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regexp-modifiers/-/plugin-transform-regexp-modifiers-7.26.0.tgz", + "integrity": "sha512-vN6saax7lrA2yA/Pak3sCxuD6F5InBjn9IcrIKQPjpsLvuHYLVroTxjdlVRHjjBWxKOqIwpTXDkOssYT4BFdRw==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7" + "@babel/helper-create-regexp-features-plugin": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-transform-reserved-words": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.25.9.tgz", + "integrity": "sha512-7DL7DKYjn5Su++4RXu8puKZm2XBPHyjWLUidaPEkCUBbE7IPcsrkRHggAOOKydH1dASWdcUBxrkOGNxUv5P3Jg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -1495,13 +1258,13 @@ } }, "node_modules/@babel/plugin-transform-shorthand-properties": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.24.7.tgz", - "integrity": "sha512-KsDsevZMDsigzbA09+vacnLpmPH4aWjcZjXdyFKGzpplxhbeB4wYtury3vglQkg6KM/xEPKt73eCjPPf1PgXBA==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.25.9.tgz", + "integrity": "sha512-MUv6t0FhO5qHnS/W8XCbHmiRWOphNufpE1IVxhK5kuN3Td9FT1x4rx4K42s3RYdMXCXpfWkGSbCSd0Z64xA7Ng==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7" + "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -1511,14 +1274,14 @@ } }, "node_modules/@babel/plugin-transform-spread": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.24.7.tgz", - "integrity": "sha512-x96oO0I09dgMDxJaANcRyD4ellXFLLiWhuwDxKZX5g2rWP1bTPkBSwCYv96VDXVT1bD9aPj8tppr5ITIh8hBng==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.25.9.tgz", + "integrity": "sha512-oNknIB0TbURU5pqJFVbOOFspVlrpVwo2H1+HUIsVDvp5VauGGDP1ZEvO8Nn5xyMEs3dakajOxlmkNW7kNgSm6A==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7", - "@babel/helper-skip-transparent-expression-wrappers": "^7.24.7" + "@babel/helper-plugin-utils": "^7.25.9", + "@babel/helper-skip-transparent-expression-wrappers": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -1528,13 +1291,13 @@ } }, "node_modules/@babel/plugin-transform-sticky-regex": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.24.7.tgz", - "integrity": "sha512-kHPSIJc9v24zEml5geKg9Mjx5ULpfncj0wRpYtxbvKyTtHCYDkVE3aHQ03FrpEo4gEe2vrJJS1Y9CJTaThA52g==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.25.9.tgz", + "integrity": "sha512-WqBUSgeVwucYDP9U/xNRQam7xV8W5Zf+6Eo7T2SRVUFlhRiMNFdFz58u0KZmCVVqs2i7SHgpRnAhzRNmKfi2uA==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7" + "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -1544,13 +1307,13 @@ } }, "node_modules/@babel/plugin-transform-template-literals": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.24.7.tgz", - "integrity": "sha512-AfDTQmClklHCOLxtGoP7HkeMw56k1/bTQjwsfhL6pppo/M4TOBSq+jjBUBLmV/4oeFg4GWMavIl44ZeCtmmZTw==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.25.9.tgz", + "integrity": "sha512-o97AE4syN71M/lxrCtQByzphAdlYluKPDBzDVzMmfCobUjjhAryZV0AIpRPrxN0eAkxXO6ZLEScmt+PNhj2OTw==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7" + "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -1560,13 +1323,13 @@ } }, "node_modules/@babel/plugin-transform-typeof-symbol": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.24.7.tgz", - "integrity": "sha512-VtR8hDy7YLB7+Pet9IarXjg/zgCMSF+1mNS/EQEiEaUPoFXCVsHG64SIxcaaI2zJgRiv+YmgaQESUfWAdbjzgg==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.25.9.tgz", + "integrity": "sha512-v61XqUMiueJROUv66BVIOi0Fv/CUuZuZMl5NkRoCVxLAnMexZ0A3kMe7vvZ0nulxMuMp0Mk6S5hNh48yki08ZA==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7" + "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -1576,13 +1339,13 @@ } }, "node_modules/@babel/plugin-transform-unicode-escapes": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.24.7.tgz", - "integrity": "sha512-U3ap1gm5+4edc2Q/P+9VrBNhGkfnf+8ZqppY71Bo/pzZmXhhLdqgaUl6cuB07O1+AQJtCLfaOmswiNbSQ9ivhw==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.25.9.tgz", + "integrity": "sha512-s5EDrE6bW97LtxOcGj1Khcx5AaXwiMmi4toFWRDP9/y0Woo6pXC+iyPu/KuhKtfSrNFd7jJB+/fkOtZy6aIC6Q==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7" + "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -1592,14 +1355,14 @@ } }, "node_modules/@babel/plugin-transform-unicode-property-regex": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-property-regex/-/plugin-transform-unicode-property-regex-7.24.7.tgz", - "integrity": "sha512-uH2O4OV5M9FZYQrwc7NdVmMxQJOCCzFeYudlZSzUAHRFeOujQefa92E74TQDVskNHCzOXoigEuoyzHDhaEaK5w==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-property-regex/-/plugin-transform-unicode-property-regex-7.25.9.tgz", + "integrity": "sha512-Jt2d8Ga+QwRluxRQ307Vlxa6dMrYEMZCgGxoPR8V52rxPyldHu3hdlHspxaqYmE7oID5+kB+UKUB/eWS+DkkWg==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.24.7", - "@babel/helper-plugin-utils": "^7.24.7" + "@babel/helper-create-regexp-features-plugin": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -1609,14 +1372,14 @@ } }, "node_modules/@babel/plugin-transform-unicode-regex": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.24.7.tgz", - "integrity": "sha512-hlQ96MBZSAXUq7ltkjtu3FJCCSMx/j629ns3hA3pXnBXjanNP0LHi+JpPeA81zaWgVK1VGH95Xuy7u0RyQ8kMg==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.25.9.tgz", + "integrity": "sha512-yoxstj7Rg9dlNn9UQxzk4fcNivwv4nUYz7fYXBaKxvw/lnmPuOm/ikoELygbYq68Bls3D/D+NBPHiLwZdZZ4HA==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.24.7", - "@babel/helper-plugin-utils": "^7.24.7" + "@babel/helper-create-regexp-features-plugin": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -1626,14 +1389,14 @@ } }, "node_modules/@babel/plugin-transform-unicode-sets-regex": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-sets-regex/-/plugin-transform-unicode-sets-regex-7.24.7.tgz", - "integrity": "sha512-2G8aAvF4wy1w/AGZkemprdGMRg5o6zPNhbHVImRz3lss55TYCBd6xStN19rt8XJHq20sqV0JbyWjOWwQRwV/wg==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-sets-regex/-/plugin-transform-unicode-sets-regex-7.25.9.tgz", + "integrity": "sha512-8BYqO3GeVNHtx69fdPshN3fnzUNLrWdHhk/icSwigksJGczKSizZ+Z6SBCxTs723Fr5VSNorTIK7a+R2tISvwQ==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.24.7", - "@babel/helper-plugin-utils": "^7.24.7" + "@babel/helper-create-regexp-features-plugin": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -1643,92 +1406,80 @@ } }, "node_modules/@babel/preset-env": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.24.7.tgz", - "integrity": "sha512-1YZNsc+y6cTvWlDHidMBsQZrZfEFjRIo/BZCT906PMdzOyXtSLTgqGdrpcuTDCXyd11Am5uQULtDIcCfnTc8fQ==", + "version": "7.26.0", + "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.26.0.tgz", + "integrity": "sha512-H84Fxq0CQJNdPFT2DrfnylZ3cf5K43rGfWK4LJGPpjKHiZlk0/RzwEus3PDDZZg+/Er7lCA03MVacueUuXdzfw==", "dev": true, "license": "MIT", "dependencies": { - "@babel/compat-data": "^7.24.7", - "@babel/helper-compilation-targets": "^7.24.7", - "@babel/helper-plugin-utils": "^7.24.7", - "@babel/helper-validator-option": "^7.24.7", - "@babel/plugin-bugfix-firefox-class-in-computed-class-key": "^7.24.7", - "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "^7.24.7", - "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.24.7", - "@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": "^7.24.7", + "@babel/compat-data": "^7.26.0", + "@babel/helper-compilation-targets": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9", + "@babel/helper-validator-option": "^7.25.9", + "@babel/plugin-bugfix-firefox-class-in-computed-class-key": "^7.25.9", + "@babel/plugin-bugfix-safari-class-field-initializer-scope": "^7.25.9", + "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "^7.25.9", + "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.25.9", + "@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": "^7.25.9", "@babel/plugin-proposal-private-property-in-object": "7.21.0-placeholder-for-preset-env.2", - "@babel/plugin-syntax-async-generators": "^7.8.4", - "@babel/plugin-syntax-class-properties": "^7.12.13", - "@babel/plugin-syntax-class-static-block": "^7.14.5", - "@babel/plugin-syntax-dynamic-import": "^7.8.3", - "@babel/plugin-syntax-export-namespace-from": "^7.8.3", - "@babel/plugin-syntax-import-assertions": "^7.24.7", - "@babel/plugin-syntax-import-attributes": "^7.24.7", - "@babel/plugin-syntax-import-meta": "^7.10.4", - "@babel/plugin-syntax-json-strings": "^7.8.3", - "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4", - "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", - "@babel/plugin-syntax-numeric-separator": "^7.10.4", - "@babel/plugin-syntax-object-rest-spread": "^7.8.3", - "@babel/plugin-syntax-optional-catch-binding": "^7.8.3", - "@babel/plugin-syntax-optional-chaining": "^7.8.3", - "@babel/plugin-syntax-private-property-in-object": "^7.14.5", - "@babel/plugin-syntax-top-level-await": "^7.14.5", + "@babel/plugin-syntax-import-assertions": "^7.26.0", + "@babel/plugin-syntax-import-attributes": "^7.26.0", "@babel/plugin-syntax-unicode-sets-regex": "^7.18.6", - "@babel/plugin-transform-arrow-functions": "^7.24.7", - "@babel/plugin-transform-async-generator-functions": "^7.24.7", - "@babel/plugin-transform-async-to-generator": "^7.24.7", - "@babel/plugin-transform-block-scoped-functions": "^7.24.7", - "@babel/plugin-transform-block-scoping": "^7.24.7", - "@babel/plugin-transform-class-properties": "^7.24.7", - "@babel/plugin-transform-class-static-block": "^7.24.7", - "@babel/plugin-transform-classes": "^7.24.7", - "@babel/plugin-transform-computed-properties": "^7.24.7", - "@babel/plugin-transform-destructuring": "^7.24.7", - "@babel/plugin-transform-dotall-regex": "^7.24.7", - "@babel/plugin-transform-duplicate-keys": "^7.24.7", - "@babel/plugin-transform-dynamic-import": "^7.24.7", - "@babel/plugin-transform-exponentiation-operator": "^7.24.7", - "@babel/plugin-transform-export-namespace-from": "^7.24.7", - "@babel/plugin-transform-for-of": "^7.24.7", - "@babel/plugin-transform-function-name": "^7.24.7", - "@babel/plugin-transform-json-strings": "^7.24.7", - "@babel/plugin-transform-literals": "^7.24.7", - "@babel/plugin-transform-logical-assignment-operators": "^7.24.7", - "@babel/plugin-transform-member-expression-literals": "^7.24.7", - "@babel/plugin-transform-modules-amd": "^7.24.7", - "@babel/plugin-transform-modules-commonjs": "^7.24.7", - "@babel/plugin-transform-modules-systemjs": "^7.24.7", - "@babel/plugin-transform-modules-umd": "^7.24.7", - "@babel/plugin-transform-named-capturing-groups-regex": "^7.24.7", - "@babel/plugin-transform-new-target": "^7.24.7", - "@babel/plugin-transform-nullish-coalescing-operator": "^7.24.7", - "@babel/plugin-transform-numeric-separator": "^7.24.7", - "@babel/plugin-transform-object-rest-spread": "^7.24.7", - "@babel/plugin-transform-object-super": "^7.24.7", - "@babel/plugin-transform-optional-catch-binding": "^7.24.7", - "@babel/plugin-transform-optional-chaining": "^7.24.7", - "@babel/plugin-transform-parameters": "^7.24.7", - "@babel/plugin-transform-private-methods": "^7.24.7", - "@babel/plugin-transform-private-property-in-object": "^7.24.7", - "@babel/plugin-transform-property-literals": "^7.24.7", - "@babel/plugin-transform-regenerator": "^7.24.7", - "@babel/plugin-transform-reserved-words": "^7.24.7", - "@babel/plugin-transform-shorthand-properties": "^7.24.7", - "@babel/plugin-transform-spread": "^7.24.7", - "@babel/plugin-transform-sticky-regex": "^7.24.7", - "@babel/plugin-transform-template-literals": "^7.24.7", - "@babel/plugin-transform-typeof-symbol": "^7.24.7", - "@babel/plugin-transform-unicode-escapes": "^7.24.7", - "@babel/plugin-transform-unicode-property-regex": "^7.24.7", - "@babel/plugin-transform-unicode-regex": "^7.24.7", - "@babel/plugin-transform-unicode-sets-regex": "^7.24.7", + "@babel/plugin-transform-arrow-functions": "^7.25.9", + "@babel/plugin-transform-async-generator-functions": "^7.25.9", + "@babel/plugin-transform-async-to-generator": "^7.25.9", + "@babel/plugin-transform-block-scoped-functions": "^7.25.9", + "@babel/plugin-transform-block-scoping": "^7.25.9", + "@babel/plugin-transform-class-properties": "^7.25.9", + "@babel/plugin-transform-class-static-block": "^7.26.0", + "@babel/plugin-transform-classes": "^7.25.9", + "@babel/plugin-transform-computed-properties": "^7.25.9", + "@babel/plugin-transform-destructuring": "^7.25.9", + "@babel/plugin-transform-dotall-regex": "^7.25.9", + "@babel/plugin-transform-duplicate-keys": "^7.25.9", + "@babel/plugin-transform-duplicate-named-capturing-groups-regex": "^7.25.9", + "@babel/plugin-transform-dynamic-import": "^7.25.9", + "@babel/plugin-transform-exponentiation-operator": "^7.25.9", + "@babel/plugin-transform-export-namespace-from": "^7.25.9", + "@babel/plugin-transform-for-of": "^7.25.9", + "@babel/plugin-transform-function-name": "^7.25.9", + "@babel/plugin-transform-json-strings": "^7.25.9", + "@babel/plugin-transform-literals": "^7.25.9", + "@babel/plugin-transform-logical-assignment-operators": "^7.25.9", + "@babel/plugin-transform-member-expression-literals": "^7.25.9", + "@babel/plugin-transform-modules-amd": "^7.25.9", + "@babel/plugin-transform-modules-commonjs": "^7.25.9", + "@babel/plugin-transform-modules-systemjs": "^7.25.9", + "@babel/plugin-transform-modules-umd": "^7.25.9", + "@babel/plugin-transform-named-capturing-groups-regex": "^7.25.9", + "@babel/plugin-transform-new-target": "^7.25.9", + "@babel/plugin-transform-nullish-coalescing-operator": "^7.25.9", + "@babel/plugin-transform-numeric-separator": "^7.25.9", + "@babel/plugin-transform-object-rest-spread": "^7.25.9", + "@babel/plugin-transform-object-super": "^7.25.9", + "@babel/plugin-transform-optional-catch-binding": "^7.25.9", + "@babel/plugin-transform-optional-chaining": "^7.25.9", + "@babel/plugin-transform-parameters": "^7.25.9", + "@babel/plugin-transform-private-methods": "^7.25.9", + "@babel/plugin-transform-private-property-in-object": "^7.25.9", + "@babel/plugin-transform-property-literals": "^7.25.9", + "@babel/plugin-transform-regenerator": "^7.25.9", + "@babel/plugin-transform-regexp-modifiers": "^7.26.0", + "@babel/plugin-transform-reserved-words": "^7.25.9", + "@babel/plugin-transform-shorthand-properties": "^7.25.9", + "@babel/plugin-transform-spread": "^7.25.9", + "@babel/plugin-transform-sticky-regex": "^7.25.9", + "@babel/plugin-transform-template-literals": "^7.25.9", + "@babel/plugin-transform-typeof-symbol": "^7.25.9", + "@babel/plugin-transform-unicode-escapes": "^7.25.9", + "@babel/plugin-transform-unicode-property-regex": "^7.25.9", + "@babel/plugin-transform-unicode-regex": "^7.25.9", + "@babel/plugin-transform-unicode-sets-regex": "^7.25.9", "@babel/preset-modules": "0.1.6-no-external-plugins", "babel-plugin-polyfill-corejs2": "^0.4.10", - "babel-plugin-polyfill-corejs3": "^0.10.4", + "babel-plugin-polyfill-corejs3": "^0.10.6", "babel-plugin-polyfill-regenerator": "^0.6.1", - "core-js-compat": "^3.31.0", + "core-js-compat": "^3.38.1", "semver": "^6.3.1" }, "engines": { @@ -1753,17 +1504,10 @@ "@babel/core": "^7.0.0-0 || ^8.0.0-0 <8.0.0" } }, - "node_modules/@babel/regjsgen": { - "version": "0.8.0", - "resolved": "https://registry.npmjs.org/@babel/regjsgen/-/regjsgen-0.8.0.tgz", - "integrity": "sha512-x/rqGMdzj+fWZvCOYForTghzbtqPDZ5gPwaoNGHdgDfF2QA/XZbCBp4Moo5scrkAMPhB7z26XM/AaHuIJdgauA==", - "dev": true, - "license": "MIT" - }, "node_modules/@babel/runtime": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.24.7.tgz", - "integrity": "sha512-UwgBRMjJP+xv857DCngvqXI3Iq6J4v0wXmwc6sapg+zyhbwmQX67LUEFrkK5tbyJ30jGuG3ZvWpBiB9LCy1kWw==", + "version": "7.26.0", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.26.0.tgz", + "integrity": "sha512-FDSOghenHTiToteC/QRlv2q3DhPZ/oOXTBoirfWNx1Cx3TMVcGWQtMMmQcSvb/JjpNeGzx8Pq/b4fKEJuWm1sw==", "dev": true, "license": "MIT", "dependencies": { @@ -1774,35 +1518,32 @@ } }, "node_modules/@babel/template": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.24.7.tgz", - "integrity": "sha512-jYqfPrU9JTF0PmPy1tLYHW4Mp4KlgxJD9l2nP9fD6yT/ICi554DmrWBAEYpIelzjHf1msDP3PxJIRt/nFNfBig==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.25.9.tgz", + "integrity": "sha512-9DGttpmPvIxBb/2uwpVo3dqJ+O6RooAFOS+lB+xDqoE2PVCE8nfoHMdZLpfCQRLwvohzXISPZcgxt80xLfsuwg==", "dev": true, "license": "MIT", "dependencies": { - "@babel/code-frame": "^7.24.7", - "@babel/parser": "^7.24.7", - "@babel/types": "^7.24.7" + "@babel/code-frame": "^7.25.9", + "@babel/parser": "^7.25.9", + "@babel/types": "^7.25.9" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/traverse": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.24.7.tgz", - "integrity": "sha512-yb65Ed5S/QAcewNPh0nZczy9JdYXkkAbIsEo+P7BE7yO3txAY30Y/oPa3QkQ5It3xVG2kpKMg9MsdxZaO31uKA==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.25.9.tgz", + "integrity": "sha512-ZCuvfwOwlz/bawvAuvcj8rrithP2/N55Tzz342AkTvq4qaWbGfmCk/tKhNaV2cthijKrPAA8SRJV5WWe7IBMJw==", "dev": true, "license": "MIT", "dependencies": { - "@babel/code-frame": "^7.24.7", - "@babel/generator": "^7.24.7", - "@babel/helper-environment-visitor": "^7.24.7", - "@babel/helper-function-name": "^7.24.7", - "@babel/helper-hoist-variables": "^7.24.7", - "@babel/helper-split-export-declaration": "^7.24.7", - "@babel/parser": "^7.24.7", - "@babel/types": "^7.24.7", + "@babel/code-frame": "^7.25.9", + "@babel/generator": "^7.25.9", + "@babel/parser": "^7.25.9", + "@babel/template": "^7.25.9", + "@babel/types": "^7.25.9", "debug": "^4.3.1", "globals": "^11.1.0" }, @@ -1811,15 +1552,14 @@ } }, "node_modules/@babel/types": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.24.7.tgz", - "integrity": "sha512-XEFXSlxiG5td2EJRe8vOmRbaXVgfcBlszKujvVmWIK/UpywWljQCfzAv3RQCGujWQ1RD4YYWEAqDXfuJiy8f5Q==", + "version": "7.26.0", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.26.0.tgz", + "integrity": "sha512-Z/yiTPj+lDVnF7lWeKCIJzaIkI0vYO87dMpZ4bg4TDrFe4XXLFWL1TbXU27gBP3QccxV9mZICCrnjnYlJjXHOA==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-string-parser": "^7.24.7", - "@babel/helper-validator-identifier": "^7.24.7", - "to-fast-properties": "^2.0.0" + "@babel/helper-string-parser": "^7.25.9", + "@babel/helper-validator-identifier": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -1882,9 +1622,9 @@ } }, "node_modules/@jridgewell/sourcemap-codec": { - "version": "1.4.15", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz", - "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==", + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz", + "integrity": "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==", "dev": true, "license": "MIT" }, @@ -1899,6 +1639,12 @@ "@jridgewell/sourcemap-codec": "^1.4.14" } }, + "node_modules/@mixmark-io/domino": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@mixmark-io/domino/-/domino-2.2.0.tgz", + "integrity": "sha512-Y28PR25bHXUg88kCV7nivXrP2Nj2RueZ3/l/jdx6J9f8J4nsEGcgX0Qe6lt7Pa+J79+kPiJU3LguR6O/6zrLOw==", + "license": "BSD-2-Clause" + }, "node_modules/@mozilla/readability": { "version": "0.5.0", "resolved": "https://registry.npmjs.org/@mozilla/readability/-/readability-0.5.0.tgz", @@ -1909,16 +1655,16 @@ } }, "node_modules/@polka/url": { - "version": "1.0.0-next.25", - "resolved": "https://registry.npmjs.org/@polka/url/-/url-1.0.0-next.25.tgz", - "integrity": "sha512-j7P6Rgr3mmtdkeDGTe0E/aYyWEWVtc5yFXtHCRHs28/jptDEWfaVOc5T7cblqy1XKPPfCxJc/8DwQ5YgLOZOVQ==", + "version": "1.0.0-next.28", + "resolved": "https://registry.npmjs.org/@polka/url/-/url-1.0.0-next.28.tgz", + "integrity": "sha512-8LduaNlMZGwdZ6qWrKlfa+2M4gahzFkprZiAt2TF8uS0qQgBizKXpXURqvTJ4WtmupWxaLqjRb2UCTe72mu+Aw==", "dev": true, "license": "MIT" }, "node_modules/@types/eslint": { - "version": "8.56.10", - "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.56.10.tgz", - "integrity": "sha512-Shavhk87gCtY2fhXDctcfS3e6FdxWkCx1iUZ9eEUbh7rTqlZT0/IzOkCOVt0fCjcFuZ9FPYfuezTBImfHCDBGQ==", + "version": "9.6.1", + "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-9.6.1.tgz", + "integrity": "sha512-FXx2pKgId/WyYo2jXw63kk7/+TY7u7AziEJxJAnSFzHlqTAS3Ync6SvgYAN/k4/PQpnnVuzoMuVnByKK2qp0ag==", "dev": true, "license": "MIT", "dependencies": { @@ -1938,9 +1684,9 @@ } }, "node_modules/@types/estree": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.5.tgz", - "integrity": "sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==", + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.6.tgz", + "integrity": "sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==", "dev": true, "license": "MIT" }, @@ -1970,13 +1716,13 @@ "license": "MIT" }, "node_modules/@types/node": { - "version": "20.14.10", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.14.10.tgz", - "integrity": "sha512-MdiXf+nDuMvY0gJKxyfZ7/6UFsETO7mGKF54MVD/ekJS6HdFtpZFBgrh6Pseu64XTb2MLyFPlbW6hj8HYRQNOQ==", + "version": "22.9.0", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.9.0.tgz", + "integrity": "sha512-vuyHg81vvWA1Z1ELfvLko2c8f34gyA0zaic0+Rllc5lbCnbSyuvb2Oxpm6TAUAC/2xZN3QGqxBNggD1nNR2AfQ==", "dev": true, "license": "MIT", "dependencies": { - "undici-types": "~5.26.4" + "undici-types": "~6.19.8" } }, "node_modules/@webassemblyjs/ast": { @@ -2202,9 +1948,9 @@ "license": "Apache-2.0" }, "node_modules/acorn": { - "version": "8.12.1", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.12.1.tgz", - "integrity": "sha512-tcpGyI9zbizT9JbV6oYE477V6mTlXvvi0T0G3SNIYE2apm/G5huBa1+K89VGeovbg+jycCrfhl3ADxErOuO6Jg==", + "version": "8.14.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.14.0.tgz", + "integrity": "sha512-cl669nCJTZBsL97OF4kUQm5g5hC2uihk0NxY3WENAC0TYdILVkAyHymAntgxGkl7K+t0cXIrH5siy5S4XkFycA==", "dev": true, "license": "MIT", "bin": { @@ -2214,20 +1960,10 @@ "node": ">=0.4.0" } }, - "node_modules/acorn-import-attributes": { - "version": "1.9.5", - "resolved": "https://registry.npmjs.org/acorn-import-attributes/-/acorn-import-attributes-1.9.5.tgz", - "integrity": "sha512-n02Vykv5uA3eHGM/Z2dQrcD56kL8TyDb2p1+0P83PClMnC/nc+anbQRhIOWnSq4Ke/KvDPrY3C9hDtC/A3eHnQ==", - "dev": true, - "license": "MIT", - "peerDependencies": { - "acorn": "^8" - } - }, "node_modules/acorn-walk": { - "version": "8.3.3", - "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.3.tgz", - "integrity": "sha512-MxXdReSRhGO7VlFe1bRG/oI7/mdLV9B9JJT0N8vZOhF7gFRR5l3M8W9G8JxmKV+JC5mGqJ0QvqfSOLsCPa4nUw==", + "version": "8.3.4", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.4.tgz", + "integrity": "sha512-ueEepnujpqee2o5aIYnvHU6C0A42MNdsIDeqy5BydrkuC5R1ZuUFnm27EeFJGoEHJQgn3uleRvmTXaJgfXbt4g==", "dev": true, "license": "MIT", "dependencies": { @@ -2238,16 +1974,16 @@ } }, "node_modules/ajv": { - "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "version": "8.17.1", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", + "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", "dev": true, "license": "MIT", "dependencies": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" + "fast-deep-equal": "^3.1.3", + "fast-uri": "^3.0.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2" }, "funding": { "type": "github", @@ -2272,51 +2008,17 @@ } } }, - "node_modules/ajv-formats/node_modules/ajv": { - "version": "8.16.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.16.0.tgz", - "integrity": "sha512-F0twR8U1ZU67JIEtekUcLkXkoO5mMMmgGD8sK/xUFzJ805jxHQl92hImFAqqXMyMYjSPOyUPAwHYhB72g5sTXw==", - "dev": true, - "license": "MIT", - "dependencies": { - "fast-deep-equal": "^3.1.3", - "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2", - "uri-js": "^4.4.1" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/ajv-formats/node_modules/json-schema-traverse": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", - "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", - "dev": true, - "license": "MIT" - }, "node_modules/ajv-keywords": { - "version": "3.5.2", - "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", - "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", - "dev": true, - "license": "MIT", - "peerDependencies": { - "ajv": "^6.9.1" - } - }, - "node_modules/ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz", + "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==", "dev": true, "license": "MIT", "dependencies": { - "color-convert": "^1.9.0" + "fast-deep-equal": "^3.1.3" }, - "engines": { - "node": ">=4" + "peerDependencies": { + "ajv": "^8.8.2" } }, "node_modules/array-union": { @@ -2343,9 +2045,9 @@ } }, "node_modules/babel-loader": { - "version": "9.1.3", - "resolved": "https://registry.npmjs.org/babel-loader/-/babel-loader-9.1.3.tgz", - "integrity": "sha512-xG3ST4DglodGf8qSwv0MdeWLhrDsw/32QMdTO5T1ZIp9gQur0HkCyFs7Awskr10JKXFXwpAhiCuYX5oGXnRGbw==", + "version": "9.2.1", + "resolved": "https://registry.npmjs.org/babel-loader/-/babel-loader-9.2.1.tgz", + "integrity": "sha512-fqe8naHt46e0yIdkjUZYqddSXfej3AHajX+CSO5X7oy0EmPc6o5Xh+RClNoHjnieWz9AW4kZxW9yyFMhVB1QLA==", "dev": true, "license": "MIT", "dependencies": { @@ -2360,63 +2062,6 @@ "webpack": ">=5" } }, - "node_modules/babel-loader/node_modules/ajv": { - "version": "8.16.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.16.0.tgz", - "integrity": "sha512-F0twR8U1ZU67JIEtekUcLkXkoO5mMMmgGD8sK/xUFzJ805jxHQl92hImFAqqXMyMYjSPOyUPAwHYhB72g5sTXw==", - "dev": true, - "license": "MIT", - "dependencies": { - "fast-deep-equal": "^3.1.3", - "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2", - "uri-js": "^4.4.1" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/babel-loader/node_modules/ajv-keywords": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz", - "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==", - "dev": true, - "license": "MIT", - "dependencies": { - "fast-deep-equal": "^3.1.3" - }, - "peerDependencies": { - "ajv": "^8.8.2" - } - }, - "node_modules/babel-loader/node_modules/json-schema-traverse": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", - "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", - "dev": true, - "license": "MIT" - }, - "node_modules/babel-loader/node_modules/schema-utils": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.2.0.tgz", - "integrity": "sha512-L0jRsrPpjdckP3oPug3/VxNKt2trR8TcabrM6FOAAlvC/9Phcmm+cuAgTlxBqdBR1WJx7Naj9WHw+aOmheSVbw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/json-schema": "^7.0.9", - "ajv": "^8.9.0", - "ajv-formats": "^2.1.1", - "ajv-keywords": "^5.1.0" - }, - "engines": { - "node": ">= 12.13.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - } - }, "node_modules/babel-plugin-polyfill-corejs2": { "version": "0.4.11", "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.4.11.tgz", @@ -2433,14 +2078,14 @@ } }, "node_modules/babel-plugin-polyfill-corejs3": { - "version": "0.10.4", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.10.4.tgz", - "integrity": "sha512-25J6I8NGfa5YkCDogHRID3fVCadIR8/pGl1/spvCkzb6lVn6SR3ojpx9nOn9iEBcUsjY24AmdKm5khcfKdylcg==", + "version": "0.10.6", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.10.6.tgz", + "integrity": "sha512-b37+KR2i/khY5sKmWNVQAnitvquQbNdWy6lJdsr0kmquCKEEUgMKK4SboVM3HtfnZilfjr4MMQ7vY58FVWDtIA==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-define-polyfill-provider": "^0.6.1", - "core-js-compat": "^3.36.1" + "@babel/helper-define-polyfill-provider": "^0.6.2", + "core-js-compat": "^3.38.0" }, "peerDependencies": { "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" @@ -2478,9 +2123,9 @@ } }, "node_modules/browserslist": { - "version": "4.23.1", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.23.1.tgz", - "integrity": "sha512-TUfofFo/KsK/bWZ9TWQ5O26tsWW4Uhmt8IYklbnUa70udB6P2wA7w7o4PY4muaEPBQaAX+CEnmmIA41NVHtPVw==", + "version": "4.24.2", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.24.2.tgz", + "integrity": "sha512-ZIc+Q62revdMcqC6aChtW4jz3My3klmCO1fEmINZY/8J3EpBg5/A/D0AKmBveUh6pgoeycoMkVMko84tuYS+Gg==", "dev": true, "funding": [ { @@ -2498,10 +2143,10 @@ ], "license": "MIT", "dependencies": { - "caniuse-lite": "^1.0.30001629", - "electron-to-chromium": "^1.4.796", - "node-releases": "^2.0.14", - "update-browserslist-db": "^1.0.16" + "caniuse-lite": "^1.0.30001669", + "electron-to-chromium": "^1.5.41", + "node-releases": "^2.0.18", + "update-browserslist-db": "^1.1.1" }, "bin": { "browserslist": "cli.js" @@ -2518,9 +2163,9 @@ "license": "MIT" }, "node_modules/caniuse-lite": { - "version": "1.0.30001640", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001640.tgz", - "integrity": "sha512-lA4VMpW0PSUrFnkmVuEKBUovSWKhj7puyCg8StBChgu298N1AtuF1sKWEvfDuimSEDbhlb/KqPKC3fs1HbuQUA==", + "version": "1.0.30001677", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001677.tgz", + "integrity": "sha512-fmfjsOlJUpMWu+mAAtZZZHz7UEwsUxIIvu1TJfO1HqFQvB/B+ii0xr9B5HpbZY/mC4XZ8SvjHJqtAY6pDPQEog==", "dev": true, "funding": [ { @@ -2538,54 +2183,6 @@ ], "license": "CC-BY-4.0" }, - "node_modules/chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/chalk/node_modules/escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/chalk/node_modules/has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=4" - } - }, - "node_modules/chalk/node_modules/supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "license": "MIT", - "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, "node_modules/chrome-trace-event": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.4.tgz", @@ -2627,23 +2224,6 @@ "node": ">=6" } }, - "node_modules/color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dev": true, - "license": "MIT", - "dependencies": { - "color-name": "1.1.3" - } - }, - "node_modules/color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", - "dev": true, - "license": "MIT" - }, "node_modules/colorette": { "version": "2.0.20", "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.20.tgz", @@ -2665,84 +2245,6 @@ "dev": true, "license": "ISC" }, - "node_modules/compression-webpack-plugin": { - "version": "11.1.0", - "resolved": "https://registry.npmjs.org/compression-webpack-plugin/-/compression-webpack-plugin-11.1.0.tgz", - "integrity": "sha512-zDOQYp10+upzLxW+VRSjEpRRwBXJdsb5lBMlRxx1g8hckIFBpe3DTI0en2w7h+beuq89576RVzfiXrkdPGrHhA==", - "dev": true, - "license": "MIT", - "dependencies": { - "schema-utils": "^4.2.0", - "serialize-javascript": "^6.0.2" - }, - "engines": { - "node": ">= 18.12.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - }, - "peerDependencies": { - "webpack": "^5.1.0" - } - }, - "node_modules/compression-webpack-plugin/node_modules/ajv": { - "version": "8.16.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.16.0.tgz", - "integrity": "sha512-F0twR8U1ZU67JIEtekUcLkXkoO5mMMmgGD8sK/xUFzJ805jxHQl92hImFAqqXMyMYjSPOyUPAwHYhB72g5sTXw==", - "dev": true, - "license": "MIT", - "dependencies": { - "fast-deep-equal": "^3.1.3", - "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2", - "uri-js": "^4.4.1" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/compression-webpack-plugin/node_modules/ajv-keywords": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz", - "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==", - "dev": true, - "license": "MIT", - "dependencies": { - "fast-deep-equal": "^3.1.3" - }, - "peerDependencies": { - "ajv": "^8.8.2" - } - }, - "node_modules/compression-webpack-plugin/node_modules/json-schema-traverse": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", - "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", - "dev": true, - "license": "MIT" - }, - "node_modules/compression-webpack-plugin/node_modules/schema-utils": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.2.0.tgz", - "integrity": "sha512-L0jRsrPpjdckP3oPug3/VxNKt2trR8TcabrM6FOAAlvC/9Phcmm+cuAgTlxBqdBR1WJx7Naj9WHw+aOmheSVbw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/json-schema": "^7.0.9", - "ajv": "^8.9.0", - "ajv-formats": "^2.1.1", - "ajv-keywords": "^5.1.0" - }, - "engines": { - "node": ">= 12.13.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - } - }, "node_modules/concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", @@ -2758,13 +2260,13 @@ "license": "MIT" }, "node_modules/core-js-compat": { - "version": "3.37.1", - "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.37.1.tgz", - "integrity": "sha512-9TNiImhKvQqSUkOvk/mMRZzOANTiEVC7WaBNhHcKM7x+/5E1l5NvsysR19zuDQScE8k+kfQXWRN3AtS/eOSHpg==", + "version": "3.39.0", + "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.39.0.tgz", + "integrity": "sha512-VgEUx3VwlExr5no0tXlBt+silBvhTryPwCXRI2Id1PN8WTKu7MreethvddqOubrYxkFdv/RnYrqlv1sFNAUelw==", "dev": true, "license": "MIT", "dependencies": { - "browserslist": "^4.23.0" + "browserslist": "^4.24.2" }, "funding": { "type": "opencollective", @@ -2794,13 +2296,13 @@ "license": "MIT" }, "node_modules/debug": { - "version": "4.3.5", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz", - "integrity": "sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==", + "version": "4.3.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz", + "integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==", "dev": true, "license": "MIT", "dependencies": { - "ms": "2.1.2" + "ms": "^2.1.3" }, "engines": { "node": ">=6.0" @@ -2830,12 +2332,6 @@ "node": ">=6" } }, - "node_modules/dompurify": { - "version": "3.1.6", - "resolved": "https://registry.npmjs.org/dompurify/-/dompurify-3.1.6.tgz", - "integrity": "sha512-cTOAhc36AalkjtBpfG6O8JimdTMWNXjiePT2xQH/ppBGi/4uIpmj8eKyIkMJErXWARyINV/sB38yf8JCLF5pbQ==", - "license": "(MPL-2.0 OR Apache-2.0)" - }, "node_modules/duplexer": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/duplexer/-/duplexer-0.1.2.tgz", @@ -2844,16 +2340,16 @@ "license": "MIT" }, "node_modules/electron-to-chromium": { - "version": "1.4.820", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.820.tgz", - "integrity": "sha512-kK/4O/YunacfboFEk/BDf7VO1HoPmDudLTJAU9NmXIOSjsV7qVIX3OrI4REZo0VmdqhcpUcncQc6N8Q3aEXlHg==", + "version": "1.5.52", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.52.tgz", + "integrity": "sha512-xtoijJTZ+qeucLBDNztDOuQBE1ksqjvNjvqFoST3nGC7fSpqJ+X6BdTBaY5BHG+IhWWmpc6b/KfpeuEDupEPOQ==", "dev": true, "license": "ISC" }, "node_modules/enhanced-resolve": { - "version": "5.17.0", - "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.17.0.tgz", - "integrity": "sha512-dwDPwZL0dmye8Txp2gzFmA6sxALaSvdRDjPH0viLcKrtlOL3tw62nWWweVD1SdILDTJrbrL6tdWVN58Wo6U3eA==", + "version": "5.17.1", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.17.1.tgz", + "integrity": "sha512-LMHl3dXhTcfv8gM4kEzIUeTQ+7fpdA0l2tUf34BddXPkz2A5xJ5L/Pchd5BL6rdccM9QGvu0sWZzK1Z1t4wwyg==", "dev": true, "license": "MIT", "dependencies": { @@ -2865,9 +2361,9 @@ } }, "node_modules/envinfo": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/envinfo/-/envinfo-7.13.0.tgz", - "integrity": "sha512-cvcaMr7KqXVh4nyzGTVqTum+gAiL265x5jUWQIDLq//zOGbW+gSW/C+OWLleY/rs9Qole6AZLMXPbtIFQbqu+Q==", + "version": "7.14.0", + "resolved": "https://registry.npmjs.org/envinfo/-/envinfo-7.14.0.tgz", + "integrity": "sha512-CO40UI41xDQzhLB1hWyqUKgFhs250pNcGbyGKe1l/e4FSaI/+YE4IMG76GDt0In67WLPACIITC+sOi08x4wIvg==", "dev": true, "license": "MIT", "bin": { @@ -2885,9 +2381,9 @@ "license": "MIT" }, "node_modules/escalade": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.2.tgz", - "integrity": "sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA==", + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", "dev": true, "license": "MIT", "engines": { @@ -2988,6 +2484,13 @@ "dev": true, "license": "MIT" }, + "node_modules/fast-uri": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.0.3.tgz", + "integrity": "sha512-aLrHthzCjH5He4Z2H9YZ+v6Ujb9ocRuW6ZzkJQOrTxleEijANq4v1TsaPaVG1PZcuurEzrLcWRyYBYXD5cEiaw==", + "dev": true, + "license": "BSD-3-Clause" + }, "node_modules/fastest-levenshtein": { "version": "1.0.16", "resolved": "https://registry.npmjs.org/fastest-levenshtein/-/fastest-levenshtein-1.0.16.tgz", @@ -3015,7 +2518,7 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/find-cache-dir/node_modules/find-up": { + "node_modules/find-up": { "version": "6.3.0", "resolved": "https://registry.npmjs.org/find-up/-/find-up-6.3.0.tgz", "integrity": "sha512-v2ZsoEuVHYy8ZIlYqwPe/39Cy+cFDzp4dXPaxNvkEuouymu+2Jbz0PxpKarJHYJTmv2HWT3O382qY8l4jMWthw==", @@ -3032,94 +2535,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/find-cache-dir/node_modules/locate-path": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-7.2.0.tgz", - "integrity": "sha512-gvVijfZvn7R+2qyPX8mAuKcFGDf6Nc61GdvGafQsHL0sBIxfKzA+usWn4GFC/bk+QdwPUD4kWFJLhElipq+0VA==", - "dev": true, - "license": "MIT", - "dependencies": { - "p-locate": "^6.0.0" - }, - "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/find-cache-dir/node_modules/p-limit": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-4.0.0.tgz", - "integrity": "sha512-5b0R4txpzjPWVw/cXXUResoD4hb6U/x9BH08L7nw+GN1sezDzPdxeRvpc9c433fZhBan/wusjbCsqwqm4EIBIQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "yocto-queue": "^1.0.0" - }, - "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/find-cache-dir/node_modules/p-locate": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-6.0.0.tgz", - "integrity": "sha512-wPrq66Llhl7/4AGC6I+cqxT07LhXvWL08LNXz1fENOw0Ap4sRZZ/gZpTTJ5jpurzzzfS2W/Ge9BY3LgLjCShcw==", - "dev": true, - "license": "MIT", - "dependencies": { - "p-limit": "^4.0.0" - }, - "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/find-cache-dir/node_modules/path-exists": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-5.0.0.tgz", - "integrity": "sha512-RjhtfwJOxzcFmNOi6ltcbcu4Iu+FL3zEj83dk4kAS+fVpTxXLO1b38RvJgT/0QwvV/L3aY9TAnyv0EOqW4GoMQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - } - }, - "node_modules/find-cache-dir/node_modules/pkg-dir": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-7.0.0.tgz", - "integrity": "sha512-Ie9z/WINcxxLp27BKOCHGde4ITq9UklYKDzVo1nhk5sqGEXU3FpkwP5GM2voTGJkGd9B3Otl+Q4uwSOeSUtOBA==", - "dev": true, - "license": "MIT", - "dependencies": { - "find-up": "^6.3.0" - }, - "engines": { - "node": ">=14.16" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/find-up": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", - "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", - "dev": true, - "license": "MIT", - "dependencies": { - "locate-path": "^5.0.0", - "path-exists": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/flat": { "version": "5.0.2", "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz", @@ -3277,9 +2692,9 @@ "license": "MIT" }, "node_modules/import-local": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.1.0.tgz", - "integrity": "sha512-ASB07uLtnDs1o6EHjKpX34BKYDSqnFerfTOJL2HvMqF70LnxpjkzDB8J44oT9pu4AMPkQwf8jl6szgvNd2tRIg==", + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.2.0.tgz", + "integrity": "sha512-2SPlun1JUPWoM6t3F0dw0FkCF/jWY8kttcY4f599GLTSjh2OCuuhdTkJQsEcZzBqbXZGKMK2OqW1oZsjtf/gQA==", "dev": true, "license": "MIT", "dependencies": { @@ -3296,6 +2711,85 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/import-local/node_modules/find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, + "license": "MIT", + "dependencies": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/import-local/node_modules/locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-locate": "^4.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/import-local/node_modules/p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-try": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/import-local/node_modules/p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-limit": "^2.2.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/import-local/node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/import-local/node_modules/pkg-dir": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", + "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "find-up": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/inflight": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", @@ -3326,9 +2820,9 @@ } }, "node_modules/is-core-module": { - "version": "2.14.0", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.14.0.tgz", - "integrity": "sha512-a5dFJih5ZLYlRtDc0dZWP7RiKr6xIKzmn/oAYCDvdLThadVgyJwlaoQPmRtMSpz+rk0OGAgIu+TcM9HUF0fk1A==", + "version": "2.15.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.15.1.tgz", + "integrity": "sha512-z0vtXSwucUJtANQWldhbtbt7BnL0vxiFjIdDLAatwhDYty2bad6s+rijD6Ri4YuYJubLzIJLUidCh09e1djEVQ==", "dev": true, "license": "MIT", "dependencies": { @@ -3430,16 +2924,16 @@ "license": "MIT" }, "node_modules/jsesc": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", - "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.0.2.tgz", + "integrity": "sha512-xKqzzWXDttJuOcawBt4KnKHHIf5oQ/Cxax+0PWFG+DFDgHNAdi+TXECADI+RYiFUMmx8792xsMbbgXj4CwnP4g==", "dev": true, "license": "MIT", "bin": { "jsesc": "bin/jsesc" }, "engines": { - "node": ">=4" + "node": ">=6" } }, "node_modules/json-parse-even-better-errors": { @@ -3450,9 +2944,9 @@ "license": "MIT" }, "node_modules/json-schema-traverse": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", "dev": true, "license": "MIT" }, @@ -3490,16 +2984,19 @@ } }, "node_modules/locate-path": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", - "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-7.2.0.tgz", + "integrity": "sha512-gvVijfZvn7R+2qyPX8mAuKcFGDf6Nc61GdvGafQsHL0sBIxfKzA+usWn4GFC/bk+QdwPUD4kWFJLhElipq+0VA==", "dev": true, "license": "MIT", "dependencies": { - "p-locate": "^4.1.0" + "p-locate": "^6.0.0" }, "engines": { - "node": ">=8" + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/lodash.debounce": { @@ -3573,9 +3070,9 @@ } }, "node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", "dev": true, "license": "MIT" }, @@ -3587,9 +3084,9 @@ "license": "MIT" }, "node_modules/node-releases": { - "version": "2.0.14", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.14.tgz", - "integrity": "sha512-y10wOWt8yZpqXmOgRo77WaHEmhYQYGNA6y421PKsKYWEK8aW+cqAphborZDhqfyKrbZEN92CN1X2KbafY2s7Yw==", + "version": "2.0.18", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.18.tgz", + "integrity": "sha512-d9VeXT4SJ7ZeOqGX6R5EM022wpL+eWPooLI+5UpWn2jCT1aosUQEhQP214x33Wkwx3JQMvIm+tIoVOdodFS40g==", "dev": true, "license": "MIT" }, @@ -3624,32 +3121,35 @@ } }, "node_modules/p-limit": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", - "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-4.0.0.tgz", + "integrity": "sha512-5b0R4txpzjPWVw/cXXUResoD4hb6U/x9BH08L7nw+GN1sezDzPdxeRvpc9c433fZhBan/wusjbCsqwqm4EIBIQ==", "dev": true, "license": "MIT", "dependencies": { - "p-try": "^2.0.0" + "yocto-queue": "^1.0.0" }, "engines": { - "node": ">=6" + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/p-locate": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", - "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-6.0.0.tgz", + "integrity": "sha512-wPrq66Llhl7/4AGC6I+cqxT07LhXvWL08LNXz1fENOw0Ap4sRZZ/gZpTTJ5jpurzzzfS2W/Ge9BY3LgLjCShcw==", "dev": true, "license": "MIT", "dependencies": { - "p-limit": "^2.2.0" + "p-limit": "^4.0.0" }, "engines": { - "node": ">=8" + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/p-map": { @@ -3673,13 +3173,13 @@ } }, "node_modules/path-exists": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-5.0.0.tgz", + "integrity": "sha512-RjhtfwJOxzcFmNOi6ltcbcu4Iu+FL3zEj83dk4kAS+fVpTxXLO1b38RvJgT/0QwvV/L3aY9TAnyv0EOqW4GoMQ==", "dev": true, "license": "MIT", "engines": { - "node": ">=8" + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" } }, "node_modules/path-is-absolute": { @@ -3717,9 +3217,9 @@ "license": "MIT" }, "node_modules/picocolors": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.1.tgz", - "integrity": "sha512-anP1Z8qwhkbmu7MFP5iTt+wQKXgwzf7zTyGlcdzabySa9vd0Xt392U0rVmz9poOaBj0uHJKyyo9/upk0HrEQew==", + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", "dev": true, "license": "ISC" }, @@ -3757,16 +3257,19 @@ } }, "node_modules/pkg-dir": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", - "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-7.0.0.tgz", + "integrity": "sha512-Ie9z/WINcxxLp27BKOCHGde4ITq9UklYKDzVo1nhk5sqGEXU3FpkwP5GM2voTGJkGd9B3Otl+Q4uwSOeSUtOBA==", "dev": true, "license": "MIT", "dependencies": { - "find-up": "^4.0.0" + "find-up": "^6.3.0" }, "engines": { - "node": ">=8" + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/punycode": { @@ -3810,9 +3313,9 @@ "license": "MIT" }, "node_modules/regenerate-unicode-properties": { - "version": "10.1.1", - "resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-10.1.1.tgz", - "integrity": "sha512-X007RyZLsCJVVrjgEFVpLUTZwyOZk3oiL75ZcuYjlIWd6rNJtOjkBwQc5AsRrpbKVkxN6sklw/k/9m2jJYOf8Q==", + "version": "10.2.0", + "resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-10.2.0.tgz", + "integrity": "sha512-DqHn3DwbmmPVzeKj9woBadqmXxLvQoQIwu7nopMc72ztvxVmVk2SBhSnx67zuye5TP+lJsb/TBQsjLKhnDf3MA==", "dev": true, "license": "MIT", "dependencies": { @@ -3840,16 +3343,16 @@ } }, "node_modules/regexpu-core": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-5.3.2.tgz", - "integrity": "sha512-RAM5FlZz+Lhmo7db9L298p2vHP5ZywrVXmVXpmAD9GuL5MPH6t9ROw1iA/wfHkQ76Qe7AaPF0nGuim96/IrQMQ==", + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-6.1.1.tgz", + "integrity": "sha512-k67Nb9jvwJcJmVpw0jPttR1/zVfnKf8Km0IPatrU/zJ5XeG3+Slx0xLXs9HByJSzXzrlz5EDvN6yLNMDc2qdnw==", "dev": true, "license": "MIT", "dependencies": { - "@babel/regjsgen": "^0.8.0", "regenerate": "^1.4.2", - "regenerate-unicode-properties": "^10.1.0", - "regjsparser": "^0.9.1", + "regenerate-unicode-properties": "^10.2.0", + "regjsgen": "^0.8.0", + "regjsparser": "^0.11.0", "unicode-match-property-ecmascript": "^2.0.0", "unicode-match-property-value-ecmascript": "^2.1.0" }, @@ -3857,27 +3360,31 @@ "node": ">=4" } }, + "node_modules/regjsgen": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.8.0.tgz", + "integrity": "sha512-RvwtGe3d7LvWiDQXeQw8p5asZUmfU1G/l6WbUXeHta7Y2PEIvBTwH6E2EfmYUK8pxcxEdEmaomqyp0vZZ7C+3Q==", + "dev": true, + "license": "MIT" + }, "node_modules/regjsparser": { - "version": "0.9.1", - "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.9.1.tgz", - "integrity": "sha512-dQUtn90WanSNl+7mQKcXAgZxvUe7Z0SqXlgzv0za4LwiUhyzBC58yQO3liFoUgu8GiJVInAhJjkj1N0EtQ5nkQ==", + "version": "0.11.2", + "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.11.2.tgz", + "integrity": "sha512-3OGZZ4HoLJkkAZx/48mTXJNlmqTGOzc0o9OWQPuWpkOlXXPbyN6OafCcoXUnBqE2D3f/T5L+pWc1kdEmnfnRsA==", "dev": true, "license": "BSD-2-Clause", "dependencies": { - "jsesc": "~0.5.0" + "jsesc": "~3.0.2" }, "bin": { "regjsparser": "bin/parser" } }, - "node_modules/regjsparser/node_modules/jsesc": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz", - "integrity": "sha512-uZz5UnB7u4T9LvwmFqXii7pZSouaRPorGs5who1Ip7VO0wxanFvBL7GkM6dTHlgX+jhBApRetaWpnDabOeTcnA==", - "dev": true, - "bin": { - "jsesc": "bin/jsesc" - } + "node_modules/remove-markdown": { + "version": "0.5.5", + "resolved": "https://registry.npmjs.org/remove-markdown/-/remove-markdown-0.5.5.tgz", + "integrity": "sha512-lMR8tOtDqazFT6W2bZidoXwkptMdF3pCxpri0AEokHg0sZlC2GdoLqnoaxsEj1o7/BtXV1MKtT3YviA1t7rW7g==", + "license": "MIT" }, "node_modules/require-from-string": { "version": "2.0.2", @@ -3966,18 +3473,19 @@ "license": "MIT" }, "node_modules/schema-utils": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.3.0.tgz", - "integrity": "sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg==", + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.2.0.tgz", + "integrity": "sha512-L0jRsrPpjdckP3oPug3/VxNKt2trR8TcabrM6FOAAlvC/9Phcmm+cuAgTlxBqdBR1WJx7Naj9WHw+aOmheSVbw==", "dev": true, "license": "MIT", "dependencies": { - "@types/json-schema": "^7.0.8", - "ajv": "^6.12.5", - "ajv-keywords": "^3.5.2" + "@types/json-schema": "^7.0.9", + "ajv": "^8.9.0", + "ajv-formats": "^2.1.1", + "ajv-keywords": "^5.1.0" }, "engines": { - "node": ">= 10.13.0" + "node": ">= 12.13.0" }, "funding": { "type": "opencollective", @@ -4116,9 +3624,9 @@ } }, "node_modules/terser": { - "version": "5.31.1", - "resolved": "https://registry.npmjs.org/terser/-/terser-5.31.1.tgz", - "integrity": "sha512-37upzU1+viGvuFtBo9NPufCb9dwM0+l9hMxYyWfBA+fbwrPqNJAhbZ6W47bBFnZHKHTUBnMvi87434qq+qnxOg==", + "version": "5.36.0", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.36.0.tgz", + "integrity": "sha512-IYV9eNMuFAV4THUspIRXkLakHnV6XO7FEdtKjf/mDyrnqUg9LnlOn6/RwRvM9SZjR4GUq8Nk8zj67FzVARr74w==", "dev": true, "license": "BSD-2-Clause", "dependencies": { @@ -4169,14 +3677,57 @@ } } }, - "node_modules/to-fast-properties": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", - "integrity": "sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==", + "node_modules/terser-webpack-plugin/node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", "dev": true, "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/terser-webpack-plugin/node_modules/ajv-keywords": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", + "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "ajv": "^6.9.1" + } + }, + "node_modules/terser-webpack-plugin/node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true, + "license": "MIT" + }, + "node_modules/terser-webpack-plugin/node_modules/schema-utils": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.3.0.tgz", + "integrity": "sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/json-schema": "^7.0.8", + "ajv": "^6.12.5", + "ajv-keywords": "^3.5.2" + }, "engines": { - "node": ">=4" + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" } }, "node_modules/totalist": { @@ -4189,17 +3740,26 @@ "node": ">=6" } }, + "node_modules/turndown": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/turndown/-/turndown-7.2.0.tgz", + "integrity": "sha512-eCZGBN4nNNqM9Owkv9HAtWRYfLA4h909E/WGAWWBpmB275ehNhZyk87/Tpvjbp0jjNl9XwCsbe6bm6CqFsgD+A==", + "license": "MIT", + "dependencies": { + "@mixmark-io/domino": "^2.2.0" + } + }, "node_modules/undici-types": { - "version": "5.26.5", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", - "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==", + "version": "6.19.8", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.19.8.tgz", + "integrity": "sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==", "dev": true, "license": "MIT" }, "node_modules/unicode-canonical-property-names-ecmascript": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.0.tgz", - "integrity": "sha512-yY5PpDlfVIU5+y/BSCxAJRBIS1Zc2dDG3Ujq+sR0U+JjUevW2JhocOF+soROYDSaAezOzOKuyyixhD6mBknSmQ==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.1.tgz", + "integrity": "sha512-dA8WbNeb2a6oQzAQ55YlT5vQAWGV9WXOsi3SskE3bcCdM0P4SDd+24zS/OCacdRq5BkdsRj9q3Pg6YyQoxIGqg==", "dev": true, "license": "MIT", "engines": { @@ -4221,9 +3781,9 @@ } }, "node_modules/unicode-match-property-value-ecmascript": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-2.1.0.tgz", - "integrity": "sha512-qxkjQt6qjg/mYscYMC0XKRn3Rh0wFPlfxB0xkt9CfyTvpX1Ra0+rAmdX2QyAobptSEvuy4RtpPRui6XkV+8wjA==", + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-2.2.0.tgz", + "integrity": "sha512-4IehN3V/+kkr5YeSSDDQG8QLqO26XpL2XP3GQtqwlT/QYSECAwFztxVHjlbh0+gjJ3XmNLS0zDsbgs9jWKExLg==", "dev": true, "license": "MIT", "engines": { @@ -4241,9 +3801,9 @@ } }, "node_modules/update-browserslist-db": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.0.tgz", - "integrity": "sha512-EdRAaAyk2cUE1wOf2DkEhzxqOQvFOoRJFNS6NeyJ01Gp2beMRpBAINjM2iDXE3KCuKhwnvHIQCJm6ThL2Z+HzQ==", + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.1.tgz", + "integrity": "sha512-R8UzCaa9Az+38REPiJ1tXlImTJXlVfgHZsglwBD/k6nj76ctsH1E3q4doGrukiLQd3sGQYu56r5+lo5r94l29A==", "dev": true, "funding": [ { @@ -4261,8 +3821,8 @@ ], "license": "MIT", "dependencies": { - "escalade": "^3.1.2", - "picocolors": "^1.0.1" + "escalade": "^3.2.0", + "picocolors": "^1.1.0" }, "bin": { "update-browserslist-db": "cli.js" @@ -4282,9 +3842,9 @@ } }, "node_modules/watchpack": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.1.tgz", - "integrity": "sha512-8wrBCMtVhqcXP2Sup1ctSkga6uc2Bx0IIvKyT7yTFier5AXHooSI+QyQQAtTb7+E0IUCCKyTFmXqdqgum2XWGg==", + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.2.tgz", + "integrity": "sha512-TnbFSbcOCcDgjZ4piURLCbJ3nJhznVh9kw6F6iokjiFPl8ONxe9A6nMDVXDiNbrSfLILs6vB07F7wLBrwPYzJw==", "dev": true, "license": "MIT", "dependencies": { @@ -4296,22 +3856,21 @@ } }, "node_modules/webpack": { - "version": "5.92.1", - "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.92.1.tgz", - "integrity": "sha512-JECQ7IwJb+7fgUFBlrJzbyu3GEuNBcdqr1LD7IbSzwkSmIevTm8PF+wej3Oxuz/JFBUZ6O1o43zsPkwm1C4TmA==", + "version": "5.96.1", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.96.1.tgz", + "integrity": "sha512-l2LlBSvVZGhL4ZrPwyr8+37AunkcYj5qh8o6u2/2rzoPc8gxFJkLj1WxNgooi9pnoc06jh0BjuXnamM4qlujZA==", "dev": true, "license": "MIT", "dependencies": { - "@types/eslint-scope": "^3.7.3", - "@types/estree": "^1.0.5", + "@types/eslint-scope": "^3.7.7", + "@types/estree": "^1.0.6", "@webassemblyjs/ast": "^1.12.1", "@webassemblyjs/wasm-edit": "^1.12.1", "@webassemblyjs/wasm-parser": "^1.12.1", - "acorn": "^8.7.1", - "acorn-import-attributes": "^1.9.5", - "browserslist": "^4.21.10", + "acorn": "^8.14.0", + "browserslist": "^4.24.0", "chrome-trace-event": "^1.0.2", - "enhanced-resolve": "^5.17.0", + "enhanced-resolve": "^5.17.1", "es-module-lexer": "^1.2.1", "eslint-scope": "5.1.1", "events": "^3.2.0", @@ -4461,6 +4020,59 @@ "node": ">=10.13.0" } }, + "node_modules/webpack/node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/webpack/node_modules/ajv-keywords": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", + "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "ajv": "^6.9.1" + } + }, + "node_modules/webpack/node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true, + "license": "MIT" + }, + "node_modules/webpack/node_modules/schema-utils": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.3.0.tgz", + "integrity": "sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/json-schema": "^7.0.8", + "ajv": "^6.12.5", + "ajv-keywords": "^3.5.2" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, "node_modules/which": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", diff --git a/app/js/readability/package.json b/packages/flutter_mozilla_components/javascript/readability/package.json similarity index 70% rename from app/js/readability/package.json rename to packages/flutter_mozilla_components/javascript/readability/package.json index 690b71ac..395989d8 100644 --- a/app/js/readability/package.json +++ b/packages/flutter_mozilla_components/javascript/readability/package.json @@ -11,16 +11,16 @@ "description": "", "dependencies": { "@mozilla/readability": "^0.5.0", - "dompurify": "^3.1.6" + "remove-markdown": "^0.5.5", + "turndown": "^7.2.0" }, "devDependencies": { - "@babel/core": "^7.24.7", - "@babel/preset-env": "^7.24.7", - "babel-loader": "^9.1.3", + "@babel/core": "^7.26.0", + "@babel/preset-env": "^7.26.0", + "babel-loader": "^9.2.1", "clean-webpack-plugin": "^4.0.0", - "compression-webpack-plugin": "^11.1.0", "terser-webpack-plugin": "^5.3.10", - "webpack": "^5.92.1", + "webpack": "^5.96.1", "webpack-bundle-analyzer": "^4.10.2", "webpack-cli": "^5.1.4" } diff --git a/packages/flutter_mozilla_components/javascript/readability/src/index.js b/packages/flutter_mozilla_components/javascript/readability/src/index.js new file mode 100644 index 00000000..620e7968 --- /dev/null +++ b/packages/flutter_mozilla_components/javascript/readability/src/index.js @@ -0,0 +1,35 @@ +import { Readability } from '@mozilla/readability'; +import TurndownService from 'turndown'; + +const removeMarkdown = require('remove-markdown'); + +const turndownService = new TurndownService(); + +function parseReaderable(document, options) { + const clonedDoc = document.cloneNode(true); + + const fullMarkdown = turndownService.turndown(clonedDoc.body.innerHTML); + + let response = { + fullContentMarkdown: fullMarkdown, + fullContentPlain: removeMarkdown(fullMarkdown), + } + + const reader = new Readability(clonedDoc, options); + const article = reader.parse(); + + if(article != null) { + const extractedMarkdown = turndownService.turndown(article.content); + + response = { + ...response, + extractedContentMarkdown: extractedMarkdown, + extractedContentPlain: removeMarkdown(extractedMarkdown) + }; + } + + return response; +} + +window.parseReaderable = parseReaderable; +export { parseReaderable }; \ No newline at end of file diff --git a/app/js/readability/webpack.config.js b/packages/flutter_mozilla_components/javascript/readability/webpack.config.js similarity index 88% rename from app/js/readability/webpack.config.js rename to packages/flutter_mozilla_components/javascript/readability/webpack.config.js index 73194482..35d619ee 100644 --- a/app/js/readability/webpack.config.js +++ b/packages/flutter_mozilla_components/javascript/readability/webpack.config.js @@ -2,7 +2,6 @@ const path = require('path'); const { BundleAnalyzerPlugin } = require('webpack-bundle-analyzer'); const TerserPlugin = require('terser-webpack-plugin'); const { CleanWebpackPlugin } = require('clean-webpack-plugin'); -const CompressionPlugin = require('compression-webpack-plugin'); module.exports = { entry: './src/index.js', @@ -45,10 +44,6 @@ module.exports = { openAnalyzer: false, generateStatsFile: true, statsOptions: { source: false } - }), - new CompressionPlugin({ - algorithm: 'gzip', - test: /\.js$/ }) ] }; diff --git a/packages/flutter_mozilla_components/lib/flutter_mozilla_components.dart b/packages/flutter_mozilla_components/lib/flutter_mozilla_components.dart index 84069066..9555c8c1 100644 --- a/packages/flutter_mozilla_components/lib/flutter_mozilla_components.dart +++ b/packages/flutter_mozilla_components/lib/flutter_mozilla_components.dart @@ -11,17 +11,22 @@ export 'src/domain/services/gecko_icon.dart'; export 'src/domain/services/gecko_readerable.dart'; export 'src/domain/services/gecko_selection_action.dart'; export 'src/domain/services/gecko_session.dart'; +export 'src/domain/services/gecko_suggestions.dart'; export 'src/domain/services/gecko_tab.dart'; +export 'src/domain/services/gecko_tab_content.dart'; export 'src/geckoview_widget.dart'; export 'src/pigeons/gecko.g.dart' show CookieSameSiteStatus, + GeckoSuggestion, + GeckoSuggestionType, HistoryMetadataKey, IconSource, IconType, Resource, ResourceSize, SecurityInfoState, + TabContent, TabContentState, WebExtensionActionType, WebExtensionData; diff --git a/packages/flutter_mozilla_components/lib/src/domain/services/gecko_readerable.dart b/packages/flutter_mozilla_components/lib/src/domain/services/gecko_readerable.dart index c19576dc..47308e8b 100644 --- a/packages/flutter_mozilla_components/lib/src/domain/services/gecko_readerable.dart +++ b/packages/flutter_mozilla_components/lib/src/domain/services/gecko_readerable.dart @@ -1,6 +1,7 @@ import 'dart:async'; import 'package:flutter/services.dart'; +import 'package:flutter_mozilla_components/src/extensions/subject.dart'; import 'package:flutter_mozilla_components/src/pigeons/gecko.g.dart'; import 'package:rxdart/rxdart.dart'; @@ -8,7 +9,6 @@ class GeckoReaderableService extends ReaderViewController { final ReaderViewEvents _events; final _appearanceVisibility = BehaviorSubject(); - final _readerVisibility = BehaviorSubject(); Stream get appearanceVisibility => _appearanceVisibility.stream; @@ -21,8 +21,8 @@ class GeckoReaderableService extends ReaderViewController { } @override - void appearanceButtonVisibility(bool visible) { - _appearanceVisibility.add(visible); + void appearanceButtonVisibility(int timestamp, bool visible) { + _appearanceVisibility.addWhenMoreRecent(timestamp, null, visible); } GeckoReaderableService.setUp({ @@ -43,6 +43,5 @@ class GeckoReaderableService extends ReaderViewController { void dispose() { unawaited(_appearanceVisibility.close()); - unawaited(_readerVisibility.close()); } } diff --git a/packages/flutter_mozilla_components/lib/src/domain/services/gecko_suggestions.dart b/packages/flutter_mozilla_components/lib/src/domain/services/gecko_suggestions.dart new file mode 100644 index 00000000..1a83908c --- /dev/null +++ b/packages/flutter_mozilla_components/lib/src/domain/services/gecko_suggestions.dart @@ -0,0 +1,56 @@ +import 'dart:async'; + +import 'package:flutter/services.dart'; +import 'package:flutter_mozilla_components/src/extensions/subject.dart'; +import 'package:flutter_mozilla_components/src/pigeons/gecko.g.dart'; +import 'package:rxdart/rxdart.dart'; + +final _apiInstance = GeckoSuggestionApi(); + +class GeckoSuggestionsService extends GeckoSuggestionEvents { + final GeckoSuggestionApi _api; + final _suggestionsSubject = BehaviorSubject>(); + + Stream> get suggestionsStream => + _suggestionsSubject.stream; + + GeckoSuggestionsService.setUp({ + BinaryMessenger? binaryMessenger, + String messageChannelSuffix = '', + GeckoSuggestionApi? api, + }) : _api = api ?? _apiInstance { + GeckoSuggestionEvents.setUp( + this, + binaryMessenger: binaryMessenger, + messageChannelSuffix: messageChannelSuffix, + ); + } + + Future onInputChanged( + String text, { + List providers = const [ + GeckoSuggestionType.session, + GeckoSuggestionType.clipboard, + GeckoSuggestionType.history, + ], + }) { + return _api.onInputChanged(text, providers); + } + + @override + void onSuggestionResult( + int timestamp, + GeckoSuggestionType suggestionType, + List suggestions, + ) { + _suggestionsSubject.addWhenMoreRecent( + timestamp, + suggestionType, + suggestions, + ); + } + + void dispose() { + unawaited(_suggestionsSubject.close()); + } +} diff --git a/packages/flutter_mozilla_components/lib/src/domain/services/gecko_tab_content.dart b/packages/flutter_mozilla_components/lib/src/domain/services/gecko_tab_content.dart new file mode 100644 index 00000000..f551eefd --- /dev/null +++ b/packages/flutter_mozilla_components/lib/src/domain/services/gecko_tab_content.dart @@ -0,0 +1,32 @@ +import 'dart:async'; + +import 'package:flutter/services.dart'; +import 'package:flutter_mozilla_components/src/extensions/subject.dart'; +import 'package:flutter_mozilla_components/src/pigeons/gecko.g.dart'; +import 'package:rxdart/rxdart.dart'; + +class GeckoTabContentService extends GeckoTabContentEvents { + final _contentSubject = BehaviorSubject(); + + Stream get tabContentStream => _contentSubject.stream; + + GeckoTabContentService.setUp({ + BinaryMessenger? binaryMessenger, + String messageChannelSuffix = '', + }) { + GeckoTabContentEvents.setUp( + this, + binaryMessenger: binaryMessenger, + messageChannelSuffix: messageChannelSuffix, + ); + } + + @override + void onContentUpdate(int timestamp, TabContent content) { + _contentSubject.addWhenMoreRecent(timestamp, content.tabId, content); + } + + void dispose() { + unawaited(_contentSubject.close()); + } +} diff --git a/packages/flutter_mozilla_components/lib/src/pigeons/gecko.g.dart b/packages/flutter_mozilla_components/lib/src/pigeons/gecko.g.dart index 7896d407..a9524958 100644 --- a/packages/flutter_mozilla_components/lib/src/pigeons/gecko.g.dart +++ b/packages/flutter_mozilla_components/lib/src/pigeons/gecko.g.dart @@ -88,6 +88,12 @@ enum WebExtensionActionType { page, } +enum GeckoSuggestionType { + session, + clipboard, + history, +} + /// Translation options that map to the Gecko Translations Options. /// /// @property downloadModel If the necessary models should be downloaded on request. If false, then @@ -1073,6 +1079,98 @@ class WebExtensionData { } } +class GeckoSuggestion { + GeckoSuggestion({ + required this.id, + required this.type, + required this.score, + this.title, + this.description, + this.editSuggestion, + this.icon, + }); + + String id; + + GeckoSuggestionType type; + + int score; + + String? title; + + String? description; + + String? editSuggestion; + + Uint8List? icon; + + Object encode() { + return [ + id, + type, + score, + title, + description, + editSuggestion, + icon, + ]; + } + + static GeckoSuggestion decode(Object result) { + result as List; + return GeckoSuggestion( + id: result[0]! as String, + type: result[1]! as GeckoSuggestionType, + score: result[2]! as int, + title: result[3] as String?, + description: result[4] as String?, + editSuggestion: result[5] as String?, + icon: result[6] as Uint8List?, + ); + } +} + +class TabContent { + TabContent({ + required this.tabId, + this.fullContentMarkdown, + this.fullContentPlain, + this.extractedContentMarkdown, + this.extractedContentPlain, + }); + + String tabId; + + String? fullContentMarkdown; + + String? fullContentPlain; + + String? extractedContentMarkdown; + + String? extractedContentPlain; + + Object encode() { + return [ + tabId, + fullContentMarkdown, + fullContentPlain, + extractedContentMarkdown, + extractedContentPlain, + ]; + } + + static TabContent decode(Object result) { + result as List; + return TabContent( + tabId: result[0]! as String, + fullContentMarkdown: result[1] as String?, + fullContentPlain: result[2] as String?, + extractedContentMarkdown: result[3] as String?, + extractedContentPlain: result[4] as String?, + ); + } +} + class _PigeonCodec extends StandardMessageCodec { const _PigeonCodec(); @@ -1102,81 +1200,90 @@ class _PigeonCodec extends StandardMessageCodec { } else if (value is WebExtensionActionType) { buffer.putUint8(135); writeValue(buffer, value.index); - } else if (value is TranslationOptions) { + } else if (value is GeckoSuggestionType) { buffer.putUint8(136); - writeValue(buffer, value.encode()); - } else if (value is ReaderState) { + writeValue(buffer, value.index); + } else if (value is TranslationOptions) { buffer.putUint8(137); writeValue(buffer, value.encode()); - } else if (value is LastMediaAccessState) { + } else if (value is ReaderState) { buffer.putUint8(138); writeValue(buffer, value.encode()); - } else if (value is HistoryMetadataKey) { + } else if (value is LastMediaAccessState) { buffer.putUint8(139); writeValue(buffer, value.encode()); - } else if (value is PackageCategoryValue) { + } else if (value is HistoryMetadataKey) { buffer.putUint8(140); writeValue(buffer, value.encode()); - } else if (value is ExternalPackage) { + } else if (value is PackageCategoryValue) { buffer.putUint8(141); writeValue(buffer, value.encode()); - } else if (value is LoadUrlFlagsValue) { + } else if (value is ExternalPackage) { buffer.putUint8(142); writeValue(buffer, value.encode()); - } else if (value is SourceValue) { + } else if (value is LoadUrlFlagsValue) { buffer.putUint8(143); writeValue(buffer, value.encode()); - } else if (value is TabState) { + } else if (value is SourceValue) { buffer.putUint8(144); writeValue(buffer, value.encode()); - } else if (value is RecoverableTab) { + } else if (value is TabState) { buffer.putUint8(145); writeValue(buffer, value.encode()); - } else if (value is RecoverableBrowserState) { + } else if (value is RecoverableTab) { buffer.putUint8(146); writeValue(buffer, value.encode()); - } else if (value is IconRequest) { + } else if (value is RecoverableBrowserState) { buffer.putUint8(147); writeValue(buffer, value.encode()); - } else if (value is ResourceSize) { + } else if (value is IconRequest) { buffer.putUint8(148); writeValue(buffer, value.encode()); - } else if (value is Resource) { + } else if (value is ResourceSize) { buffer.putUint8(149); writeValue(buffer, value.encode()); - } else if (value is IconResult) { + } else if (value is Resource) { buffer.putUint8(150); writeValue(buffer, value.encode()); - } else if (value is CookiePartitionKey) { + } else if (value is IconResult) { buffer.putUint8(151); writeValue(buffer, value.encode()); - } else if (value is Cookie) { + } else if (value is CookiePartitionKey) { buffer.putUint8(152); writeValue(buffer, value.encode()); - } else if (value is HistoryItem) { + } else if (value is Cookie) { buffer.putUint8(153); writeValue(buffer, value.encode()); - } else if (value is HistoryState) { + } else if (value is HistoryItem) { buffer.putUint8(154); writeValue(buffer, value.encode()); - } else if (value is ReaderableState) { + } else if (value is HistoryState) { buffer.putUint8(155); writeValue(buffer, value.encode()); - } else if (value is SecurityInfoState) { + } else if (value is ReaderableState) { buffer.putUint8(156); writeValue(buffer, value.encode()); - } else if (value is TabContentState) { + } else if (value is SecurityInfoState) { buffer.putUint8(157); writeValue(buffer, value.encode()); - } else if (value is FindResultState) { + } else if (value is TabContentState) { buffer.putUint8(158); writeValue(buffer, value.encode()); - } else if (value is CustomSelectionAction) { + } else if (value is FindResultState) { buffer.putUint8(159); writeValue(buffer, value.encode()); - } else if (value is WebExtensionData) { + } else if (value is CustomSelectionAction) { buffer.putUint8(160); writeValue(buffer, value.encode()); + } else if (value is WebExtensionData) { + buffer.putUint8(161); + writeValue(buffer, value.encode()); + } else if (value is GeckoSuggestion) { + buffer.putUint8(162); + writeValue(buffer, value.encode()); + } else if (value is TabContent) { + buffer.putUint8(163); + writeValue(buffer, value.encode()); } else { super.writeValue(buffer, value); } @@ -1207,55 +1314,62 @@ class _PigeonCodec extends StandardMessageCodec { final int? value = readValue(buffer) as int?; return value == null ? null : WebExtensionActionType.values[value]; case 136: - return TranslationOptions.decode(readValue(buffer)!); + final int? value = readValue(buffer) as int?; + return value == null ? null : GeckoSuggestionType.values[value]; case 137: - return ReaderState.decode(readValue(buffer)!); + return TranslationOptions.decode(readValue(buffer)!); case 138: - return LastMediaAccessState.decode(readValue(buffer)!); + return ReaderState.decode(readValue(buffer)!); case 139: - return HistoryMetadataKey.decode(readValue(buffer)!); + return LastMediaAccessState.decode(readValue(buffer)!); case 140: - return PackageCategoryValue.decode(readValue(buffer)!); + return HistoryMetadataKey.decode(readValue(buffer)!); case 141: - return ExternalPackage.decode(readValue(buffer)!); + return PackageCategoryValue.decode(readValue(buffer)!); case 142: - return LoadUrlFlagsValue.decode(readValue(buffer)!); + return ExternalPackage.decode(readValue(buffer)!); case 143: - return SourceValue.decode(readValue(buffer)!); + return LoadUrlFlagsValue.decode(readValue(buffer)!); case 144: - return TabState.decode(readValue(buffer)!); + return SourceValue.decode(readValue(buffer)!); case 145: - return RecoverableTab.decode(readValue(buffer)!); + return TabState.decode(readValue(buffer)!); case 146: - return RecoverableBrowserState.decode(readValue(buffer)!); + return RecoverableTab.decode(readValue(buffer)!); case 147: - return IconRequest.decode(readValue(buffer)!); + return RecoverableBrowserState.decode(readValue(buffer)!); case 148: - return ResourceSize.decode(readValue(buffer)!); + return IconRequest.decode(readValue(buffer)!); case 149: - return Resource.decode(readValue(buffer)!); + return ResourceSize.decode(readValue(buffer)!); case 150: - return IconResult.decode(readValue(buffer)!); + return Resource.decode(readValue(buffer)!); case 151: - return CookiePartitionKey.decode(readValue(buffer)!); + return IconResult.decode(readValue(buffer)!); case 152: - return Cookie.decode(readValue(buffer)!); + return CookiePartitionKey.decode(readValue(buffer)!); case 153: - return HistoryItem.decode(readValue(buffer)!); + return Cookie.decode(readValue(buffer)!); case 154: - return HistoryState.decode(readValue(buffer)!); + return HistoryItem.decode(readValue(buffer)!); case 155: - return ReaderableState.decode(readValue(buffer)!); + return HistoryState.decode(readValue(buffer)!); case 156: - return SecurityInfoState.decode(readValue(buffer)!); + return ReaderableState.decode(readValue(buffer)!); case 157: - return TabContentState.decode(readValue(buffer)!); + return SecurityInfoState.decode(readValue(buffer)!); case 158: - return FindResultState.decode(readValue(buffer)!); + return TabContentState.decode(readValue(buffer)!); case 159: - return CustomSelectionAction.decode(readValue(buffer)!); + return FindResultState.decode(readValue(buffer)!); case 160: + return CustomSelectionAction.decode(readValue(buffer)!); + case 161: return WebExtensionData.decode(readValue(buffer)!); + case 162: + return GeckoSuggestion.decode(readValue(buffer)!); + case 163: + return TabContent.decode(readValue(buffer)!); default: return super.readValueOfType(type, buffer); } @@ -2812,7 +2926,7 @@ class ReaderViewEvents { abstract class ReaderViewController { static const MessageCodec pigeonChannelCodec = _PigeonCodec(); - void appearanceButtonVisibility(bool visible); + void appearanceButtonVisibility(int timestamp, bool visible); static void setUp(ReaderViewController? api, {BinaryMessenger? binaryMessenger, String messageChannelSuffix = '',}) { messageChannelSuffix = messageChannelSuffix.isNotEmpty ? '.$messageChannelSuffix' : ''; @@ -2827,11 +2941,14 @@ abstract class ReaderViewController { assert(message != null, 'Argument for dev.flutter.pigeon.flutter_mozilla_components.ReaderViewController.appearanceButtonVisibility was null.'); final List args = (message as List?)!; - final bool? arg_visible = (args[0] as bool?); + final int? arg_timestamp = (args[0] as int?); + assert(arg_timestamp != null, + 'Argument for dev.flutter.pigeon.flutter_mozilla_components.ReaderViewController.appearanceButtonVisibility was null, expected non-null int.'); + final bool? arg_visible = (args[1] as bool?); assert(arg_visible != null, 'Argument for dev.flutter.pigeon.flutter_mozilla_components.ReaderViewController.appearanceButtonVisibility was null, expected non-null bool.'); try { - api.appearanceButtonVisibility(arg_visible!); + api.appearanceButtonVisibility(arg_timestamp!, arg_visible!); return wrapResponse(empty: true); } on PlatformException catch (e) { return wrapResponse(error: e); @@ -3088,3 +3205,118 @@ abstract class GeckoAddonEvents { } } } + +class GeckoSuggestionApi { + /// Constructor for [GeckoSuggestionApi]. The [binaryMessenger] named argument is + /// available for dependency injection. If it is left null, the default + /// BinaryMessenger will be used which routes to the host platform. + GeckoSuggestionApi({BinaryMessenger? binaryMessenger, String messageChannelSuffix = ''}) + : pigeonVar_binaryMessenger = binaryMessenger, + pigeonVar_messageChannelSuffix = messageChannelSuffix.isNotEmpty ? '.$messageChannelSuffix' : ''; + final BinaryMessenger? pigeonVar_binaryMessenger; + + static const MessageCodec pigeonChannelCodec = _PigeonCodec(); + + final String pigeonVar_messageChannelSuffix; + + Future onInputChanged(String text, List providers) async { + final String pigeonVar_channelName = 'dev.flutter.pigeon.flutter_mozilla_components.GeckoSuggestionApi.onInputChanged$pigeonVar_messageChannelSuffix'; + final BasicMessageChannel pigeonVar_channel = BasicMessageChannel( + pigeonVar_channelName, + pigeonChannelCodec, + binaryMessenger: pigeonVar_binaryMessenger, + ); + final List? pigeonVar_replyList = + await pigeonVar_channel.send([text, providers]) as List?; + if (pigeonVar_replyList == null) { + throw _createConnectionError(pigeonVar_channelName); + } else if (pigeonVar_replyList.length > 1) { + throw PlatformException( + code: pigeonVar_replyList[0]! as String, + message: pigeonVar_replyList[1] as String?, + details: pigeonVar_replyList[2], + ); + } else { + return; + } + } +} + +abstract class GeckoSuggestionEvents { + static const MessageCodec pigeonChannelCodec = _PigeonCodec(); + + void onSuggestionResult(int timestamp, GeckoSuggestionType suggestionType, List suggestions); + + static void setUp(GeckoSuggestionEvents? api, {BinaryMessenger? binaryMessenger, String messageChannelSuffix = '',}) { + messageChannelSuffix = messageChannelSuffix.isNotEmpty ? '.$messageChannelSuffix' : ''; + { + final BasicMessageChannel pigeonVar_channel = BasicMessageChannel( + 'dev.flutter.pigeon.flutter_mozilla_components.GeckoSuggestionEvents.onSuggestionResult$messageChannelSuffix', pigeonChannelCodec, + binaryMessenger: binaryMessenger); + if (api == null) { + pigeonVar_channel.setMessageHandler(null); + } else { + pigeonVar_channel.setMessageHandler((Object? message) async { + assert(message != null, + 'Argument for dev.flutter.pigeon.flutter_mozilla_components.GeckoSuggestionEvents.onSuggestionResult was null.'); + final List args = (message as List?)!; + final int? arg_timestamp = (args[0] as int?); + assert(arg_timestamp != null, + 'Argument for dev.flutter.pigeon.flutter_mozilla_components.GeckoSuggestionEvents.onSuggestionResult was null, expected non-null int.'); + final GeckoSuggestionType? arg_suggestionType = (args[1] as GeckoSuggestionType?); + assert(arg_suggestionType != null, + 'Argument for dev.flutter.pigeon.flutter_mozilla_components.GeckoSuggestionEvents.onSuggestionResult was null, expected non-null GeckoSuggestionType.'); + final List? arg_suggestions = (args[2] as List?)?.cast(); + assert(arg_suggestions != null, + 'Argument for dev.flutter.pigeon.flutter_mozilla_components.GeckoSuggestionEvents.onSuggestionResult was null, expected non-null List.'); + try { + api.onSuggestionResult(arg_timestamp!, arg_suggestionType!, arg_suggestions!); + return wrapResponse(empty: true); + } on PlatformException catch (e) { + return wrapResponse(error: e); + } catch (e) { + return wrapResponse(error: PlatformException(code: 'error', message: e.toString())); + } + }); + } + } + } +} + +abstract class GeckoTabContentEvents { + static const MessageCodec pigeonChannelCodec = _PigeonCodec(); + + void onContentUpdate(int timestamp, TabContent content); + + static void setUp(GeckoTabContentEvents? api, {BinaryMessenger? binaryMessenger, String messageChannelSuffix = '',}) { + messageChannelSuffix = messageChannelSuffix.isNotEmpty ? '.$messageChannelSuffix' : ''; + { + final BasicMessageChannel pigeonVar_channel = BasicMessageChannel( + 'dev.flutter.pigeon.flutter_mozilla_components.GeckoTabContentEvents.onContentUpdate$messageChannelSuffix', pigeonChannelCodec, + binaryMessenger: binaryMessenger); + if (api == null) { + pigeonVar_channel.setMessageHandler(null); + } else { + pigeonVar_channel.setMessageHandler((Object? message) async { + assert(message != null, + 'Argument for dev.flutter.pigeon.flutter_mozilla_components.GeckoTabContentEvents.onContentUpdate was null.'); + final List args = (message as List?)!; + final int? arg_timestamp = (args[0] as int?); + assert(arg_timestamp != null, + 'Argument for dev.flutter.pigeon.flutter_mozilla_components.GeckoTabContentEvents.onContentUpdate was null, expected non-null int.'); + final TabContent? arg_content = (args[1] as TabContent?); + assert(arg_content != null, + 'Argument for dev.flutter.pigeon.flutter_mozilla_components.GeckoTabContentEvents.onContentUpdate was null, expected non-null TabContent.'); + try { + api.onContentUpdate(arg_timestamp!, arg_content!); + return wrapResponse(empty: true); + } on PlatformException catch (e) { + return wrapResponse(error: e); + } catch (e) { + return wrapResponse(error: PlatformException(code: 'error', message: e.toString())); + } + }); + } + } + } +} diff --git a/packages/flutter_mozilla_components/pigeons/gecko.dart b/packages/flutter_mozilla_components/pigeons/gecko.dart index eb1b84a5..57beabc2 100644 --- a/packages/flutter_mozilla_components/pigeons/gecko.dart +++ b/packages/flutter_mozilla_components/pigeons/gecko.dart @@ -499,6 +499,44 @@ class WebExtensionData { ); } +enum GeckoSuggestionType { session, clipboard, history } + +class GeckoSuggestion { + final String id; + final GeckoSuggestionType type; + final int score; + final String? title; + final String? description; + final String? editSuggestion; + final Uint8List? icon; + + GeckoSuggestion( + this.id, + this.type, + this.score, + this.title, + this.description, + this.editSuggestion, + this.icon, + ); +} + +class TabContent { + final String tabId; + final String? fullContentMarkdown; + final String? fullContentPlain; + final String? extractedContentMarkdown; + final String? extractedContentPlain; + + TabContent( + this.tabId, + this.fullContentMarkdown, + this.fullContentPlain, + this.extractedContentMarkdown, + this.extractedContentPlain, + ); +} + // /// Represents all the different supported types of data that can be found from long clicking // /// an element. // sealed class HitResult { @@ -843,7 +881,7 @@ abstract class ReaderViewEvents { @FlutterApi() abstract class ReaderViewController { - void appearanceButtonVisibility(bool visible); + void appearanceButtonVisibility(int timestamp, bool visible); } @HostApi() @@ -885,3 +923,25 @@ abstract class GeckoAddonEvents { Uint8List icon, ); } + +@HostApi() +abstract class GeckoSuggestionApi { + void onInputChanged(String text, List providers); +} + +@FlutterApi() +abstract class GeckoSuggestionEvents { + void onSuggestionResult( + int timestamp, + GeckoSuggestionType suggestionType, + List suggestions, + ); +} + +@FlutterApi() +abstract class GeckoTabContentEvents { + void onContentUpdate( + int timestamp, + TabContent content, + ); +}