diff --git a/CHANGELOG.md b/CHANGELOG.md index b7b3f067..a901b0ea 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,18 @@ # Changelog +## 3.4.0 +- Fixed extra spaces in titles which could cause issues (thanks @rickdoesdev !) +- Fixed an issue with image paths in some circumstances (thanks @rickdoesdev !) +- Added parametersizations for "mixed-kebab" and "mixed_snake" which retain original casing but replace spaces (thanks @NSHenry !) + - Also added a special "obsidian-cal" parameterization which is the same as "mixed-kebab" with duplicate `-` removed for additional compatibility with the Obsidian Consistent Attachment Location plugin (thanks @NSHenry !) +- Added lowecase and uppercase options to parameterizations (thanks @redxtech !) +- Updated Turndown to v7.1.3 (thanks @WeHat !) +- Updated Readability to v0.5.0 (thanks @WeHat !) +- Fixed some issues with code block parsing and formatting (thanks @WeHat !) +- Fixed an issue with some sites missing a proper title (thanks @WeHat !) +- Fixed an issue with bad base urls causing issues with links in certain circumstances (thanks @WeHat !) +- Fixed an issue with readability removing everything in certain circumstances (thanks @WeHat !) +- Send properly configured title to the Obsidian integration (thanks @nekton39 !) +- Updates to the README (thanks @2gn and @eugenesvk !) ## 3.3.0 - Remove hidden content before exporting (thanks @nhaouari !). This allows you to use a different extension (e.g. Adblock) to hide elements that would otherwise clutter up your export - Fixes for Obsidian integration in Safari (thanks @aancw !) diff --git a/README.md b/README.md index e2d13911..840a361e 100644 --- a/README.md +++ b/README.md @@ -23,12 +23,27 @@ The extension is available for [Firefox](https://addons.mozilla.org/en-GB/firefo # Obsidian Integration For integration with obsidian, you need to install and enable community plugins named "Advanced Obsidian URI". This plugin help us to bypass character limitation in URL. Because it's using clipboard as the source for creating new file. -More information: https://vinzent03.github.io/obsidian-advanced-uri/ +More information about Advanced Obsidian URI plugin: https://vinzent03.github.io/obsidian-advanced-uri/ + +You need to do some configurations in order to use this integration. +
+ Steps to follow + + 1. Left-Click on the extension + 2. Click on the gear icon to open the configuration menu + 3. Scroll down to "Obsidian integration" section and turn "enable obsidian integration" on. + 4. Fill out the form below (Obsidian vault name and Obsidian folder name.) + 5. Right-click on the extension and open the menu + 6. In "MarkDownload - Markdown Web Clipper", select "Send Tab to Obsidian" + +
+ + # External Libraries It uses the following libraries: -- [Readability.js](https://github.com/mozilla/readability) by Mozilla in version from commit [1fde3ac626bc4c2e5e54daa57c57d48b7ed9c574](https://github.com/mozilla/readability/commit/1fde3ac626bc4c2e5e54daa57c57d48b7ed9c574). This library is also used for the Firefox Reader View and it simplifies the page so that only the important parts are clipped. (Licensed under Apache License Version 2.0) -- [Turndown](https://github.com/mixmark-io/turndown) by Dom Christie in version 7.1.1 is used to convert the simplified HTML (from Readability.js) into markdown. (Licensed under MIT License) +- [Readability.js](https://github.com/mozilla/readability) by Mozilla version [0.5.0](https://github.com/mozilla/readability/releases/tag/0.5.0). This library is also used for the Firefox Reader View and it simplifies the page so that only the important parts are clipped. (Licensed under Apache License Version 2.0) +- [Turndown](https://github.com/mixmark-io/turndown) by Dom Christie in version [7.1.3](https://github.com/mixmark-io/turndown/releases/tag/v7.1.3) is used to convert the simplified HTML (from Readability.js) into markdown. (Licensed under MIT License) - [Moment.js](https://momentjs.com) version 2.29.4 used to format dates in template variables # Permissions @@ -42,7 +57,7 @@ It uses the following libraries: The Common Mark icon courtesy of https://github.com/dcurtis/markdown-mark ## Pricing -This is an open-source extension I made *for fun*. It's intention is to be completely free. +This is an open-source extension I made *for fun*. Its intention is to be completely free. It's free on Firefox, Edge and Chrome (and other Chromium browsers), but unfortunately for Safari there is a yearly developer fee, so I've decided to charge a small price for the Safari version to help cover that cost. @@ -56,25 +71,19 @@ in my hat via the following: [![Paypal](https://img.shields.io/badge/paypal-deathau-yellow?style=social&logo=paypal)](https://paypal.me/deathau) # Version History -## 3.3.0 -- Remove hidden content before exporting (thanks @nhaouari !). This allows you to use a different extension (e.g. Adblock) to hide elements that would otherwise clutter up your export -- Fixes for Obsidian integration in Safari (thanks @aancw !) -- Keep a few more HTML tags that have no markdown equivalent (`u`, `ins`, `del`, `small`, `big`) (thanks @mnaoumov !) -- Add support for KaTeX formulas parsing (thanks @mnaoumov !) -- Fixed saving for options when imported from file (and show a little 'saved' indicator) -- Added a toggle for downloading images in the context menu and popup -- Added a link to the options in the popup -- Added some basic error handling to the popup -- Changes to how html inside code blocks is handled (thanks @mnaumov !) -- Treat codehilite without specified language as plaintext (thanks @mnaoumov !) -- Ensure sequential line breaks in `
` are preserved in code blocks (thanks @mnaumov !)
-- Update user guide link in README to point to GitHub
-- Added keyboard shortcuts to copy selection / current tab to obsidian (user-definable in browsers that support that) (thanks @legolasdimir and @likeablob !)
-- Select multiple tabs (hold crtl/cmd) then copy all tab urls as a markdown link list via keyboard shortcut or context menu (thanks @romanPrignon !)
-- Allow users to include custom text such like `{date:YYYY-MM-DD}/`` in their Obsidian Folder Name setting (thanks @likeablob !)
-- Fixed a small typo in the user guide (thanks @devon-research !)
-- Fix for missing headings on sites like Substack (thanks @eactisgrosso !)
-- Add support for websites using MathJax 3 (thanks @LeLocTai !)
-- Moved previous version history into [CHANGELOG.md](./CHANGELOG.md)
-
-> Previous version history is recorded in [CHANGELOG.md](./CHANGELOG.md)
\ No newline at end of file
+## 3.4.0
+- Fixed extra spaces in titles which could cause issues (thanks @rickdoesdev !)
+- Fixed an issue with image paths in some circumstances (thanks @rickdoesdev !)
+- Added parametersizations for "mixed-kebab" and "mixed_snake" which retain original casing but replace spaces (thanks @NSHenry !)
+  - Also added a special "obsidian-cal" parameterization which is the same as "mixed-kebab" with duplicate `-` removed for additional compatibility with the Obsidian Consistent Attachment Location plugin (thanks @NSHenry !)
+- Added lowecase and uppercase options to parameterizations (thanks @redxtech !)
+- Updated Turndown to v7.1.3 (thanks @WeHat !)
+- Updated Readability to v0.5.0 (thanks @WeHat !)
+- Fixed some issues with code block parsing and formatting (thanks @WeHat !)
+- Fixed an issue with some sites missing a proper title (thanks @WeHat !)
+- Fixed an issue with bad base urls causing issues with links in certain circumstances (thanks @WeHat !)
+- Fixed an issue with readability removing everything in certain circumstances (thanks @WeHat !)
+- Send properly configured title to the Obsidian integration (thanks @nekton39 !)
+- Updates to the README (thanks @2gn and @eugenesvk !)
+
+> Previous version history is recorded in [CHANGELOG.md](./CHANGELOG.md)
diff --git a/UPGRADE_NOTES.md b/UPGRADE_NOTES.md
new file mode 100644
index 00000000..da611208
--- /dev/null
+++ b/UPGRADE_NOTES.md
@@ -0,0 +1,101 @@
+# MarkDownload Manifest V3 升级说明
+
+## 已完成的修改
+
+### 1. Manifest.json 升级
+- 从 Manifest V2 升级到 Manifest V3
+- 更新权限:将 `` 移动到 `host_permissions`
+- 将 `browser_action` 更改为 `action`
+- 将 `background.scripts` 更改为 `background.service_worker`
+- 添加了 `scripting` 权限以支持动态脚本注入
+- 添加了 `content_scripts` 声明以自动注入内容脚本
+- **修复**: 移除了 `options_ui` 中不兼容的 `chrome_style` 和 `browser_style` 选项
+- **修复**: 将命令 `_execute_browser_action` 改为 `_execute_action`
+
+### 2. Background Script 转换为 Service Worker
+- 创建了新的 `src/background/service-worker.js` 文件
+- 将所有依赖脚本使用 `importScripts()` 导入
+- 更新了所有 Chrome API 调用以适配 Manifest V3
+- 使用 `chrome.scripting.executeScript()` 替代 `chrome.tabs.executeScript()`
+- 添加了详细的调试日志用于问题排查
+
+### 3. 内容脚本改进
+- 添加了详细的调试日志
+- 改进了DOM处理和错误处理
+- 增强了剪贴板操作的兼容性
+- 添加了更好的浏览器API兼容性检查
+
+### 4. 调试功能
+- 在所有关键函数中添加了console.log输出
+- 添加了错误处理和回退机制
+- 提供了详细的操作状态信息
+
+## 测试建议
+
+### 1. 加载扩展
+1. 打开 Chrome 浏览器
+2. 导航到 `chrome://extensions/`
+3. 启用"开发者模式"
+4. 点击"加载已解压的扩展程序"
+5. 选择 `src` 目录
+
+### 2. 测试功能
+1. **基本测试**:
+   - 右键点击页面,检查是否出现 MarkDownload 上下文菜单
+   - 点击扩展图标,检查弹出窗口是否正常显示
+
+2. **核心功能测试**:
+   - 测试"Download Tab As Markdown"
+   - 测试"Copy Tab As Markdown"
+   - 测试选中文本后的"Copy Selection As Markdown"
+
+3. **调试检查**:
+   - 打开 Chrome 开发者工具
+   - 检查 Console 标签页中的 MarkDownload 日志输出
+   - Service Worker 日志可在扩展管理页面的"Service Worker"链接中查看
+
+### 3. 常见问题排查
+
+#### 如果扩展无法加载:
+1. 检查 manifest.json 语法是否正确
+2. 确保所有引用的文件都存在
+3. 查看扩展管理页面的错误信息
+
+**已修复的常见错误:**
+- ✅ "The chrome_style option cannot be used with manifest version 3" - 已从 `options_ui` 中移除 `chrome_style` 和 `browser_style`
+- ✅ "_execute_browser_action command not recognized" - 已更改为 `_execute_action`
+
+#### 如果功能不工作:
+1. 检查 Service Worker 是否运行(在扩展管理页面)
+2. 查看浏览器控制台的错误信息
+3. 检查 MarkDownload 的调试日志
+
+#### 如果权限问题:
+1. 确保网站允许执行脚本
+2. 检查是否在受限页面(如 chrome://)上使用
+3. 验证 host_permissions 是否正确设置
+
+## 技术细节
+
+### Service Worker 变化
+- 不再是持久的背景页面,而是事件驱动的
+- 需要使用 `importScripts()` 导入依赖
+- API 调用从 `browser.*` 改为 `chrome.*`
+
+### 内容脚本注入
+- 从动态注入改为声明式注入
+- 使用 `chrome.scripting.executeScript()` 进行必要时的动态注入
+- 改进了脚本可用性检查
+
+### 权限模型
+- `` 权限移至 `host_permissions`
+- 添加了 `scripting` 权限支持动态脚本执行
+
+## 已知限制
+- 在某些受保护的页面(如 chrome:// 页面)上无法工作
+- Service Worker 在空闲时会被暂停,但会在需要时自动恢复
+
+## 版本兼容性
+- 支持 Chrome 88+ (Manifest V3 最低要求)
+- 向后兼容原有功能
+- 保持与 Firefox 的兼容性(通过 browser-polyfill)
diff --git a/src/background/Readability.js b/src/background/Readability.js
index ce06df45..b745aa01 100644
--- a/src/background/Readability.js
+++ b/src/background/Readability.js
@@ -1,4 +1,3 @@
-/*eslint-env es6:false*/
 /*
  * Copyright (c) 2010 Arc90 Inc
  *
@@ -54,6 +53,7 @@ function Readability(doc, options) {
     return el.innerHTML;
   };
   this._disableJSONLD = !!options.disableJSONLD;
+  this._allowedVideoRegex = options.allowedVideoRegex || this.REGEXPS.videos;
 
   // Start with all flags set
   this._flags = this.FLAG_STRIP_UNLIKELYS |
@@ -73,12 +73,7 @@ function Readability(doc, options) {
       return `<${node.localName} ${attrPairs}>`;
     };
     this.log = function () {
-      if (typeof dump !== "undefined") {
-        var msg = Array.prototype.map.call(arguments, function(x) {
-          return (x && x.nodeName) ? logNode(x) : x;
-        }).join(" ");
-        dump("Reader: (Readability) " + msg + "\n");
-      } else if (typeof console !== "undefined") {
+      if (typeof console !== "undefined") {
         let args = Array.from(arguments, arg => {
           if (arg && arg.nodeType == this.ELEMENT_NODE) {
             return logNode(arg);
@@ -87,6 +82,12 @@ function Readability(doc, options) {
         });
         args.unshift("Reader: (Readability)");
         console.log.apply(console, args);
+      } else if (typeof dump !== "undefined") {
+        /* global dump */
+        var msg = Array.prototype.map.call(arguments, function(x) {
+          return (x && x.nodeName) ? logNode(x) : x;
+        }).join(" ");
+        dump("Reader: (Readability) " + msg + "\n");
       }
     };
   } else {
@@ -140,6 +141,9 @@ Readability.prototype = {
     hashUrl: /^#.+/,
     srcsetUrl: /(\S+)(\s+[\d.]+[xw])?(\s*(?:,|$))/g,
     b64DataUrl: /^data:\s*([^\s;,]+)\s*;\s*base64\s*,/i,
+    // Commas as used in Latin, Sindhi, Chinese and various other scripts.
+    // see: https://en.wikipedia.org/wiki/Comma#Comma_variants
+    commas: /\u002C|\u060C|\uFE50|\uFE10|\uFE11|\u2E41|\u2E34|\u2E32|\uFF0C/g,
     // See: https://schema.org/Article
     jsonLdArticleTypes: /^Article|AdvertiserContentArticle|NewsArticle|AnalysisNewsArticle|AskPublicNewsArticle|BackgroundNewsArticle|OpinionNewsArticle|ReportageNewsArticle|ReviewNewsArticle|Report|SatiricalArticle|ScholarlyArticle|MedicalScholarlyArticle|SocialMediaPosting|BlogPosting|LiveBlogPosting|DiscussionForumPosting|TechArticle|APIReference$/
   },
@@ -909,6 +913,12 @@ Readability.prototype = {
           continue;
         }
 
+        // User is not able to see elements applied with both "aria-modal = true" and "role = dialog"
+        if (node.getAttribute("aria-modal") == "true" && node.getAttribute("role") == "dialog") {
+          node = this._removeAndGetNext(node);
+          continue;
+        }
+
         // Check to see if this node is a byline, and remove it if it is.
         if (this._checkByline(node, matchString)) {
           node = this._removeAndGetNext(node);
@@ -1023,7 +1033,7 @@ Readability.prototype = {
         contentScore += 1;
 
         // Add points for any commas within this paragraph.
-        contentScore += innerText.split(",").length;
+        contentScore += innerText.split(this.REGEXPS.commas).length;
 
         // For every 100 characters in this paragraph, add another point. Up to 3 points.
         contentScore += Math.min(Math.floor(innerText.length / 100), 3);
@@ -1437,6 +1447,9 @@ Readability.prototype = {
           ) {
             metadata.siteName = parsed.publisher.name.trim();
           }
+          if (typeof parsed.datePublished === "string") {
+            metadata.datePublished = parsed.datePublished.trim();
+          }
           return;
         } catch (err) {
           this.log(err.message);
@@ -1460,7 +1473,7 @@ Readability.prototype = {
     var metaElements = this._doc.getElementsByTagName("meta");
 
     // property is a space-separated list of values
-    var propertyPattern = /\s*(dc|dcterm|og|twitter)\s*:\s*(author|creator|description|title|site_name)\s*/gi;
+    var propertyPattern = /\s*(article|dc|dcterm|og|twitter)\s*:\s*(author|creator|description|published_time|title|site_name)\s*/gi;
 
     // name is a single value
     var namePattern = /^\s*(?:(dc|dcterm|og|twitter|weibo:(article|webpage))\s*[\.:]\s*)?(author|creator|description|title|site_name)\s*$/i;
@@ -1531,12 +1544,17 @@ Readability.prototype = {
     metadata.siteName = jsonld.siteName ||
                         values["og:site_name"];
 
+    // get article published time
+    metadata.publishedTime = jsonld.datePublished ||
+      values["article:published_time"] || null;
+
     // in many sites the meta value is escaped with HTML entities,
     // so here we need to unescape it
     metadata.title = this._unescapeHtmlEntities(metadata.title);
     metadata.byline = this._unescapeHtmlEntities(metadata.byline);
     metadata.excerpt = this._unescapeHtmlEntities(metadata.excerpt);
     metadata.siteName = this._unescapeHtmlEntities(metadata.siteName);
+    metadata.publishedTime = this._unescapeHtmlEntities(metadata.publishedTime);
 
     return metadata;
   },
@@ -1642,12 +1660,7 @@ Readability.prototype = {
    * @param Element
   **/
   _removeScripts: function(doc) {
-    this._removeNodes(this._getAllNodesWithTag(doc, ["script"]), function(scriptNode) {
-      scriptNode.nodeValue = "";
-      scriptNode.removeAttribute("src");
-      return true;
-    });
-    this._removeNodes(this._getAllNodesWithTag(doc, ["noscript"]));
+    this._removeNodes(this._getAllNodesWithTag(doc, ["script", "noscript"]));
   },
 
   /**
@@ -1837,13 +1850,13 @@ Readability.prototype = {
       if (isEmbed) {
         // First, check the elements attributes to see if any of them contain youtube or vimeo
         for (var i = 0; i < element.attributes.length; i++) {
-          if (this.REGEXPS.videos.test(element.attributes[i].value)) {
+          if (this._allowedVideoRegex.test(element.attributes[i].value)) {
             return false;
           }
         }
 
         // For embed with  tag, check inner HTML as well.
-        if (element.tagName === "object" && this.REGEXPS.videos.test(element.innerHTML)) {
+        if (element.tagName === "object" && this._allowedVideoRegex.test(element.innerHTML)) {
           return false;
         }
       }
@@ -2112,13 +2125,13 @@ Readability.prototype = {
         for (var i = 0; i < embeds.length; i++) {
           // If this embed has attribute that matches video regex, don't delete it.
           for (var j = 0; j < embeds[i].attributes.length; j++) {
-            if (this.REGEXPS.videos.test(embeds[i].attributes[j].value)) {
+            if (this._allowedVideoRegex.test(embeds[i].attributes[j].value)) {
               return false;
             }
           }
 
           // For embed with  tag, check inner HTML as well.
-          if (embeds[i].tagName === "object" && this.REGEXPS.videos.test(embeds[i].innerHTML)) {
+          if (embeds[i].tagName === "object" && this._allowedVideoRegex.test(embeds[i].innerHTML)) {
             return false;
           }
 
@@ -2136,6 +2149,21 @@ Readability.prototype = {
           (!isList && weight < 25 && linkDensity > 0.2) ||
           (weight >= 25 && linkDensity > 0.5) ||
           ((embedCount === 1 && contentLength < 75) || embedCount > 1);
+        // Allow simple lists of images to remain in pages
+        if (isList && haveToRemove) {
+          for (var x = 0; x < node.children.length; x++) {
+            let child = node.children[x];
+            // Don't filter in lists with li's that contain more than one child
+            if (child.children.length > 1) {
+              return haveToRemove;
+            }
+          }
+          let li_count = node.getElementsByTagName("li").length;
+          // Only allow the list to remain if every li contains an image
+          if (img == li_count) {
+            return false;
+          }
+        }
         return haveToRemove;
       }
       return false;
@@ -2205,6 +2233,7 @@ Readability.prototype = {
   _isProbablyVisible: function(node) {
     // Have to null-check node.style and node.className.indexOf to deal with SVG and MathML nodes.
     return (!node.style || node.style.display != "none")
+      && (!node.style || node.style.visibility != "hidden")
       && !node.hasAttribute("hidden")
       //check for "fallback-image" so that wikimedia math images are displayed
       && (!node.hasAttribute("aria-hidden") || node.getAttribute("aria-hidden") != "true" || (node.className && node.className.indexOf && node.className.indexOf("fallback-image") !== -1));
@@ -2273,11 +2302,13 @@ Readability.prototype = {
       textContent: textContent,
       length: textContent.length,
       excerpt: metadata.excerpt,
-      siteName: metadata.siteName || this._articleSiteName
+      siteName: metadata.siteName || this._articleSiteName,
+      publishedTime: metadata.publishedTime
     };
   }
 };
 
 if (typeof module === "object") {
+  /* global module */
   module.exports = Readability;
 }
diff --git a/src/background/background.js b/src/background/background.js
deleted file mode 100644
index 5b5445f5..00000000
--- a/src/background/background.js
+++ /dev/null
@@ -1,1016 +0,0 @@
-// log some info
-browser.runtime.getPlatformInfo().then(async platformInfo => {
-  const browserInfo = browser.runtime.getBrowserInfo ? await browser.runtime.getBrowserInfo() : "Can't get browser info"
-  console.info(platformInfo, browserInfo);
-});
-
-// add notification listener for foreground page messages
-browser.runtime.onMessage.addListener(notify);
-// create context menus
-createMenus()
-
-TurndownService.prototype.defaultEscape = TurndownService.prototype.escape;
-
-// function to convert the article content to markdown using Turndown
-function turndown(content, options, article) {
-
-  if (options.turndownEscape) TurndownService.prototype.escape = TurndownService.prototype.defaultEscape;
-  else TurndownService.prototype.escape = s => s;
-
-  var turndownService = new TurndownService(options);
-
-  turndownService.use(turndownPluginGfm.gfm)
-
-  turndownService.keep(['iframe', 'sub', 'sup', 'u', 'ins', 'del', 'small', 'big']);
-
-  let imageList = {};
-  // add an image rule
-  turndownService.addRule('images', {
-    filter: function (node, tdopts) {
-      // if we're looking at an img node with a src
-      if (node.nodeName == 'IMG' && node.getAttribute('src')) {
-        
-        // get the original src
-        let src = node.getAttribute('src')
-        // set the new src
-        node.setAttribute('src', validateUri(src, article.baseURI));
-        
-        // if we're downloading images, there's more to do.
-        if (options.downloadImages) {
-          // generate a file name for the image
-          let imageFilename = getImageFilename(src, options, false);
-          if (!imageList[src] || imageList[src] != imageFilename) {
-            // if the imageList already contains this file, add a number to differentiate
-            let i = 1;
-            while (Object.values(imageList).includes(imageFilename)) {
-              const parts = imageFilename.split('.');
-              if (i == 1) parts.splice(parts.length - 1, 0, i++);
-              else parts.splice(parts.length - 2, 1, i++);
-              imageFilename = parts.join('.');
-            }
-            // add it to the list of images to download later
-            imageList[src] = imageFilename;
-          }
-          // check if we're doing an obsidian style link
-          const obsidianLink = options.imageStyle.startsWith("obsidian");
-          // figure out the (local) src of the image
-          const localSrc = options.imageStyle === 'obsidian-nofolder'
-            // if using "nofolder" then we just need the filename, no folder
-            ? imageFilename.substring(imageFilename.lastIndexOf('/') + 1)
-            // otherwise we may need to modify the filename to uri encode parts for a pure markdown link
-            : imageFilename.split('/').map(s => obsidianLink ? s : encodeURI(s)).join('/')
-          
-          // set the new src attribute to be the local filename
-          if(options.imageStyle != 'originalSource' && options.imageStyle != 'base64') node.setAttribute('src', localSrc);
-          // pass the filter if we're making an obsidian link (or stripping links)
-          return true;
-        }
-        else return true
-      }
-      // don't pass the filter, just output a normal markdown link
-      return false;
-    },
-    replacement: function (content, node, tdopts) {
-      // if we're stripping images, output nothing
-      if (options.imageStyle == 'noImage') return '';
-      // if this is an obsidian link, so output that
-      else if (options.imageStyle.startsWith('obsidian')) return `![[${node.getAttribute('src')}]]`;
-      // otherwise, output the normal markdown link
-      else {
-        var alt = cleanAttribute(node.getAttribute('alt'));
-        var src = node.getAttribute('src') || '';
-        var title = cleanAttribute(node.getAttribute('title'));
-        var titlePart = title ? ' "' + title + '"' : '';
-        if (options.imageRefStyle == 'referenced') {
-          var id = this.references.length + 1;
-          this.references.push('[fig' + id + ']: ' + src + titlePart);
-          return '![' + alt + '][fig' + id + ']';
-        }
-        else return src ? '![' + alt + ']' + '(' + src + titlePart + ')' : ''
-      }
-    },
-    references: [],
-    append: function (options) {
-      var references = '';
-      if (this.references.length) {
-        references = '\n\n' + this.references.join('\n') + '\n\n';
-        this.references = []; // Reset references
-      }
-      return references
-    }
-
-  });
-
-  // add a rule for links
-  turndownService.addRule('links', {
-    filter: (node, tdopts) => {
-      // check that this is indeed a link
-      if (node.nodeName == 'A' && node.getAttribute('href')) {
-        // get the href
-        const href = node.getAttribute('href');
-        // set the new href
-        node.setAttribute('href', validateUri(href, article.baseURI));
-        // if we are to strip links, the filter needs to pass
-        return options.linkStyle == 'stripLinks';
-      }
-      // we're not passing the filter, just do the normal thing.
-      return false;
-    },
-    // if the filter passes, we're stripping links, so just return the content
-    replacement: (content, node, tdopts) => content
-  });
-
-  // handle multiple lines math
-  turndownService.addRule('mathjax', {
-    filter(node, options) {
-      return article.math.hasOwnProperty(node.id);
-    },
-    replacement(content, node, options) {
-      const math = article.math[node.id];
-      let tex = math.tex.trim().replaceAll('\xa0', '');
-
-      if (math.inline) {
-        tex = tex.replaceAll('\n', ' ');
-        return `$${tex}$`;
-      }
-      else
-        return `$$\n${tex}\n$$`;
-    }
-  });
-
-  function repeat(character, count) {
-    return Array(count + 1).join(character);
-  }
-
-  function convertToFencedCodeBlock(node, options) {
-    node.innerHTML = node.innerHTML.replaceAll('', '
'); - const langMatch = node.id?.match(/code-lang-(.+)/); - const language = langMatch?.length > 0 ? langMatch[1] : ''; - - var code; - - if (language) { - var div = document.createElement('div'); - document.body.appendChild(div); - div.appendChild(node); - code = node.innerText; - div.remove(); - } else { - code = node.innerHTML; - } - - var fenceChar = options.fence.charAt(0); - var fenceSize = 3; - var fenceInCodeRegex = new RegExp('^' + fenceChar + '{3,}', 'gm'); - - var match; - while ((match = fenceInCodeRegex.exec(code))) { - if (match[0].length >= fenceSize) { - fenceSize = match[0].length + 1; - } - } - - var fence = repeat(fenceChar, fenceSize); - - return ( - '\n\n' + fence + language + '\n' + - code.replace(/\n$/, '') + - '\n' + fence + '\n\n' - ) - } - - turndownService.addRule('fencedCodeBlock', { - filter: function (node, options) { - return ( - options.codeBlockStyle === 'fenced' && - node.nodeName === 'PRE' && - node.firstChild && - node.firstChild.nodeName === 'CODE' - ); - }, - replacement: function (content, node, options) { - return convertToFencedCodeBlock(node.firstChild, options); - } - }); - - // handle
 as code blocks
-  turndownService.addRule('pre', {
-    filter: (node, tdopts) => node.nodeName == 'PRE' && (!node.firstChild || node.firstChild.nodeName != 'CODE'),
-    replacement: (content, node, tdopts) => {
-      return convertToFencedCodeBlock(node, tdopts);
-    }
-  });
-
-  let markdown = options.frontmatter + turndownService.turndown(content)
-      + options.backmatter;
-
-  // strip out non-printing special characters which CodeMirror displays as a red dot
-  // see: https://codemirror.net/doc/manual.html#option_specialChars
-  markdown = markdown.replace(/[\u0000-\u0009\u000b\u000c\u000e-\u001f\u007f-\u009f\u00ad\u061c\u200b-\u200f\u2028\u2029\ufeff\ufff9-\ufffc]/g, '');
-  
-  return { markdown: markdown, imageList: imageList };
-}
-
-function cleanAttribute(attribute) {
-  return attribute ? attribute.replace(/(\n+\s*)+/g, '\n') : ''
-}
-
-function validateUri(href, baseURI) {
-  // check if the href is a valid url
-  try {
-    new URL(href);
-  }
-  catch {
-    // if it's not a valid url, that likely means we have to prepend the base uri
-    const baseUri = new URL(baseURI);
-
-    // if the href starts with '/', we need to go from the origin
-    if (href.startsWith('/')) {
-      href = baseUri.origin + href
-    }
-    // otherwise we need to go from the local folder
-    else {
-      href = baseUri.href + (baseUri.href.endsWith('/') ? '/' : '') + href
-    }
-  }
-  return href;
-}
-
-function getImageFilename(src, options, prependFilePath = true) {
-  const slashPos = src.lastIndexOf('/');
-  const queryPos = src.indexOf('?');
-  let filename = src.substring(slashPos + 1, queryPos > 0 ? queryPos : src.length);
-
-  let imagePrefix = (options.imagePrefix || '');
-
-  if (prependFilePath && options.title.includes('/')) {
-    imagePrefix = options.title.substring(0, options.title.lastIndexOf('/') + 1) + imagePrefix;
-  }
-  else if (prependFilePath) {
-    imagePrefix = options.title + (imagePrefix.startsWith('/') ? '' : '/') + imagePrefix
-  }
-  
-  if (filename.includes(';base64,')) {
-    // this is a base64 encoded image, so what are we going to do for a filename here?
-    filename = 'image.' + filename.substring(0, filename.indexOf(';'));
-  }
-  
-  let extension = filename.substring(filename.lastIndexOf('.'));
-  if (extension == filename) {
-    // there is no extension, so we need to figure one out
-    // for now, give it an 'idunno' extension and we'll process it later
-    filename = filename + '.idunno';
-  }
-
-  filename = generateValidFileName(filename, options.disallowedChars);
-
-  return imagePrefix + filename;
-}
-
-// function to replace placeholder strings with article info
-function textReplace(string, article, disallowedChars = null) {
-  for (const key in article) {
-    if (article.hasOwnProperty(key) && key != "content") {
-      let s = (article[key] || '') + '';
-      if (s && disallowedChars) s = this.generateValidFileName(s, disallowedChars);
-
-      string = string.replace(new RegExp('{' + key + '}', 'g'), s)
-        .replace(new RegExp('{' + key + ':kebab}', 'g'), s.replace(/ /g, '-').toLowerCase())
-        .replace(new RegExp('{' + key + ':snake}', 'g'), s.replace(/ /g, '_').toLowerCase())
-        .replace(new RegExp('{' + key + ':camel}', 'g'), s.replace(/ ./g, (str) => str.trim().toUpperCase()).replace(/^./, (str) => str.toLowerCase()))
-        .replace(new RegExp('{' + key + ':pascal}', 'g'), s.replace(/ ./g, (str) => str.trim().toUpperCase()).replace(/^./, (str) => str.toUpperCase()))
-    }
-  }
-
-  // replace date formats
-  const now = new Date();
-  const dateRegex = /{date:(.+?)}/g
-  const matches = string.match(dateRegex);
-  if (matches && matches.forEach) {
-    matches.forEach(match => {
-      const format = match.substring(6, match.length - 1);
-      const dateString = moment(now).format(format);
-      string = string.replaceAll(match, dateString);
-    });
-  }
-
-  // replace keywords
-  const keywordRegex = /{keywords:?(.*)?}/g
-  const keywordMatches = string.match(keywordRegex);
-  if (keywordMatches && keywordMatches.forEach) {
-    keywordMatches.forEach(match => {
-      let seperator = match.substring(10, match.length - 1)
-      try {
-        seperator = JSON.parse(JSON.stringify(seperator).replace(/\\\\/g, '\\'));
-      }
-      catch { }
-      const keywordsString = (article.keywords || []).join(seperator);
-      string = string.replace(new RegExp(match.replace(/\\/g, '\\\\'), 'g'), keywordsString);
-    })
-  }
-
-  // replace anything left in curly braces
-  const defaultRegex = /{(.*?)}/g
-  string = string.replace(defaultRegex, '')
-
-  return string;
-}
-
-// function to convert an article info object into markdown
-async function convertArticleToMarkdown(article, downloadImages = null) {
-  const options = await getOptions();
-  if (downloadImages != null) {
-    options.downloadImages = downloadImages;
-  }
-
-  // substitute front and backmatter templates if necessary
-  if (options.includeTemplate) {
-    options.frontmatter = textReplace(options.frontmatter, article) + '\n';
-    options.backmatter = '\n' + textReplace(options.backmatter, article);
-  }
-  else {
-    options.frontmatter = options.backmatter = '';
-  }
-
-  options.imagePrefix = textReplace(options.imagePrefix, article, options.disallowedChars)
-    .split('/').map(s=>generateValidFileName(s, options.disallowedChars)).join('/');
-
-  let result = turndown(article.content, options, article);
-  if (options.downloadImages && options.downloadMode == 'downloadsApi') {
-    // pre-download the images
-    result = await preDownloadImages(result.imageList, result.markdown);
-  }
-  return result;
-}
-
-// function to turn the title into a valid file name
-function generateValidFileName(title, disallowedChars = null) {
-  if (!title) return title;
-  else title = title + '';
-  // remove < > : " / \ | ? * 
-  var illegalRe = /[\/\?<>\\:\*\|":]/g;
-  // and non-breaking spaces (thanks @Licat)
-  var name = title.replace(illegalRe, "").replace(new RegExp('\u00A0', 'g'), ' ');
-  
-  if (disallowedChars) {
-    for (let c of disallowedChars) {
-      if (`[\\^$.|?*+()`.includes(c)) c = `\\${c}`;
-      name = name.replace(new RegExp(c, 'g'), '');
-    }
-  }
-  
-  return name;
-}
-
-async function preDownloadImages(imageList, markdown) {
-  const options = await getOptions();
-  let newImageList = {};
-  // originally, I was downloading the markdown file first, then all the images
-  // however, in some cases we need to download images *first* so we can get the
-  // proper file extension to put into the markdown.
-  // so... here we are waiting for all the downloads and replacements to complete
-  await Promise.all(Object.entries(imageList).map(([src, filename]) => new Promise((resolve, reject) => {
-        // we're doing an xhr so we can get it as a blob and determine filetype
-        // before the final save
-        const xhr = new XMLHttpRequest();
-        xhr.open('GET', src);
-        xhr.responseType = "blob";
-        xhr.onload = async function () {
-          // here's the returned blob
-          const blob = xhr.response;
-
-          if (options.imageStyle == 'base64') {
-            var reader = new FileReader();
-            reader.onloadend = function () {
-              markdown = markdown.replaceAll(src, reader.result)
-              resolve()
-            }
-            reader.readAsDataURL(blob);
-          }
-          else {
-
-            let newFilename = filename;
-            if (newFilename.endsWith('.idunno')) {
-              // replace any unknown extension with a lookup based on mime type
-              newFilename = filename.replace('.idunno', '.' + mimedb[blob.type]);
-
-              // and replace any instances of this in the markdown
-              // remember to url encode for replacement if it's not an obsidian link
-              if (!options.imageStyle.startsWith("obsidian")) {
-                markdown = markdown.replaceAll(filename.split('/').map(s => encodeURI(s)).join('/'), newFilename.split('/').map(s => encodeURI(s)).join('/'))
-              }
-              else {
-                markdown = markdown.replaceAll(filename, newFilename)
-              }
-            }
-
-            // create an object url for the blob (no point fetching it twice)
-            const blobUrl = URL.createObjectURL(blob);
-
-            // add this blob into the new image list
-            newImageList[blobUrl] = newFilename;
-
-            // resolve this promise now
-            // (the file might not be saved yet, but the blob is and replacements are complete)
-            resolve();
-          }
-        };
-        xhr.onerror = function () {
-          reject('A network error occurred attempting to download ' + src);
-        };
-        xhr.send();
-  })));
-
-  return { imageList: newImageList, markdown: markdown };
-}
-
-// function to actually download the markdown file
-async function downloadMarkdown(markdown, title, tabId, imageList = {}, mdClipsFolder = '') {
-  // get the options
-  const options = await getOptions();
-  
-  // download via the downloads API
-  if (options.downloadMode == 'downloadsApi' && browser.downloads) {
-    
-    // create the object url with markdown data as a blob
-    const url = URL.createObjectURL(new Blob([markdown], {
-      type: "text/markdown;charset=utf-8"
-    }));
-  
-    try {
-
-      if(mdClipsFolder && !mdClipsFolder.endsWith('/')) mdClipsFolder += '/';
-      // start the download
-      const id = await browser.downloads.download({
-        url: url,
-        filename: mdClipsFolder + title + ".md",
-        saveAs: options.saveAs
-      });
-
-      // add a listener for the download completion
-      browser.downloads.onChanged.addListener(downloadListener(id, url));
-
-      // download images (if enabled)
-      if (options.downloadImages) {
-        // get the relative path of the markdown file (if any) for image path
-        const destPath = mdClipsFolder + title.substring(0, title.lastIndexOf('/'));
-        if(destPath && !destPath.endsWith('/')) destPath += '/';
-        Object.entries(imageList).forEach(async ([src, filename]) => {
-          // start the download of the image
-          const imgId = await browser.downloads.download({
-            url: src,
-            // set a destination path (relative to md file)
-            filename: destPath ? destPath + filename : filename,
-            saveAs: false
-          })
-          // add a listener (so we can release the blob url)
-          browser.downloads.onChanged.addListener(downloadListener(imgId, src));
-        });
-      }
-    }
-    catch (err) {
-      console.error("Download failed", err);
-    }
-  }
-  // // download via obsidian://new uri
-  // else if (options.downloadMode == 'obsidianUri') {
-  //   try {
-  //     await ensureScripts(tabId);
-  //     let uri = 'obsidian://new?';
-  //     uri += `${options.obsidianPathType}=${encodeURIComponent(title)}`;
-  //     if (options.obsidianVault) uri += `&vault=${encodeURIComponent(options.obsidianVault)}`;
-  //     uri += `&content=${encodeURIComponent(markdown)}`;
-  //     let code = `window.location='${uri}'`;
-  //     await browser.tabs.executeScript(tabId, {code: code});
-  //   }
-  //   catch (error) {
-  //     // This could happen if the extension is not allowed to run code in
-  //     // the page, for example if the tab is a privileged page.
-  //     console.error("Failed to execute script: " + error);
-  //   };
-    
-  // }
-  // download via content link
-  else {
-    try {
-      await ensureScripts(tabId);
-      const filename = mdClipsFolder + generateValidFileName(title, options.disallowedChars) + ".md";
-      const code = `downloadMarkdown("${filename}","${base64EncodeUnicode(markdown)}");`
-      await browser.tabs.executeScript(tabId, {code: code});
-    }
-    catch (error) {
-      // This could happen if the extension is not allowed to run code in
-      // the page, for example if the tab is a privileged page.
-      console.error("Failed to execute script: " + error);
-    };
-  }
-}
-
-function downloadListener(id, url) {
-  const self = (delta) => {
-    if (delta.id === id && delta.state && delta.state.current == "complete") {
-      // detatch this listener
-      browser.downloads.onChanged.removeListener(self);
-      //release the url for the blob
-      URL.revokeObjectURL(url);
-    }
-  }
-  return self;
-}
-
-function base64EncodeUnicode(str) {
-  // Firstly, escape the string using encodeURIComponent to get the UTF-8 encoding of the characters, 
-  // Secondly, we convert the percent encodings into raw bytes, and add it to btoa() function.
-  const utf8Bytes = encodeURIComponent(str).replace(/%([0-9A-F]{2})/g, function (match, p1) {
-    return String.fromCharCode('0x' + p1);
-  });
-
-  return btoa(utf8Bytes);
-}
-
-//function that handles messages from the injected script into the site
-async function notify(message) {
-  const options = await this.getOptions();
-  // message for initial clipping of the dom
-  if (message.type == "clip") {
-    // get the article info from the passed in dom
-    const article = await getArticleFromDom(message.dom);
-
-    // if selection info was passed in (and we're to clip the selection)
-    // replace the article content
-    if (message.selection && message.clipSelection) {
-      article.content = message.selection;
-    }
-    
-    // convert the article to markdown
-    const { markdown, imageList } = await convertArticleToMarkdown(article);
-
-    // format the title
-    article.title = await formatTitle(article);
-
-    // format the mdClipsFolder
-    const mdClipsFolder = await formatMdClipsFolder(article);
-
-    // display the data in the popup
-    await browser.runtime.sendMessage({ type: "display.md", markdown: markdown, article: article, imageList: imageList, mdClipsFolder: mdClipsFolder});
-  }
-  // message for triggering download
-  else if (message.type == "download") {
-    downloadMarkdown(message.markdown, message.title, message.tab.id, message.imageList, message.mdClipsFolder);
-  }
-}
-
-browser.commands.onCommand.addListener(function (command) {
-  const tab = browser.tabs.getCurrent()
-  if (command == "download_tab_as_markdown") {
-    const info = { menuItemId: "download-markdown-all" };
-    downloadMarkdownFromContext(info, tab);
-  }
-  else if (command == "copy_tab_as_markdown") {
-    const info = { menuItemId: "copy-markdown-all" };
-    copyMarkdownFromContext(info, tab);
-  }
-  else if (command == "copy_selection_as_markdown") {
-    const info = { menuItemId: "copy-markdown-selection" };
-    copyMarkdownFromContext(info, tab);
-  }
-  else if (command == "copy_tab_as_markdown_link") {
-    copyTabAsMarkdownLink(tab);
-  }
-  else if (command == "copy_selected_tab_as_markdown_link") {
-    copySelectedTabAsMarkdownLink(tab);
-  }
-  else if (command == "copy_selection_to_obsidian") {
-    const info = { menuItemId: "copy-markdown-obsidian" };
-    copyMarkdownFromContext(info, tab);
-  }
-  else if (command == "copy_tab_to_obsidian") {
-    const info = { menuItemId: "copy-markdown-obsall" };
-    copyMarkdownFromContext(info, tab);
-  }
-});
-
-// click handler for the context menus
-browser.contextMenus.onClicked.addListener(function (info, tab) {
-  // one of the copy to clipboard commands
-  if (info.menuItemId.startsWith("copy-markdown")) {
-    copyMarkdownFromContext(info, tab);
-  }
-  else if (info.menuItemId == "download-markdown-alltabs" || info.menuItemId == "tab-download-markdown-alltabs") {
-    downloadMarkdownForAllTabs(info);
-  }
-  // one of the download commands
-  else if (info.menuItemId.startsWith("download-markdown")) {
-    downloadMarkdownFromContext(info, tab);
-  }
-  // copy tab as markdown link
-  else if (info.menuItemId.startsWith("copy-tab-as-markdown-link-all")) {
-    copyTabAsMarkdownLinkAll(tab);
-  }
-  // copy only selected tab as markdown link
-  else if (info.menuItemId.startsWith("copy-tab-as-markdown-link-selected")) {
-    copySelectedTabAsMarkdownLink(tab);
-  }
-  else if (info.menuItemId.startsWith("copy-tab-as-markdown-link")) {
-    copyTabAsMarkdownLink(tab);
-  }
-  // a settings toggle command
-  else if (info.menuItemId.startsWith("toggle-") || info.menuItemId.startsWith("tabtoggle-")) {
-    toggleSetting(info.menuItemId.split('-')[1]);
-  }
-});
-
-// this function toggles the specified option
-async function toggleSetting(setting, options = null) {
-  // if there's no options object passed in, we need to go get one
-  if (options == null) {
-      // get the options from storage and toggle the setting
-      await toggleSetting(setting, await getOptions());
-  }
-  else {
-    // toggle the option and save back to storage
-    options[setting] = !options[setting];
-    await browser.storage.sync.set(options);
-    if (setting == "includeTemplate") {
-      browser.contextMenus.update("toggle-includeTemplate", {
-        checked: options.includeTemplate
-      });
-      try {
-        browser.contextMenus.update("tabtoggle-includeTemplate", {
-          checked: options.includeTemplate
-        });
-      } catch { }
-    }
-    
-    if (setting == "downloadImages") {
-      browser.contextMenus.update("toggle-downloadImages", {
-        checked: options.downloadImages
-      });
-      try {
-        browser.contextMenus.update("tabtoggle-downloadImages", {
-          checked: options.downloadImages
-        });
-      } catch { }
-    }
-  }
-}
-
-// this function ensures the content script is loaded (and loads it if it isn't)
-async function ensureScripts(tabId) {
-  const results = await browser.tabs.executeScript(tabId, { code: "typeof getSelectionAndDom === 'function';" })
-  // The content script's last expression will be true if the function
-  // has been defined. If this is not the case, then we need to run
-  // pageScraper.js to define function getSelectionAndDom.
-  if (!results || results[0] !== true) {
-    await browser.tabs.executeScript(tabId, {file: "/contentScript/contentScript.js"});
-  }
-}
-
-// get Readability article info from the dom passed in
-async function getArticleFromDom(domString) {
-  // parse the dom
-  const parser = new DOMParser();
-  const dom = parser.parseFromString(domString, "text/html");
-
-  if (dom.documentElement.nodeName == "parsererror") {
-    console.error("error while parsing");
-  }
-
-  const math = {};
-
-  const storeMathInfo = (el, mathInfo) => {
-    let randomId = URL.createObjectURL(new Blob([]));
-    randomId = randomId.substring(randomId.length - 36);
-    el.id = randomId;
-    math[randomId] = mathInfo;
-  };
-
-  dom.body.querySelectorAll('script[id^=MathJax-Element-]')?.forEach(mathSource => {
-    const type = mathSource.attributes.type.value
-    storeMathInfo(mathSource, {
-      tex: mathSource.innerText,
-      inline: type ? !type.includes('mode=display') : false
-    });
-  });
-
-  dom.body.querySelectorAll('[markdownload-latex]')?.forEach(mathJax3Node =>  {
-    const tex = mathJax3Node.getAttribute('markdownload-latex')
-    const display = mathJax3Node.getAttribute('display')
-    const inline = !(display && display === 'true')
-
-    const mathNode = document.createElement(inline ? "i" : "p")
-    mathNode.textContent = tex;
-    mathJax3Node.parentNode.insertBefore(mathNode, mathJax3Node.nextSibling)
-    mathJax3Node.parentNode.removeChild(mathJax3Node)
-
-    storeMathInfo(mathNode, {
-      tex: tex,
-      inline: inline
-    });
-  });
-
-  dom.body.querySelectorAll('.katex-mathml')?.forEach(kaTeXNode => {
-    storeMathInfo(kaTeXNode, {
-      tex: kaTeXNode.querySelector('annotation').textContent,
-      inline: true
-    });
-  });
-
-  dom.body.querySelectorAll('[class*=highlight-text],[class*=highlight-source]')?.forEach(codeSource => {
-    const language = codeSource.className.match(/highlight-(?:text|source)-([a-z0-9]+)/)?.[1]
-    if (codeSource.firstChild.nodeName == "PRE") {
-      codeSource.firstChild.id = `code-lang-${language}`
-    }
-  });
-
-  dom.body.querySelectorAll('[class*=language-]')?.forEach(codeSource => {
-    const language = codeSource.className.match(/language-([a-z0-9]+)/)?.[1]
-    codeSource.id = `code-lang-${language}`;
-  });
-
-  dom.body.querySelectorAll('pre br')?.forEach(br => {
-    // we need to keep 
tags because they are removed by Readability.js - br.outerHTML = ''; - }); - - dom.body.querySelectorAll('.codehilite > pre')?.forEach(codeSource => { - if (codeSource.firstChild.nodeName !== 'CODE' && !codeSource.className.includes('language')) { - codeSource.id = `code-lang-text`; - } - }); - - dom.body.querySelectorAll('h1, h2, h3, h4, h5, h6')?.forEach(header => { - // Readability.js will strip out headings from the dom if certain words appear in their className - // See: https://github.com/mozilla/readability/issues/807 - header.className = ''; - header.outerHTML = header.outerHTML; - }); - - // simplify the dom into an article - const article = new Readability(dom).parse(); - - // get the base uri from the dom and attach it as important article info - article.baseURI = dom.baseURI; - // also grab the page title - article.pageTitle = dom.title; - // and some URL info - const url = new URL(dom.baseURI); - article.hash = url.hash; - article.host = url.host; - article.origin = url.origin; - article.hostname = url.hostname; - article.pathname = url.pathname; - article.port = url.port; - article.protocol = url.protocol; - article.search = url.search; - - - // make sure the dom has a head - if (dom.head) { - // and the keywords, should they exist, as an array - article.keywords = dom.head.querySelector('meta[name="keywords"]')?.content?.split(',')?.map(s => s.trim()); - - // add all meta tags, so users can do whatever they want - dom.head.querySelectorAll('meta[name][content], meta[property][content]')?.forEach(meta => { - const key = (meta.getAttribute('name') || meta.getAttribute('property')) - const val = meta.getAttribute('content') - if (key && val && !article[key]) { - article[key] = val; - } - }) - } - - article.math = math - - // return the article - return article; -} - -// get Readability article info from the content of the tab id passed in -// `selection` is a bool indicating whether we should just get the selected text -async function getArticleFromContent(tabId, selection = false) { - // run the content script function to get the details - const results = await browser.tabs.executeScript(tabId, { code: "getSelectionAndDom()" }); - - // make sure we actually got a valid result - if (results && results[0] && results[0].dom) { - const article = await getArticleFromDom(results[0].dom, selection); - - // if we're to grab the selection, and we've selected something, - // replace the article content with the selection - if (selection && results[0].selection) { - article.content = results[0].selection; - } - - //return the article - return article; - } - else return null; -} - -// function to apply the title template -async function formatTitle(article) { - let options = await getOptions(); - - let title = textReplace(options.title, article, options.disallowedChars + '/'); - title = title.split('/').map(s=>generateValidFileName(s, options.disallowedChars)).join('/'); - return title; -} - -async function formatMdClipsFolder(article) { - let options = await getOptions(); - - let mdClipsFolder = ''; - if (options.mdClipsFolder && options.downloadMode == 'downloadsApi') { - mdClipsFolder = textReplace(options.mdClipsFolder, article, options.disallowedChars); - mdClipsFolder = mdClipsFolder.split('/').map(s => generateValidFileName(s, options.disallowedChars)).join('/'); - if (!mdClipsFolder.endsWith('/')) mdClipsFolder += '/'; - } - - return mdClipsFolder; -} - -async function formatObsidianFolder(article) { - let options = await getOptions(); - - let obsidianFolder = ''; - if (options.obsidianFolder) { - obsidianFolder = textReplace(options.obsidianFolder, article, options.disallowedChars); - obsidianFolder = obsidianFolder.split('/').map(s => generateValidFileName(s, options.disallowedChars)).join('/'); - if (!obsidianFolder.endsWith('/')) obsidianFolder += '/'; - } - - return obsidianFolder; -} - -// function to download markdown, triggered by context menu -async function downloadMarkdownFromContext(info, tab) { - await ensureScripts(tab.id); - const article = await getArticleFromContent(tab.id, info.menuItemId == "download-markdown-selection"); - const title = await formatTitle(article); - const { markdown, imageList } = await convertArticleToMarkdown(article); - // format the mdClipsFolder - const mdClipsFolder = await formatMdClipsFolder(article); - await downloadMarkdown(markdown, title, tab.id, imageList, mdClipsFolder); - -} - -// function to copy a tab url as a markdown link -async function copyTabAsMarkdownLink(tab) { - try { - await ensureScripts(tab.id); - const article = await getArticleFromContent(tab.id); - const title = await formatTitle(article); - await browser.tabs.executeScript(tab.id, { code: `copyToClipboard("[${title}](${article.baseURI})")` }); - // await navigator.clipboard.writeText(`[${title}](${article.baseURI})`); - } - catch (error) { - // This could happen if the extension is not allowed to run code in - // the page, for example if the tab is a privileged page. - console.error("Failed to copy as markdown link: " + error); - }; -} - -// function to copy all tabs as markdown links -async function copyTabAsMarkdownLinkAll(tab) { - try { - const options = await getOptions(); - options.frontmatter = options.backmatter = ''; - const tabs = await browser.tabs.query({ - currentWindow: true - }); - - const links = []; - for(const tab of tabs) { - await ensureScripts(tab.id); - const article = await getArticleFromContent(tab.id); - const title = await formatTitle(article); - const link = `${options.bulletListMarker} [${title}](${article.baseURI})` - links.push(link) - }; - - const markdown = links.join(`\n`) - await browser.tabs.executeScript(tab.id, { code: `copyToClipboard(${JSON.stringify(markdown)})` }); - - } - catch (error) { - // This could happen if the extension is not allowed to run code in - // the page, for example if the tab is a privileged page. - console.error("Failed to copy as markdown link: " + error); - }; -} - -// function to copy only selected tabs as markdown links -async function copySelectedTabAsMarkdownLink(tab) { - try { - const options = await getOptions(); - options.frontmatter = options.backmatter = ''; - const tabs = await browser.tabs.query({ - currentWindow: true, - highlighted: true - }); - - const links = []; - for (const tab of tabs) { - await ensureScripts(tab.id); - const article = await getArticleFromContent(tab.id); - const title = await formatTitle(article); - const link = `${options.bulletListMarker} [${title}](${article.baseURI})` - links.push(link) - }; - - const markdown = links.join(`\n`) - await browser.tabs.executeScript(tab.id, { code: `copyToClipboard(${JSON.stringify(markdown)})` }); - - } - catch (error) { - // This could happen if the extension is not allowed to run code in - // the page, for example if the tab is a privileged page. - console.error("Failed to copy as markdown link: " + error); - }; -} - -// function to copy markdown to the clipboard, triggered by context menu -async function copyMarkdownFromContext(info, tab) { - try{ - await ensureScripts(tab.id); - - const platformOS = navigator.platform; - var folderSeparator = ""; - if(platformOS.indexOf("Win") === 0){ - folderSeparator = "\\"; - }else{ - folderSeparator = "/"; - } - - if (info.menuItemId == "copy-markdown-link") { - const options = await getOptions(); - options.frontmatter = options.backmatter = ''; - const article = await getArticleFromContent(tab.id, false); - const { markdown } = turndown(`${info.linkText || info.selectionText}`, { ...options, downloadImages: false }, article); - await browser.tabs.executeScript(tab.id, {code: `copyToClipboard(${JSON.stringify(markdown)})`}); - } - else if (info.menuItemId == "copy-markdown-image") { - await browser.tabs.executeScript(tab.id, {code: `copyToClipboard("![](${info.srcUrl})")`}); - } - else if(info.menuItemId == "copy-markdown-obsidian") { - const article = await getArticleFromContent(tab.id, info.menuItemId == "copy-markdown-obsidian"); - const title = article.title; - const options = await getOptions(); - const obsidianVault = options.obsidianVault; - const obsidianFolder = await formatObsidianFolder(article); - const { markdown } = await convertArticleToMarkdown(article, downloadImages = false); - await browser.tabs.executeScript(tab.id, { code: `copyToClipboard(${JSON.stringify(markdown)})` }); - await chrome.tabs.update({url: "obsidian://advanced-uri?vault=" + obsidianVault + "&clipboard=true&mode=new&filepath=" + obsidianFolder + generateValidFileName(title)}); - } - else if(info.menuItemId == "copy-markdown-obsall") { - const article = await getArticleFromContent(tab.id, info.menuItemId == "copy-markdown-obsall"); - const title = article.title; - const options = await getOptions(); - const obsidianVault = options.obsidianVault; - const obsidianFolder = await formatObsidianFolder(article); - const { markdown } = await convertArticleToMarkdown(article, downloadImages = false); - await browser.tabs.executeScript(tab.id, { code: `copyToClipboard(${JSON.stringify(markdown)})` }); - await browser.tabs.update({url: "obsidian://advanced-uri?vault=" + obsidianVault + "&clipboard=true&mode=new&filepath=" + obsidianFolder + generateValidFileName(title)}); - } - else { - const article = await getArticleFromContent(tab.id, info.menuItemId == "copy-markdown-selection"); - const { markdown } = await convertArticleToMarkdown(article, downloadImages = false); - await browser.tabs.executeScript(tab.id, { code: `copyToClipboard(${JSON.stringify(markdown)})` }); - } - } - catch (error) { - // This could happen if the extension is not allowed to run code in - // the page, for example if the tab is a privileged page. - console.error("Failed to copy text: " + error); - }; -} - -async function downloadMarkdownForAllTabs(info) { - const tabs = await browser.tabs.query({ - currentWindow: true - }); - tabs.forEach(tab => { - downloadMarkdownFromContext(info, tab); - }); -} - -/** - * String.prototype.replaceAll() polyfill - * https://gomakethings.com/how-to-replace-a-section-of-a-string-with-another-one-with-vanilla-js/ - * @author Chris Ferdinandi - * @license MIT - */ -if (!String.prototype.replaceAll) { - String.prototype.replaceAll = function(str, newStr){ - - // If a regex pattern - if (Object.prototype.toString.call(str).toLowerCase() === '[object regexp]') { - return this.replace(str, newStr); - } - - // If a string - return this.replace(new RegExp(str, 'g'), newStr); - - }; -} diff --git a/src/background/jszip.min.js b/src/background/jszip.min.js new file mode 100644 index 00000000..ff4cfd5e --- /dev/null +++ b/src/background/jszip.min.js @@ -0,0 +1,13 @@ +/*! + +JSZip v3.10.1 - A JavaScript class for generating and reading zip files + + +(c) 2009-2016 Stuart Knightley +Dual licenced under the MIT license or GPLv3. See https://raw.github.com/Stuk/jszip/main/LICENSE.markdown. + +JSZip uses the library pako released under the MIT license : +https://github.com/nodeca/pako/blob/main/LICENSE +*/ + +!function(e){if("object"==typeof exports&&"undefined"!=typeof module)module.exports=e();else if("function"==typeof define&&define.amd)define([],e);else{("undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof self?self:this).JSZip=e()}}(function(){return function s(a,o,h){function u(r,e){if(!o[r]){if(!a[r]){var t="function"==typeof require&&require;if(!e&&t)return t(r,!0);if(l)return l(r,!0);var n=new Error("Cannot find module '"+r+"'");throw n.code="MODULE_NOT_FOUND",n}var i=o[r]={exports:{}};a[r][0].call(i.exports,function(e){var t=a[r][1][e];return u(t||e)},i,i.exports,s,a,o,h)}return o[r].exports}for(var l="function"==typeof require&&require,e=0;e>2,s=(3&t)<<4|r>>4,a=1>6:64,o=2>4,r=(15&i)<<4|(s=p.indexOf(e.charAt(o++)))>>2,n=(3&s)<<6|(a=p.indexOf(e.charAt(o++))),l[h++]=t,64!==s&&(l[h++]=r),64!==a&&(l[h++]=n);return l}},{"./support":30,"./utils":32}],2:[function(e,t,r){"use strict";var n=e("./external"),i=e("./stream/DataWorker"),s=e("./stream/Crc32Probe"),a=e("./stream/DataLengthProbe");function o(e,t,r,n,i){this.compressedSize=e,this.uncompressedSize=t,this.crc32=r,this.compression=n,this.compressedContent=i}o.prototype={getContentWorker:function(){var e=new i(n.Promise.resolve(this.compressedContent)).pipe(this.compression.uncompressWorker()).pipe(new a("data_length")),t=this;return e.on("end",function(){if(this.streamInfo.data_length!==t.uncompressedSize)throw new Error("Bug : uncompressed data size mismatch")}),e},getCompressedWorker:function(){return new i(n.Promise.resolve(this.compressedContent)).withStreamInfo("compressedSize",this.compressedSize).withStreamInfo("uncompressedSize",this.uncompressedSize).withStreamInfo("crc32",this.crc32).withStreamInfo("compression",this.compression)}},o.createWorkerFrom=function(e,t,r){return e.pipe(new s).pipe(new a("uncompressedSize")).pipe(t.compressWorker(r)).pipe(new a("compressedSize")).withStreamInfo("compression",t)},t.exports=o},{"./external":6,"./stream/Crc32Probe":25,"./stream/DataLengthProbe":26,"./stream/DataWorker":27}],3:[function(e,t,r){"use strict";var n=e("./stream/GenericWorker");r.STORE={magic:"\0\0",compressWorker:function(){return new n("STORE compression")},uncompressWorker:function(){return new n("STORE decompression")}},r.DEFLATE=e("./flate")},{"./flate":7,"./stream/GenericWorker":28}],4:[function(e,t,r){"use strict";var n=e("./utils");var o=function(){for(var e,t=[],r=0;r<256;r++){e=r;for(var n=0;n<8;n++)e=1&e?3988292384^e>>>1:e>>>1;t[r]=e}return t}();t.exports=function(e,t){return void 0!==e&&e.length?"string"!==n.getTypeOf(e)?function(e,t,r,n){var i=o,s=n+r;e^=-1;for(var a=n;a>>8^i[255&(e^t[a])];return-1^e}(0|t,e,e.length,0):function(e,t,r,n){var i=o,s=n+r;e^=-1;for(var a=n;a>>8^i[255&(e^t.charCodeAt(a))];return-1^e}(0|t,e,e.length,0):0}},{"./utils":32}],5:[function(e,t,r){"use strict";r.base64=!1,r.binary=!1,r.dir=!1,r.createFolders=!0,r.date=null,r.compression=null,r.compressionOptions=null,r.comment=null,r.unixPermissions=null,r.dosPermissions=null},{}],6:[function(e,t,r){"use strict";var n=null;n="undefined"!=typeof Promise?Promise:e("lie"),t.exports={Promise:n}},{lie:37}],7:[function(e,t,r){"use strict";var n="undefined"!=typeof Uint8Array&&"undefined"!=typeof Uint16Array&&"undefined"!=typeof Uint32Array,i=e("pako"),s=e("./utils"),a=e("./stream/GenericWorker"),o=n?"uint8array":"array";function h(e,t){a.call(this,"FlateWorker/"+e),this._pako=null,this._pakoAction=e,this._pakoOptions=t,this.meta={}}r.magic="\b\0",s.inherits(h,a),h.prototype.processChunk=function(e){this.meta=e.meta,null===this._pako&&this._createPako(),this._pako.push(s.transformTo(o,e.data),!1)},h.prototype.flush=function(){a.prototype.flush.call(this),null===this._pako&&this._createPako(),this._pako.push([],!0)},h.prototype.cleanUp=function(){a.prototype.cleanUp.call(this),this._pako=null},h.prototype._createPako=function(){this._pako=new i[this._pakoAction]({raw:!0,level:this._pakoOptions.level||-1});var t=this;this._pako.onData=function(e){t.push({data:e,meta:t.meta})}},r.compressWorker=function(e){return new h("Deflate",e)},r.uncompressWorker=function(){return new h("Inflate",{})}},{"./stream/GenericWorker":28,"./utils":32,pako:38}],8:[function(e,t,r){"use strict";function A(e,t){var r,n="";for(r=0;r>>=8;return n}function n(e,t,r,n,i,s){var a,o,h=e.file,u=e.compression,l=s!==O.utf8encode,f=I.transformTo("string",s(h.name)),c=I.transformTo("string",O.utf8encode(h.name)),d=h.comment,p=I.transformTo("string",s(d)),m=I.transformTo("string",O.utf8encode(d)),_=c.length!==h.name.length,g=m.length!==d.length,b="",v="",y="",w=h.dir,k=h.date,x={crc32:0,compressedSize:0,uncompressedSize:0};t&&!r||(x.crc32=e.crc32,x.compressedSize=e.compressedSize,x.uncompressedSize=e.uncompressedSize);var S=0;t&&(S|=8),l||!_&&!g||(S|=2048);var z=0,C=0;w&&(z|=16),"UNIX"===i?(C=798,z|=function(e,t){var r=e;return e||(r=t?16893:33204),(65535&r)<<16}(h.unixPermissions,w)):(C=20,z|=function(e){return 63&(e||0)}(h.dosPermissions)),a=k.getUTCHours(),a<<=6,a|=k.getUTCMinutes(),a<<=5,a|=k.getUTCSeconds()/2,o=k.getUTCFullYear()-1980,o<<=4,o|=k.getUTCMonth()+1,o<<=5,o|=k.getUTCDate(),_&&(v=A(1,1)+A(B(f),4)+c,b+="up"+A(v.length,2)+v),g&&(y=A(1,1)+A(B(p),4)+m,b+="uc"+A(y.length,2)+y);var E="";return E+="\n\0",E+=A(S,2),E+=u.magic,E+=A(a,2),E+=A(o,2),E+=A(x.crc32,4),E+=A(x.compressedSize,4),E+=A(x.uncompressedSize,4),E+=A(f.length,2),E+=A(b.length,2),{fileRecord:R.LOCAL_FILE_HEADER+E+f+b,dirRecord:R.CENTRAL_FILE_HEADER+A(C,2)+E+A(p.length,2)+"\0\0\0\0"+A(z,4)+A(n,4)+f+b+p}}var I=e("../utils"),i=e("../stream/GenericWorker"),O=e("../utf8"),B=e("../crc32"),R=e("../signature");function s(e,t,r,n){i.call(this,"ZipFileWorker"),this.bytesWritten=0,this.zipComment=t,this.zipPlatform=r,this.encodeFileName=n,this.streamFiles=e,this.accumulate=!1,this.contentBuffer=[],this.dirRecords=[],this.currentSourceOffset=0,this.entriesCount=0,this.currentFile=null,this._sources=[]}I.inherits(s,i),s.prototype.push=function(e){var t=e.meta.percent||0,r=this.entriesCount,n=this._sources.length;this.accumulate?this.contentBuffer.push(e):(this.bytesWritten+=e.data.length,i.prototype.push.call(this,{data:e.data,meta:{currentFile:this.currentFile,percent:r?(t+100*(r-n-1))/r:100}}))},s.prototype.openedSource=function(e){this.currentSourceOffset=this.bytesWritten,this.currentFile=e.file.name;var t=this.streamFiles&&!e.file.dir;if(t){var r=n(e,t,!1,this.currentSourceOffset,this.zipPlatform,this.encodeFileName);this.push({data:r.fileRecord,meta:{percent:0}})}else this.accumulate=!0},s.prototype.closedSource=function(e){this.accumulate=!1;var t=this.streamFiles&&!e.file.dir,r=n(e,t,!0,this.currentSourceOffset,this.zipPlatform,this.encodeFileName);if(this.dirRecords.push(r.dirRecord),t)this.push({data:function(e){return R.DATA_DESCRIPTOR+A(e.crc32,4)+A(e.compressedSize,4)+A(e.uncompressedSize,4)}(e),meta:{percent:100}});else for(this.push({data:r.fileRecord,meta:{percent:0}});this.contentBuffer.length;)this.push(this.contentBuffer.shift());this.currentFile=null},s.prototype.flush=function(){for(var e=this.bytesWritten,t=0;t=this.index;t--)r=(r<<8)+this.byteAt(t);return this.index+=e,r},readString:function(e){return n.transformTo("string",this.readData(e))},readData:function(){},lastIndexOfSignature:function(){},readAndCheckSignature:function(){},readDate:function(){var e=this.readInt(4);return new Date(Date.UTC(1980+(e>>25&127),(e>>21&15)-1,e>>16&31,e>>11&31,e>>5&63,(31&e)<<1))}},t.exports=i},{"../utils":32}],19:[function(e,t,r){"use strict";var n=e("./Uint8ArrayReader");function i(e){n.call(this,e)}e("../utils").inherits(i,n),i.prototype.readData=function(e){this.checkOffset(e);var t=this.data.slice(this.zero+this.index,this.zero+this.index+e);return this.index+=e,t},t.exports=i},{"../utils":32,"./Uint8ArrayReader":21}],20:[function(e,t,r){"use strict";var n=e("./DataReader");function i(e){n.call(this,e)}e("../utils").inherits(i,n),i.prototype.byteAt=function(e){return this.data.charCodeAt(this.zero+e)},i.prototype.lastIndexOfSignature=function(e){return this.data.lastIndexOf(e)-this.zero},i.prototype.readAndCheckSignature=function(e){return e===this.readData(4)},i.prototype.readData=function(e){this.checkOffset(e);var t=this.data.slice(this.zero+this.index,this.zero+this.index+e);return this.index+=e,t},t.exports=i},{"../utils":32,"./DataReader":18}],21:[function(e,t,r){"use strict";var n=e("./ArrayReader");function i(e){n.call(this,e)}e("../utils").inherits(i,n),i.prototype.readData=function(e){if(this.checkOffset(e),0===e)return new Uint8Array(0);var t=this.data.subarray(this.zero+this.index,this.zero+this.index+e);return this.index+=e,t},t.exports=i},{"../utils":32,"./ArrayReader":17}],22:[function(e,t,r){"use strict";var n=e("../utils"),i=e("../support"),s=e("./ArrayReader"),a=e("./StringReader"),o=e("./NodeBufferReader"),h=e("./Uint8ArrayReader");t.exports=function(e){var t=n.getTypeOf(e);return n.checkSupport(t),"string"!==t||i.uint8array?"nodebuffer"===t?new o(e):i.uint8array?new h(n.transformTo("uint8array",e)):new s(n.transformTo("array",e)):new a(e)}},{"../support":30,"../utils":32,"./ArrayReader":17,"./NodeBufferReader":19,"./StringReader":20,"./Uint8ArrayReader":21}],23:[function(e,t,r){"use strict";r.LOCAL_FILE_HEADER="PK",r.CENTRAL_FILE_HEADER="PK",r.CENTRAL_DIRECTORY_END="PK",r.ZIP64_CENTRAL_DIRECTORY_LOCATOR="PK",r.ZIP64_CENTRAL_DIRECTORY_END="PK",r.DATA_DESCRIPTOR="PK\b"},{}],24:[function(e,t,r){"use strict";var n=e("./GenericWorker"),i=e("../utils");function s(e){n.call(this,"ConvertWorker to "+e),this.destType=e}i.inherits(s,n),s.prototype.processChunk=function(e){this.push({data:i.transformTo(this.destType,e.data),meta:e.meta})},t.exports=s},{"../utils":32,"./GenericWorker":28}],25:[function(e,t,r){"use strict";var n=e("./GenericWorker"),i=e("../crc32");function s(){n.call(this,"Crc32Probe"),this.withStreamInfo("crc32",0)}e("../utils").inherits(s,n),s.prototype.processChunk=function(e){this.streamInfo.crc32=i(e.data,this.streamInfo.crc32||0),this.push(e)},t.exports=s},{"../crc32":4,"../utils":32,"./GenericWorker":28}],26:[function(e,t,r){"use strict";var n=e("../utils"),i=e("./GenericWorker");function s(e){i.call(this,"DataLengthProbe for "+e),this.propName=e,this.withStreamInfo(e,0)}n.inherits(s,i),s.prototype.processChunk=function(e){if(e){var t=this.streamInfo[this.propName]||0;this.streamInfo[this.propName]=t+e.data.length}i.prototype.processChunk.call(this,e)},t.exports=s},{"../utils":32,"./GenericWorker":28}],27:[function(e,t,r){"use strict";var n=e("../utils"),i=e("./GenericWorker");function s(e){i.call(this,"DataWorker");var t=this;this.dataIsReady=!1,this.index=0,this.max=0,this.data=null,this.type="",this._tickScheduled=!1,e.then(function(e){t.dataIsReady=!0,t.data=e,t.max=e&&e.length||0,t.type=n.getTypeOf(e),t.isPaused||t._tickAndRepeat()},function(e){t.error(e)})}n.inherits(s,i),s.prototype.cleanUp=function(){i.prototype.cleanUp.call(this),this.data=null},s.prototype.resume=function(){return!!i.prototype.resume.call(this)&&(!this._tickScheduled&&this.dataIsReady&&(this._tickScheduled=!0,n.delay(this._tickAndRepeat,[],this)),!0)},s.prototype._tickAndRepeat=function(){this._tickScheduled=!1,this.isPaused||this.isFinished||(this._tick(),this.isFinished||(n.delay(this._tickAndRepeat,[],this),this._tickScheduled=!0))},s.prototype._tick=function(){if(this.isPaused||this.isFinished)return!1;var e=null,t=Math.min(this.max,this.index+16384);if(this.index>=this.max)return this.end();switch(this.type){case"string":e=this.data.substring(this.index,t);break;case"uint8array":e=this.data.subarray(this.index,t);break;case"array":case"nodebuffer":e=this.data.slice(this.index,t)}return this.index=t,this.push({data:e,meta:{percent:this.max?this.index/this.max*100:0}})},t.exports=s},{"../utils":32,"./GenericWorker":28}],28:[function(e,t,r){"use strict";function n(e){this.name=e||"default",this.streamInfo={},this.generatedError=null,this.extraStreamInfo={},this.isPaused=!0,this.isFinished=!1,this.isLocked=!1,this._listeners={data:[],end:[],error:[]},this.previous=null}n.prototype={push:function(e){this.emit("data",e)},end:function(){if(this.isFinished)return!1;this.flush();try{this.emit("end"),this.cleanUp(),this.isFinished=!0}catch(e){this.emit("error",e)}return!0},error:function(e){return!this.isFinished&&(this.isPaused?this.generatedError=e:(this.isFinished=!0,this.emit("error",e),this.previous&&this.previous.error(e),this.cleanUp()),!0)},on:function(e,t){return this._listeners[e].push(t),this},cleanUp:function(){this.streamInfo=this.generatedError=this.extraStreamInfo=null,this._listeners=[]},emit:function(e,t){if(this._listeners[e])for(var r=0;r "+e:e}},t.exports=n},{}],29:[function(e,t,r){"use strict";var h=e("../utils"),i=e("./ConvertWorker"),s=e("./GenericWorker"),u=e("../base64"),n=e("../support"),a=e("../external"),o=null;if(n.nodestream)try{o=e("../nodejs/NodejsStreamOutputAdapter")}catch(e){}function l(e,o){return new a.Promise(function(t,r){var n=[],i=e._internalType,s=e._outputType,a=e._mimeType;e.on("data",function(e,t){n.push(e),o&&o(t)}).on("error",function(e){n=[],r(e)}).on("end",function(){try{var e=function(e,t,r){switch(e){case"blob":return h.newBlob(h.transformTo("arraybuffer",t),r);case"base64":return u.encode(t);default:return h.transformTo(e,t)}}(s,function(e,t){var r,n=0,i=null,s=0;for(r=0;r>>6:(r<65536?t[s++]=224|r>>>12:(t[s++]=240|r>>>18,t[s++]=128|r>>>12&63),t[s++]=128|r>>>6&63),t[s++]=128|63&r);return t}(e)},s.utf8decode=function(e){return h.nodebuffer?o.transformTo("nodebuffer",e).toString("utf-8"):function(e){var t,r,n,i,s=e.length,a=new Array(2*s);for(t=r=0;t>10&1023,a[r++]=56320|1023&n)}return a.length!==r&&(a.subarray?a=a.subarray(0,r):a.length=r),o.applyFromCharCode(a)}(e=o.transformTo(h.uint8array?"uint8array":"array",e))},o.inherits(a,n),a.prototype.processChunk=function(e){var t=o.transformTo(h.uint8array?"uint8array":"array",e.data);if(this.leftOver&&this.leftOver.length){if(h.uint8array){var r=t;(t=new Uint8Array(r.length+this.leftOver.length)).set(this.leftOver,0),t.set(r,this.leftOver.length)}else t=this.leftOver.concat(t);this.leftOver=null}var n=function(e,t){var r;for((t=t||e.length)>e.length&&(t=e.length),r=t-1;0<=r&&128==(192&e[r]);)r--;return r<0?t:0===r?t:r+u[e[r]]>t?r:t}(t),i=t;n!==t.length&&(h.uint8array?(i=t.subarray(0,n),this.leftOver=t.subarray(n,t.length)):(i=t.slice(0,n),this.leftOver=t.slice(n,t.length))),this.push({data:s.utf8decode(i),meta:e.meta})},a.prototype.flush=function(){this.leftOver&&this.leftOver.length&&(this.push({data:s.utf8decode(this.leftOver),meta:{}}),this.leftOver=null)},s.Utf8DecodeWorker=a,o.inherits(l,n),l.prototype.processChunk=function(e){this.push({data:s.utf8encode(e.data),meta:e.meta})},s.Utf8EncodeWorker=l},{"./nodejsUtils":14,"./stream/GenericWorker":28,"./support":30,"./utils":32}],32:[function(e,t,a){"use strict";var o=e("./support"),h=e("./base64"),r=e("./nodejsUtils"),u=e("./external");function n(e){return e}function l(e,t){for(var r=0;r>8;this.dir=!!(16&this.externalFileAttributes),0==e&&(this.dosPermissions=63&this.externalFileAttributes),3==e&&(this.unixPermissions=this.externalFileAttributes>>16&65535),this.dir||"/"!==this.fileNameStr.slice(-1)||(this.dir=!0)},parseZIP64ExtraField:function(){if(this.extraFields[1]){var e=n(this.extraFields[1].value);this.uncompressedSize===s.MAX_VALUE_32BITS&&(this.uncompressedSize=e.readInt(8)),this.compressedSize===s.MAX_VALUE_32BITS&&(this.compressedSize=e.readInt(8)),this.localHeaderOffset===s.MAX_VALUE_32BITS&&(this.localHeaderOffset=e.readInt(8)),this.diskNumberStart===s.MAX_VALUE_32BITS&&(this.diskNumberStart=e.readInt(4))}},readExtraFields:function(e){var t,r,n,i=e.index+this.extraFieldsLength;for(this.extraFields||(this.extraFields={});e.index+4>>6:(r<65536?t[s++]=224|r>>>12:(t[s++]=240|r>>>18,t[s++]=128|r>>>12&63),t[s++]=128|r>>>6&63),t[s++]=128|63&r);return t},r.buf2binstring=function(e){return l(e,e.length)},r.binstring2buf=function(e){for(var t=new h.Buf8(e.length),r=0,n=t.length;r>10&1023,o[n++]=56320|1023&i)}return l(o,n)},r.utf8border=function(e,t){var r;for((t=t||e.length)>e.length&&(t=e.length),r=t-1;0<=r&&128==(192&e[r]);)r--;return r<0?t:0===r?t:r+u[e[r]]>t?r:t}},{"./common":41}],43:[function(e,t,r){"use strict";t.exports=function(e,t,r,n){for(var i=65535&e|0,s=e>>>16&65535|0,a=0;0!==r;){for(r-=a=2e3>>1:e>>>1;t[r]=e}return t}();t.exports=function(e,t,r,n){var i=o,s=n+r;e^=-1;for(var a=n;a>>8^i[255&(e^t[a])];return-1^e}},{}],46:[function(e,t,r){"use strict";var h,c=e("../utils/common"),u=e("./trees"),d=e("./adler32"),p=e("./crc32"),n=e("./messages"),l=0,f=4,m=0,_=-2,g=-1,b=4,i=2,v=8,y=9,s=286,a=30,o=19,w=2*s+1,k=15,x=3,S=258,z=S+x+1,C=42,E=113,A=1,I=2,O=3,B=4;function R(e,t){return e.msg=n[t],t}function T(e){return(e<<1)-(4e.avail_out&&(r=e.avail_out),0!==r&&(c.arraySet(e.output,t.pending_buf,t.pending_out,r,e.next_out),e.next_out+=r,t.pending_out+=r,e.total_out+=r,e.avail_out-=r,t.pending-=r,0===t.pending&&(t.pending_out=0))}function N(e,t){u._tr_flush_block(e,0<=e.block_start?e.block_start:-1,e.strstart-e.block_start,t),e.block_start=e.strstart,F(e.strm)}function U(e,t){e.pending_buf[e.pending++]=t}function P(e,t){e.pending_buf[e.pending++]=t>>>8&255,e.pending_buf[e.pending++]=255&t}function L(e,t){var r,n,i=e.max_chain_length,s=e.strstart,a=e.prev_length,o=e.nice_match,h=e.strstart>e.w_size-z?e.strstart-(e.w_size-z):0,u=e.window,l=e.w_mask,f=e.prev,c=e.strstart+S,d=u[s+a-1],p=u[s+a];e.prev_length>=e.good_match&&(i>>=2),o>e.lookahead&&(o=e.lookahead);do{if(u[(r=t)+a]===p&&u[r+a-1]===d&&u[r]===u[s]&&u[++r]===u[s+1]){s+=2,r++;do{}while(u[++s]===u[++r]&&u[++s]===u[++r]&&u[++s]===u[++r]&&u[++s]===u[++r]&&u[++s]===u[++r]&&u[++s]===u[++r]&&u[++s]===u[++r]&&u[++s]===u[++r]&&sh&&0!=--i);return a<=e.lookahead?a:e.lookahead}function j(e){var t,r,n,i,s,a,o,h,u,l,f=e.w_size;do{if(i=e.window_size-e.lookahead-e.strstart,e.strstart>=f+(f-z)){for(c.arraySet(e.window,e.window,f,f,0),e.match_start-=f,e.strstart-=f,e.block_start-=f,t=r=e.hash_size;n=e.head[--t],e.head[t]=f<=n?n-f:0,--r;);for(t=r=f;n=e.prev[--t],e.prev[t]=f<=n?n-f:0,--r;);i+=f}if(0===e.strm.avail_in)break;if(a=e.strm,o=e.window,h=e.strstart+e.lookahead,u=i,l=void 0,l=a.avail_in,u=x)for(s=e.strstart-e.insert,e.ins_h=e.window[s],e.ins_h=(e.ins_h<=x&&(e.ins_h=(e.ins_h<=x)if(n=u._tr_tally(e,e.strstart-e.match_start,e.match_length-x),e.lookahead-=e.match_length,e.match_length<=e.max_lazy_match&&e.lookahead>=x){for(e.match_length--;e.strstart++,e.ins_h=(e.ins_h<=x&&(e.ins_h=(e.ins_h<=x&&e.match_length<=e.prev_length){for(i=e.strstart+e.lookahead-x,n=u._tr_tally(e,e.strstart-1-e.prev_match,e.prev_length-x),e.lookahead-=e.prev_length-1,e.prev_length-=2;++e.strstart<=i&&(e.ins_h=(e.ins_h<e.pending_buf_size-5&&(r=e.pending_buf_size-5);;){if(e.lookahead<=1){if(j(e),0===e.lookahead&&t===l)return A;if(0===e.lookahead)break}e.strstart+=e.lookahead,e.lookahead=0;var n=e.block_start+r;if((0===e.strstart||e.strstart>=n)&&(e.lookahead=e.strstart-n,e.strstart=n,N(e,!1),0===e.strm.avail_out))return A;if(e.strstart-e.block_start>=e.w_size-z&&(N(e,!1),0===e.strm.avail_out))return A}return e.insert=0,t===f?(N(e,!0),0===e.strm.avail_out?O:B):(e.strstart>e.block_start&&(N(e,!1),e.strm.avail_out),A)}),new M(4,4,8,4,Z),new M(4,5,16,8,Z),new M(4,6,32,32,Z),new M(4,4,16,16,W),new M(8,16,32,32,W),new M(8,16,128,128,W),new M(8,32,128,256,W),new M(32,128,258,1024,W),new M(32,258,258,4096,W)],r.deflateInit=function(e,t){return Y(e,t,v,15,8,0)},r.deflateInit2=Y,r.deflateReset=K,r.deflateResetKeep=G,r.deflateSetHeader=function(e,t){return e&&e.state?2!==e.state.wrap?_:(e.state.gzhead=t,m):_},r.deflate=function(e,t){var r,n,i,s;if(!e||!e.state||5>8&255),U(n,n.gzhead.time>>16&255),U(n,n.gzhead.time>>24&255),U(n,9===n.level?2:2<=n.strategy||n.level<2?4:0),U(n,255&n.gzhead.os),n.gzhead.extra&&n.gzhead.extra.length&&(U(n,255&n.gzhead.extra.length),U(n,n.gzhead.extra.length>>8&255)),n.gzhead.hcrc&&(e.adler=p(e.adler,n.pending_buf,n.pending,0)),n.gzindex=0,n.status=69):(U(n,0),U(n,0),U(n,0),U(n,0),U(n,0),U(n,9===n.level?2:2<=n.strategy||n.level<2?4:0),U(n,3),n.status=E);else{var a=v+(n.w_bits-8<<4)<<8;a|=(2<=n.strategy||n.level<2?0:n.level<6?1:6===n.level?2:3)<<6,0!==n.strstart&&(a|=32),a+=31-a%31,n.status=E,P(n,a),0!==n.strstart&&(P(n,e.adler>>>16),P(n,65535&e.adler)),e.adler=1}if(69===n.status)if(n.gzhead.extra){for(i=n.pending;n.gzindex<(65535&n.gzhead.extra.length)&&(n.pending!==n.pending_buf_size||(n.gzhead.hcrc&&n.pending>i&&(e.adler=p(e.adler,n.pending_buf,n.pending-i,i)),F(e),i=n.pending,n.pending!==n.pending_buf_size));)U(n,255&n.gzhead.extra[n.gzindex]),n.gzindex++;n.gzhead.hcrc&&n.pending>i&&(e.adler=p(e.adler,n.pending_buf,n.pending-i,i)),n.gzindex===n.gzhead.extra.length&&(n.gzindex=0,n.status=73)}else n.status=73;if(73===n.status)if(n.gzhead.name){i=n.pending;do{if(n.pending===n.pending_buf_size&&(n.gzhead.hcrc&&n.pending>i&&(e.adler=p(e.adler,n.pending_buf,n.pending-i,i)),F(e),i=n.pending,n.pending===n.pending_buf_size)){s=1;break}s=n.gzindexi&&(e.adler=p(e.adler,n.pending_buf,n.pending-i,i)),0===s&&(n.gzindex=0,n.status=91)}else n.status=91;if(91===n.status)if(n.gzhead.comment){i=n.pending;do{if(n.pending===n.pending_buf_size&&(n.gzhead.hcrc&&n.pending>i&&(e.adler=p(e.adler,n.pending_buf,n.pending-i,i)),F(e),i=n.pending,n.pending===n.pending_buf_size)){s=1;break}s=n.gzindexi&&(e.adler=p(e.adler,n.pending_buf,n.pending-i,i)),0===s&&(n.status=103)}else n.status=103;if(103===n.status&&(n.gzhead.hcrc?(n.pending+2>n.pending_buf_size&&F(e),n.pending+2<=n.pending_buf_size&&(U(n,255&e.adler),U(n,e.adler>>8&255),e.adler=0,n.status=E)):n.status=E),0!==n.pending){if(F(e),0===e.avail_out)return n.last_flush=-1,m}else if(0===e.avail_in&&T(t)<=T(r)&&t!==f)return R(e,-5);if(666===n.status&&0!==e.avail_in)return R(e,-5);if(0!==e.avail_in||0!==n.lookahead||t!==l&&666!==n.status){var o=2===n.strategy?function(e,t){for(var r;;){if(0===e.lookahead&&(j(e),0===e.lookahead)){if(t===l)return A;break}if(e.match_length=0,r=u._tr_tally(e,0,e.window[e.strstart]),e.lookahead--,e.strstart++,r&&(N(e,!1),0===e.strm.avail_out))return A}return e.insert=0,t===f?(N(e,!0),0===e.strm.avail_out?O:B):e.last_lit&&(N(e,!1),0===e.strm.avail_out)?A:I}(n,t):3===n.strategy?function(e,t){for(var r,n,i,s,a=e.window;;){if(e.lookahead<=S){if(j(e),e.lookahead<=S&&t===l)return A;if(0===e.lookahead)break}if(e.match_length=0,e.lookahead>=x&&0e.lookahead&&(e.match_length=e.lookahead)}if(e.match_length>=x?(r=u._tr_tally(e,1,e.match_length-x),e.lookahead-=e.match_length,e.strstart+=e.match_length,e.match_length=0):(r=u._tr_tally(e,0,e.window[e.strstart]),e.lookahead--,e.strstart++),r&&(N(e,!1),0===e.strm.avail_out))return A}return e.insert=0,t===f?(N(e,!0),0===e.strm.avail_out?O:B):e.last_lit&&(N(e,!1),0===e.strm.avail_out)?A:I}(n,t):h[n.level].func(n,t);if(o!==O&&o!==B||(n.status=666),o===A||o===O)return 0===e.avail_out&&(n.last_flush=-1),m;if(o===I&&(1===t?u._tr_align(n):5!==t&&(u._tr_stored_block(n,0,0,!1),3===t&&(D(n.head),0===n.lookahead&&(n.strstart=0,n.block_start=0,n.insert=0))),F(e),0===e.avail_out))return n.last_flush=-1,m}return t!==f?m:n.wrap<=0?1:(2===n.wrap?(U(n,255&e.adler),U(n,e.adler>>8&255),U(n,e.adler>>16&255),U(n,e.adler>>24&255),U(n,255&e.total_in),U(n,e.total_in>>8&255),U(n,e.total_in>>16&255),U(n,e.total_in>>24&255)):(P(n,e.adler>>>16),P(n,65535&e.adler)),F(e),0=r.w_size&&(0===s&&(D(r.head),r.strstart=0,r.block_start=0,r.insert=0),u=new c.Buf8(r.w_size),c.arraySet(u,t,l-r.w_size,r.w_size,0),t=u,l=r.w_size),a=e.avail_in,o=e.next_in,h=e.input,e.avail_in=l,e.next_in=0,e.input=t,j(r);r.lookahead>=x;){for(n=r.strstart,i=r.lookahead-(x-1);r.ins_h=(r.ins_h<>>=y=v>>>24,p-=y,0===(y=v>>>16&255))C[s++]=65535&v;else{if(!(16&y)){if(0==(64&y)){v=m[(65535&v)+(d&(1<>>=y,p-=y),p<15&&(d+=z[n++]<>>=y=v>>>24,p-=y,!(16&(y=v>>>16&255))){if(0==(64&y)){v=_[(65535&v)+(d&(1<>>=y,p-=y,(y=s-a)>3,d&=(1<<(p-=w<<3))-1,e.next_in=n,e.next_out=s,e.avail_in=n>>24&255)+(e>>>8&65280)+((65280&e)<<8)+((255&e)<<24)}function s(){this.mode=0,this.last=!1,this.wrap=0,this.havedict=!1,this.flags=0,this.dmax=0,this.check=0,this.total=0,this.head=null,this.wbits=0,this.wsize=0,this.whave=0,this.wnext=0,this.window=null,this.hold=0,this.bits=0,this.length=0,this.offset=0,this.extra=0,this.lencode=null,this.distcode=null,this.lenbits=0,this.distbits=0,this.ncode=0,this.nlen=0,this.ndist=0,this.have=0,this.next=null,this.lens=new I.Buf16(320),this.work=new I.Buf16(288),this.lendyn=null,this.distdyn=null,this.sane=0,this.back=0,this.was=0}function a(e){var t;return e&&e.state?(t=e.state,e.total_in=e.total_out=t.total=0,e.msg="",t.wrap&&(e.adler=1&t.wrap),t.mode=P,t.last=0,t.havedict=0,t.dmax=32768,t.head=null,t.hold=0,t.bits=0,t.lencode=t.lendyn=new I.Buf32(n),t.distcode=t.distdyn=new I.Buf32(i),t.sane=1,t.back=-1,N):U}function o(e){var t;return e&&e.state?((t=e.state).wsize=0,t.whave=0,t.wnext=0,a(e)):U}function h(e,t){var r,n;return e&&e.state?(n=e.state,t<0?(r=0,t=-t):(r=1+(t>>4),t<48&&(t&=15)),t&&(t<8||15=s.wsize?(I.arraySet(s.window,t,r-s.wsize,s.wsize,0),s.wnext=0,s.whave=s.wsize):(n<(i=s.wsize-s.wnext)&&(i=n),I.arraySet(s.window,t,r-n,i,s.wnext),(n-=i)?(I.arraySet(s.window,t,r-n,n,0),s.wnext=n,s.whave=s.wsize):(s.wnext+=i,s.wnext===s.wsize&&(s.wnext=0),s.whave>>8&255,r.check=B(r.check,E,2,0),l=u=0,r.mode=2;break}if(r.flags=0,r.head&&(r.head.done=!1),!(1&r.wrap)||(((255&u)<<8)+(u>>8))%31){e.msg="incorrect header check",r.mode=30;break}if(8!=(15&u)){e.msg="unknown compression method",r.mode=30;break}if(l-=4,k=8+(15&(u>>>=4)),0===r.wbits)r.wbits=k;else if(k>r.wbits){e.msg="invalid window size",r.mode=30;break}r.dmax=1<>8&1),512&r.flags&&(E[0]=255&u,E[1]=u>>>8&255,r.check=B(r.check,E,2,0)),l=u=0,r.mode=3;case 3:for(;l<32;){if(0===o)break e;o--,u+=n[s++]<>>8&255,E[2]=u>>>16&255,E[3]=u>>>24&255,r.check=B(r.check,E,4,0)),l=u=0,r.mode=4;case 4:for(;l<16;){if(0===o)break e;o--,u+=n[s++]<>8),512&r.flags&&(E[0]=255&u,E[1]=u>>>8&255,r.check=B(r.check,E,2,0)),l=u=0,r.mode=5;case 5:if(1024&r.flags){for(;l<16;){if(0===o)break e;o--,u+=n[s++]<>>8&255,r.check=B(r.check,E,2,0)),l=u=0}else r.head&&(r.head.extra=null);r.mode=6;case 6:if(1024&r.flags&&(o<(d=r.length)&&(d=o),d&&(r.head&&(k=r.head.extra_len-r.length,r.head.extra||(r.head.extra=new Array(r.head.extra_len)),I.arraySet(r.head.extra,n,s,d,k)),512&r.flags&&(r.check=B(r.check,n,d,s)),o-=d,s+=d,r.length-=d),r.length))break e;r.length=0,r.mode=7;case 7:if(2048&r.flags){if(0===o)break e;for(d=0;k=n[s+d++],r.head&&k&&r.length<65536&&(r.head.name+=String.fromCharCode(k)),k&&d>9&1,r.head.done=!0),e.adler=r.check=0,r.mode=12;break;case 10:for(;l<32;){if(0===o)break e;o--,u+=n[s++]<>>=7&l,l-=7&l,r.mode=27;break}for(;l<3;){if(0===o)break e;o--,u+=n[s++]<>>=1)){case 0:r.mode=14;break;case 1:if(j(r),r.mode=20,6!==t)break;u>>>=2,l-=2;break e;case 2:r.mode=17;break;case 3:e.msg="invalid block type",r.mode=30}u>>>=2,l-=2;break;case 14:for(u>>>=7&l,l-=7&l;l<32;){if(0===o)break e;o--,u+=n[s++]<>>16^65535)){e.msg="invalid stored block lengths",r.mode=30;break}if(r.length=65535&u,l=u=0,r.mode=15,6===t)break e;case 15:r.mode=16;case 16:if(d=r.length){if(o>>=5,l-=5,r.ndist=1+(31&u),u>>>=5,l-=5,r.ncode=4+(15&u),u>>>=4,l-=4,286>>=3,l-=3}for(;r.have<19;)r.lens[A[r.have++]]=0;if(r.lencode=r.lendyn,r.lenbits=7,S={bits:r.lenbits},x=T(0,r.lens,0,19,r.lencode,0,r.work,S),r.lenbits=S.bits,x){e.msg="invalid code lengths set",r.mode=30;break}r.have=0,r.mode=19;case 19:for(;r.have>>16&255,b=65535&C,!((_=C>>>24)<=l);){if(0===o)break e;o--,u+=n[s++]<>>=_,l-=_,r.lens[r.have++]=b;else{if(16===b){for(z=_+2;l>>=_,l-=_,0===r.have){e.msg="invalid bit length repeat",r.mode=30;break}k=r.lens[r.have-1],d=3+(3&u),u>>>=2,l-=2}else if(17===b){for(z=_+3;l>>=_)),u>>>=3,l-=3}else{for(z=_+7;l>>=_)),u>>>=7,l-=7}if(r.have+d>r.nlen+r.ndist){e.msg="invalid bit length repeat",r.mode=30;break}for(;d--;)r.lens[r.have++]=k}}if(30===r.mode)break;if(0===r.lens[256]){e.msg="invalid code -- missing end-of-block",r.mode=30;break}if(r.lenbits=9,S={bits:r.lenbits},x=T(D,r.lens,0,r.nlen,r.lencode,0,r.work,S),r.lenbits=S.bits,x){e.msg="invalid literal/lengths set",r.mode=30;break}if(r.distbits=6,r.distcode=r.distdyn,S={bits:r.distbits},x=T(F,r.lens,r.nlen,r.ndist,r.distcode,0,r.work,S),r.distbits=S.bits,x){e.msg="invalid distances set",r.mode=30;break}if(r.mode=20,6===t)break e;case 20:r.mode=21;case 21:if(6<=o&&258<=h){e.next_out=a,e.avail_out=h,e.next_in=s,e.avail_in=o,r.hold=u,r.bits=l,R(e,c),a=e.next_out,i=e.output,h=e.avail_out,s=e.next_in,n=e.input,o=e.avail_in,u=r.hold,l=r.bits,12===r.mode&&(r.back=-1);break}for(r.back=0;g=(C=r.lencode[u&(1<>>16&255,b=65535&C,!((_=C>>>24)<=l);){if(0===o)break e;o--,u+=n[s++]<>v)])>>>16&255,b=65535&C,!(v+(_=C>>>24)<=l);){if(0===o)break e;o--,u+=n[s++]<>>=v,l-=v,r.back+=v}if(u>>>=_,l-=_,r.back+=_,r.length=b,0===g){r.mode=26;break}if(32&g){r.back=-1,r.mode=12;break}if(64&g){e.msg="invalid literal/length code",r.mode=30;break}r.extra=15&g,r.mode=22;case 22:if(r.extra){for(z=r.extra;l>>=r.extra,l-=r.extra,r.back+=r.extra}r.was=r.length,r.mode=23;case 23:for(;g=(C=r.distcode[u&(1<>>16&255,b=65535&C,!((_=C>>>24)<=l);){if(0===o)break e;o--,u+=n[s++]<>v)])>>>16&255,b=65535&C,!(v+(_=C>>>24)<=l);){if(0===o)break e;o--,u+=n[s++]<>>=v,l-=v,r.back+=v}if(u>>>=_,l-=_,r.back+=_,64&g){e.msg="invalid distance code",r.mode=30;break}r.offset=b,r.extra=15&g,r.mode=24;case 24:if(r.extra){for(z=r.extra;l>>=r.extra,l-=r.extra,r.back+=r.extra}if(r.offset>r.dmax){e.msg="invalid distance too far back",r.mode=30;break}r.mode=25;case 25:if(0===h)break e;if(d=c-h,r.offset>d){if((d=r.offset-d)>r.whave&&r.sane){e.msg="invalid distance too far back",r.mode=30;break}p=d>r.wnext?(d-=r.wnext,r.wsize-d):r.wnext-d,d>r.length&&(d=r.length),m=r.window}else m=i,p=a-r.offset,d=r.length;for(hd?(m=R[T+a[v]],A[I+a[v]]):(m=96,0),h=1<>S)+(u-=h)]=p<<24|m<<16|_|0,0!==u;);for(h=1<>=1;if(0!==h?(E&=h-1,E+=h):E=0,v++,0==--O[b]){if(b===w)break;b=t[r+a[v]]}if(k>>7)]}function U(e,t){e.pending_buf[e.pending++]=255&t,e.pending_buf[e.pending++]=t>>>8&255}function P(e,t,r){e.bi_valid>d-r?(e.bi_buf|=t<>d-e.bi_valid,e.bi_valid+=r-d):(e.bi_buf|=t<>>=1,r<<=1,0<--t;);return r>>>1}function Z(e,t,r){var n,i,s=new Array(g+1),a=0;for(n=1;n<=g;n++)s[n]=a=a+r[n-1]<<1;for(i=0;i<=t;i++){var o=e[2*i+1];0!==o&&(e[2*i]=j(s[o]++,o))}}function W(e){var t;for(t=0;t>1;1<=r;r--)G(e,s,r);for(i=h;r=e.heap[1],e.heap[1]=e.heap[e.heap_len--],G(e,s,1),n=e.heap[1],e.heap[--e.heap_max]=r,e.heap[--e.heap_max]=n,s[2*i]=s[2*r]+s[2*n],e.depth[i]=(e.depth[r]>=e.depth[n]?e.depth[r]:e.depth[n])+1,s[2*r+1]=s[2*n+1]=i,e.heap[1]=i++,G(e,s,1),2<=e.heap_len;);e.heap[--e.heap_max]=e.heap[1],function(e,t){var r,n,i,s,a,o,h=t.dyn_tree,u=t.max_code,l=t.stat_desc.static_tree,f=t.stat_desc.has_stree,c=t.stat_desc.extra_bits,d=t.stat_desc.extra_base,p=t.stat_desc.max_length,m=0;for(s=0;s<=g;s++)e.bl_count[s]=0;for(h[2*e.heap[e.heap_max]+1]=0,r=e.heap_max+1;r<_;r++)p<(s=h[2*h[2*(n=e.heap[r])+1]+1]+1)&&(s=p,m++),h[2*n+1]=s,u>=7;n>>=1)if(1&r&&0!==e.dyn_ltree[2*t])return o;if(0!==e.dyn_ltree[18]||0!==e.dyn_ltree[20]||0!==e.dyn_ltree[26])return h;for(t=32;t>>3,(s=e.static_len+3+7>>>3)<=i&&(i=s)):i=s=r+5,r+4<=i&&-1!==t?J(e,t,r,n):4===e.strategy||s===i?(P(e,2+(n?1:0),3),K(e,z,C)):(P(e,4+(n?1:0),3),function(e,t,r,n){var i;for(P(e,t-257,5),P(e,r-1,5),P(e,n-4,4),i=0;i>>8&255,e.pending_buf[e.d_buf+2*e.last_lit+1]=255&t,e.pending_buf[e.l_buf+e.last_lit]=255&r,e.last_lit++,0===t?e.dyn_ltree[2*r]++:(e.matches++,t--,e.dyn_ltree[2*(A[r]+u+1)]++,e.dyn_dtree[2*N(t)]++),e.last_lit===e.lit_bufsize-1},r._tr_align=function(e){P(e,2,3),L(e,m,z),function(e){16===e.bi_valid?(U(e,e.bi_buf),e.bi_buf=0,e.bi_valid=0):8<=e.bi_valid&&(e.pending_buf[e.pending++]=255&e.bi_buf,e.bi_buf>>=8,e.bi_valid-=8)}(e)}},{"../utils/common":41}],53:[function(e,t,r){"use strict";t.exports=function(){this.input=null,this.next_in=0,this.avail_in=0,this.total_in=0,this.output=null,this.next_out=0,this.avail_out=0,this.total_out=0,this.msg="",this.state=null,this.data_type=2,this.adler=0}},{}],54:[function(e,t,r){(function(e){!function(r,n){"use strict";if(!r.setImmediate){var i,s,t,a,o=1,h={},u=!1,l=r.document,e=Object.getPrototypeOf&&Object.getPrototypeOf(r);e=e&&e.setTimeout?e:r,i="[object process]"==={}.toString.call(r.process)?function(e){process.nextTick(function(){c(e)})}:function(){if(r.postMessage&&!r.importScripts){var e=!0,t=r.onmessage;return r.onmessage=function(){e=!1},r.postMessage("","*"),r.onmessage=t,e}}()?(a="setImmediate$"+Math.random()+"$",r.addEventListener?r.addEventListener("message",d,!1):r.attachEvent("onmessage",d),function(e){r.postMessage(a+e,"*")}):r.MessageChannel?((t=new MessageChannel).port1.onmessage=function(e){c(e.data)},function(e){t.port2.postMessage(e)}):l&&"onreadystatechange"in l.createElement("script")?(s=l.documentElement,function(e){var t=l.createElement("script");t.onreadystatechange=function(){c(e),t.onreadystatechange=null,s.removeChild(t),t=null},s.appendChild(t)}):function(e){setTimeout(c,0,e)},e.setImmediate=function(e){"function"!=typeof e&&(e=new Function(""+e));for(var t=new Array(arguments.length-1),r=0;r ## Excerpt\n> {excerpt}\n\n---", + backmatter: "", + title: "{pageTitle}", + includeTemplate: false, + saveAs: false, + downloadImages: false, + imagePrefix: '{pageTitle}/', + imageFilenameTemplate: '{pageTitle:kebab}_{imageIndex}.{ext}', + mdClipsFolder: null, + disallowedChars: '[]#^', + downloadMode: 'downloadsApi', + turndownEscape: true, + contextMenus: true, + obsidianIntegration: false, + obsidianVault: "", + obsidianFolder: "", +}; + +// Function to get options from storage +async function getOptions() { + let options = defaultOptions; + try { + const result = await chrome.storage.sync.get(defaultOptions); + options = { ...defaultOptions, ...result }; + } catch (err) { + console.error('MarkDownload: Failed to get options:', err); + } + if (!chrome.downloads) options.downloadMode = 'contentLink'; + return options; +} + +// Service Worker Event Listeners +chrome.runtime.onStartup.addListener(() => { + console.log('MarkDownload: Extension startup'); + createMenus().catch(e => console.error('MarkDownload: Failed to create menus on startup:', e)); +}); + +chrome.runtime.onInstalled.addListener((details) => { + console.log('MarkDownload: Extension installed/updated:', details.reason); + createMenus().catch(e => console.error('MarkDownload: Failed to create menus on install:', e)); +}); + +// Keep service worker alive +chrome.runtime.onSuspend.addListener(() => { + console.log('MarkDownload: Service Worker is being suspended'); +}); + +chrome.runtime.onSuspendCanceled.addListener(() => { + console.log('MarkDownload: Service Worker suspension cancelled'); +}); + +// Log platform info for debugging +chrome.runtime.getPlatformInfo().then(platformInfo => { + console.log('MarkDownload Platform Info:', platformInfo); + + // Try to get browser info if available + if (chrome.runtime.getBrowserInfo) { + chrome.runtime.getBrowserInfo().then(browserInfo => { + console.log('MarkDownload Browser Info:', browserInfo); + }).catch(e => console.warn('MarkDownload: Could not get browser info:', e)); + } +}).catch(e => { + console.warn('MarkDownload: Could not get platform info:', e); +}); + +// Initialize TurndownService prototype +if (typeof TurndownService !== 'undefined') { + TurndownService.prototype.defaultEscape = TurndownService.prototype.escape; + console.log('MarkDownload: TurndownService initialized'); +} + +// Core helper functions +function cleanAttribute(attribute) { + return attribute ? attribute.replace(/(\n+\s*)+/g, '\n') : ''; +} + +function validateUri(href, baseURI) { + try { + new URL(href); + } catch { + const baseUri = new URL(baseURI); + if (href.startsWith('/')) { + href = baseUri.origin + href; + } else { + href = baseUri.href + (baseUri.href.endsWith('/') ? '' : '') + href; + } + } + return href; +} + +// Helper functions for Obsidian integration +function generateValidFileName(title, disallowedChars = null) { + if (!title) return title; + title = title + ''; + + var illegalRe = /[\/\?<>\\:\*\|":]/g; + var name = title.replace(illegalRe, "").replace(new RegExp('\u00A0', 'g'), ' ') + .replace(new RegExp(/\s+/, 'g'), ' ') + .trim(); + + if (disallowedChars) { + for (let c of disallowedChars) { + if (`[\\^$.|?*+()`.includes(c)) c = `\\${c}`; + name = name.replace(new RegExp(c, 'g'), ''); + } + } + + return name; +} + +function textReplace(string, article, disallowedChars = null) { + for (const key in article) { + if (article.hasOwnProperty(key) && key != "content") { + let s = (article[key] || '') + ''; + if (s && disallowedChars) s = generateValidFileName(s, disallowedChars); + + string = string.replace(new RegExp('{' + key + '}', 'g'), s) + .replace(new RegExp('{' + key + ':lower}', 'g'), s.toLowerCase()) + .replace(new RegExp('{' + key + ':upper}', 'g'), s.toUpperCase()) + .replace(new RegExp('{' + key + ':kebab}', 'g'), s.replace(/ /g, '-').toLowerCase()) + .replace(new RegExp('{' + key + ':mixed-kebab}', 'g'), s.replace(/ /g, '-')) + .replace(new RegExp('{' + key + ':snake}', 'g'), s.replace(/ /g, '_').toLowerCase()) + .replace(new RegExp('{' + key + ':mixed_snake}', 'g'), s.replace(/ /g, '_')) + .replace(new RegExp('{' + key + ':obsidian-cal}', 'g'), s.replace(/ /g, '-').replace(/-{2,}/g, "-")) + .replace(new RegExp('{' + key + ':camel}', 'g'), s.replace(/ ./g, (str) => str.trim().toUpperCase()).replace(/^./, (str) => str.toLowerCase())) + .replace(new RegExp('{' + key + ':pascal}', 'g'), s.replace(/ ./g, (str) => str.trim().toUpperCase()).replace(/^./, (str) => str.toUpperCase())); + } + } + + // Replace date formats + const now = new Date(); + const dateRegex = /{date:(.+?)}/g; + const matches = string.match(dateRegex); + if (matches && matches.forEach) { + matches.forEach(match => { + const format = match.substring(6, match.length - 1); + if (typeof moment !== 'undefined') { + const dateString = moment(now).format(format); + string = string.replaceAll(match, dateString); + } else { + // Fallback if moment is not available + string = string.replaceAll(match, now.toISOString()); + } + }); + } + + // Replace keywords + const keywordRegex = /{keywords:?(.*)?}/g; + const keywordMatches = string.match(keywordRegex); + if (keywordMatches && keywordMatches.forEach) { + keywordMatches.forEach(match => { + let seperator = match.substring(10, match.length - 1); + try { + seperator = JSON.parse(JSON.stringify(seperator).replace(/\\\\/g, '\\')); + } catch { } + const keywordsString = (article.keywords || []).join(seperator); + string = string.replace(new RegExp(match.replace(/\\/g, '\\\\'), 'g'), keywordsString); + }); + } + + // Replace anything left in curly braces + string = string.replace(/{(.*?)}/g, ''); + return string; +} + +// Image processing functions moved to content script + +// Text replacement functions moved to content script + +// Polyfill for replaceAll if needed +if (!String.prototype.replaceAll) { + String.prototype.replaceAll = function(str, newStr) { + if (Object.prototype.toString.call(str).toLowerCase() === '[object regexp]') { + return this.replace(str, newStr); + } + return this.replace(new RegExp(str, 'g'), newStr); + }; +} + +// Context menu creation function +async function createMenus() { + console.log('MarkDownload: Creating context menus'); + const options = await getOptions(); + + try { + await chrome.contextMenus.removeAll(); + } catch (e) { + console.warn('MarkDownload: Failed to remove existing menus:', e); + } + + if (options.contextMenus) { + // Page context menus + const pageMenuItems = [ + { + id: "download-markdown-alltabs", + title: "Download All Tabs as Markdown", + contexts: ["all"] + }, + { + id: "separator-0", + type: "separator", + contexts: ["all"] + }, + { + id: "download-markdown-selection", + title: "Download Selection As Markdown", + contexts: ["selection"] + }, + { + id: "download-markdown-all", + title: "Download Tab As Markdown", + contexts: ["all"] + }, + { + id: "separator-1", + type: "separator", + contexts: ["all"] + }, + { + id: "copy-markdown-selection", + title: "Copy Selection As Markdown", + contexts: ["selection"] + }, + { + id: "copy-markdown-link", + title: "Copy Link As Markdown", + contexts: ["link"] + }, + { + id: "copy-markdown-image", + title: "Copy Image As Markdown", + contexts: ["image"] + }, + { + id: "copy-markdown-all", + title: "Copy Tab As Markdown", + contexts: ["all"] + }, + { + id: "copy-tab-as-markdown-link", + title: "Copy Tab URL as Markdown Link", + contexts: ["all"] + }, + { + id: "copy-tab-as-markdown-link-all", + title: "Copy All Tab URLs as Markdown Link List", + contexts: ["all"] + }, + { + id: "copy-tab-as-markdown-link-selected", + title: "Copy Selected Tab URLs as Markdown Link List", + contexts: ["all"] + } + ]; + + // Add Obsidian integration menus if enabled + if (options.obsidianIntegration) { + pageMenuItems.push( + { + id: "copy-markdown-obsidian", + title: "Send Text selection to Obsidian", + contexts: ["selection"] + }, + { + id: "copy-markdown-obsall", + title: "Send Tab to Obsidian", + contexts: ["all"] + } + ); + } + + // Add separator and toggle options + pageMenuItems.push( + { + id: "separator-2", + type: "separator", + contexts: ["all"] + }, + { + id: "toggle-includeTemplate", + type: "checkbox", + title: "Include front/back template", + contexts: ["all"], + checked: options.includeTemplate + }, + { + id: "toggle-downloadImages", + type: "checkbox", + title: "Download Images", + contexts: ["all"], + checked: options.downloadImages + } + ); + + // Create page context menus + for (const item of pageMenuItems) { + try { + await chrome.contextMenus.create(item); + console.log('MarkDownload: Created page menu item:', item.id, '- Title:', item.title); + } catch (e) { + console.warn('MarkDownload: Failed to create page menu item:', item.id, e); + } + } + + console.log('MarkDownload: Context menus created successfully'); + + // Test: List all created menus for debugging + try { + const result = await new Promise((resolve) => { + chrome.contextMenus.query({}, resolve); + }); + console.log('MarkDownload: Verified menus exist:', result?.length || 'query not supported'); + } catch (e) { + console.log('MarkDownload: Menu verification not available'); + } + } +} + +// Main Turndown conversion function +// Turndown conversion function moved to content script + +// Message handling from content scripts and popup +chrome.runtime.onMessage.addListener((message, sender, sendResponse) => { + console.log('MarkDownload: Received message:', message.type, 'from tab:', sender.tab?.id, 'message.tabId:', message?.tabId); + + // Handle message asynchronously + (async () => { + try { + await handleMessage(message, sender, sendResponse); + } catch (error) { + console.error('MarkDownload: Message handling error:', error); + sendResponse({ error: error.message }); + } + })(); + + return true; // Indicate async response +}); + +// Handle messages from content scripts and popup +async function handleMessage(message, sender, sendResponse) { + try { + if (message.type === "clip") { + console.log('MarkDownload: Processing clip message'); + + // Prefer tabId from message (popup), fallback to sender.tab.id + const tabId = message.tabId || sender.tab?.id; + if (!tabId) { + sendResponse({ error: 'No valid tab ID' }); + return; + } + console.log('MarkDownload: Using tab ID for clip:', tabId); + + // Use complete processing in content script (including markdown conversion) + const result = await getCompleteMarkdownFromContent(tabId, message.clipSelection); + + if (!result) { + sendResponse({ error: 'Failed to process complete article' }); + return; + } + + // Format folder + const mdClipsFolder = await formatMdClipsFolder(result.article); + + // Send response back (for request) and also broadcast for popup listeners + const responsePayload = { + type: "display.md", + markdown: result.markdown, + article: result.article, + imageList: result.imageList, + mdClipsFolder: mdClipsFolder + }; + try { sendResponse(responsePayload); } catch {} + try { chrome.runtime.sendMessage(responsePayload); } catch {} + } else if (message.type === "download") { + console.log('MarkDownload: Processing download message'); + const tabId = message.tabId || sender.tab?.id; + await downloadMarkdown(message.markdown, message.title, tabId, message.imageList, message.mdClipsFolder); + sendResponse({ success: true }); + } else if (message.type === "recreateMenus") { + console.log('MarkDownload: Recreating context menus'); + await createMenus(); + sendResponse({ success: true }); + } else if (message.type === "sendToObsidian") { + try { + console.log('MarkDownload: Received sendToObsidian request from popup'); + const tabId = message.tabId || sender.tab?.id; + if (!tabId) { + sendResponse({ error: 'No active tab' }); + return; + } + // Ensure content script and copy markdown to clipboard + await ensureContentScript(tabId); + await executeScript(tabId, (markdown) => copyToClipboard(markdown), [message.markdown]); + // Build Obsidian URI using options supplied or stored + const options = message.options || await getOptions(); + if (!options.obsidianIntegration) { + sendResponse({ error: 'Obsidian integration not enabled' }); + return; + } + const folder = options.obsidianFolder || ''; + const vault = options.obsidianVault || ''; + let obsidianFolder = ''; + if (folder) { + const article = { title: message.title || 'Untitled', baseURI: '' }; + obsidianFolder = textReplace(folder, article, options.disallowedChars); + obsidianFolder = obsidianFolder.split('/').map(s => generateValidFileName(s, options.disallowedChars)).join('/'); + if (!obsidianFolder.endsWith('/')) obsidianFolder += '/'; + } + const filename = generateValidFileName(message.title || 'Untitled', options.disallowedChars); + const filepath = obsidianFolder + filename; + const obsidianUri = 'obsidian://advanced-uri?vault=' + encodeURIComponent(vault) + '&clipboard=true&mode=new&filepath=' + encodeURIComponent(filepath); + try { + await chrome.tabs.update(tabId, { url: obsidianUri }); + } catch (err) { + try { + await chrome.tabs.create({ url: obsidianUri }); + } catch (err2) { + console.error('MarkDownload: Failed to open Obsidian URI:', err2); + } + } + sendResponse({ success: true }); + } catch (err) { + console.error('MarkDownload: sendToObsidian handler error:', err); + sendResponse({ error: err?.message || String(err) }); + } + } else { + sendResponse({ error: 'Unknown message type: ' + message.type }); + } + } catch (error) { + console.error('MarkDownload: Error handling message:', error); + sendResponse({ error: error.message }); + } +} + +// Context menu click handlers +chrome.contextMenus.onClicked.addListener(async (info, tab) => { + console.log('MarkDownload: Context menu clicked:', info.menuItemId, 'on tab:', tab.id); + console.log('MarkDownload: Full info object:', info); + console.log('MarkDownload: Tab object:', tab); + + try { + if (info.menuItemId === "copy-markdown-obsidian" || info.menuItemId === "copy-markdown-obsall") { + console.log('MarkDownload: Routing to sendToObsidian'); + await sendToObsidian(info, tab); + } else if (info.menuItemId.startsWith("copy-markdown")) { + console.log('MarkDownload: Routing to copyMarkdownFromContext'); + await copyMarkdownFromContext(info, tab); + } else if (info.menuItemId === "download-markdown-alltabs") { + console.log('MarkDownload: Routing to downloadMarkdownForAllTabs'); + await downloadMarkdownForAllTabs(info); + } else if (info.menuItemId.startsWith("download-markdown")) { + console.log('MarkDownload: Routing to downloadMarkdownFromContext'); + await downloadMarkdownFromContext(info, tab); + } else if (info.menuItemId.startsWith("copy-tab-as-markdown-link")) { + console.log('MarkDownload: Routing to copyTabAsMarkdownLink'); + await copyTabAsMarkdownLink(tab); + } else if (info.menuItemId.startsWith("toggle-")) { + console.log('MarkDownload: Routing to toggleSetting'); + await toggleSetting(info.menuItemId.split('-')[1]); + } else { + console.warn('MarkDownload: Unhandled menu item:', info.menuItemId); + } + console.log('MarkDownload: Context menu action completed for:', info.menuItemId); + } catch (error) { + console.error('MarkDownload: Context menu action failed:', info.menuItemId, error); + } +}); + +// Command handlers +chrome.commands.onCommand.addListener((command) => { + console.log('MarkDownload: Command executed:', command); + + chrome.tabs.query({ active: true, currentWindow: true }, (tabs) => { + const tab = tabs[0]; + + if (command === "download_tab_as_markdown") { + downloadMarkdownFromContext({ menuItemId: "download-markdown-all" }, tab); + } else if (command === "copy_tab_as_markdown") { + copyMarkdownFromContext({ menuItemId: "copy-markdown-all" }, tab); + } else if (command === "copy_selection_as_markdown") { + copyMarkdownFromContext({ menuItemId: "copy-markdown-selection" }, tab); + } else if (command === "copy_tab_as_markdown_link") { + copyTabAsMarkdownLink(tab); + } else if (command === "copy_selection_to_obsidian") { + sendToObsidian({ menuItemId: "copy-markdown-obsidian" }, tab); + } else if (command === "copy_tab_to_obsidian") { + sendToObsidian({ menuItemId: "copy-markdown-obsall" }, tab); + } + }); +}); + +// Helper function to execute scripts in tabs (Manifest V3 compatible) +async function executeScript(tabId, func, args = []) { + try { + const result = await chrome.scripting.executeScript({ + target: { tabId: tabId }, + func: func, + args: args + }); + return result[0]?.result; + } catch (error) { + console.error('MarkDownload: Failed to execute script:', error); + throw error; + } +} + +// Helper function to inject content script if needed +async function ensureContentScript(tabId) { + try { + const result = await executeScript(tabId, () => { + return typeof getSelectionAndDom === 'function'; + }); + + if (!result) { + console.log('MarkDownload: Injecting content script into tab:', tabId); + await chrome.scripting.executeScript({ + target: { tabId: tabId }, + files: ['browser-polyfill.min.js', 'contentScript/contentScript.js'] + }); + } + } catch (error) { + console.error('MarkDownload: Failed to ensure content script:', error); + throw error; + } +} + +// Function to get complete article and markdown from content script +async function getCompleteMarkdownFromContent(tabId, selection = false) { + try { + console.log('MarkDownload: Getting complete markdown from tab:', tabId, 'selection:', selection); + await ensureContentScript(tabId); + + // Get options from storage + const options = await getOptions(); + + // Get DOM content + const result = await executeScript(tabId, () => { + return getSelectionAndDom(); + }); + + if (!result || !result.dom) { + console.error('MarkDownload: No DOM content received'); + return null; + } + + // Process complete article in content script (including markdown conversion) + const completeResult = await executeScript(tabId, (domString, options, selection) => { + return processCompleteArticle(domString, options, selection); + }, [result.dom, options, selection]); + + if (!completeResult) { + console.error('MarkDownload: Failed to process complete article'); + return null; + } + + console.log('MarkDownload: Complete markdown processed successfully, title:', completeResult.title, 'markdown length:', completeResult.markdown.length); + return completeResult; + } catch (error) { + console.error('MarkDownload: Failed to get complete markdown from content:', error); + return null; + } +} + +// Note: DOM processing has been moved to content script to avoid Service Worker limitations + +// DOM-dependent functions have been moved to content script + +async function formatMdClipsFolder(article) { + let options = await getOptions(); + let mdClipsFolder = ''; + if (options.mdClipsFolder && options.downloadMode == 'downloadsApi') { + mdClipsFolder = textReplace(options.mdClipsFolder, article, options.disallowedChars); + mdClipsFolder = mdClipsFolder.split('/').map(s => generateValidFileName(s, options.disallowedChars)).join('/'); + if (!mdClipsFolder.endsWith('/')) mdClipsFolder += '/'; + } + return mdClipsFolder; +} + +// Download function +async function downloadMarkdown(markdown, title, tabId, imageList = {}, mdClipsFolder = '') { + + console.log('MarkDownload: Download params - title:', title, 'tabId:', tabId, 'imageList keys:', Object.keys(imageList).length, 'mdClipsFolder:', mdClipsFolder); + + const options = await getOptions(); + console.log('MarkDownload: Options - downloadMode:', options.downloadMode, 'downloadImages:', options.downloadImages, 'saveAs:', options.saveAs); + + // if we're downloading images, we're going to zip them up + if (options.downloadImages && Object.keys(imageList).length > 0) { + const zip = new JSZip(); + let safeTitle = title.replace(/[\\/|\\:*?"<>]/g, ' '); + const imageFolder = zip.folder("images"); + + // loop through the image list and replace the images in the markdown + for (const [src, filename] of Object.entries(imageList)) { + const localImagePath = "images/" + filename; + markdown = markdown.replaceAll(src, localImagePath); + imageFolder.file(filename, fetch(src).then(res => res.blob())); + } + + // add the markdown file to the zip + zip.file(safeTitle + '.md', markdown); + + // generate the zip and download it + const content = await zip.generateAsync({ type: 'base64' }); + const dataUrl = 'data:application/zip;base64,' + content; + + const id = await chrome.downloads.download({ + url: dataUrl, + filename: mdClipsFolder + safeTitle + ".zip", + saveAs: options.saveAs + }); + + return; + } + + if (options.downloadMode == 'downloadsApi' && chrome.downloads) { + console.log('MarkDownload: Using downloads API'); + // Use data URL directly; createObjectURL is not available in MV3 service worker +const dataUrl = 'data:text/markdown;charset=utf-8,' + encodeURIComponent(markdown); + console.log('MarkDownload: Data URL length:', dataUrl.length); + + try { + if (mdClipsFolder && !mdClipsFolder.endsWith('/')) mdClipsFolder += '/'; + const filename = mdClipsFolder + title + ".md"; + console.log('MarkDownload: Downloading file:', filename); + + const id = await chrome.downloads.download({ + url: dataUrl, + filename: filename, + saveAs: options.saveAs + }); + console.log('MarkDownload: Download started with ID:', id); + + // Download images (if enabled) + if (options.downloadImages && Object.keys(imageList).length > 0) { + console.log('MarkDownload: Downloading images:', Object.keys(imageList).length); + // Get the relative path of the markdown file (if any) for image path + let destPath = mdClipsFolder + title.substring(0, title.lastIndexOf('/')); + if(destPath && !destPath.endsWith('/')) destPath += '/'; + + Object.entries(imageList).forEach(async ([src, filename]) => { + try { + // Start the download of the image + const imgId = await chrome.downloads.download({ + url: src, + // Set a destination path (relative to md file) + filename: destPath ? destPath + filename : filename, + saveAs: false + }); + console.log('MarkDownload: Image download started:', filename); + } catch (imgErr) { + console.error('MarkDownload: Image download failed:', src, imgErr); + } + }); + } + } catch (err) { + console.error("MarkDownload: Download failed", err); + console.error("MarkDownload: Error details:", err.message, err.stack); + } + } else { + console.log('MarkDownload: Using content link fallback method'); + // Fallback to content link method + try { + await ensureContentScript(tabId); + const filename = mdClipsFolder + generateValidFileName(title, options.disallowedChars) + ".md"; + console.log('MarkDownload: Fallback filename:', filename); + + const base64Data = btoa(encodeURIComponent(markdown).replace(/%([0-9A-F]{2})/g, function (match, p1) { + return String.fromCharCode('0x' + p1); + })); + + await executeScript(tabId, (filename, data) => { + const link = document.createElement('a'); + link.download = filename; + link.href = `data:text/markdown;base64,${data}`; + link.click(); + }, [filename, base64Data]); + console.log('MarkDownload: Fallback download completed'); + } catch (error) { + console.error("MarkDownload: Content link download failed:", error); + console.error("MarkDownload: Fallback error details:", error.message, error.stack); + } + } +} + +// Context menu action handlers +async function downloadMarkdownFromContext(info, tab) { + try { + console.log('MarkDownload: Download from context menu'); + + // Get complete markdown result from content script + const result = await getCompleteMarkdownFromContent(tab.id, info.menuItemId === "download-markdown-selection"); + if (!result) { + console.error('MarkDownload: Failed to get complete markdown result'); + return; + } + + const mdClipsFolder = await formatMdClipsFolder(result.article); + + await downloadMarkdown(result.markdown, result.title, tab.id, result.imageList, mdClipsFolder); + } catch (error) { + console.error('MarkDownload: Download from context failed:', error); + } +} + +async function copyMarkdownFromContext(info, tab) { + try { + console.log('MarkDownload: Copy from context menu, menuItemId:', info.menuItemId); + await ensureContentScript(tab.id); + + if (info.menuItemId === "copy-markdown-link") { + console.log('MarkDownload: Processing link copy'); + const options = await getOptions(); + options.frontmatter = options.backmatter = ''; + const article = await getArticleFromContent(tab.id, false); + if (!article) { + console.error('MarkDownload: Failed to get article for link'); + return; + } + const { markdown } = turndown(`${info.linkText || info.selectionText}`, { ...options, downloadImages: false }, article); + console.log('MarkDownload: Link markdown generated, length:', markdown.length); + + await executeScript(tab.id, (text) => { + console.log('MarkDownload: Copying link to clipboard, length:', text.length); + navigator.clipboard.writeText(text).then(() => { + console.log('MarkDownload: Link copied to clipboard successfully'); + }).catch(err => { + console.error('MarkDownload: Failed to copy link to clipboard:', err); + }); + }, [markdown]); + } else if (info.menuItemId === "copy-markdown-image") { + console.log('MarkDownload: Processing image copy'); + await executeScript(tab.id, (url) => { + console.log('MarkDownload: Copying image to clipboard:', url); + navigator.clipboard.writeText(`![](${url})`).then(() => { + console.log('MarkDownload: Image copied to clipboard successfully'); + }).catch(err => { + console.error('MarkDownload: Failed to copy image to clipboard:', err); + }); + }, [info.srcUrl]); + } else { + console.log('MarkDownload: Processing general copy, selection:', info.menuItemId === "copy-markdown-selection"); + + // Get complete markdown result (including conversion) from content script + const result = await getCompleteMarkdownFromContent(tab.id, info.menuItemId === "copy-markdown-selection"); + if (!result) { + console.error('MarkDownload: Failed to get complete markdown result'); + return; + } + + console.log('MarkDownload: Complete result retrieved, title:', result.title, 'markdown length:', result.markdown?.length || 0); + + if (!result.markdown) { + console.error('MarkDownload: No markdown content received'); + return; + } + + // Copy to clipboard via content script + await executeScript(tab.id, (markdown) => { + console.log('MarkDownload ContentScript: Copying markdown to clipboard, length:', markdown?.length); + + if (!markdown) { + console.error('MarkDownload ContentScript: No markdown content to copy'); + return false; + } + + return copyToClipboard(markdown); + }, [result.markdown]); + + console.log('MarkDownload: Copy operation completed'); + } + } catch (error) { + console.error('MarkDownload: Copy from context failed:', error); + } +} + +async function copyTabAsMarkdownLink(tab) { + try { + console.log('MarkDownload: Copy tab as markdown link'); + const result = await getCompleteMarkdownFromContent(tab.id, false); + if (!result) { + console.error('MarkDownload: Failed to get article for link'); + return; + } + + await executeScript(tab.id, (title, url) => { + const linkMarkdown = `[${title}](${url})`; + console.log('MarkDownload ContentScript: Copying link to clipboard:', linkMarkdown); + return copyToClipboard(linkMarkdown); + }, [result.title, result.article.baseURI]); + } catch (error) { + console.error('MarkDownload: Copy tab link failed:', error); + } +} + +async function downloadMarkdownForAllTabs(info) { + try { + console.log('MarkDownload: Download all tabs as markdown'); + const tabs = await chrome.tabs.query({ currentWindow: true }); + + for (const tab of tabs) { + try { + await downloadMarkdownFromContext(info, tab); + } catch (e) { + console.warn('MarkDownload: Failed to download tab:', tab.id, e); + } + } + } catch (error) { + console.error('MarkDownload: Download all tabs failed:', error); + } +} + +// Settings toggle +async function toggleSetting(setting, options = null) { + if (options == null) { + options = await getOptions(); + } + + options[setting] = !options[setting]; + await chrome.storage.sync.set(options); + + if (setting === "includeTemplate") { + chrome.contextMenus.update("toggle-includeTemplate", { + checked: options.includeTemplate + }); + } + + if (setting === "downloadImages") { + chrome.contextMenus.update("toggle-downloadImages", { + checked: options.downloadImages + }); + } +} + +// Obsidian integration function (using clipboard method like original) +async function sendToObsidian(info, tab) { + try { + console.log('MarkDownload: Sending to Obsidian, menuItemId:', info.menuItemId); + + // Get complete markdown result from content script + const result = await getCompleteMarkdownFromContent(tab.id, info.menuItemId === "copy-markdown-obsidian"); + if (!result) { + console.error('MarkDownload: Failed to get complete markdown result for Obsidian'); + return; + } + + console.log('MarkDownload: Obsidian result retrieved, title:', result.title, 'markdown length:', result.markdown?.length || 0); + + if (!result.markdown) { + console.error('MarkDownload: No markdown content received for Obsidian'); + return; + } + + // Get Obsidian options + const options = await getOptions(); + if (!options.obsidianIntegration) { + console.error('MarkDownload: Obsidian integration not enabled'); + return; + } + + // Step 1: Copy markdown to clipboard (like original implementation) + console.log('MarkDownload: Copying markdown to clipboard for Obsidian'); + await executeScript(tab.id, (markdown) => { + console.log('MarkDownload ContentScript: Copying markdown to clipboard for Obsidian'); + return copyToClipboard(markdown); + }, [result.markdown]); + + // Step 2: Prepare Obsidian URI using clipboard method + const vault = options.obsidianVault || ''; + const folder = options.obsidianFolder || ''; + + // Format folder like original implementation + let obsidianFolder = ''; + if (folder) { + // Use text replacement and filename generation like original + obsidianFolder = result.article ? + textReplace(folder, result.article, options.disallowedChars) : folder; + obsidianFolder = obsidianFolder.split('/').map(s => generateValidFileName(s, options.disallowedChars)).join('/'); + if (!obsidianFolder.endsWith('/')) obsidianFolder += '/'; + } + + // Generate filename like original + const filename = generateValidFileName(result.title, options.disallowedChars); + const filepath = obsidianFolder + filename; + + // Create Obsidian URI using clipboard method (like original) + const obsidianUri = 'obsidian://advanced-uri?' + + 'vault=' + encodeURIComponent(vault) + + '&clipboard=true' + + '&mode=new' + + '&filepath=' + encodeURIComponent(filepath); + + console.log('MarkDownload: Opening Obsidian URI (clipboard method):', obsidianUri); + + // Try to open Obsidian URI directly + try { + // Method 1: Try to update current tab (most direct) + await chrome.tabs.update(tab.id, { url: obsidianUri }); + console.log('MarkDownload: Obsidian URI opened successfully via tab update'); + } catch (error) { + console.log('MarkDownload: Tab update failed, trying alternative method:', error); + + // Method 2: Fallback to creating new tab + try { + await chrome.tabs.create({ url: obsidianUri }); + console.log('MarkDownload: Obsidian URI opened successfully via new tab'); + } catch (error2) { + console.error('MarkDownload: All methods failed:', error2); + + // Method 3: Final fallback - show notification with manual instructions + await executeScript(tab.id, (uri) => { + alert('MarkDownload: Content copied to clipboard!\n\nTo open in Obsidian:\n1. Open Obsidian\n2. Create new note\n3. Paste content (Ctrl+V)\n\nOr click OK to try opening Obsidian URI again.'); + window.open(uri, '_blank'); + }, [obsidianUri]); + } + } + + console.log('MarkDownload: Obsidian operation completed'); + } catch (error) { + console.error('MarkDownload: Send to Obsidian failed:', error); + } +} + +console.log('MarkDownload Service Worker fully loaded and ready'); diff --git a/src/background/turndown.js b/src/background/turndown.js index f77de140..bf5a62f2 100644 --- a/src/background/turndown.js +++ b/src/background/turndown.js @@ -1,7 +1,7 @@ var TurndownService = (function () { 'use strict'; - function extend(destination) { + function extend (destination) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { @@ -11,15 +11,15 @@ var TurndownService = (function () { return destination } - function repeat(character, count) { + function repeat (character, count) { return Array(count + 1).join(character) } - function trimLeadingNewlines(string) { + function trimLeadingNewlines (string) { return string.replace(/^\n*/, '') } - function trimTrailingNewlines(string) { + function trimTrailingNewlines (string) { // avoid match-at-end regexp bottleneck, see #370 var indexEnd = string.length; while (indexEnd > 0 && string[indexEnd - 1] === '\n') indexEnd--; @@ -35,7 +35,7 @@ var TurndownService = (function () { 'TFOOT', 'TH', 'THEAD', 'TR', 'UL' ]; - function isBlock(node) { + function isBlock (node) { return is(node, blockElements) } @@ -44,11 +44,11 @@ var TurndownService = (function () { 'KEYGEN', 'LINK', 'META', 'PARAM', 'SOURCE', 'TRACK', 'WBR' ]; - function isVoid(node) { + function isVoid (node) { return is(node, voidElements) } - function hasVoid(node) { + function hasVoid (node) { return has(node, voidElements) } @@ -57,19 +57,19 @@ var TurndownService = (function () { 'AUDIO', 'VIDEO' ]; - function isMeaningfulWhenBlank(node) { + function isMeaningfulWhenBlank (node) { return is(node, meaningfulWhenBlankElements) } - function hasMeaningfulWhenBlank(node) { + function hasMeaningfulWhenBlank (node) { return has(node, meaningfulWhenBlankElements) } - function is(node, tagNames) { + function is (node, tagNames) { return tagNames.indexOf(node.nodeName) >= 0 } - function has(node, tagNames) { + function has (node, tagNames) { return ( node.getElementsByTagName && tagNames.some(function (tagName) { @@ -335,7 +335,7 @@ var TurndownService = (function () { } }; - function cleanAttribute(attribute) { + function cleanAttribute (attribute) { return attribute ? attribute.replace(/(\n+\s*)+/g, '\n') : '' } @@ -343,7 +343,7 @@ var TurndownService = (function () { * Manages a collection of rules used to convert HTML to Markdown */ - function Rules(options) { + function Rules (options) { this.options = options; this._keep = []; this._remove = []; @@ -399,7 +399,7 @@ var TurndownService = (function () { } }; - function findRule(rules, node, options) { + function findRule (rules, node, options) { for (var i = 0; i < rules.length; i++) { var rule = rules[i]; if (filterValue(rule, node, options)) return rule @@ -407,7 +407,7 @@ var TurndownService = (function () { return void 0 } - function filterValue(rule, node, options) { + function filterValue (rule, node, options) { var filter = rule.filter; if (typeof filter === 'string') { if (filter === node.nodeName.toLowerCase()) return true @@ -452,7 +452,7 @@ var TurndownService = (function () { * * @param {Object} options */ - function collapseWhitespace(options) { + function collapseWhitespace (options) { var element = options.element; var isBlock = options.isBlock; var isVoid = options.isVoid; @@ -473,7 +473,7 @@ var TurndownService = (function () { var text = node.data.replace(/[ \r\n\t]+/g, ' '); if ((!prevText || / $/.test(prevText.data)) && - !keepLeadingWs && text[0] === ' ') { + !keepLeadingWs && text[0] === ' ') { text = text.substr(1); } @@ -527,7 +527,7 @@ var TurndownService = (function () { * @param {Node} node * @return {Node} node */ - function remove(node) { + function remove (node) { var next = node.nextSibling || node.parentNode; node.parentNode.removeChild(node); @@ -544,7 +544,7 @@ var TurndownService = (function () { * @param {Function} isPre * @return {Node} */ - function next(prev, current, isPre) { + function next (prev, current, isPre) { if ((prev && prev.parentNode === current) || isPre(current)) { return current.nextSibling || current.parentNode } @@ -562,7 +562,7 @@ var TurndownService = (function () { * Parsing HTML strings */ - function canParseHTMLNatively() { + function canParseHTMLNatively () { var Parser = root.DOMParser; var canParse = false; @@ -573,13 +573,13 @@ var TurndownService = (function () { if (new Parser().parseFromString('', 'text/html')) { canParse = true; } - } catch (e) { } + } catch (e) {} return canParse } - function createHTMLParser() { - var Parser = function () { }; + function createHTMLParser () { + var Parser = function () {}; { if (shouldUseActiveX()) { @@ -604,19 +604,19 @@ var TurndownService = (function () { return Parser } - function shouldUseActiveX() { + function shouldUseActiveX () { var useActiveX = false; try { document.implementation.createHTMLDocument('').open(); } catch (e) { - if (window.ActiveXObject) useActiveX = true; + if (root.ActiveXObject) useActiveX = true; } return useActiveX } var HTMLParser = canParseHTMLNatively() ? root.DOMParser : createHTMLParser(); - function RootNode(input, options) { + function RootNode (input, options) { var root; if (typeof input === 'string') { var doc = htmlParser().parseFromString( @@ -641,16 +641,16 @@ var TurndownService = (function () { } var _htmlParser; - function htmlParser() { + function htmlParser () { _htmlParser = _htmlParser || new HTMLParser(); return _htmlParser } - function isPreOrCode(node) { + function isPreOrCode (node) { return node.nodeName === 'PRE' || node.nodeName === 'CODE' } - function Node(node, options) { + function Node (node, options) { node.isBlock = isBlock(node); node.isCode = node.nodeName === 'CODE' || node.parentNode.isCode; node.isBlank = isBlank(node); @@ -658,7 +658,7 @@ var TurndownService = (function () { return node } - function isBlank(node) { + function isBlank (node) { return ( !isVoid(node) && !isMeaningfulWhenBlank(node) && @@ -668,7 +668,7 @@ var TurndownService = (function () { ) } - function flankingWhitespace(node, options) { + function flankingWhitespace (node, options) { if (node.isBlock || (options.preformattedCode && node.isCode)) { return { leading: '', trailing: '' } } @@ -688,8 +688,8 @@ var TurndownService = (function () { return { leading: edges.leading, trailing: edges.trailing } } - function edgeWhitespace(string) { - var m = string.match(/^(([ \t\r\n]*)(\s*))[\s\S]*?((\s*?)([ \t\r\n]*))$/); + function edgeWhitespace (string) { + var m = string.match(/^(([ \t\r\n]*)(\s*))(?:(?=\S)[\s\S]*\S)?((\s*?)([ \t\r\n]*))$/); return { leading: m[1], // whole string for whitespace-only strings leadingAscii: m[2], @@ -700,7 +700,7 @@ var TurndownService = (function () { } } - function isFlankedByWhitespace(side, node, options) { + function isFlankedByWhitespace (side, node, options) { var sibling; var regExp; var isFlanked; @@ -742,7 +742,7 @@ var TurndownService = (function () { [/^(\d+)\. /g, '$1\\. '] ]; - function TurndownService(options) { + function TurndownService (options) { if (!(this instanceof TurndownService)) return new TurndownService(options) var defaults = { @@ -876,7 +876,7 @@ var TurndownService = (function () { * @type String */ - function process(parentNode) { + function process (parentNode) { var self = this; return reduce.call(parentNode.childNodes, function (output, node) { node = new Node(node, self.options); @@ -900,7 +900,7 @@ var TurndownService = (function () { * @type String */ - function postProcess(output) { + function postProcess (output) { var self = this; this.rules.forEach(function (rule) { if (typeof rule.append === 'function') { @@ -919,7 +919,7 @@ var TurndownService = (function () { * @type String */ - function replacementForNode(node) { + function replacementForNode (node) { var rule = this.rules.forNode(node); var content = process.call(this, node); var whitespace = node.flankingWhitespace; @@ -940,7 +940,7 @@ var TurndownService = (function () { * @type String */ - function join(output, replacement) { + function join (output, replacement) { var s1 = trimTrailingNewlines(output); var s2 = trimLeadingNewlines(replacement); var nls = Math.max(output.length - s1.length, replacement.length - s2.length); @@ -957,7 +957,7 @@ var TurndownService = (function () { * @type String|Object|Array|Boolean|Number */ - function canConvert(input) { + function canConvert (input) { return ( input != null && ( typeof input === 'string' || @@ -970,4 +970,4 @@ var TurndownService = (function () { return TurndownService; -}()); \ No newline at end of file +}()); diff --git a/src/contentScript/contentScript.js b/src/contentScript/contentScript.js index 1ef736ef..146f9dc1 100644 --- a/src/contentScript/contentScript.js +++ b/src/contentScript/contentScript.js @@ -1,34 +1,501 @@ function notifyExtension() { // send a message that the content should be clipped - browser.runtime.sendMessage({ type: "clip", dom: content}); + console.log('MarkDownload ContentScript: Notifying extension'); + const content = getHTMLOfDocument(); + console.log('MarkDownload ContentScript: DOM content length:', content.length); + + if (typeof browser === 'undefined' && typeof chrome !== 'undefined') { + window.browser = chrome; + } + + browser.runtime.sendMessage({ + type: "clip", + dom: content + }).then(response => { + console.log('MarkDownload ContentScript: Response received:', response); + }).catch(error => { + console.error('MarkDownload ContentScript: Error sending message:', error); + }); +} + +// 初始化 TurndownService +if (typeof TurndownService !== 'undefined') { + TurndownService.prototype.defaultEscape = TurndownService.prototype.escape; + console.log('MarkDownload ContentScript: TurndownService initialized'); +} + +// Helper functions moved from service worker +function cleanAttribute(attribute) { + return attribute ? attribute.replace(/(\n+\s*)+/g, '\n') : ''; +} + +function validateUri(href, baseURI) { + try { + new URL(href); + } catch { + const baseUri = new URL(baseURI); + if (href.startsWith('/')) { + href = baseUri.origin + href; + } else { + href = baseUri.href + (baseUri.href.endsWith('/') ? '' : '') + href; + } + } + return href; +} + +function generateValidFileName(title, disallowedChars = null) { + if (!title) return title; + title = title + ''; + + var illegalRe = /[\/\?<>\\:\*\|":]/g; + var name = title.replace(illegalRe, "").replace(new RegExp('\u00A0', 'g'), ' ') + .replace(new RegExp(/\s+/, 'g'), ' ') + .trim(); + + if (disallowedChars) { + for (let c of disallowedChars) { + if (`[\\^$.|?*+()`.includes(c)) c = `\\${c}`; + name = name.replace(new RegExp(c, 'g'), ''); + } + } + + return name; +} + +function getImageFilename(src, options, article, imageIndex, prependFilePath = true) { + // If imageFilenameTemplate is set, use template-based naming + if (options.imageFilenameTemplate && options.imageFilenameTemplate.trim()) { + // Extract original filename and extension + const slashPos = src.lastIndexOf('/'); + const queryPos = src.indexOf('?'); + let originalFilename = src.substring(slashPos + 1, queryPos > 0 ? queryPos : src.length); + + if (originalFilename.includes(';base64,')) { + originalFilename = 'image.' + originalFilename.substring(0, originalFilename.indexOf(';')); + } + + let extension = originalFilename.substring(originalFilename.lastIndexOf('.')); + if (extension === originalFilename || extension === '') { + extension = '.png'; // Default extension + } + + // Prepare template variables + const templateVars = { + ...article, + imageIndex: String(imageIndex).padStart(3, '0'), // 001, 002, 003, etc. + originalFilename: originalFilename.substring(0, originalFilename.lastIndexOf('.') || originalFilename.length), + ext: extension.substring(1) // Remove the dot + }; + + // Apply text replacement to the template + let filename = textReplace(options.imageFilenameTemplate, templateVars, options.disallowedChars); + filename = generateValidFileName(filename, options.disallowedChars); + + // Add prefix if needed (for backward compatibility) + if (prependFilePath) { + let imagePrefix = (options.imagePrefix || ''); + if (options.title.includes('/')) { + imagePrefix = options.title.substring(0, options.title.lastIndexOf('/') + 1) + imagePrefix; + } else { + imagePrefix = options.title + (imagePrefix.startsWith('/') ? '' : '/') + imagePrefix; + } + filename = imagePrefix + filename; + } + + return filename; + } + + // Fallback to original logic if no template is set + const slashPos = src.lastIndexOf('/'); + const queryPos = src.indexOf('?'); + let filename = src.substring(slashPos + 1, queryPos > 0 ? queryPos : src.length); + + let imagePrefix = (options.imagePrefix || ''); + + if (prependFilePath && options.title.includes('/')) { + imagePrefix = options.title.substring(0, options.title.lastIndexOf('/') + 1) + imagePrefix; + } else if (prependFilePath) { + imagePrefix = options.title + (imagePrefix.startsWith('/') ? '' : '/') + imagePrefix; + } + + if (filename.includes(';base64,')) { + filename = 'image.' + filename.substring(0, filename.indexOf(';')); + } + + let extension = filename.substring(filename.lastIndexOf('.')); + if (extension == filename) { + filename = filename + '.idunno'; + } + + filename = generateValidFileName(filename, options.disallowedChars); + return imagePrefix + filename; +} + +function textReplace(string, article, disallowedChars = null) { + for (const key in article) { + if (article.hasOwnProperty(key) && key != "content") { + let s = (article[key] || '') + ''; + if (s && disallowedChars) s = generateValidFileName(s, disallowedChars); + + string = string.replace(new RegExp('{' + key + '}', 'g'), s) + .replace(new RegExp('{' + key + ':lower}', 'g'), s.toLowerCase()) + .replace(new RegExp('{' + key + ':upper}', 'g'), s.toUpperCase()) + .replace(new RegExp('{' + key + ':kebab}', 'g'), s.replace(/ /g, '-').toLowerCase()) + .replace(new RegExp('{' + key + ':mixed-kebab}', 'g'), s.replace(/ /g, '-')) + .replace(new RegExp('{' + key + ':snake}', 'g'), s.replace(/ /g, '_').toLowerCase()) + .replace(new RegExp('{' + key + ':mixed_snake}', 'g'), s.replace(/ /g, '_')) + .replace(new RegExp('{' + key + ':obsidian-cal}', 'g'), s.replace(/ /g, '-').replace(/-{2,}/g, "-")) + .replace(new RegExp('{' + key + ':camel}', 'g'), s.replace(/ ./g, (str) => str.trim().toUpperCase()).replace(/^./, (str) => str.toLowerCase())) + .replace(new RegExp('{' + key + ':pascal}', 'g'), s.replace(/ ./g, (str) => str.trim().toUpperCase()).replace(/^./, (str) => str.toUpperCase())); + } + } + + // Replace date formats + const now = new Date(); + const dateRegex = /{date:(.+?)}/g; + const matches = string.match(dateRegex); + if (matches && matches.forEach) { + matches.forEach(match => { + const format = match.substring(6, match.length - 1); + if (typeof moment !== 'undefined') { + const dateString = moment(now).format(format); + string = string.replaceAll(match, dateString); + } else { + string = string.replaceAll(match, now.toISOString()); + } + }); + } + + // Replace keywords + const keywordRegex = /{keywords:?(.*)?}/g; + const keywordMatches = string.match(keywordRegex); + if (keywordMatches && keywordMatches.forEach) { + keywordMatches.forEach(match => { + let seperator = match.substring(10, match.length - 1); + try { + seperator = JSON.parse(JSON.stringify(seperator).replace(/\\\\/g, '\\')); + } catch { } + const keywordsString = (article.keywords || []).join(seperator); + string = string.replace(new RegExp(match.replace(/\\/g, '\\\\'), 'g'), keywordsString); + }); + } + + string = string.replace(/{(.*?)}/g, ''); + return string; +} + +// Main turndown function +function turndownContent(content, options, article) { + console.log('MarkDownload ContentScript: Converting content to markdown'); + + if (options.turndownEscape) TurndownService.prototype.escape = TurndownService.prototype.defaultEscape; + else TurndownService.prototype.escape = s => s; + + var turndownService = new TurndownService(options); + turndownService.use(turndownPluginGfm.gfm); + turndownService.keep(['iframe', 'sub', 'sup', 'u', 'ins', 'del', 'small', 'big']); + + let imageList = {}; + let imageIndex = 1; // Counter for image ordering + + // Add image rule + turndownService.addRule('images', { + filter: function (node, tdopts) { + if (node.nodeName == 'IMG' && node.getAttribute('src')) { + let src = node.getAttribute('src'); + console.log('MarkDownload ContentScript: Found image:', src); + node.setAttribute('src', validateUri(src, article.baseURI)); + + if (options.downloadImages) { + console.log('MarkDownload ContentScript: Download images enabled, processing image:', src); + let imageFilename = getImageFilename(src, options, article, imageIndex, false); + if (!imageList[src] || imageList[src] != imageFilename) { + let i = 1; + let originalFilename = imageFilename; + while (Object.values(imageList).includes(imageFilename)) { + const parts = originalFilename.split('.'); + if (parts.length > 1) { + parts.splice(parts.length - 1, 0, `(${i})`); + imageFilename = parts.join('.'); + } else { + imageFilename = originalFilename + `(${i})`; + } + i++; + } + imageList[src] = imageFilename; + imageIndex++; // Increment the global image counter + console.log('MarkDownload ContentScript: Added image to list:', src, '->', imageFilename); + } + + const obsidianLink = options.imageStyle.startsWith("obsidian"); + const localSrc = options.imageStyle === 'obsidian-nofolder' + ? imageFilename.substring(imageFilename.lastIndexOf('/') + 1) + : imageFilename.split('/').map(s => obsidianLink ? s : encodeURI(s)).join('/'); + + if(options.imageStyle != 'originalSource' && options.imageStyle != 'base64') { + node.setAttribute('src', localSrc); + } + return true; + } else return true; + } + return false; + }, + replacement: function (content, node, tdopts) { + if (options.imageStyle == 'noImage') return ''; + else if (options.imageStyle.startsWith('obsidian')) return `![[${node.getAttribute('src')}]]`; + else { + var alt = cleanAttribute(node.getAttribute('alt')); + var src = node.getAttribute('src') || ''; + var title = cleanAttribute(node.getAttribute('title')); + var titlePart = title ? ' "' + title + '"' : ''; + if (options.imageRefStyle == 'referenced') { + var id = this.references.length + 1; + this.references.push('[fig' + id + ']: ' + src + titlePart); + return '![' + alt + '][fig' + id + ']'; + } + else return src ? '![' + alt + ']' + '(' + src + titlePart + ')' : ''; + } + }, + references: [], + append: function (options) { + var references = ''; + if (this.references.length) { + references = '\n\n' + this.references.join('\n') + '\n\n'; + this.references = []; + } + return references; + } + }); + + // Add link rule + turndownService.addRule('links', { + filter: (node, tdopts) => { + if (node.nodeName == 'A' && node.getAttribute('href')) { + const href = node.getAttribute('href'); + node.setAttribute('href', validateUri(href, article.baseURI)); + return options.linkStyle == 'stripLinks'; + } + return false; + }, + replacement: (content, node, tdopts) => content + }); + + // Add math rule + turndownService.addRule('mathjax', { + filter(node, options) { + return article.math && article.math.hasOwnProperty(node.id); + }, + replacement(content, node, options) { + const math = article.math[node.id]; + let tex = math.tex.trim().replaceAll('\xa0', ''); + + if (math.inline) { + tex = tex.replaceAll('\n', ' '); + return `$${tex}$`; + } else { + return `$$\n${tex}\n$$`; + } + } + }); + + let markdown = options.frontmatter + turndownService.turndown(content) + options.backmatter; + + // Strip out non-printing special characters + markdown = markdown.replace(/[\u0000-\u0008\u000b\u000c\u000e-\u001f\u007f-\u009f\u00ad\u061c\u200b-\u200f\u2028\u2029\ufeff\ufff9-\ufffc]/g, ''); + + return { markdown: markdown, imageList: imageList }; +} + +// Complete article processing function +function processCompleteArticle(domString, options, selection = false) { + console.log('MarkDownload ContentScript: Processing complete article'); + + try { + // Step 1: Process DOM to article + const article = processArticleFromDOM(domString); + + if (!article) { + throw new Error('Failed to process article from DOM'); + } + + // Step 2: Apply selection if provided + const selectionData = getHTMLOfSelection(); + if (selection && selectionData) { + article.content = selectionData; + } + + // Step 3: Prepare options + if (options.includeTemplate) { + options.frontmatter = textReplace(options.frontmatter, article) + '\n'; + options.backmatter = '\n' + textReplace(options.backmatter, article); + } else { + options.frontmatter = options.backmatter = ''; + } + + options.imagePrefix = textReplace(options.imagePrefix, article, options.disallowedChars) + .split('/').map(s => generateValidFileName(s, options.disallowedChars)).join('/'); + + // Step 4: Convert to markdown + const result = turndownContent(article.content, options, article); + + // Step 5: Format title + let title = textReplace(options.title, article, options.disallowedChars + '/'); + title = title.split('/').map(s => generateValidFileName(s, options.disallowedChars)).join('/'); + + console.log('MarkDownload ContentScript: Article processing complete, title:', title, 'markdown length:', result.markdown.length, 'images found:', Object.keys(result.imageList).length); + + return { + markdown: result.markdown, + imageList: result.imageList, + title: title, + article: article + }; + } catch (error) { + console.error('MarkDownload ContentScript: Error processing complete article:', error); + throw error; + } +} + +// 新增:处理来自Service Worker的DOM处理请求 +function processArticleFromDOM(domString) { + console.log('MarkDownload ContentScript: Processing DOM to article'); + + try { + const parser = new DOMParser(); + const dom = parser.parseFromString(domString, "text/html"); + + if (dom.documentElement.nodeName == "parsererror") { + console.error("MarkDownload ContentScript: DOM parsing error"); + throw new Error("DOM parsing failed"); + } + + const math = {}; + + // 简化的数学公式处理 + if (dom.body) { + dom.body.querySelectorAll('h1, h2, h3, h4, h5, h6')?.forEach(header => { + header.className = ''; + }); + dom.documentElement.removeAttribute('class'); + } + + // 使用 Readability 提取文章 + const article = new Readability(dom).parse(); + + if (!article) { + throw new Error("Failed to parse article from DOM"); + } + + // 添加元数据 + article.baseURI = dom.baseURI || window.location.href; + article.pageTitle = dom.title || document.title || 'Untitled'; + + try { + const url = new URL(article.baseURI); + article.hash = url.hash; + article.host = url.host; + article.origin = url.origin; + article.hostname = url.hostname; + article.pathname = url.pathname; + article.port = url.port; + article.protocol = url.protocol; + article.search = url.search; + } catch (e) { + console.warn('MarkDownload ContentScript: Failed to parse URL info:', e); + } + + if (dom.head) { + article.keywords = dom.head.querySelector('meta[name="keywords"]')?.content?.split(',')?.map(s => s.trim()); + + dom.head.querySelectorAll('meta[name][content], meta[property][content]')?.forEach(meta => { + const key = (meta.getAttribute('name') || meta.getAttribute('property')); + const val = meta.getAttribute('content'); + if (key && val && !article[key]) { + article[key] = val; + } + }); + } + + article.math = math; + console.log('MarkDownload ContentScript: Article processed successfully, title:', article.title); + return article; + } catch (error) { + console.error('MarkDownload ContentScript: Error processing DOM:', error); + throw error; + } } function getHTMLOfDocument() { + console.log('MarkDownload ContentScript: Starting document processing'); + console.log('MarkDownload ContentScript: Page URL:', window.location.href); + console.log('MarkDownload ContentScript: Page title:', document.title); + + try { + // make sure a title tag exists so that pageTitle is not empty and + // a filename can be generated. + if (!document.head) { + console.warn('MarkDownload ContentScript: No document head found, creating one'); + const head = document.createElement('head'); + document.documentElement.insertBefore(head, document.body); + } + + if (document.head.getElementsByTagName('title').length == 0) { + console.log('MarkDownload ContentScript: Adding missing title tag'); + let titleEl = document.createElement('title'); + // prepare a good default text (the text displayed in the window title) + titleEl.innerText = document.title || 'Untitled'; + document.head.append(titleEl); + } + // if the document doesn't have a "base" element make one // this allows the DOM parser in future steps to fix relative uris - let baseEl = document.createElement('base'); - // check for a existing base elements let baseEls = document.head.getElementsByTagName('base'); + let baseEl; + if (baseEls.length > 0) { baseEl = baseEls[0]; - } - // if we don't find one, append this new one. - else { + } else { + console.log('MarkDownload ContentScript: Adding base element'); + baseEl = document.createElement('base'); document.head.append(baseEl); } - // if the base element doesn't have a href, use the current location - if (!baseEl.getAttribute('href')) { + // make sure the 'base' element always has a good 'href` + // attribute so that the DOMParser generates usable + // baseURI and documentURI properties when used in the + // background context. + + let href = baseEl.getAttribute('href'); + + if (!href || !href.startsWith(window.location.origin)) { + console.log('MarkDownload ContentScript: Setting base href to:', window.location.href); baseEl.setAttribute('href', window.location.href); } - - // remove the hidden content from the page + // remove the hidden content from the page + if (document.body) { + console.log('MarkDownload ContentScript: Removing hidden nodes'); removeHiddenNodes(document.body); - + } else { + console.warn('MarkDownload ContentScript: No document body found'); + } + // get the content of the page as a string - return document.documentElement.outerHTML; + const htmlContent = document.documentElement.outerHTML; + console.log('MarkDownload ContentScript: Generated HTML length:', htmlContent.length); + + // Basic validation + if (!htmlContent || htmlContent.length < 100) { + console.warn('MarkDownload ContentScript: Generated HTML seems too small'); + } + + return htmlContent; + } catch (error) { + console.error('MarkDownload ContentScript: Error processing document:', error); + // Return basic HTML as fallback + return `${document.title || 'Error'}

Error processing page content.

`; + } } // code taken from here: https://www.reddit.com/r/javascript/comments/27bcao/anyone_have_a_method_for_finding_all_the_hidden/ @@ -56,7 +523,6 @@ function removeHiddenNodes(root) { } return root } - // code taken from here: https://stackoverflow.com/a/5084044/304786 function getHTMLOfSelection() { @@ -85,24 +551,93 @@ function getHTMLOfSelection() { } function getSelectionAndDom() { + console.log('MarkDownload ContentScript: Getting selection and DOM'); + + try { + const selection = getHTMLOfSelection(); + const dom = getHTMLOfDocument(); + + console.log('MarkDownload ContentScript: Selection length:', selection.length); + console.log('MarkDownload ContentScript: DOM length:', dom.length); + + return { + selection: selection, + dom: dom + }; + } catch (error) { + console.error('MarkDownload ContentScript: Error getting selection and DOM:', error); return { - selection: getHTMLOfSelection(), + selection: '', dom: getHTMLOfDocument() + }; } } // This function must be called in a visible page, such as a browserAction popup // or a content script. Calling it in a background page has no effect! function copyToClipboard(text) { - navigator.clipboard.writeText(text); + console.log('MarkDownload ContentScript: Copying to clipboard, length:', text.length); + + if (navigator.clipboard && navigator.clipboard.writeText) { + navigator.clipboard.writeText(text).then(() => { + console.log('MarkDownload ContentScript: Successfully copied to clipboard'); + }).catch(error => { + console.error('MarkDownload ContentScript: Failed to copy to clipboard:', error); + + // Fallback method + try { + const textArea = document.createElement('textarea'); + textArea.value = text; + textArea.style.position = 'fixed'; + textArea.style.left = '-999999px'; + textArea.style.top = '-999999px'; + document.body.appendChild(textArea); + textArea.select(); + textArea.setSelectionRange(0, 99999); + document.execCommand('copy'); + document.body.removeChild(textArea); + console.log('MarkDownload ContentScript: Fallback copy successful'); + } catch (fallbackError) { + console.error('MarkDownload ContentScript: Fallback copy failed:', fallbackError); + } + }); + } else { + console.warn('MarkDownload ContentScript: Clipboard API not available, using fallback'); + // Fallback method for older browsers + try { + const textArea = document.createElement('textarea'); + textArea.value = text; + textArea.style.position = 'fixed'; + textArea.style.left = '-999999px'; + textArea.style.top = '-999999px'; + document.body.appendChild(textArea); + textArea.select(); + textArea.setSelectionRange(0, 99999); + document.execCommand('copy'); + document.body.removeChild(textArea); + console.log('MarkDownload ContentScript: Fallback copy successful'); + } catch (error) { + console.error('MarkDownload ContentScript: All copy methods failed:', error); + } + } } function downloadMarkdown(filename, text) { + console.log('MarkDownload ContentScript: Starting download:', filename, 'Data length:', text.length); + + try { let datauri = `data:text/markdown;base64,${text}`; var link = document.createElement('a'); link.download = filename; link.href = datauri; + link.style.display = 'none'; + document.body.appendChild(link); link.click(); + document.body.removeChild(link); + console.log('MarkDownload ContentScript: Download triggered successfully'); + } catch (error) { + console.error('MarkDownload ContentScript: Download failed:', error); + } } function downloadImage(filename, url) { @@ -151,8 +686,21 @@ function downloadImage(filename, url) { */ } +// Initialize content script with debugging +console.log('MarkDownload ContentScript: Initializing on', window.location.href); + +// Ensure browser polyfill compatibility +if (typeof browser === 'undefined' && typeof chrome !== 'undefined') { + window.browser = chrome; +} + (function loadPageContextScript(){ + try { var s = document.createElement('script'); s.src = browser.runtime.getURL('contentScript/pageContext.js'); (document.head||document.documentElement).appendChild(s); + console.log('MarkDownload ContentScript: Page context script loaded'); + } catch (error) { + console.error('MarkDownload ContentScript: Failed to load page context script:', error); + } })() diff --git a/src/contentScript/pageContext.js b/src/contentScript/pageContext.js index 90525dbf..d7c008fe 100644 --- a/src/contentScript/pageContext.js +++ b/src/contentScript/pageContext.js @@ -1,11 +1,25 @@ function addLatexToMathJax3() { - if (!MathJax?.startup?.document?.math) - return + // Check if MathJax exists and has the required properties + if (typeof MathJax === 'undefined' || !MathJax?.startup?.document?.math) { + console.log('MarkDownload PageContext: MathJax not available, skipping LaTeX processing'); + return; + } - for (math of MathJax.startup.document.math) - { - math.typesetRoot.setAttribute("markdownload-latex", math.math) + try { + console.log('MarkDownload PageContext: Processing MathJax LaTeX'); + for (const math of MathJax.startup.document.math) { + if (math.typesetRoot && math.math) { + math.typesetRoot.setAttribute("markdownload-latex", math.math); + } + } + console.log('MarkDownload PageContext: MathJax LaTeX processing completed'); + } catch (error) { + console.warn('MarkDownload PageContext: Error processing MathJax LaTeX:', error); } } -addLatexToMathJax3() + +// Only run if we're in a proper browser context +if (typeof window !== 'undefined') { + addLatexToMathJax3(); +} diff --git a/src/manifest.json b/src/manifest.json index 037dc7d5..b61d2fa7 100644 --- a/src/manifest.json +++ b/src/manifest.json @@ -1,8 +1,8 @@ { - "manifest_version": 2, + "manifest_version": 3, "name": "MarkDownload - Markdown Web Clipper", - "version": "3.3.0", - "author": "Gordon Pedsersen", + "version": "3.4.0", + "author": "Gordon Pedsensen", "description": "This extension works like a web clipper, but it downloads articles in markdown format.", "icons": { "16": "icons/favicon-16x16.png", @@ -13,14 +13,17 @@ "512": "icons/favicon-512x512.png" }, "permissions": [ - "", "activeTab", "downloads", "storage", "contextMenus", - "clipboardWrite" + "clipboardWrite", + "scripting" ], - "browser_action": { + "host_permissions": [ + "" + ], + "action": { "default_title": "MarkDownload", "default_popup": "popup/popup.html", "default_icon": { @@ -31,26 +34,36 @@ } }, "background": { - "scripts": [ - "browser-polyfill.min.js", - "background/apache-mime-types.js", - "background/moment.min.js", - "background/turndown.js", - "background/turndown-plugin-gfm.js", - "/background/Readability.js", - "shared/context-menus.js", - "shared/default-options.js", - "background/background.js" - ] + "service_worker": "background/service-worker.js" }, + "content_scripts": [ + { + "matches": [""], + "js": [ + "browser-polyfill.min.js", + "background/apache-mime-types.js", + "background/moment.min.js", + "background/turndown.js", + "background/turndown-plugin-gfm.js", + "background/Readability.js", + "shared/default-options.js", + "contentScript/contentScript.js" + ], + "run_at": "document_end" + } + ], + "web_accessible_resources": [ + { + "resources": ["contentScript/pageContext.js"], + "matches": [""] + } + ], "options_ui": { "page": "options/options.html", - "browser_style": false, - "chrome_style": false, "open_in_tab": false }, "commands": { - "_execute_browser_action": { + "_execute_action": { "suggested_key": { "default": "Alt+Shift+M" } diff --git a/src/options/options.css b/src/options/options.css index 4427b09c..2629fa2e 100644 --- a/src/options/options.css +++ b/src/options/options.css @@ -194,6 +194,42 @@ label p{ transition:all 0.3s ease-out; } +/* Styling for standalone template help */ +.template-help { + margin-bottom: 20px; + border: 1px solid var(--border); + border-radius: 5px; + background: var(--bg); + box-shadow: 0 2px 4px rgba(0,0,0,0.05); +} + +.template-help summary { + cursor: pointer; + font-size: 14px; + color: var(--primary); + padding: 12px 20px; + border-bottom: 1px solid transparent; + transition: all 0.3s ease; +} + +.template-help summary:hover { + background: var(--bg-primary); + color: var(--primary); +} + +.template-help[open] summary { + border-bottom-color: var(--border); + background: var(--bg-primary); +} + +.template-help .instructions { + border: none; + border-radius: 0; + box-shadow: none; + margin: 0; + background: transparent; +} + .textbox-container > label, .button-container > label { margin: 8px 20px; diff --git a/src/options/options.html b/src/options/options.html index 71d5eccf..5ff1802d 100644 --- a/src/options/options.html +++ b/src/options/options.html @@ -44,10 +44,15 @@

Custom text ℹ️

Additionally, you can 'parameterize' any of the text variables (other than date and keywords) by using the following syntax:

    +
  • {variable:lower} - lower case: Every word lower case
  • +
  • {variable:upper} - UPPER CASE: Every word upper case
  • {variable:pascal} - PascalCase: Every word capital
  • {variable:camel} - camelCase: every word capital except the first word
  • {variable:kebab} - kebab-case: hyphens between words, all lowercase
  • +
  • {variable:mixed-kebab} - kebab-case: hyphens between words, no case changes
  • {variable:snake} - snake_case: underscores between words, all lowercase
  • +
  • {variable:mixed_snake} - snake_case: underscores between words, no case changes
  • +
  • {variable:obsidian-cal} - Compatibility for Obsidan Custom Attachment Location: hyphens between words, no case changes, double hypens removed

@@ -158,7 +163,7 @@

Obsidian Path Type

- +

@@ -172,6 +177,44 @@

Obsidian Path Type

+ +
+ + +
+ +
+ 📝 Template Variables & Examples + + Configure how image files are named when downloaded. Available variables: +
    +
  • {pageTitle} - Article title (same as used for markdown filename)
  • +
  • {imageIndex} - Image sequence number (001, 002, 003...)
  • +
  • {originalFilename} - Original image filename (without extension)
  • +
  • {ext} - File extension (png, jpg, gif, etc.)
  • +
  • {byline} - Author information
  • +
  • Plus all other article variables: {title}, {excerpt}, {date:FORMAT}, etc.
  • +
+ +

Formatting options (same as title template):

+
    +
  • :kebab - kebab-case (article-title)
  • +
  • :snake - snake_case (article_title)
  • +
  • :camel - camelCase (articleTitle)
  • +
  • :pascal - PascalCase (ArticleTitle)
  • +
  • :lower - lowercase
  • +
  • :upper - UPPERCASE
  • +
+ +

Examples:

+
    +
  • {pageTitle:kebab}_{imageIndex}.{ext} → article-title_001.jpg
  • +
  • {pageTitle:snake}_{imageIndex}.{ext} → article_title_002.png
  • +
  • {byline:kebab}_{pageTitle:camel}_{imageIndex}.{ext} → john-doe_articleTitle_003.gif
  • +
  • img_{imageIndex}_{originalFilename}.{ext} → img_004_screenshot.jpg
  • +
+
+
@@ -372,7 +415,6 @@

Import / Export

- diff --git a/src/options/options.js b/src/options/options.js index 24485e1f..9c5c75b0 100644 --- a/src/options/options.js +++ b/src/options/options.js @@ -14,6 +14,7 @@ const saveOptions = e => { saveAs: document.querySelector("[name='saveAs']").checked, downloadImages: document.querySelector("[name='downloadImages']").checked, imagePrefix: document.querySelector("[name='imagePrefix']").value, + imageFilenameTemplate: document.querySelector("[name='imageFilenameTemplate']").value, mdClipsFolder: document.querySelector("[name='mdClipsFolder']").value, turndownEscape: document.querySelector("[name='turndownEscape']").checked, contextMenus: document.querySelector("[name='contextMenus']").checked, @@ -42,25 +43,15 @@ const saveOptions = e => { const save = () => { const spinner = document.getElementById("spinner"); spinner.style.display = "block"; - browser.storage.sync.set(options) + chrome.storage.sync.set(options) .then(() => { - browser.contextMenus.update("toggle-includeTemplate", { + chrome.contextMenus.update("toggle-includeTemplate", { checked: options.includeTemplate }); - try { - browser.contextMenus.update("tabtoggle-includeTemplate", { - checked: options.includeTemplate - }); - } catch { } - browser.contextMenus.update("toggle-downloadImages", { + chrome.contextMenus.update("toggle-downloadImages", { checked: options.downloadImages }); - try { - browser.contextMenus.update("tabtoggle-downloadImages", { - checked: options.downloadImages - }); - } catch { } }) .then(() => { document.querySelectorAll(".status").forEach(statusEl => { @@ -96,10 +87,10 @@ const setCurrentChoice = result => { // if browser doesn't support the download api (i.e. Safari) // we have to use contentLink download mode - if (!browser.downloads) { + if (!chrome.downloads) { options.downloadMode = 'contentLink'; document.querySelectorAll("[name='downloadMode']").forEach(el => el.disabled = true) - document.querySelector('#downloadMode p').innerText = "The Downloas API is unavailable in this browser." + document.querySelector('#downloadMode p').innerText = "The Downloads API is unavailable in this browser." } const downloadImages = options.downloadImages && options.downloadMode == 'downloadsApi'; @@ -118,6 +109,7 @@ const setCurrentChoice = result => { document.querySelector("[name='saveAs']").checked = options.saveAs; document.querySelector("[name='downloadImages']").checked = options.downloadImages; document.querySelector("[name='imagePrefix']").value = options.imagePrefix; + document.querySelector("[name='imageFilenameTemplate']").value = options.imageFilenameTemplate || '{pageTitle:kebab}_{imageIndex}.{ext}'; document.querySelector("[name='mdClipsFolder']").value = result.mdClipsFolder; document.querySelector("[name='turndownEscape']").checked = options.turndownEscape; document.querySelector("[name='contextMenus']").checked = options.contextMenus; @@ -149,7 +141,7 @@ const restoreOptions = () => { console.error(error); } - browser.storage.sync.get(defaultOptions).then(setCurrentChoice, onError); + chrome.storage.sync.get(defaultOptions).then(setCurrentChoice, onError); } function textareaInput(){ @@ -180,6 +172,8 @@ const refereshElements = () => { const downloadImages = options.downloadImages && options.downloadMode == 'downloadsApi'; show(document.getElementById("imagePrefix"), downloadImages); + show(document.getElementById("imageFilenameTemplate"), downloadImages); + show(document.querySelector(".template-help"), downloadImages); document.getElementById('markdown').disabled = !downloadImages; document.getElementById('base64').disabled = !downloadImages; @@ -201,8 +195,9 @@ const inputChange = e => { let lines = ev.target.result; options = JSON.parse(lines); setCurrentChoice(options); - browser.contextMenus.removeAll() - createMenus() + chrome.contextMenus.removeAll() + // Notify service worker to recreate menus + chrome.runtime.sendMessage({ type: "recreateMenus" }).catch(() => {}); save(); refereshElements(); }; @@ -213,8 +208,11 @@ const inputChange = e => { options[key] = value; if (key == "contextMenus") { - if (value) { createMenus() } - else { browser.contextMenus.removeAll() } + if (value) { + // Notify service worker to recreate menus + chrome.runtime.sendMessage({ type: "recreateMenus" }).catch(() => {}); + } + else { chrome.contextMenus.removeAll() } } save(); @@ -240,7 +238,7 @@ const buttonClick = (e) => { var d = new Date(); var datestring = d.getFullYear() + "-" + ("0" + (d.getMonth() + 1)).slice(-2) + "-" + ("0" + d.getDate()).slice(-2); - browser.downloads.download({ + chrome.downloads.download({ url: url, saveAs: true, filename: `MarkDownload-export-${datestring}.json` diff --git a/src/package-lock.json b/src/package-lock.json index 0e2176e8..0fc36389 100644 --- a/src/package-lock.json +++ b/src/package-lock.json @@ -4,6 +4,9 @@ "requires": true, "packages": { "": { + "dependencies": { + "jszip": "^3.10.1" + }, "devDependencies": { "web-ext": "^7.4.0" } @@ -115,12 +118,12 @@ } }, "node_modules/@babel/runtime": { - "version": "7.20.1", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.20.1.tgz", - "integrity": "sha512-mrzLkl6U9YLF8qpqI7TB82PESyEGjm/0Ly91jG575eVxMMlb8fYfOXFZIJ8XfLrJZQbm7dlKry2bJmXBUEkdFg==", + "version": "7.21.0", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.21.0.tgz", + "integrity": "sha512-xwII0//EObnq89Ji5AKYQaRYiW/nZ3llSv29d49IuxPhKbtJoLP+9QUUZ4nVragQVtaVGeZrpB+ZtG/Pdy/POw==", "dev": true, "dependencies": { - "regenerator-runtime": "^0.13.10" + "regenerator-runtime": "^0.13.11" }, "engines": { "node": ">=6.9.0" @@ -165,16 +168,52 @@ "node": ">= 0.10.4" } }, + "node_modules/@eslint-community/eslint-utils": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz", + "integrity": "sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==", + "dev": true, + "dependencies": { + "eslint-visitor-keys": "^3.3.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" + } + }, + "node_modules/@eslint-community/eslint-utils/node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "dev": true, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@eslint-community/regexpp": { + "version": "4.11.0", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.11.0.tgz", + "integrity": "sha512-G/M/tIiMrTAxEWRfLfQJMmGNX28IxBg4PBz8XqQhqUHLFI6TL2htpIB1iQCj144V5ee/JaKyT9/WZ0MGZWfA7A==", + "dev": true, + "engines": { + "node": "^12.0.0 || ^14.0.0 || >=16.0.0" + } + }, "node_modules/@eslint/eslintrc": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.3.3.tgz", - "integrity": "sha512-uj3pT6Mg+3t39fvLrj8iuCIJ38zKO9FpGtJ4BBJebJhEwjoT+KLVNCcHT5QC9NGRIEi7fZ0ZR8YRb884auB4Lg==", + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.4.tgz", + "integrity": "sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==", "dev": true, "dependencies": { "ajv": "^6.12.4", "debug": "^4.3.2", - "espree": "^9.4.0", - "globals": "^13.15.0", + "espree": "^9.6.0", + "globals": "^13.19.0", "ignore": "^5.2.0", "import-fresh": "^3.2.1", "js-yaml": "^4.1.0", @@ -204,6 +243,35 @@ "url": "https://github.com/sponsors/epoberezkin" } }, + "node_modules/@eslint/eslintrc/node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "dev": true, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@eslint/eslintrc/node_modules/espree": { + "version": "9.6.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz", + "integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==", + "dev": true, + "dependencies": { + "acorn": "^8.9.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^3.4.1" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, "node_modules/@eslint/eslintrc/node_modules/json-schema-traverse": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", @@ -222,14 +290,34 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/@eslint/js": { + "version": "8.57.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.57.0.tgz", + "integrity": "sha512-Ys+3g2TaW7gADOJzPt83SJtCDhMjndcDMFVQ/Tj9iA1BfJzFKD9mAUXT3OenpuPHbI6P/myECxRJrofUsDx/5g==", + "dev": true, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "node_modules/@fluent/syntax": { + "version": "0.19.0", + "resolved": "https://registry.npmjs.org/@fluent/syntax/-/syntax-0.19.0.tgz", + "integrity": "sha512-5D2qVpZrgpjtqU4eNOcWGp1gnUCgjfM+vKGE2y03kKN6z5EBhtx0qdRFbg8QuNNj8wXNoX93KJoYb+NqoxswmQ==", + "dev": true, + "engines": { + "node": ">=14.0.0", + "npm": ">=7.0.0" + } + }, "node_modules/@humanwhocodes/config-array": { - "version": "0.11.7", - "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.7.tgz", - "integrity": "sha512-kBbPWzN8oVMLb0hOUYXhmxggL/1cJE6ydvjDIGi9EnAGUyA7cLVKQg+d/Dsm+KZwx2czGHrCmMVLiyg8s5JPKw==", + "version": "0.11.14", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.14.tgz", + "integrity": "sha512-3T8LkOmg45BV5FICb15QQMsyUSWrQ8AygVfC7ZG32zOalnqrilm018ZVCw0eapXux8FtA33q8PSRSstjee3jSg==", + "deprecated": "Use @eslint/config-array instead", "dev": true, "dependencies": { - "@humanwhocodes/object-schema": "^1.2.1", - "debug": "^4.1.1", + "@humanwhocodes/object-schema": "^2.0.2", + "debug": "^4.3.1", "minimatch": "^3.0.5" }, "engines": { @@ -250,15 +338,60 @@ } }, "node_modules/@humanwhocodes/object-schema": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz", - "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==", + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.3.tgz", + "integrity": "sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==", + "deprecated": "Use @eslint/object-schema instead", "dev": true }, + "node_modules/@isaacs/cliui": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", + "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", + "dev": true, + "dependencies": { + "string-width": "^5.1.2", + "string-width-cjs": "npm:string-width@^4.2.0", + "strip-ansi": "^7.0.1", + "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", + "wrap-ansi": "^8.1.0", + "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@isaacs/cliui/node_modules/ansi-regex": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", + "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/@isaacs/cliui/node_modules/strip-ansi": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", + "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", + "dev": true, + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, "node_modules/@mdn/browser-compat-data": { - "version": "5.2.17", - "resolved": "https://registry.npmjs.org/@mdn/browser-compat-data/-/browser-compat-data-5.2.17.tgz", - "integrity": "sha512-aA+rFHhXmq14GVIcEWNk8OntLEOQFwEZk9ZgG5VcDquz+pQhIjJPXacR+rwL9Z0Elfg909EcRRHC96p06/CNUg==", + "version": "5.5.29", + "resolved": "https://registry.npmjs.org/@mdn/browser-compat-data/-/browser-compat-data-5.5.29.tgz", + "integrity": "sha512-NHdG3QOiAsxh8ygBSKMa/WaNJwpNt87uVqW+S2RlnSqgeRdk+L3foNWTX6qd0I3NHSlCFb47rgopeNCJtRDY5A==", "dev": true }, "node_modules/@nodelib/fs.scandir": { @@ -296,6 +429,16 @@ "node": ">= 8" } }, + "node_modules/@pkgjs/parseargs": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", + "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", + "dev": true, + "optional": true, + "engines": { + "node": ">=14" + } + }, "node_modules/@pnpm/network.ca-file": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/@pnpm/network.ca-file/-/network.ca-file-1.0.1.tgz", @@ -358,14 +501,20 @@ "dev": true }, "node_modules/@types/yauzl": { - "version": "2.10.0", - "resolved": "https://registry.npmjs.org/@types/yauzl/-/yauzl-2.10.0.tgz", - "integrity": "sha512-Cn6WYCm0tXv8p6k+A8PvbDG763EDpBoTzHdA+Q/MF6H3sapGjCm9NzoaJncJS9tUKSuCoDs9XHxYYsQDgxR6kw==", + "version": "2.10.3", + "resolved": "https://registry.npmjs.org/@types/yauzl/-/yauzl-2.10.3.tgz", + "integrity": "sha512-oJoftv0LSuaDZE3Le4DbKX+KS9G36NzOeSap90UIK0yMA/NhKJhqlSGtNDORNRaIbQfzjXDrQa0ytJ6mNRGz/Q==", "dev": true, "dependencies": { "@types/node": "*" } }, + "node_modules/@ungap/structured-clone": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.2.0.tgz", + "integrity": "sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==", + "dev": true + }, "node_modules/abort-controller": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz", @@ -379,9 +528,9 @@ } }, "node_modules/acorn": { - "version": "8.8.1", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.1.tgz", - "integrity": "sha512-7zFpHzhnqYKrkYdUjF1HI1bzd0VygEGX8lFk4k5zVMqHEoES+P+7TKI+EvLO9WVMJ8eekdO0aDEK044xTXwPPA==", + "version": "8.12.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.12.1.tgz", + "integrity": "sha512-tcpGyI9zbizT9JbV6oYE477V6mTlXvvi0T0G3SNIYE2apm/G5huBa1+K89VGeovbg+jycCrfhl3ADxErOuO6Jg==", "dev": true, "bin": { "acorn": "bin/acorn" @@ -400,57 +549,57 @@ } }, "node_modules/addons-linter": { - "version": "5.23.0", - "resolved": "https://registry.npmjs.org/addons-linter/-/addons-linter-5.23.0.tgz", - "integrity": "sha512-Vo6+5YlM2Ge3yYMY+gNg9Smcfcl1J0ZMfGVXnGJjUwDVHuszHVIvurunQuJURnO4FR1gi4Vy1sWye8ArRL5LOw==", + "version": "6.28.0", + "resolved": "https://registry.npmjs.org/addons-linter/-/addons-linter-6.28.0.tgz", + "integrity": "sha512-fCTjXL/yG4hwq74JG8tQdrvEu0OvGrEN9yU+Df0020RDtHl3g/tTCyMeC4G1uyk8IuyMzp4myCBNnOGC7MWSQQ==", "dev": true, "dependencies": { - "@mdn/browser-compat-data": "5.2.17", + "@fluent/syntax": "0.19.0", + "@mdn/browser-compat-data": "5.5.29", "addons-moz-compare": "1.3.0", - "addons-scanner-utils": "8.1.0", - "ajv": "8.11.2", - "ajv-merge-patch": "5.0.1", + "addons-scanner-utils": "9.10.1", + "ajv": "8.13.0", "chalk": "4.1.2", "cheerio": "1.0.0-rc.12", "columnify": "1.6.0", "common-tags": "1.8.2", - "deepmerge": "4.2.2", - "eslint": "8.28.0", - "eslint-plugin-no-unsanitized": "4.0.1", - "eslint-visitor-keys": "3.3.0", - "espree": "9.4.1", + "deepmerge": "4.3.1", + "eslint": "8.57.0", + "eslint-plugin-no-unsanitized": "4.0.2", + "eslint-visitor-keys": "4.0.0", + "espree": "10.0.1", "esprima": "4.0.1", - "fluent-syntax": "0.13.0", - "glob": "8.0.3", - "image-size": "1.0.2", + "fast-json-patch": "3.1.1", + "glob": "10.4.1", + "image-size": "1.1.1", "is-mergeable-object": "1.1.1", "jed": "1.1.1", + "json-merge-patch": "1.0.2", "os-locale": "5.0.0", - "pino": "8.7.0", - "postcss": "8.4.19", + "pino": "8.20.0", "relaxed-json": "1.0.3", - "semver": "7.3.8", + "semver": "7.6.2", "sha.js": "2.4.11", "source-map-support": "0.5.21", "tosource": "1.0.0", "upath": "2.0.1", - "yargs": "17.6.2", + "yargs": "17.7.2", "yauzl": "2.10.0" }, "bin": { "addons-linter": "bin/addons-linter" }, "engines": { - "node": ">=12.21.0" + "node": ">=16.0.0" } }, "node_modules/addons-linter/node_modules/addons-scanner-utils": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/addons-scanner-utils/-/addons-scanner-utils-8.1.0.tgz", - "integrity": "sha512-wxqnmmrzZXjz4B4GZbFcR4HJxTP+pGu+C6iOjMJdmL6mgZZey/UEVJlU6XTxu8GdGv0bUoJxyIioH8XEDxy91Q==", + "version": "9.10.1", + "resolved": "https://registry.npmjs.org/addons-scanner-utils/-/addons-scanner-utils-9.10.1.tgz", + "integrity": "sha512-Tz9OUQx9Ja0TyQ+H2GakB9KlJ50myI6ESBGRlA8N80nHBzMjjPRFGm0APADSaCd5NP74SrFtEvL4TRpDwZXETA==", "dev": true, "dependencies": { - "@types/yauzl": "2.10.0", + "@types/yauzl": "2.10.3", "common-tags": "1.8.2", "first-chunk-stream": "3.0.0", "strip-bom-stream": "4.0.0", @@ -458,9 +607,9 @@ "yauzl": "2.10.0" }, "peerDependencies": { - "body-parser": "1.20.1", - "express": "4.18.2", - "node-fetch": "2.6.7", + "body-parser": "1.20.2", + "express": "4.18.3", + "node-fetch": "2.6.11", "safe-compare": "1.1.4" }, "peerDependenciesMeta": { @@ -487,41 +636,53 @@ "balanced-match": "^1.0.0" } }, + "node_modules/addons-linter/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true + }, "node_modules/addons-linter/node_modules/glob": { - "version": "8.0.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-8.0.3.tgz", - "integrity": "sha512-ull455NHSHI/Y1FqGaaYFaLGkNMMJbavMrEGFXG/PGrg6y7sutWHUHrz6gy6WEBH6akM1M414dWKCNs+IhKdiQ==", + "version": "10.4.1", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.1.tgz", + "integrity": "sha512-2jelhlq3E4ho74ZyVLN03oKdAZVUa6UDZzFLVH1H7dnoax+y9qyaq8zBkfDIggjniU19z0wU18y16jMB2eyVIw==", "dev": true, "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^5.0.1", - "once": "^1.3.0" + "foreground-child": "^3.1.0", + "jackspeak": "^3.1.2", + "minimatch": "^9.0.4", + "minipass": "^7.1.2", + "path-scurry": "^1.11.1" + }, + "bin": { + "glob": "dist/esm/bin.mjs" }, "engines": { - "node": ">=12" + "node": ">=16 || 14 >=14.18" }, "funding": { "url": "https://github.com/sponsors/isaacs" } }, "node_modules/addons-linter/node_modules/minimatch": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.1.tgz", - "integrity": "sha512-362NP+zlprccbEt/SkxKfRMHnNY85V74mVnpUpNyr3F35covl09Kec7/sEFLt3RA4oXmewtoaanoIf67SE5Y5g==", + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", + "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", "dev": true, "dependencies": { "brace-expansion": "^2.0.1" }, "engines": { - "node": ">=10" + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" } }, "node_modules/addons-linter/node_modules/node-fetch": { - "version": "2.6.7", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz", - "integrity": "sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==", + "version": "2.6.11", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.11.tgz", + "integrity": "sha512-4I6pdBY1EthSqDmJkiNk3JIT8cswwR9nfeW/cPdUagJYEQG7R95WRH74wpz7ma8Gh/9dI9FP+OU+0E4FvtA55w==", "dev": true, "optional": true, "peer": true, @@ -540,6 +701,50 @@ } } }, + "node_modules/addons-linter/node_modules/semver": { + "version": "7.6.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.2.tgz", + "integrity": "sha512-FNAIBWCx9qcRhoHcgcJ0gvU7SN1lYU2ZXuSfl04bSC5OpvDHFyJCjdNHomPXxjQlCBU67YW64PzY7/VIEH7F2w==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/addons-linter/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/addons-linter/node_modules/yargs": { + "version": "17.7.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", + "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", + "dev": true, + "dependencies": { + "cliui": "^8.0.1", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.3", + "y18n": "^5.0.5", + "yargs-parser": "^21.1.1" + }, + "engines": { + "node": ">=12" + } + }, "node_modules/addons-moz-compare": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/addons-moz-compare/-/addons-moz-compare-1.3.0.tgz", @@ -547,43 +752,30 @@ "dev": true }, "node_modules/adm-zip": { - "version": "0.5.9", - "resolved": "https://registry.npmjs.org/adm-zip/-/adm-zip-0.5.9.tgz", - "integrity": "sha512-s+3fXLkeeLjZ2kLjCBwQufpI5fuN+kIGBxu6530nVQZGVol0d7Y/M88/xw9HGGUcJjKf8LutN3VPRUBq6N7Ajg==", + "version": "0.5.15", + "resolved": "https://registry.npmjs.org/adm-zip/-/adm-zip-0.5.15.tgz", + "integrity": "sha512-jYPWSeOA8EFoZnucrKCNihqBjoEGQSU4HKgHYQgKNEQ0pQF9a/DYuo/+fAxY76k4qe75LUlLWpAM1QWcBMTOKw==", "dev": true, "engines": { - "node": ">=6.0" + "node": ">=12.0" } }, "node_modules/ajv": { - "version": "8.11.2", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.11.2.tgz", - "integrity": "sha512-E4bfmKAhGiSTvMfL1Myyycaub+cUEU2/IvpylXkUu7CHBkBj1f/ikdzbD7YQ6FKUbixDxeYvB/xY4fvyroDlQg==", + "version": "8.13.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.13.0.tgz", + "integrity": "sha512-PRA911Blj99jR5RMeTunVbNXMF6Lp4vZXnk5GQjcnUWUTsrXtekg/pnmFFI2u/I36Y/2bITGS30GZCXei6uNkA==", "dev": true, "dependencies": { - "fast-deep-equal": "^3.1.1", + "fast-deep-equal": "^3.1.3", "json-schema-traverse": "^1.0.0", "require-from-string": "^2.0.2", - "uri-js": "^4.2.2" + "uri-js": "^4.4.1" }, "funding": { "type": "github", "url": "https://github.com/sponsors/epoberezkin" } }, - "node_modules/ajv-merge-patch": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ajv-merge-patch/-/ajv-merge-patch-5.0.1.tgz", - "integrity": "sha512-0UP3aJCzfzBOkmLR+EinJDCfg6DNtprj3bVPo7JJNgUpZMKt097t9xxQOWFGRoB4JvKKIHE2qe0HkVaS/HyrjQ==", - "dev": true, - "dependencies": { - "fast-json-patch": "^2.0.6", - "json-merge-patch": "^1.0.2" - }, - "peerDependencies": { - "ajv": ">=8.0.0" - } - }, "node_modules/ansi-align": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/ansi-align/-/ansi-align-3.0.1.tgz", @@ -713,9 +905,9 @@ } }, "node_modules/aws4": { - "version": "1.11.0", - "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.11.0.tgz", - "integrity": "sha512-xh1Rl34h6Fi1DC2WWKfxUTVqRsNnr6LsKz2+hfwDxQJWmrx8+c7ylaqBMcHfl1U1r2dsifOvKX3LQuLNZ+XSvA==", + "version": "1.13.1", + "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.13.1.tgz", + "integrity": "sha512-u5w79Rd7SU4JaIlA/zFqG+gOiuq25q5VLyZ8E+ijJeILuTxVzZgp2CaGw/UTw6pXYN9XMO9yiqj/nEHmhTG5CA==", "dev": true }, "node_modules/balanced-match": { @@ -932,9 +1124,9 @@ } }, "node_modules/camelcase": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-7.0.0.tgz", - "integrity": "sha512-JToIvOmz6nhGsUhAYScbo2d6Py5wojjNfoxoc2mEVLUdJ70gJK2gnd+ABY1Tc3sVMyK7QDPtN0T/XdlCQWITyQ==", + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-7.0.1.tgz", + "integrity": "sha512-xlx1yCK2Oc1APsPXDL2LdlNP6+uu8OCDdhOBSVT279M/S+y75O30C2VuD8T2ogdePBBl7PfPF4504tnLgX3zfw==", "dev": true, "engines": { "node": ">=14.16" @@ -1217,9 +1409,9 @@ } }, "node_modules/core-js": { - "version": "3.25.3", - "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.25.3.tgz", - "integrity": "sha512-y1hvKXmPHvm5B7w4ln1S4uc9eV/O5+iFExSRUimnvIph11uaizFR8LFMdONN8hG3P2pipUfX4Y/fR8rAEtcHcQ==", + "version": "3.29.0", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.29.0.tgz", + "integrity": "sha512-VG23vuEisJNkGl6XQmFJd3rEG/so/CNatqeE+7uZAwTSwFeB/qaO0be8xZYUNWprJ/GIwL8aMt9cj1kvbpTZhg==", "dev": true, "hasInstallScript": true, "funding": { @@ -1230,8 +1422,7 @@ "node_modules/core-util-is": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", - "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==", - "dev": true + "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==" }, "node_modules/cross-spawn": { "version": "7.0.3", @@ -1315,9 +1506,9 @@ } }, "node_modules/data-uri-to-buffer": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-4.0.0.tgz", - "integrity": "sha512-Vr3mLBA8qWmcuschSLAOogKgQ/Jwxulv3RNE4FXnYWRGujzrRWQI4m12fQqRkwX06C0KanhLr4hK+GydchZsaA==", + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-4.0.1.tgz", + "integrity": "sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A==", "dev": true, "engines": { "node": ">= 12" @@ -1410,9 +1601,9 @@ } }, "node_modules/deepmerge": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.2.2.tgz", - "integrity": "sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg==", + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz", + "integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==", "dev": true, "engines": { "node": ">=0.10.0" @@ -1511,14 +1702,14 @@ } }, "node_modules/domutils": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/domutils/-/domutils-3.0.1.tgz", - "integrity": "sha512-z08c1l761iKhDFtfXO04C7kTdPBLi41zwOZl00WS8b5eiaebNpY00HKbztwBq+e3vyqWNwWF3mP9YLUeqIrF+Q==", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-3.1.0.tgz", + "integrity": "sha512-H78uMmQtI2AhgDJjWeQmHwJJ2bLPD3GMmO7Zja/ZZh84wkm+4ut+IUnUdRa8uCGX88DiVx1j6FRe1XfxEgjEZA==", "dev": true, "dependencies": { "dom-serializer": "^2.0.0", "domelementtype": "^2.3.0", - "domhandler": "^5.0.1" + "domhandler": "^5.0.3" }, "funding": { "url": "https://github.com/fb55/domutils?sponsor=1" @@ -1594,9 +1785,9 @@ } }, "node_modules/entities": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/entities/-/entities-4.4.0.tgz", - "integrity": "sha512-oYp7156SP8LkeGD0GF85ad1X9Ai79WtRsZ2gxJqtBuzH+98YUV6jkHEKlZkMbcrjJjIVJNIDP/3WL9wQkoPbWA==", + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", + "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", "dev": true, "engines": { "node": ">=0.12" @@ -1630,9 +1821,9 @@ } }, "node_modules/escalade": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", - "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.2.tgz", + "integrity": "sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA==", "dev": true, "engines": { "node": ">=6" @@ -1663,49 +1854,48 @@ } }, "node_modules/eslint": { - "version": "8.28.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.28.0.tgz", - "integrity": "sha512-S27Di+EVyMxcHiwDrFzk8dJYAaD+/5SoWKxL1ri/71CRHsnJnRDPNt2Kzj24+MT9FDupf4aqqyqPrvI8MvQ4VQ==", + "version": "8.57.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.57.0.tgz", + "integrity": "sha512-dZ6+mexnaTIbSBZWgou51U6OmzIhYM2VcNdtiTtI7qPNZm35Akpr0f6vtw3w1Kmn5PYo+tZVfh13WrhpS6oLqQ==", "dev": true, "dependencies": { - "@eslint/eslintrc": "^1.3.3", - "@humanwhocodes/config-array": "^0.11.6", + "@eslint-community/eslint-utils": "^4.2.0", + "@eslint-community/regexpp": "^4.6.1", + "@eslint/eslintrc": "^2.1.4", + "@eslint/js": "8.57.0", + "@humanwhocodes/config-array": "^0.11.14", "@humanwhocodes/module-importer": "^1.0.1", "@nodelib/fs.walk": "^1.2.8", - "ajv": "^6.10.0", + "@ungap/structured-clone": "^1.2.0", + "ajv": "^6.12.4", "chalk": "^4.0.0", "cross-spawn": "^7.0.2", "debug": "^4.3.2", "doctrine": "^3.0.0", "escape-string-regexp": "^4.0.0", - "eslint-scope": "^7.1.1", - "eslint-utils": "^3.0.0", - "eslint-visitor-keys": "^3.3.0", - "espree": "^9.4.0", - "esquery": "^1.4.0", + "eslint-scope": "^7.2.2", + "eslint-visitor-keys": "^3.4.3", + "espree": "^9.6.1", + "esquery": "^1.4.2", "esutils": "^2.0.2", "fast-deep-equal": "^3.1.3", "file-entry-cache": "^6.0.1", "find-up": "^5.0.0", "glob-parent": "^6.0.2", - "globals": "^13.15.0", - "grapheme-splitter": "^1.0.4", + "globals": "^13.19.0", + "graphemer": "^1.4.0", "ignore": "^5.2.0", - "import-fresh": "^3.0.0", "imurmurhash": "^0.1.4", "is-glob": "^4.0.0", "is-path-inside": "^3.0.3", - "js-sdsl": "^4.1.4", "js-yaml": "^4.1.0", "json-stable-stringify-without-jsonify": "^1.0.1", "levn": "^0.4.1", "lodash.merge": "^4.6.2", "minimatch": "^3.1.2", "natural-compare": "^1.4.0", - "optionator": "^0.9.1", - "regexpp": "^3.2.0", + "optionator": "^0.9.3", "strip-ansi": "^6.0.1", - "strip-json-comments": "^3.1.0", "text-table": "^0.2.0" }, "bin": { @@ -1719,18 +1909,18 @@ } }, "node_modules/eslint-plugin-no-unsanitized": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/eslint-plugin-no-unsanitized/-/eslint-plugin-no-unsanitized-4.0.1.tgz", - "integrity": "sha512-y/lAMWnPPC7RYuUdxlEL/XiCL8FehN9h9s3Kjqbp/Kv0i9NZs+IXSC2kS546Fa4Bumwy31HlVS/OdWX0Kxb5Xg==", + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/eslint-plugin-no-unsanitized/-/eslint-plugin-no-unsanitized-4.0.2.tgz", + "integrity": "sha512-Pry0S9YmHoz8NCEMRQh7N0Yexh2MYCNPIlrV52hTmS7qXnTghWsjXouF08bgsrrZqaW9tt1ZiK3j5NEmPE+EjQ==", "dev": true, "peerDependencies": { "eslint": "^6 || ^7 || ^8" } }, "node_modules/eslint-scope": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.1.1.tgz", - "integrity": "sha512-QKQM/UXpIiHcLqJ5AOyIW7XZmzjkzQXYE54n1++wb0u9V/abW3l9uQnxX8Z5Xd18xyKIMTUAyQ0k1e8pz6LUrw==", + "version": "7.2.2", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz", + "integrity": "sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==", "dev": true, "dependencies": { "esrecurse": "^4.3.0", @@ -1738,42 +1928,21 @@ }, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - } - }, - "node_modules/eslint-utils": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-3.0.0.tgz", - "integrity": "sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==", - "dev": true, - "dependencies": { - "eslint-visitor-keys": "^2.0.0" - }, - "engines": { - "node": "^10.0.0 || ^12.0.0 || >= 14.0.0" }, "funding": { - "url": "https://github.com/sponsors/mysticatea" - }, - "peerDependencies": { - "eslint": ">=5" - } - }, - "node_modules/eslint-utils/node_modules/eslint-visitor-keys": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz", - "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==", - "dev": true, - "engines": { - "node": ">=10" + "url": "https://opencollective.com/eslint" } }, "node_modules/eslint-visitor-keys": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz", - "integrity": "sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.0.0.tgz", + "integrity": "sha512-OtIRv/2GyiF6o/d8K7MYKKbXrOUBIK6SfkIRM4Z0dY3w+LiQ0vy3F57m0Z71bjbyeiWFiHJ8brqnmE6H6/jEuw==", "dev": true, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" } }, "node_modules/eslint/node_modules/ajv": { @@ -1792,36 +1961,53 @@ "url": "https://github.com/sponsors/epoberezkin" } }, - "node_modules/eslint/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 + "node_modules/eslint/node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "dev": true, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } }, - "node_modules/eslint/node_modules/strip-json-comments": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", - "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "node_modules/eslint/node_modules/espree": { + "version": "9.6.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz", + "integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==", "dev": true, + "dependencies": { + "acorn": "^8.9.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^3.4.1" + }, "engines": { - "node": ">=8" + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "url": "https://opencollective.com/eslint" } }, + "node_modules/eslint/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 + }, "node_modules/espree": { - "version": "9.4.1", - "resolved": "https://registry.npmjs.org/espree/-/espree-9.4.1.tgz", - "integrity": "sha512-XwctdmTO6SIvCzd9810yyNzIrOrqNYV9Koizx4C/mRhf9uq0o4yHoCEU/670pOxOL/MSraektvSAji79kX90Vg==", + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-10.0.1.tgz", + "integrity": "sha512-MWkrWZbJsL2UwnjxTX3gG8FneachS/Mwg7tdGXce011sJd5b0JG54vat5KHnfSBODZ3Wvzd2WnjxyzsRoVv+ww==", "dev": true, "dependencies": { - "acorn": "^8.8.0", + "acorn": "^8.11.3", "acorn-jsx": "^5.3.2", - "eslint-visitor-keys": "^3.3.0" + "eslint-visitor-keys": "^4.0.0" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { "url": "https://opencollective.com/eslint" @@ -1841,9 +2027,9 @@ } }, "node_modules/esquery": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.4.0.tgz", - "integrity": "sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w==", + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.6.0.tgz", + "integrity": "sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==", "dev": true, "dependencies": { "estraverse": "^5.1.0" @@ -1945,21 +2131,9 @@ "dev": true }, "node_modules/fast-json-patch": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/fast-json-patch/-/fast-json-patch-2.2.1.tgz", - "integrity": "sha512-4j5uBaTnsYAV5ebkidvxiLUYOwjQ+JSFljeqfTxCrH9bDmlCQaOJFS84oDJ2rAXZq2yskmk3ORfoP9DCwqFNig==", - "dev": true, - "dependencies": { - "fast-deep-equal": "^2.0.1" - }, - "engines": { - "node": ">= 0.4.0" - } - }, - "node_modules/fast-json-patch/node_modules/fast-deep-equal": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz", - "integrity": "sha512-bCK/2Z4zLidyB4ReuIsvALH6w31YfAQDmXMqMx6FyfHqvBxtjC0eRumeSu4Bs3XtXwpyIywtSTrVT99BxY1f9w==", + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/fast-json-patch/-/fast-json-patch-3.1.1.tgz", + "integrity": "sha512-vf6IHUX2SBcA+5/+4883dsIjpBTqmfBjmYiWK1savxQmFk4JfBMLa7ynTYOs1Rolp/T1betJxHiGD3g1Mn8lUQ==", "dev": true }, "node_modules/fast-json-stable-stringify": { @@ -1975,18 +2149,18 @@ "dev": true }, "node_modules/fast-redact": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/fast-redact/-/fast-redact-3.1.2.tgz", - "integrity": "sha512-+0em+Iya9fKGfEQGcd62Yv6onjBmmhV1uh86XVfOU8VwAe6kaFdQCWI9s0/Nnugx5Vd9tdbZ7e6gE2tR9dzXdw==", + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/fast-redact/-/fast-redact-3.5.0.tgz", + "integrity": "sha512-dwsoQlS7h9hMeYUq1W++23NDcBLV4KqONnITDV9DjfS3q1SgDGVrBdvvTLUotWtPSD7asWDV9/CmsZPy8Hf70A==", "dev": true, "engines": { "node": ">=6" } }, "node_modules/fastq": { - "version": "1.13.0", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.13.0.tgz", - "integrity": "sha512-YpkpUnK8od0o1hmeSc7UUs/eB/vIPWJYjKck2QKIzAf71Vm1AAQ3EbuZB3g2JIy+pg+ERD0vqI79KyZiB2e2Nw==", + "version": "1.17.1", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.17.1.tgz", + "integrity": "sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==", "dev": true, "dependencies": { "reusify": "^1.0.4" @@ -2053,16 +2227,16 @@ } }, "node_modules/firefox-profile": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/firefox-profile/-/firefox-profile-4.2.2.tgz", - "integrity": "sha512-3kI17Xl9dL9AeRkpV1yahsJ+UbekkPtlQswKrIsTY1NLgxtEOR4R19rjGGz5+7/rP8Jt6fvxHk+Bai9R6Eai3w==", + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/firefox-profile/-/firefox-profile-4.3.2.tgz", + "integrity": "sha512-/C+Eqa0YgIsQT2p66p7Ygzqe7NlE/GNTbhw2SBCm5V3OsWDPITNdTPEcH2Q2fe7eMpYYNPKdUcuVioZBZiR6kA==", "dev": true, "dependencies": { "adm-zip": "~0.5.x", "fs-extra": "~9.0.1", "ini": "~2.0.0", "minimist": "^1.2.5", - "xml2js": "~0.4.23" + "xml2js": "^0.5.0" }, "bin": { "firefox-profile": "lib/cli.js" @@ -2102,12 +2276,13 @@ } }, "node_modules/flat-cache": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz", - "integrity": "sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==", + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.2.0.tgz", + "integrity": "sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==", "dev": true, "dependencies": { - "flatted": "^3.1.0", + "flatted": "^3.2.9", + "keyv": "^4.5.3", "rimraf": "^3.0.2" }, "engines": { @@ -2115,18 +2290,37 @@ } }, "node_modules/flatted": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.7.tgz", - "integrity": "sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==", + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.1.tgz", + "integrity": "sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw==", "dev": true }, - "node_modules/fluent-syntax": { - "version": "0.13.0", - "resolved": "https://registry.npmjs.org/fluent-syntax/-/fluent-syntax-0.13.0.tgz", - "integrity": "sha512-0Bk1AsliuYB550zr4JV9AYhsETsD3ELXUQzdXGJfIc1Ni/ukAfBdQInDhVMYJUaT2QxoamNslwkYF7MlOrPUwg==", + "node_modules/foreground-child": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.0.tgz", + "integrity": "sha512-Ld2g8rrAyMYFXBhEqMz8ZAHBi4J4uS1i/CxGMDnjyFWddMXLVcDp051DZfu+t7+ab7Wv6SMqpWmyFIj5UbfFvg==", "dev": true, + "dependencies": { + "cross-spawn": "^7.0.0", + "signal-exit": "^4.0.1" + }, "engines": { - "node": ">=8.9.0" + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/foreground-child/node_modules/signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "dev": true, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" } }, "node_modules/forever-agent": { @@ -2174,9 +2368,9 @@ } }, "node_modules/fs-extra": { - "version": "10.1.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz", - "integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==", + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.1.0.tgz", + "integrity": "sha512-0rcTq621PD5jM/e0a3EJoGC/1TC5ZBCERW82LQuwfGnCa1V8w7dpYH1yNu+SLb6E5dkeCBzKEyLGlFrnr+dUyw==", "dev": true, "dependencies": { "graceful-fs": "^4.2.0", @@ -2184,7 +2378,7 @@ "universalify": "^2.0.0" }, "engines": { - "node": ">=12" + "node": ">=14.14" } }, "node_modules/fs.realpath": { @@ -2194,9 +2388,9 @@ "dev": true }, "node_modules/fx-runner": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/fx-runner/-/fx-runner-1.3.0.tgz", - "integrity": "sha512-5b37H4GCyhF+Nf8xk9mylXoDq4wb7pbGAXxlCXp/631UTeeZomWSYcEGXumY4wk8g2QAqjPMGdWW+RbNt8PUcA==", + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/fx-runner/-/fx-runner-1.4.0.tgz", + "integrity": "sha512-rci1g6U0rdTg6bAaBboP7XdRu01dzTAaKXxFf+PUqGuCv6Xu7o8NZdY1D5MvKGIjb6EdS1g3VlXOgksir1uGkg==", "dev": true, "dependencies": { "commander": "2.9.0", @@ -2328,9 +2522,9 @@ } }, "node_modules/globals": { - "version": "13.18.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.18.0.tgz", - "integrity": "sha512-/mR4KI8Ps2spmoc0Ulu9L7agOF0du1CZNQ3dke8yItYlyKNmGrkONemBbd6V8UTc1Wgcqn21t3WYB7dbRmh6/A==", + "version": "13.24.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz", + "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==", "dev": true, "dependencies": { "type-fest": "^0.20.2" @@ -2391,10 +2585,10 @@ "integrity": "sha512-8tLu60LgxF6XpdbK8OW3FA+IfTNBn1ZHGHKF4KQbEeSkajYw5PlYJcKluntgegDPTg8UkHjpet1T82vk6TQ68w==", "dev": true }, - "node_modules/grapheme-splitter": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/grapheme-splitter/-/grapheme-splitter-1.0.4.tgz", - "integrity": "sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ==", + "node_modules/graphemer": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", + "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", "dev": true }, "node_modules/growly": { @@ -2470,9 +2664,9 @@ } }, "node_modules/htmlparser2": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-8.0.1.tgz", - "integrity": "sha512-4lVbmc1diZC7GUJQtRQ5yBAeUCL1exyMwmForWkRLnwyzWBFxN633SALPMGYaWZvKe9j1pRZJpauvmxENSp/EA==", + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-8.0.2.tgz", + "integrity": "sha512-GYdjWKDkbRLkZ5geuHs5NY1puJ+PXwP7+fHPRz06Eirsb9ugf6d8kkXav6ADhcODhFFPMIXyxkxSuMf3D6NCFA==", "dev": true, "funding": [ "https://github.com/fb55/htmlparser2?sponsor=1", @@ -2483,15 +2677,15 @@ ], "dependencies": { "domelementtype": "^2.3.0", - "domhandler": "^5.0.2", + "domhandler": "^5.0.3", "domutils": "^3.0.1", - "entities": "^4.3.0" + "entities": "^4.4.0" } }, "node_modules/http-cache-semantics": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.0.tgz", - "integrity": "sha512-carPklcUh7ROWRK7Cv27RPtdhYhUsela/ue5/jKzjegVvXDqM2ILE9Q2BGn9JZJh1g87cp56su/FgQSzcWS8cQ==", + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.1.tgz", + "integrity": "sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ==", "dev": true }, "node_modules/http-signature": { @@ -2552,18 +2746,18 @@ ] }, "node_modules/ignore": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.1.tgz", - "integrity": "sha512-d2qQLzTJ9WxQftPAuEQpSPmKqzxePjzVbpAVv62AQ64NTL+wR4JkrVqR/LqFsFEUsHDAiId52mJteHDFuDkElA==", + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", + "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", "dev": true, "engines": { "node": ">= 4" } }, "node_modules/image-size": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/image-size/-/image-size-1.0.2.tgz", - "integrity": "sha512-xfOoWjceHntRb3qFCrh5ZFORYH8XCdYpASltMhZ/Q0KZiOwjdE/Yl2QCiWdwD+lygV5bMCvauzgu5PxBX/Yerg==", + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/image-size/-/image-size-1.1.1.tgz", + "integrity": "sha512-541xKlUw6jr/6gGuk92F+mYM5zaFAc5ahphvkqvNe2bQ6gVBkd6bfrmVJ2t4KDAfikAYZyIqTnktX3i6/aQDrQ==", "dev": true, "dependencies": { "queue": "6.0.2" @@ -2572,14 +2766,13 @@ "image-size": "bin/image-size.js" }, "engines": { - "node": ">=14.0.0" + "node": ">=16.x" } }, "node_modules/immediate": { "version": "3.0.6", "resolved": "https://registry.npmjs.org/immediate/-/immediate-3.0.6.tgz", - "integrity": "sha1-nbHb0Pr43m++D13V5Wu2BigN5ps=", - "dev": true + "integrity": "sha1-nbHb0Pr43m++D13V5Wu2BigN5ps=" }, "node_modules/import-fresh": { "version": "3.3.0", @@ -2628,8 +2821,7 @@ "node_modules/inherits": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", - "dev": true + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" }, "node_modules/ini": { "version": "2.0.0", @@ -2836,8 +3028,7 @@ "node_modules/isarray": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", - "dev": true + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" }, "node_modules/isexe": { "version": "2.0.0", @@ -2851,6 +3042,21 @@ "integrity": "sha512-Yljz7ffyPbrLpLngrMtZ7NduUgVvi6wG9RJ9IUcyCd59YQ911PBJphODUcbOVbqYfxe1wuYf/LJ8PauMRwsM/g==", "dev": true }, + "node_modules/jackspeak": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.3.tgz", + "integrity": "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==", + "dev": true, + "dependencies": { + "@isaacs/cliui": "^8.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + }, + "optionalDependencies": { + "@pkgjs/parseargs": "^0.11.0" + } + }, "node_modules/jed": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/jed/-/jed-1.1.1.tgz", @@ -2858,24 +3064,14 @@ "dev": true }, "node_modules/jose": { - "version": "4.11.1", - "resolved": "https://registry.npmjs.org/jose/-/jose-4.11.1.tgz", - "integrity": "sha512-YRv4Tk/Wlug8qicwqFNFVEZSdbROCHRAC6qu/i0dyNKr5JQdoa2pIGoS04lLO/jXQX7Z9omoNewYIVIxqZBd9Q==", + "version": "4.13.1", + "resolved": "https://registry.npmjs.org/jose/-/jose-4.13.1.tgz", + "integrity": "sha512-MSJQC5vXco5Br38mzaQKiq9mwt7lwj2eXpgpRyQYNHYt2lq1PjkWa7DLXX0WVcQLE9HhMh3jPiufS7fhJf+CLQ==", "dev": true, "funding": { "url": "https://github.com/sponsors/panva" } }, - "node_modules/js-sdsl": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/js-sdsl/-/js-sdsl-4.2.0.tgz", - "integrity": "sha512-dyBIzQBDkCqCu+0upx25Y2jGdbTGxE9fshMsCdK0ViOongpV+n5tXRcZY9v7CaVQ79AGS9KA1KHtojxiM7aXSQ==", - "dev": true, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/js-sdsl" - } - }, "node_modules/js-tokens": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", @@ -2958,34 +3154,19 @@ } }, "node_modules/jsonwebtoken": { - "version": "8.5.1", - "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-8.5.1.tgz", - "integrity": "sha512-XjwVfRS6jTMsqYs0EsuJ4LGxXV14zQybNd4L2r0UvbVnSF9Af8x7p5MzbJ90Ioz/9TI41/hTCvznF/loiSzn8w==", + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-9.0.0.tgz", + "integrity": "sha512-tuGfYXxkQGDPnLJ7SibiQgVgeDgfbPq2k2ICcbgqW8WxWLBAxKQM/ZCu/IT8SOSwmaYl4dpTFCW5xZv7YbbWUw==", "dev": true, "dependencies": { "jws": "^3.2.2", - "lodash.includes": "^4.3.0", - "lodash.isboolean": "^3.0.3", - "lodash.isinteger": "^4.0.4", - "lodash.isnumber": "^3.0.3", - "lodash.isplainobject": "^4.0.6", - "lodash.isstring": "^4.0.1", - "lodash.once": "^4.0.0", + "lodash": "^4.17.21", "ms": "^2.1.1", - "semver": "^5.6.0" + "semver": "^7.3.8" }, "engines": { - "node": ">=4", - "npm": ">=1.4.28" - } - }, - "node_modules/jsonwebtoken/node_modules/semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", - "dev": true, - "bin": { - "semver": "bin/semver" + "node": ">=12", + "npm": ">=6" } }, "node_modules/jsprim": { @@ -3004,15 +3185,15 @@ } }, "node_modules/jszip": { - "version": "3.7.1", - "resolved": "https://registry.npmjs.org/jszip/-/jszip-3.7.1.tgz", - "integrity": "sha512-ghL0tz1XG9ZEmRMcEN2vt7xabrDdqHHeykgARpmZ0BiIctWxM47Vt63ZO2dnp4QYt/xJVLLy5Zv1l/xRdh2byg==", - "dev": true, + "version": "3.10.1", + "resolved": "https://registry.npmjs.org/jszip/-/jszip-3.10.1.tgz", + "integrity": "sha512-xXDvecyTpGLrqFrvkrUSoxxfJI5AH7U8zxxtVclpsUtMCq4JQ290LY8AW5c7Ggnr/Y/oK+bQMbqK2qmtk3pN4g==", + "license": "(MIT OR GPL-3.0-or-later)", "dependencies": { "lie": "~3.3.0", "pako": "~1.0.2", "readable-stream": "~2.3.6", - "set-immediate-shim": "~1.0.1" + "setimmediate": "^1.0.5" } }, "node_modules/jwa": { @@ -3037,9 +3218,9 @@ } }, "node_modules/keyv": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.0.tgz", - "integrity": "sha512-2YvuMsA+jnFGtBareKqgANOEKe1mk3HKiXu2fRmAfyxG0MJAywNhi5ttWA3PMjl4NmpyjZNbFifR2vNjW1znfA==", + "version": "4.5.4", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", + "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", "dev": true, "dependencies": { "json-buffer": "3.0.1" @@ -3089,7 +3270,6 @@ "version": "3.3.0", "resolved": "https://registry.npmjs.org/lie/-/lie-3.3.0.tgz", "integrity": "sha512-UaiMJzeWRlEujzAuw5LokY1L5ecNQYZKfmyZ9L7wDHb/p5etKaxXhohBcrw0EYby+G/NA52vRSN4N39dxHAIwQ==", - "dev": true, "dependencies": { "immediate": "~3.0.5" } @@ -3143,40 +3323,10 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/lodash.includes": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/lodash.includes/-/lodash.includes-4.3.0.tgz", - "integrity": "sha512-W3Bx6mdkRTGtlJISOvVD/lbqjTlPPUDTMnlXZFnVwi9NKJ6tiAk6LVdlhZMm17VZisqhKcgzpO5Wz91PCt5b0w==", - "dev": true - }, - "node_modules/lodash.isboolean": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz", - "integrity": "sha512-Bz5mupy2SVbPHURB98VAcw+aHh4vRV5IPNhILUCsOzRmsTmSQ17jIuqopAentWoehktxGd9e/hbIXq980/1QJg==", - "dev": true - }, - "node_modules/lodash.isinteger": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz", - "integrity": "sha512-DBwtEWN2caHQ9/imiNeEA5ys1JoRtRfY3d7V9wkqtbycnAmTvRRmbHKDV4a0EYc678/dia0jrte4tjYwVBaZUA==", - "dev": true - }, - "node_modules/lodash.isnumber": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/lodash.isnumber/-/lodash.isnumber-3.0.3.tgz", - "integrity": "sha512-QYqzpfwO3/CWf3XP+Z+tkQsfaLL/EnUlXWVkIk5FUPc4sBdTehEqZONuyRt2P67PXAk+NXmTBcc97zw9t1FQrw==", - "dev": true - }, - "node_modules/lodash.isplainobject": { - "version": "4.0.6", - "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz", - "integrity": "sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==", - "dev": true - }, - "node_modules/lodash.isstring": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/lodash.isstring/-/lodash.isstring-4.0.1.tgz", - "integrity": "sha512-0wJxfxH1wgO3GrbuP+dTTk7op+6L41QCXbGINEmD+ny/G/eCqGzxyCsh7159S+mgDDcoarnBw6PC1PS5+wUGgw==", + "node_modules/lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", "dev": true }, "node_modules/lodash.merge": { @@ -3185,12 +3335,6 @@ "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", "dev": true }, - "node_modules/lodash.once": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz", - "integrity": "sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg==", - "dev": true - }, "node_modules/lowercase-keys": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-3.0.0.tgz", @@ -3199,22 +3343,16 @@ "engines": { "node": "^12.20.0 || ^14.13.1 || >=16.0.0" }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "dev": true, - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=10" + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/lru-cache": { + "version": "10.4.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", + "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", + "dev": true + }, "node_modules/make-error": { "version": "1.3.6", "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", @@ -3319,6 +3457,15 @@ "integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==", "dev": true }, + "node_modules/minipass": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz", + "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==", + "dev": true, + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, "node_modules/mkdirp": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", @@ -3453,18 +3600,6 @@ "dev": true, "optional": true }, - "node_modules/nanoid": { - "version": "3.3.4", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.4.tgz", - "integrity": "sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw==", - "dev": true, - "bin": { - "nanoid": "bin/nanoid.cjs" - }, - "engines": { - "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" - } - }, "node_modules/natural-compare": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", @@ -3501,9 +3636,9 @@ } }, "node_modules/node-fetch": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-3.3.0.tgz", - "integrity": "sha512-BKwRP/O0UvoMKp7GNdwPlObhYGB5DQqwhEDQlNKuoqwVYSxkSZCSbHjnFFmUEtwSKRPU4kNK8PbDYYitwaE3QA==", + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-3.3.1.tgz", + "integrity": "sha512-cRVc/kyto/7E5shrWca1Wsea4y6tL9iYJE5FBCius3JQfb/4P4I295PfhgbJQBLTx6lATE4z+wK0rPM4VS2uow==", "dev": true, "dependencies": { "data-uri-to-buffer": "^4.0.0", @@ -3596,10 +3731,13 @@ } }, "node_modules/on-exit-leak-free": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/on-exit-leak-free/-/on-exit-leak-free-2.1.0.tgz", - "integrity": "sha512-VuCaZZAjReZ3vUwgOB8LxAosIurDiAW0s13rI1YwmaP++jvcxP77AWoQvenZebpCA2m8WC1/EosPYPMjnRAp/w==", - "dev": true + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/on-exit-leak-free/-/on-exit-leak-free-2.1.2.tgz", + "integrity": "sha512-0eJJY6hXLGf1udHwfNftBqH+g73EU4B504nZeKpz1sYRKafAghwxEJunB2O7rDZkL4PGfsMVnTXZ2EjibbqcsA==", + "dev": true, + "engines": { + "node": ">=14.0.0" + } }, "node_modules/once": { "version": "1.4.0", @@ -3626,9 +3764,9 @@ } }, "node_modules/open": { - "version": "8.4.0", - "resolved": "https://registry.npmjs.org/open/-/open-8.4.0.tgz", - "integrity": "sha512-XgFPPM+B28FtCCgSb9I+s9szOC1vZRSwgWsRUA5ylIxRTgKozqjOCrVOqGsYABPYK5qnfqClxZTFBa8PKt2v6Q==", + "version": "8.4.2", + "resolved": "https://registry.npmjs.org/open/-/open-8.4.2.tgz", + "integrity": "sha512-7x81NCL719oNbsq/3mh+hVrAWmFuEYUqrq/Iw3kUzH8ReypT9QQ0BLoJS7/G9k6N81XjW4qHWtjWwe/9eLy1EQ==", "dev": true, "dependencies": { "define-lazy-prop": "^2.0.0", @@ -3643,9 +3781,9 @@ } }, "node_modules/optionator": { - "version": "0.9.1", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz", - "integrity": "sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==", + "version": "0.9.4", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", + "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==", "dev": true, "dependencies": { "deep-is": "^0.1.3", @@ -3653,7 +3791,7 @@ "levn": "^0.4.1", "prelude-ls": "^1.2.1", "type-check": "^0.4.0", - "word-wrap": "^1.2.3" + "word-wrap": "^1.2.5" }, "engines": { "node": ">= 0.8.0" @@ -3763,8 +3901,7 @@ "node_modules/pako": { "version": "1.0.11", "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz", - "integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==", - "dev": true + "integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==" }, "node_modules/parent-module": { "version": "1.0.1", @@ -3848,6 +3985,22 @@ "node": ">=8" } }, + "node_modules/path-scurry": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz", + "integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==", + "dev": true, + "dependencies": { + "lru-cache": "^10.2.0", + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" + }, + "engines": { + "node": ">=16 || 14 >=14.18" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/pend": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz", @@ -3860,28 +4013,22 @@ "integrity": "sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow==", "dev": true }, - "node_modules/picocolors": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", - "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==", - "dev": true - }, "node_modules/pino": { - "version": "8.7.0", - "resolved": "https://registry.npmjs.org/pino/-/pino-8.7.0.tgz", - "integrity": "sha512-l9sA5uPxmZzwydhMWUcm1gI0YxNnYl8MfSr2h8cwLvOAzQLBLewzF247h/vqHe3/tt6fgtXeG9wdjjoetdI/vA==", + "version": "8.20.0", + "resolved": "https://registry.npmjs.org/pino/-/pino-8.20.0.tgz", + "integrity": "sha512-uhIfMj5TVp+WynVASaVEJFTncTUe4dHBq6CWplu/vBgvGHhvBvQfxz+vcOrnnBQdORH3izaGEurLfNlq3YxdFQ==", "dev": true, "dependencies": { "atomic-sleep": "^1.0.0", "fast-redact": "^3.1.1", "on-exit-leak-free": "^2.1.0", - "pino-abstract-transport": "v1.0.0", + "pino-abstract-transport": "^1.1.0", "pino-std-serializers": "^6.0.0", - "process-warning": "^2.0.0", + "process-warning": "^3.0.0", "quick-format-unescaped": "^4.0.3", "real-require": "^0.2.0", "safe-stable-stringify": "^2.3.1", - "sonic-boom": "^3.1.0", + "sonic-boom": "^3.7.0", "thread-stream": "^2.0.0" }, "bin": { @@ -3889,9 +4036,9 @@ } }, "node_modules/pino-abstract-transport": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/pino-abstract-transport/-/pino-abstract-transport-1.0.0.tgz", - "integrity": "sha512-c7vo5OpW4wIS42hUVcT5REsL8ZljsUfBjqV/e2sFxmFEFZiq1XLUp5EYLtuDH6PEHq9W1egWqRbnLUP5FuZmOA==", + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/pino-abstract-transport/-/pino-abstract-transport-1.2.0.tgz", + "integrity": "sha512-Guhh8EZfPCfH+PMXAb6rKOjGQEoy0xlAIn+irODG5kgfYV+BQ0rGYYWTIel3P5mmyXqkYkPmdIkywsn6QKUR1Q==", "dev": true, "dependencies": { "readable-stream": "^4.0.0", @@ -3899,50 +4046,36 @@ } }, "node_modules/pino-abstract-transport/node_modules/readable-stream": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-4.2.0.tgz", - "integrity": "sha512-gJrBHsaI3lgBoGMW/jHZsQ/o/TIWiu5ENCJG1BB7fuCKzpFM8GaS2UoBVt9NO+oI+3FcrBNbUkl3ilDe09aY4A==", + "version": "4.5.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-4.5.2.tgz", + "integrity": "sha512-yjavECdqeZ3GLXNgRXgeQEdz9fvDDkNKyHnbHRFtOr7/LcfgBcmct7t/ET+HaCTqfh06OzoAxrkN/IfjJBVe+g==", "dev": true, "dependencies": { "abort-controller": "^3.0.0", "buffer": "^6.0.3", "events": "^3.3.0", - "process": "^0.11.10" + "process": "^0.11.10", + "string_decoder": "^1.3.0" }, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" } }, - "node_modules/pino-std-serializers": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/pino-std-serializers/-/pino-std-serializers-6.0.0.tgz", - "integrity": "sha512-mMMOwSKrmyl+Y12Ri2xhH1lbzQxwwpuru9VjyJpgFIH4asSj88F2csdMwN6+M5g1Ll4rmsYghHLQJw81tgZ7LQ==", - "dev": true - }, - "node_modules/postcss": { - "version": "8.4.19", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.19.tgz", - "integrity": "sha512-h+pbPsyhlYj6N2ozBmHhHrs9DzGmbaarbLvWipMRO7RLS+v4onj26MPFXA5OBYFxyqYhUJK456SwDcY9H2/zsA==", + "node_modules/pino-abstract-transport/node_modules/string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/postcss" - } - ], "dependencies": { - "nanoid": "^3.3.4", - "picocolors": "^1.0.0", - "source-map-js": "^1.0.2" - }, - "engines": { - "node": "^10 || ^12 || >=14" + "safe-buffer": "~5.2.0" } }, + "node_modules/pino-std-serializers": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/pino-std-serializers/-/pino-std-serializers-6.2.2.tgz", + "integrity": "sha512-cHjPPsE+vhj/tnhCy/wiMh3M3z3h/j15zHQX+S9GkTBgqJuTuJzYJ4gUyACLhDaJ7kk9ba9iRDmbH2tJU03OiA==", + "dev": true + }, "node_modules/prelude-ls": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", @@ -3964,13 +4097,12 @@ "node_modules/process-nextick-args": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", - "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", - "dev": true + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==" }, "node_modules/process-warning": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/process-warning/-/process-warning-2.0.0.tgz", - "integrity": "sha512-+MmoAXoUX+VTHAlwns0h+kFUWFs/3FZy+ZuchkgjyOu3oioLAo2LB5aCfKPh2+P9O18i3m43tUEv3YqttSy0Ww==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/process-warning/-/process-warning-3.0.0.tgz", + "integrity": "sha512-mqn0kFRl0EoqhnL0GQ0veqFHyIN1yig9RHh/InzORTUiZHFRAur+aMtRkELNwGs9aNwKS6tg/An4NYBPGwvtzQ==", "dev": true }, "node_modules/promise-toolbox": { @@ -4008,9 +4140,9 @@ } }, "node_modules/punycode": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", - "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", "dev": true, "engines": { "node": ">=6" @@ -4121,7 +4253,6 @@ "version": "2.3.7", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", - "dev": true, "dependencies": { "core-util-is": "~1.0.0", "inherits": "~2.0.3", @@ -4135,8 +4266,7 @@ "node_modules/readable-stream/node_modules/safe-buffer": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "dev": true + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" }, "node_modules/real-require": { "version": "0.2.0", @@ -4153,18 +4283,6 @@ "integrity": "sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==", "dev": true }, - "node_modules/regexpp": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz", - "integrity": "sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==", - "dev": true, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/mysticatea" - } - }, "node_modules/registry-auth-token": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/registry-auth-token/-/registry-auth-token-5.0.1.tgz", @@ -4451,9 +4569,9 @@ "optional": true }, "node_modules/safe-stable-stringify": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/safe-stable-stringify/-/safe-stable-stringify-2.4.1.tgz", - "integrity": "sha512-dVHE6bMtS/bnL2mwualjc6IxEv1F+OCUpA46pKUj6F8uDbUM0jCCulPqRNPSnWwGNKx5etqMjZYdXtrm5KJZGA==", + "version": "2.4.3", + "resolved": "https://registry.npmjs.org/safe-stable-stringify/-/safe-stable-stringify-2.4.3.tgz", + "integrity": "sha512-e2bDA2WJT0wxseVd4lsDP4+3ONX6HpMXQa1ZhFQ7SU+GjvORCmShbCMltrtIDfkYhVHrOcPtj+KhmDBdPdZD1g==", "dev": true, "engines": { "node": ">=10" @@ -4466,19 +4584,16 @@ "dev": true }, "node_modules/sax": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", - "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==", + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/sax/-/sax-1.4.1.tgz", + "integrity": "sha512-+aWOz7yVScEGoKNd4PA10LZ8sk0A/z5+nXQG5giUO5rprX9jgYsTdov9qCchZiPIZezbZH+jRut8nPodFAX4Jg==", "dev": true }, "node_modules/semver": { - "version": "7.3.8", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", - "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", + "version": "7.6.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", + "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", "dev": true, - "dependencies": { - "lru-cache": "^6.0.0" - }, "bin": { "semver": "bin/semver.js" }, @@ -4501,14 +4616,10 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/set-immediate-shim": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/set-immediate-shim/-/set-immediate-shim-1.0.1.tgz", - "integrity": "sha1-SysbJ+uAip+NzEgaWOXlb1mfP2E=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } + "node_modules/setimmediate": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz", + "integrity": "sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==" }, "node_modules/sha.js": { "version": "2.4.11", @@ -4557,17 +4668,18 @@ "dev": true }, "node_modules/sign-addon": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/sign-addon/-/sign-addon-5.1.0.tgz", - "integrity": "sha512-fag/csbsw25WpW+G+uWE6rRImSjlfwQNjuP28fFhvXpfW+kXccxl/o1QEW+hXtTidwpysksb7Y0B8UCeMkYkSA==", + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/sign-addon/-/sign-addon-5.3.0.tgz", + "integrity": "sha512-7nHlCzhQgVMLBNiXVEgbG/raq48awOW0lYMN5uo1BaB3mp0+k8M8pvDwbfTlr3apcxZJsk9HQsAW1POwoJugpQ==", + "deprecated": "Package no longer supported. Contact Support at https://www.npmjs.com/support for more info.", "dev": true, "dependencies": { "common-tags": "1.8.2", - "core-js": "3.25.3", + "core-js": "3.29.0", "deepcopy": "2.1.0", "es6-error": "4.1.1", "es6-promisify": "7.0.0", - "jsonwebtoken": "8.5.1", + "jsonwebtoken": "9.0.0", "mz": "2.7.0", "request": "2.88.2", "source-map-support": "0.5.21", @@ -4581,9 +4693,9 @@ "dev": true }, "node_modules/sonic-boom": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/sonic-boom/-/sonic-boom-3.2.0.tgz", - "integrity": "sha512-SbbZ+Kqj/XIunvIAgUZRlqd6CGQYq71tRRbXR92Za8J/R3Yh4Av+TWENiSiEgnlwckYLyP0YZQWVfyNC0dzLaA==", + "version": "3.8.1", + "resolved": "https://registry.npmjs.org/sonic-boom/-/sonic-boom-3.8.1.tgz", + "integrity": "sha512-y4Z8LCDBuum+PBP3lSV7RHrXscqksve/bi0as7mhwVnBW+/wUqKT/2Kb7um8yqcFy0duYbbPxzt89Zy2nOCaxg==", "dev": true, "dependencies": { "atomic-sleep": "^1.0.0" @@ -4598,15 +4710,6 @@ "node": ">=0.10.0" } }, - "node_modules/source-map-js": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz", - "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/source-map-support": { "version": "0.5.21", "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", @@ -4641,18 +4744,18 @@ } }, "node_modules/split2": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/split2/-/split2-4.1.0.tgz", - "integrity": "sha512-VBiJxFkxiXRlUIeyMQi8s4hgvKCSjtknJv/LVYbrgALPwf5zSKmEwV9Lst25AkvMDnvxODugjdl6KZgwKM1WYQ==", + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/split2/-/split2-4.2.0.tgz", + "integrity": "sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==", "dev": true, "engines": { "node": ">= 10.x" } }, "node_modules/sshpk": { - "version": "1.17.0", - "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.17.0.tgz", - "integrity": "sha512-/9HIEs1ZXGhSPE8X6Ccm7Nam1z8KcoCqPdI7ecm1N33EzAetWahvQWVqLZtaZQ+IDKX4IyA2o0gBzqIMkAagHQ==", + "version": "1.18.0", + "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.18.0.tgz", + "integrity": "sha512-2p2KJZTSqQ/I3+HX42EpYOa2l3f8Erv8MWKsy2I9uf4wA7yFIkXRffYdsx86y6z4vHtV8u7g+pPlr8/4ouAxsQ==", "dev": true, "dependencies": { "asn1": "~0.2.3", @@ -4701,7 +4804,6 @@ "version": "1.1.1", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "dev": true, "dependencies": { "safe-buffer": "~5.1.0" } @@ -4709,8 +4811,7 @@ "node_modules/string_decoder/node_modules/safe-buffer": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "dev": true + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" }, "node_modules/string-width": { "version": "5.1.2", @@ -4729,6 +4830,27 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/string-width-cjs": { + "name": "string-width", + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/string-width-cjs/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true + }, "node_modules/string-width/node_modules/ansi-regex": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", @@ -4768,6 +4890,19 @@ "node": ">=8" } }, + "node_modules/strip-ansi-cjs": { + "name": "strip-ansi", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/strip-bom": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-5.0.0.tgz", @@ -4866,9 +5001,9 @@ } }, "node_modules/thread-stream": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/thread-stream/-/thread-stream-2.2.0.tgz", - "integrity": "sha512-rUkv4/fnb4rqy/gGy7VuqK6wE1+1DOCOWy4RMeaV69ZHMP11tQKZvZSip1yTgrKCMZzEMcCL/bKfHvSfDHx+iQ==", + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/thread-stream/-/thread-stream-2.7.0.tgz", + "integrity": "sha512-qQiRWsU/wvNolI6tbbCKd9iKaTnCXsTwVxhhKM6nctPdujTyztjlbUkUTUymidWcMnZ5pWR0ej4a0tjsW021vw==", "dev": true, "dependencies": { "real-require": "^0.2.0" @@ -4953,9 +5088,9 @@ } }, "node_modules/type-detect": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", - "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.1.0.tgz", + "integrity": "sha512-Acylog8/luQ8L7il+geoSxhEkazvkslg7PSNKOX59mbB9cOveP5aq9h74Y7YU8yDpJwetzQQrfIwtf4Wp4LKcw==", "dev": true, "engines": { "node": ">=4" @@ -5004,9 +5139,9 @@ } }, "node_modules/universalify": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz", - "integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", + "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", "dev": true, "engines": { "node": ">= 10.0.0" @@ -5074,8 +5209,7 @@ "node_modules/util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=", - "dev": true + "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" }, "node_modules/uuid": { "version": "8.3.2", @@ -5129,42 +5263,42 @@ } }, "node_modules/web-ext": { - "version": "7.4.0", - "resolved": "https://registry.npmjs.org/web-ext/-/web-ext-7.4.0.tgz", - "integrity": "sha512-dT2HJaGNXxRNuOtzaVBtEULccL0kM2SN1ark1NnN/ZSlbucobBxCDj6119iki72YyuXpaXZCJGqfZtVf1Znocg==", + "version": "7.12.0", + "resolved": "https://registry.npmjs.org/web-ext/-/web-ext-7.12.0.tgz", + "integrity": "sha512-h+uWOYBlHlPKy5CqxuZKocgOdL8J7I4ctMw/rAGbQl7jq7tr+NmY/Lhh2FPMSlJ1Y0T2VeUqwBVighK0MM1+zA==", "dev": true, "dependencies": { - "@babel/runtime": "7.20.1", + "@babel/runtime": "7.21.0", "@devicefarmer/adbkit": "3.2.3", - "addons-linter": "5.23.0", + "addons-linter": "6.28.0", "bunyan": "1.8.15", - "camelcase": "7.0.0", + "camelcase": "7.0.1", "chrome-launcher": "0.15.1", "debounce": "1.2.1", "decamelize": "6.0.0", "es6-error": "4.1.1", - "firefox-profile": "4.2.2", - "fs-extra": "10.1.0", - "fx-runner": "1.3.0", + "firefox-profile": "4.3.2", + "fs-extra": "11.1.0", + "fx-runner": "1.4.0", "import-fresh": "3.3.0", - "jose": "4.11.1", + "jose": "4.13.1", "mkdirp": "1.0.4", "multimatch": "6.0.0", "mz": "2.7.0", - "node-fetch": "3.3.0", + "node-fetch": "3.3.1", "node-notifier": "10.0.1", - "open": "8.4.0", + "open": "8.4.2", "parse-json": "6.0.2", "promise-toolbox": "0.21.0", - "sign-addon": "5.1.0", + "sign-addon": "5.3.0", "source-map-support": "0.5.21", "strip-bom": "5.0.0", "strip-json-comments": "5.0.0", "tmp": "0.2.1", "update-notifier": "6.0.2", "watchpack": "2.4.0", - "ws": "8.11.0", - "yargs": "17.6.2", + "ws": "8.13.0", + "yargs": "17.7.1", "zip-dir": "2.0.0" }, "bin": { @@ -5176,9 +5310,9 @@ } }, "node_modules/web-streams-polyfill": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-3.2.1.tgz", - "integrity": "sha512-e0MO3wdXWKrLbL0DgGnUV7WHVuw9OUvL4hjgnPkIeEvESk74gAITi5G606JtZPp39cd8HA9VQzCIvA49LpPN5Q==", + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-3.3.3.tgz", + "integrity": "sha512-d2JWLCivmZYTSIoge9MsgFCZrt571BikcWGYkjC1khllbTeDlGqZ2D8vD8E/lJa8WGWbb7Plm8/XJYV7IJHZZw==", "dev": true, "engines": { "node": ">= 8" @@ -5247,18 +5381,18 @@ "dev": true }, "node_modules/word-wrap": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", - "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==", + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", + "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", "dev": true, "engines": { "node": ">=0.10.0" } }, "node_modules/wrap-ansi": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.0.1.tgz", - "integrity": "sha512-QFF+ufAqhoYHvoHdajT/Po7KoXVBPXS2bgjIam5isfWJPfIOnQZ50JtUiVvCv/sjgacf3yRrt2ZKUZ/V4itN4g==", + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", + "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", "dev": true, "dependencies": { "ansi-styles": "^6.1.0", @@ -5272,6 +5406,44 @@ "url": "https://github.com/chalk/wrap-ansi?sponsor=1" } }, + "node_modules/wrap-ansi-cjs": { + "name": "wrap-ansi", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrap-ansi-cjs/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true + }, + "node_modules/wrap-ansi-cjs/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/wrap-ansi/node_modules/ansi-regex": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", @@ -5330,16 +5502,16 @@ } }, "node_modules/ws": { - "version": "8.11.0", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.11.0.tgz", - "integrity": "sha512-HPG3wQd9sNQoT9xHyNCXoDUa+Xw/VevmY9FoHyQ+g+rrMn4j6FB4np7Z0OhdTgjx6MgQLK7jwSy1YecU1+4Asg==", + "version": "8.13.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.13.0.tgz", + "integrity": "sha512-x9vcZYTrFPC7aSIbj7sRCYo7L/Xb8Iy+pW0ng0wt2vCJv7M9HOMy0UoN3rr+IFC7hb7vXoqS+P9ktyLLLhO+LA==", "dev": true, "engines": { "node": ">=10.0.0" }, "peerDependencies": { "bufferutil": "^4.0.1", - "utf-8-validate": "^5.0.2" + "utf-8-validate": ">=5.0.2" }, "peerDependenciesMeta": { "bufferutil": { @@ -5363,9 +5535,9 @@ } }, "node_modules/xml2js": { - "version": "0.4.23", - "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.4.23.tgz", - "integrity": "sha512-ySPiMjM0+pLDftHgXY4By0uswI3SPKLDw/i3UXbnO8M/p28zqexCUoPmQFrYD+/1BzhGJSs2i1ERWKJAtiLrug==", + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.5.0.tgz", + "integrity": "sha512-drPFnkQJik/O+uPKpqSgr22mpuFHqKdbS835iAQrUC73L2F5WkboIRd63ai/2Yg6I1jzifPFKH2NTK+cfglkIA==", "dev": true, "dependencies": { "sax": ">=0.6.0", @@ -5393,16 +5565,10 @@ "node": ">=10" } }, - "node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true - }, "node_modules/yargs": { - "version": "17.6.2", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.6.2.tgz", - "integrity": "sha512-1/9UrdHjDZc0eOU0HxOHoS78C69UD3JRMvzlJ7S79S2nTaWRA/whGCTV8o9e/N/1Va9YIV7Q4sOxD8VV4pCWOw==", + "version": "17.7.1", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.1.tgz", + "integrity": "sha512-cwiTb08Xuv5fqF4AovYacTFNxk62th7LKJ6BL9IGUpTJrWoU7/7WdQGTP2SjKf1dUNBGzDd28p/Yfs/GI6JrLw==", "dev": true, "dependencies": { "cliui": "^8.0.1", @@ -5571,12 +5737,12 @@ } }, "@babel/runtime": { - "version": "7.20.1", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.20.1.tgz", - "integrity": "sha512-mrzLkl6U9YLF8qpqI7TB82PESyEGjm/0Ly91jG575eVxMMlb8fYfOXFZIJ8XfLrJZQbm7dlKry2bJmXBUEkdFg==", + "version": "7.21.0", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.21.0.tgz", + "integrity": "sha512-xwII0//EObnq89Ji5AKYQaRYiW/nZ3llSv29d49IuxPhKbtJoLP+9QUUZ4nVragQVtaVGeZrpB+ZtG/Pdy/POw==", "dev": true, "requires": { - "regenerator-runtime": "^0.13.10" + "regenerator-runtime": "^0.13.11" } }, "@devicefarmer/adbkit": { @@ -5606,16 +5772,39 @@ "integrity": "sha512-ZzZY/b66W2Jd6NHbAhLyDWOEIBWC11VizGFk7Wx7M61JZRz7HR9Cq5P+65RKWUU7u6wgsE8Lmh9nE4Mz+U2eTg==", "dev": true }, + "@eslint-community/eslint-utils": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz", + "integrity": "sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==", + "dev": true, + "requires": { + "eslint-visitor-keys": "^3.3.0" + }, + "dependencies": { + "eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "dev": true + } + } + }, + "@eslint-community/regexpp": { + "version": "4.11.0", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.11.0.tgz", + "integrity": "sha512-G/M/tIiMrTAxEWRfLfQJMmGNX28IxBg4PBz8XqQhqUHLFI6TL2htpIB1iQCj144V5ee/JaKyT9/WZ0MGZWfA7A==", + "dev": true + }, "@eslint/eslintrc": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.3.3.tgz", - "integrity": "sha512-uj3pT6Mg+3t39fvLrj8iuCIJ38zKO9FpGtJ4BBJebJhEwjoT+KLVNCcHT5QC9NGRIEi7fZ0ZR8YRb884auB4Lg==", + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.4.tgz", + "integrity": "sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==", "dev": true, "requires": { "ajv": "^6.12.4", "debug": "^4.3.2", - "espree": "^9.4.0", - "globals": "^13.15.0", + "espree": "^9.6.0", + "globals": "^13.19.0", "ignore": "^5.2.0", "import-fresh": "^3.2.1", "js-yaml": "^4.1.0", @@ -5635,6 +5824,23 @@ "uri-js": "^4.2.2" } }, + "eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "dev": true + }, + "espree": { + "version": "9.6.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz", + "integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==", + "dev": true, + "requires": { + "acorn": "^8.9.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^3.4.1" + } + }, "json-schema-traverse": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", @@ -5649,14 +5855,26 @@ } } }, + "@eslint/js": { + "version": "8.57.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.57.0.tgz", + "integrity": "sha512-Ys+3g2TaW7gADOJzPt83SJtCDhMjndcDMFVQ/Tj9iA1BfJzFKD9mAUXT3OenpuPHbI6P/myECxRJrofUsDx/5g==", + "dev": true + }, + "@fluent/syntax": { + "version": "0.19.0", + "resolved": "https://registry.npmjs.org/@fluent/syntax/-/syntax-0.19.0.tgz", + "integrity": "sha512-5D2qVpZrgpjtqU4eNOcWGp1gnUCgjfM+vKGE2y03kKN6z5EBhtx0qdRFbg8QuNNj8wXNoX93KJoYb+NqoxswmQ==", + "dev": true + }, "@humanwhocodes/config-array": { - "version": "0.11.7", - "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.7.tgz", - "integrity": "sha512-kBbPWzN8oVMLb0hOUYXhmxggL/1cJE6ydvjDIGi9EnAGUyA7cLVKQg+d/Dsm+KZwx2czGHrCmMVLiyg8s5JPKw==", + "version": "0.11.14", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.14.tgz", + "integrity": "sha512-3T8LkOmg45BV5FICb15QQMsyUSWrQ8AygVfC7ZG32zOalnqrilm018ZVCw0eapXux8FtA33q8PSRSstjee3jSg==", "dev": true, "requires": { - "@humanwhocodes/object-schema": "^1.2.1", - "debug": "^4.1.1", + "@humanwhocodes/object-schema": "^2.0.2", + "debug": "^4.3.1", "minimatch": "^3.0.5" } }, @@ -5667,15 +5885,46 @@ "dev": true }, "@humanwhocodes/object-schema": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz", - "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==", + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.3.tgz", + "integrity": "sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==", "dev": true }, + "@isaacs/cliui": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", + "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", + "dev": true, + "requires": { + "string-width": "^5.1.2", + "string-width-cjs": "npm:string-width@^4.2.0", + "strip-ansi": "^7.0.1", + "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", + "wrap-ansi": "^8.1.0", + "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" + }, + "dependencies": { + "ansi-regex": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", + "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", + "dev": true + }, + "strip-ansi": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", + "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", + "dev": true, + "requires": { + "ansi-regex": "^6.0.1" + } + } + } + }, "@mdn/browser-compat-data": { - "version": "5.2.17", - "resolved": "https://registry.npmjs.org/@mdn/browser-compat-data/-/browser-compat-data-5.2.17.tgz", - "integrity": "sha512-aA+rFHhXmq14GVIcEWNk8OntLEOQFwEZk9ZgG5VcDquz+pQhIjJPXacR+rwL9Z0Elfg909EcRRHC96p06/CNUg==", + "version": "5.5.29", + "resolved": "https://registry.npmjs.org/@mdn/browser-compat-data/-/browser-compat-data-5.5.29.tgz", + "integrity": "sha512-NHdG3QOiAsxh8ygBSKMa/WaNJwpNt87uVqW+S2RlnSqgeRdk+L3foNWTX6qd0I3NHSlCFb47rgopeNCJtRDY5A==", "dev": true }, "@nodelib/fs.scandir": { @@ -5704,6 +5953,13 @@ "fastq": "^1.6.0" } }, + "@pkgjs/parseargs": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", + "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", + "dev": true, + "optional": true + }, "@pnpm/network.ca-file": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/@pnpm/network.ca-file/-/network.ca-file-1.0.1.tgz", @@ -5751,14 +6007,20 @@ "dev": true }, "@types/yauzl": { - "version": "2.10.0", - "resolved": "https://registry.npmjs.org/@types/yauzl/-/yauzl-2.10.0.tgz", - "integrity": "sha512-Cn6WYCm0tXv8p6k+A8PvbDG763EDpBoTzHdA+Q/MF6H3sapGjCm9NzoaJncJS9tUKSuCoDs9XHxYYsQDgxR6kw==", + "version": "2.10.3", + "resolved": "https://registry.npmjs.org/@types/yauzl/-/yauzl-2.10.3.tgz", + "integrity": "sha512-oJoftv0LSuaDZE3Le4DbKX+KS9G36NzOeSap90UIK0yMA/NhKJhqlSGtNDORNRaIbQfzjXDrQa0ytJ6mNRGz/Q==", "dev": true, "requires": { "@types/node": "*" } }, + "@ungap/structured-clone": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.2.0.tgz", + "integrity": "sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==", + "dev": true + }, "abort-controller": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz", @@ -5769,9 +6031,9 @@ } }, "acorn": { - "version": "8.8.1", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.1.tgz", - "integrity": "sha512-7zFpHzhnqYKrkYdUjF1HI1bzd0VygEGX8lFk4k5zVMqHEoES+P+7TKI+EvLO9WVMJ8eekdO0aDEK044xTXwPPA==", + "version": "8.12.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.12.1.tgz", + "integrity": "sha512-tcpGyI9zbizT9JbV6oYE477V6mTlXvvi0T0G3SNIYE2apm/G5huBa1+K89VGeovbg+jycCrfhl3ADxErOuO6Jg==", "dev": true }, "acorn-jsx": { @@ -5782,51 +6044,51 @@ "requires": {} }, "addons-linter": { - "version": "5.23.0", - "resolved": "https://registry.npmjs.org/addons-linter/-/addons-linter-5.23.0.tgz", - "integrity": "sha512-Vo6+5YlM2Ge3yYMY+gNg9Smcfcl1J0ZMfGVXnGJjUwDVHuszHVIvurunQuJURnO4FR1gi4Vy1sWye8ArRL5LOw==", + "version": "6.28.0", + "resolved": "https://registry.npmjs.org/addons-linter/-/addons-linter-6.28.0.tgz", + "integrity": "sha512-fCTjXL/yG4hwq74JG8tQdrvEu0OvGrEN9yU+Df0020RDtHl3g/tTCyMeC4G1uyk8IuyMzp4myCBNnOGC7MWSQQ==", "dev": true, "requires": { - "@mdn/browser-compat-data": "5.2.17", + "@fluent/syntax": "0.19.0", + "@mdn/browser-compat-data": "5.5.29", "addons-moz-compare": "1.3.0", - "addons-scanner-utils": "8.1.0", - "ajv": "8.11.2", - "ajv-merge-patch": "5.0.1", + "addons-scanner-utils": "9.10.1", + "ajv": "8.13.0", "chalk": "4.1.2", "cheerio": "1.0.0-rc.12", "columnify": "1.6.0", "common-tags": "1.8.2", - "deepmerge": "4.2.2", - "eslint": "8.28.0", - "eslint-plugin-no-unsanitized": "4.0.1", - "eslint-visitor-keys": "3.3.0", - "espree": "9.4.1", + "deepmerge": "4.3.1", + "eslint": "8.57.0", + "eslint-plugin-no-unsanitized": "4.0.2", + "eslint-visitor-keys": "4.0.0", + "espree": "10.0.1", "esprima": "4.0.1", - "fluent-syntax": "0.13.0", - "glob": "8.0.3", - "image-size": "1.0.2", + "fast-json-patch": "3.1.1", + "glob": "10.4.1", + "image-size": "1.1.1", "is-mergeable-object": "1.1.1", "jed": "1.1.1", + "json-merge-patch": "1.0.2", "os-locale": "5.0.0", - "pino": "8.7.0", - "postcss": "8.4.19", + "pino": "8.20.0", "relaxed-json": "1.0.3", - "semver": "7.3.8", + "semver": "7.6.2", "sha.js": "2.4.11", "source-map-support": "0.5.21", "tosource": "1.0.0", "upath": "2.0.1", - "yargs": "17.6.2", + "yargs": "17.7.2", "yauzl": "2.10.0" }, "dependencies": { "addons-scanner-utils": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/addons-scanner-utils/-/addons-scanner-utils-8.1.0.tgz", - "integrity": "sha512-wxqnmmrzZXjz4B4GZbFcR4HJxTP+pGu+C6iOjMJdmL6mgZZey/UEVJlU6XTxu8GdGv0bUoJxyIioH8XEDxy91Q==", + "version": "9.10.1", + "resolved": "https://registry.npmjs.org/addons-scanner-utils/-/addons-scanner-utils-9.10.1.tgz", + "integrity": "sha512-Tz9OUQx9Ja0TyQ+H2GakB9KlJ50myI6ESBGRlA8N80nHBzMjjPRFGm0APADSaCd5NP74SrFtEvL4TRpDwZXETA==", "dev": true, "requires": { - "@types/yauzl": "2.10.0", + "@types/yauzl": "2.10.3", "common-tags": "1.8.2", "first-chunk-stream": "3.0.0", "strip-bom-stream": "4.0.0", @@ -5843,37 +6105,75 @@ "balanced-match": "^1.0.0" } }, + "emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true + }, "glob": { - "version": "8.0.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-8.0.3.tgz", - "integrity": "sha512-ull455NHSHI/Y1FqGaaYFaLGkNMMJbavMrEGFXG/PGrg6y7sutWHUHrz6gy6WEBH6akM1M414dWKCNs+IhKdiQ==", + "version": "10.4.1", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.1.tgz", + "integrity": "sha512-2jelhlq3E4ho74ZyVLN03oKdAZVUa6UDZzFLVH1H7dnoax+y9qyaq8zBkfDIggjniU19z0wU18y16jMB2eyVIw==", "dev": true, "requires": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^5.0.1", - "once": "^1.3.0" + "foreground-child": "^3.1.0", + "jackspeak": "^3.1.2", + "minimatch": "^9.0.4", + "minipass": "^7.1.2", + "path-scurry": "^1.11.1" } }, "minimatch": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.1.tgz", - "integrity": "sha512-362NP+zlprccbEt/SkxKfRMHnNY85V74mVnpUpNyr3F35covl09Kec7/sEFLt3RA4oXmewtoaanoIf67SE5Y5g==", + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", + "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", "dev": true, "requires": { "brace-expansion": "^2.0.1" } }, - "node-fetch": { - "version": "2.6.7", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz", - "integrity": "sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==", + "node-fetch": { + "version": "2.6.11", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.11.tgz", + "integrity": "sha512-4I6pdBY1EthSqDmJkiNk3JIT8cswwR9nfeW/cPdUagJYEQG7R95WRH74wpz7ma8Gh/9dI9FP+OU+0E4FvtA55w==", + "dev": true, + "optional": true, + "peer": true, + "requires": { + "whatwg-url": "^5.0.0" + } + }, + "semver": { + "version": "7.6.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.2.tgz", + "integrity": "sha512-FNAIBWCx9qcRhoHcgcJ0gvU7SN1lYU2ZXuSfl04bSC5OpvDHFyJCjdNHomPXxjQlCBU67YW64PzY7/VIEH7F2w==", + "dev": true + }, + "string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "requires": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + } + }, + "yargs": { + "version": "17.7.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", + "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", "dev": true, - "optional": true, - "peer": true, "requires": { - "whatwg-url": "^5.0.0" + "cliui": "^8.0.1", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.3", + "y18n": "^5.0.5", + "yargs-parser": "^21.1.1" } } } @@ -5885,31 +6185,21 @@ "dev": true }, "adm-zip": { - "version": "0.5.9", - "resolved": "https://registry.npmjs.org/adm-zip/-/adm-zip-0.5.9.tgz", - "integrity": "sha512-s+3fXLkeeLjZ2kLjCBwQufpI5fuN+kIGBxu6530nVQZGVol0d7Y/M88/xw9HGGUcJjKf8LutN3VPRUBq6N7Ajg==", + "version": "0.5.15", + "resolved": "https://registry.npmjs.org/adm-zip/-/adm-zip-0.5.15.tgz", + "integrity": "sha512-jYPWSeOA8EFoZnucrKCNihqBjoEGQSU4HKgHYQgKNEQ0pQF9a/DYuo/+fAxY76k4qe75LUlLWpAM1QWcBMTOKw==", "dev": true }, "ajv": { - "version": "8.11.2", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.11.2.tgz", - "integrity": "sha512-E4bfmKAhGiSTvMfL1Myyycaub+cUEU2/IvpylXkUu7CHBkBj1f/ikdzbD7YQ6FKUbixDxeYvB/xY4fvyroDlQg==", + "version": "8.13.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.13.0.tgz", + "integrity": "sha512-PRA911Blj99jR5RMeTunVbNXMF6Lp4vZXnk5GQjcnUWUTsrXtekg/pnmFFI2u/I36Y/2bITGS30GZCXei6uNkA==", "dev": true, "requires": { - "fast-deep-equal": "^3.1.1", + "fast-deep-equal": "^3.1.3", "json-schema-traverse": "^1.0.0", "require-from-string": "^2.0.2", - "uri-js": "^4.2.2" - } - }, - "ajv-merge-patch": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ajv-merge-patch/-/ajv-merge-patch-5.0.1.tgz", - "integrity": "sha512-0UP3aJCzfzBOkmLR+EinJDCfg6DNtprj3bVPo7JJNgUpZMKt097t9xxQOWFGRoB4JvKKIHE2qe0HkVaS/HyrjQ==", - "dev": true, - "requires": { - "fast-json-patch": "^2.0.6", - "json-merge-patch": "^1.0.2" + "uri-js": "^4.4.1" } }, "ansi-align": { @@ -6013,9 +6303,9 @@ "dev": true }, "aws4": { - "version": "1.11.0", - "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.11.0.tgz", - "integrity": "sha512-xh1Rl34h6Fi1DC2WWKfxUTVqRsNnr6LsKz2+hfwDxQJWmrx8+c7ylaqBMcHfl1U1r2dsifOvKX3LQuLNZ+XSvA==", + "version": "1.13.1", + "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.13.1.tgz", + "integrity": "sha512-u5w79Rd7SU4JaIlA/zFqG+gOiuq25q5VLyZ8E+ijJeILuTxVzZgp2CaGw/UTw6pXYN9XMO9yiqj/nEHmhTG5CA==", "dev": true }, "balanced-match": { @@ -6166,9 +6456,9 @@ "dev": true }, "camelcase": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-7.0.0.tgz", - "integrity": "sha512-JToIvOmz6nhGsUhAYScbo2d6Py5wojjNfoxoc2mEVLUdJ70gJK2gnd+ABY1Tc3sVMyK7QDPtN0T/XdlCQWITyQ==", + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-7.0.1.tgz", + "integrity": "sha512-xlx1yCK2Oc1APsPXDL2LdlNP6+uu8OCDdhOBSVT279M/S+y75O30C2VuD8T2ogdePBBl7PfPF4504tnLgX3zfw==", "dev": true }, "caseless": { @@ -6383,16 +6673,15 @@ } }, "core-js": { - "version": "3.25.3", - "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.25.3.tgz", - "integrity": "sha512-y1hvKXmPHvm5B7w4ln1S4uc9eV/O5+iFExSRUimnvIph11uaizFR8LFMdONN8hG3P2pipUfX4Y/fR8rAEtcHcQ==", + "version": "3.29.0", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.29.0.tgz", + "integrity": "sha512-VG23vuEisJNkGl6XQmFJd3rEG/so/CNatqeE+7uZAwTSwFeB/qaO0be8xZYUNWprJ/GIwL8aMt9cj1kvbpTZhg==", "dev": true }, "core-util-is": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", - "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==", - "dev": true + "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==" }, "cross-spawn": { "version": "7.0.3", @@ -6451,9 +6740,9 @@ } }, "data-uri-to-buffer": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-4.0.0.tgz", - "integrity": "sha512-Vr3mLBA8qWmcuschSLAOogKgQ/Jwxulv3RNE4FXnYWRGujzrRWQI4m12fQqRkwX06C0KanhLr4hK+GydchZsaA==", + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-4.0.1.tgz", + "integrity": "sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A==", "dev": true }, "debounce": { @@ -6516,9 +6805,9 @@ } }, "deepmerge": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.2.2.tgz", - "integrity": "sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg==", + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz", + "integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==", "dev": true }, "defaults": { @@ -6584,14 +6873,14 @@ } }, "domutils": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/domutils/-/domutils-3.0.1.tgz", - "integrity": "sha512-z08c1l761iKhDFtfXO04C7kTdPBLi41zwOZl00WS8b5eiaebNpY00HKbztwBq+e3vyqWNwWF3mP9YLUeqIrF+Q==", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-3.1.0.tgz", + "integrity": "sha512-H78uMmQtI2AhgDJjWeQmHwJJ2bLPD3GMmO7Zja/ZZh84wkm+4ut+IUnUdRa8uCGX88DiVx1j6FRe1XfxEgjEZA==", "dev": true, "requires": { "dom-serializer": "^2.0.0", "domelementtype": "^2.3.0", - "domhandler": "^5.0.1" + "domhandler": "^5.0.3" } }, "dot-prop": { @@ -6654,9 +6943,9 @@ } }, "entities": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/entities/-/entities-4.4.0.tgz", - "integrity": "sha512-oYp7156SP8LkeGD0GF85ad1X9Ai79WtRsZ2gxJqtBuzH+98YUV6jkHEKlZkMbcrjJjIVJNIDP/3WL9wQkoPbWA==", + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", + "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", "dev": true }, "error-ex": { @@ -6681,9 +6970,9 @@ "dev": true }, "escalade": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", - "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.2.tgz", + "integrity": "sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA==", "dev": true }, "escape-goat": { @@ -6699,49 +6988,48 @@ "dev": true }, "eslint": { - "version": "8.28.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.28.0.tgz", - "integrity": "sha512-S27Di+EVyMxcHiwDrFzk8dJYAaD+/5SoWKxL1ri/71CRHsnJnRDPNt2Kzj24+MT9FDupf4aqqyqPrvI8MvQ4VQ==", + "version": "8.57.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.57.0.tgz", + "integrity": "sha512-dZ6+mexnaTIbSBZWgou51U6OmzIhYM2VcNdtiTtI7qPNZm35Akpr0f6vtw3w1Kmn5PYo+tZVfh13WrhpS6oLqQ==", "dev": true, "requires": { - "@eslint/eslintrc": "^1.3.3", - "@humanwhocodes/config-array": "^0.11.6", + "@eslint-community/eslint-utils": "^4.2.0", + "@eslint-community/regexpp": "^4.6.1", + "@eslint/eslintrc": "^2.1.4", + "@eslint/js": "8.57.0", + "@humanwhocodes/config-array": "^0.11.14", "@humanwhocodes/module-importer": "^1.0.1", "@nodelib/fs.walk": "^1.2.8", - "ajv": "^6.10.0", + "@ungap/structured-clone": "^1.2.0", + "ajv": "^6.12.4", "chalk": "^4.0.0", "cross-spawn": "^7.0.2", "debug": "^4.3.2", "doctrine": "^3.0.0", "escape-string-regexp": "^4.0.0", - "eslint-scope": "^7.1.1", - "eslint-utils": "^3.0.0", - "eslint-visitor-keys": "^3.3.0", - "espree": "^9.4.0", - "esquery": "^1.4.0", + "eslint-scope": "^7.2.2", + "eslint-visitor-keys": "^3.4.3", + "espree": "^9.6.1", + "esquery": "^1.4.2", "esutils": "^2.0.2", "fast-deep-equal": "^3.1.3", "file-entry-cache": "^6.0.1", "find-up": "^5.0.0", "glob-parent": "^6.0.2", - "globals": "^13.15.0", - "grapheme-splitter": "^1.0.4", + "globals": "^13.19.0", + "graphemer": "^1.4.0", "ignore": "^5.2.0", - "import-fresh": "^3.0.0", "imurmurhash": "^0.1.4", "is-glob": "^4.0.0", "is-path-inside": "^3.0.3", - "js-sdsl": "^4.1.4", "js-yaml": "^4.1.0", "json-stable-stringify-without-jsonify": "^1.0.1", "levn": "^0.4.1", "lodash.merge": "^4.6.2", "minimatch": "^3.1.2", "natural-compare": "^1.4.0", - "optionator": "^0.9.1", - "regexpp": "^3.2.0", + "optionator": "^0.9.3", "strip-ansi": "^6.0.1", - "strip-json-comments": "^3.1.0", "text-table": "^0.2.0" }, "dependencies": { @@ -6757,69 +7045,63 @@ "uri-js": "^4.2.2" } }, + "eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "dev": true + }, + "espree": { + "version": "9.6.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz", + "integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==", + "dev": true, + "requires": { + "acorn": "^8.9.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^3.4.1" + } + }, "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 - }, - "strip-json-comments": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", - "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", - "dev": true } } }, "eslint-plugin-no-unsanitized": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/eslint-plugin-no-unsanitized/-/eslint-plugin-no-unsanitized-4.0.1.tgz", - "integrity": "sha512-y/lAMWnPPC7RYuUdxlEL/XiCL8FehN9h9s3Kjqbp/Kv0i9NZs+IXSC2kS546Fa4Bumwy31HlVS/OdWX0Kxb5Xg==", + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/eslint-plugin-no-unsanitized/-/eslint-plugin-no-unsanitized-4.0.2.tgz", + "integrity": "sha512-Pry0S9YmHoz8NCEMRQh7N0Yexh2MYCNPIlrV52hTmS7qXnTghWsjXouF08bgsrrZqaW9tt1ZiK3j5NEmPE+EjQ==", "dev": true, "requires": {} }, "eslint-scope": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.1.1.tgz", - "integrity": "sha512-QKQM/UXpIiHcLqJ5AOyIW7XZmzjkzQXYE54n1++wb0u9V/abW3l9uQnxX8Z5Xd18xyKIMTUAyQ0k1e8pz6LUrw==", + "version": "7.2.2", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz", + "integrity": "sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==", "dev": true, "requires": { "esrecurse": "^4.3.0", "estraverse": "^5.2.0" } }, - "eslint-utils": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-3.0.0.tgz", - "integrity": "sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==", - "dev": true, - "requires": { - "eslint-visitor-keys": "^2.0.0" - }, - "dependencies": { - "eslint-visitor-keys": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz", - "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==", - "dev": true - } - } - }, "eslint-visitor-keys": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz", - "integrity": "sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.0.0.tgz", + "integrity": "sha512-OtIRv/2GyiF6o/d8K7MYKKbXrOUBIK6SfkIRM4Z0dY3w+LiQ0vy3F57m0Z71bjbyeiWFiHJ8brqnmE6H6/jEuw==", "dev": true }, "espree": { - "version": "9.4.1", - "resolved": "https://registry.npmjs.org/espree/-/espree-9.4.1.tgz", - "integrity": "sha512-XwctdmTO6SIvCzd9810yyNzIrOrqNYV9Koizx4C/mRhf9uq0o4yHoCEU/670pOxOL/MSraektvSAji79kX90Vg==", + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-10.0.1.tgz", + "integrity": "sha512-MWkrWZbJsL2UwnjxTX3gG8FneachS/Mwg7tdGXce011sJd5b0JG54vat5KHnfSBODZ3Wvzd2WnjxyzsRoVv+ww==", "dev": true, "requires": { - "acorn": "^8.8.0", + "acorn": "^8.11.3", "acorn-jsx": "^5.3.2", - "eslint-visitor-keys": "^3.3.0" + "eslint-visitor-keys": "^4.0.0" } }, "esprima": { @@ -6829,9 +7111,9 @@ "dev": true }, "esquery": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.4.0.tgz", - "integrity": "sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w==", + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.6.0.tgz", + "integrity": "sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==", "dev": true, "requires": { "estraverse": "^5.1.0" @@ -6906,21 +7188,10 @@ "dev": true }, "fast-json-patch": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/fast-json-patch/-/fast-json-patch-2.2.1.tgz", - "integrity": "sha512-4j5uBaTnsYAV5ebkidvxiLUYOwjQ+JSFljeqfTxCrH9bDmlCQaOJFS84oDJ2rAXZq2yskmk3ORfoP9DCwqFNig==", - "dev": true, - "requires": { - "fast-deep-equal": "^2.0.1" - }, - "dependencies": { - "fast-deep-equal": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz", - "integrity": "sha512-bCK/2Z4zLidyB4ReuIsvALH6w31YfAQDmXMqMx6FyfHqvBxtjC0eRumeSu4Bs3XtXwpyIywtSTrVT99BxY1f9w==", - "dev": true - } - } + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/fast-json-patch/-/fast-json-patch-3.1.1.tgz", + "integrity": "sha512-vf6IHUX2SBcA+5/+4883dsIjpBTqmfBjmYiWK1savxQmFk4JfBMLa7ynTYOs1Rolp/T1betJxHiGD3g1Mn8lUQ==", + "dev": true }, "fast-json-stable-stringify": { "version": "2.1.0", @@ -6935,15 +7206,15 @@ "dev": true }, "fast-redact": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/fast-redact/-/fast-redact-3.1.2.tgz", - "integrity": "sha512-+0em+Iya9fKGfEQGcd62Yv6onjBmmhV1uh86XVfOU8VwAe6kaFdQCWI9s0/Nnugx5Vd9tdbZ7e6gE2tR9dzXdw==", + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/fast-redact/-/fast-redact-3.5.0.tgz", + "integrity": "sha512-dwsoQlS7h9hMeYUq1W++23NDcBLV4KqONnITDV9DjfS3q1SgDGVrBdvvTLUotWtPSD7asWDV9/CmsZPy8Hf70A==", "dev": true }, "fastq": { - "version": "1.13.0", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.13.0.tgz", - "integrity": "sha512-YpkpUnK8od0o1hmeSc7UUs/eB/vIPWJYjKck2QKIzAf71Vm1AAQ3EbuZB3g2JIy+pg+ERD0vqI79KyZiB2e2Nw==", + "version": "1.17.1", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.17.1.tgz", + "integrity": "sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==", "dev": true, "requires": { "reusify": "^1.0.4" @@ -6988,16 +7259,16 @@ } }, "firefox-profile": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/firefox-profile/-/firefox-profile-4.2.2.tgz", - "integrity": "sha512-3kI17Xl9dL9AeRkpV1yahsJ+UbekkPtlQswKrIsTY1NLgxtEOR4R19rjGGz5+7/rP8Jt6fvxHk+Bai9R6Eai3w==", + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/firefox-profile/-/firefox-profile-4.3.2.tgz", + "integrity": "sha512-/C+Eqa0YgIsQT2p66p7Ygzqe7NlE/GNTbhw2SBCm5V3OsWDPITNdTPEcH2Q2fe7eMpYYNPKdUcuVioZBZiR6kA==", "dev": true, "requires": { "adm-zip": "~0.5.x", "fs-extra": "~9.0.1", "ini": "~2.0.0", "minimist": "^1.2.5", - "xml2js": "~0.4.23" + "xml2js": "^0.5.0" }, "dependencies": { "fs-extra": { @@ -7027,26 +7298,39 @@ "dev": true }, "flat-cache": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz", - "integrity": "sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==", + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.2.0.tgz", + "integrity": "sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==", "dev": true, "requires": { - "flatted": "^3.1.0", + "flatted": "^3.2.9", + "keyv": "^4.5.3", "rimraf": "^3.0.2" } }, "flatted": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.7.tgz", - "integrity": "sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==", + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.1.tgz", + "integrity": "sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw==", "dev": true }, - "fluent-syntax": { - "version": "0.13.0", - "resolved": "https://registry.npmjs.org/fluent-syntax/-/fluent-syntax-0.13.0.tgz", - "integrity": "sha512-0Bk1AsliuYB550zr4JV9AYhsETsD3ELXUQzdXGJfIc1Ni/ukAfBdQInDhVMYJUaT2QxoamNslwkYF7MlOrPUwg==", - "dev": true + "foreground-child": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.0.tgz", + "integrity": "sha512-Ld2g8rrAyMYFXBhEqMz8ZAHBi4J4uS1i/CxGMDnjyFWddMXLVcDp051DZfu+t7+ab7Wv6SMqpWmyFIj5UbfFvg==", + "dev": true, + "requires": { + "cross-spawn": "^7.0.0", + "signal-exit": "^4.0.1" + }, + "dependencies": { + "signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "dev": true + } + } }, "forever-agent": { "version": "0.6.1", @@ -7081,9 +7365,9 @@ } }, "fs-extra": { - "version": "10.1.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz", - "integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==", + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.1.0.tgz", + "integrity": "sha512-0rcTq621PD5jM/e0a3EJoGC/1TC5ZBCERW82LQuwfGnCa1V8w7dpYH1yNu+SLb6E5dkeCBzKEyLGlFrnr+dUyw==", "dev": true, "requires": { "graceful-fs": "^4.2.0", @@ -7098,9 +7382,9 @@ "dev": true }, "fx-runner": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/fx-runner/-/fx-runner-1.3.0.tgz", - "integrity": "sha512-5b37H4GCyhF+Nf8xk9mylXoDq4wb7pbGAXxlCXp/631UTeeZomWSYcEGXumY4wk8g2QAqjPMGdWW+RbNt8PUcA==", + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/fx-runner/-/fx-runner-1.4.0.tgz", + "integrity": "sha512-rci1g6U0rdTg6bAaBboP7XdRu01dzTAaKXxFf+PUqGuCv6Xu7o8NZdY1D5MvKGIjb6EdS1g3VlXOgksir1uGkg==", "dev": true, "requires": { "commander": "2.9.0", @@ -7201,9 +7485,9 @@ } }, "globals": { - "version": "13.18.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.18.0.tgz", - "integrity": "sha512-/mR4KI8Ps2spmoc0Ulu9L7agOF0du1CZNQ3dke8yItYlyKNmGrkONemBbd6V8UTc1Wgcqn21t3WYB7dbRmh6/A==", + "version": "13.24.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz", + "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==", "dev": true, "requires": { "type-fest": "^0.20.2" @@ -7248,10 +7532,10 @@ "integrity": "sha512-8tLu60LgxF6XpdbK8OW3FA+IfTNBn1ZHGHKF4KQbEeSkajYw5PlYJcKluntgegDPTg8UkHjpet1T82vk6TQ68w==", "dev": true }, - "grapheme-splitter": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/grapheme-splitter/-/grapheme-splitter-1.0.4.tgz", - "integrity": "sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ==", + "graphemer": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", + "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", "dev": true }, "growly": { @@ -7309,21 +7593,21 @@ "dev": true }, "htmlparser2": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-8.0.1.tgz", - "integrity": "sha512-4lVbmc1diZC7GUJQtRQ5yBAeUCL1exyMwmForWkRLnwyzWBFxN633SALPMGYaWZvKe9j1pRZJpauvmxENSp/EA==", + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-8.0.2.tgz", + "integrity": "sha512-GYdjWKDkbRLkZ5geuHs5NY1puJ+PXwP7+fHPRz06Eirsb9ugf6d8kkXav6ADhcODhFFPMIXyxkxSuMf3D6NCFA==", "dev": true, "requires": { "domelementtype": "^2.3.0", - "domhandler": "^5.0.2", + "domhandler": "^5.0.3", "domutils": "^3.0.1", - "entities": "^4.3.0" + "entities": "^4.4.0" } }, "http-cache-semantics": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.0.tgz", - "integrity": "sha512-carPklcUh7ROWRK7Cv27RPtdhYhUsela/ue5/jKzjegVvXDqM2ILE9Q2BGn9JZJh1g87cp56su/FgQSzcWS8cQ==", + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.1.tgz", + "integrity": "sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ==", "dev": true }, "http-signature": { @@ -7360,15 +7644,15 @@ "dev": true }, "ignore": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.1.tgz", - "integrity": "sha512-d2qQLzTJ9WxQftPAuEQpSPmKqzxePjzVbpAVv62AQ64NTL+wR4JkrVqR/LqFsFEUsHDAiId52mJteHDFuDkElA==", + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", + "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", "dev": true }, "image-size": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/image-size/-/image-size-1.0.2.tgz", - "integrity": "sha512-xfOoWjceHntRb3qFCrh5ZFORYH8XCdYpASltMhZ/Q0KZiOwjdE/Yl2QCiWdwD+lygV5bMCvauzgu5PxBX/Yerg==", + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/image-size/-/image-size-1.1.1.tgz", + "integrity": "sha512-541xKlUw6jr/6gGuk92F+mYM5zaFAc5ahphvkqvNe2bQ6gVBkd6bfrmVJ2t4KDAfikAYZyIqTnktX3i6/aQDrQ==", "dev": true, "requires": { "queue": "6.0.2" @@ -7377,8 +7661,7 @@ "immediate": { "version": "3.0.6", "resolved": "https://registry.npmjs.org/immediate/-/immediate-3.0.6.tgz", - "integrity": "sha1-nbHb0Pr43m++D13V5Wu2BigN5ps=", - "dev": true + "integrity": "sha1-nbHb0Pr43m++D13V5Wu2BigN5ps=" }, "import-fresh": { "version": "3.3.0", @@ -7415,8 +7698,7 @@ "inherits": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", - "dev": true + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" }, "ini": { "version": "2.0.0", @@ -7557,8 +7839,7 @@ "isarray": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", - "dev": true + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" }, "isexe": { "version": "2.0.0", @@ -7572,6 +7853,16 @@ "integrity": "sha512-Yljz7ffyPbrLpLngrMtZ7NduUgVvi6wG9RJ9IUcyCd59YQ911PBJphODUcbOVbqYfxe1wuYf/LJ8PauMRwsM/g==", "dev": true }, + "jackspeak": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.3.tgz", + "integrity": "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==", + "dev": true, + "requires": { + "@isaacs/cliui": "^8.0.2", + "@pkgjs/parseargs": "^0.11.0" + } + }, "jed": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/jed/-/jed-1.1.1.tgz", @@ -7579,15 +7870,9 @@ "dev": true }, "jose": { - "version": "4.11.1", - "resolved": "https://registry.npmjs.org/jose/-/jose-4.11.1.tgz", - "integrity": "sha512-YRv4Tk/Wlug8qicwqFNFVEZSdbROCHRAC6qu/i0dyNKr5JQdoa2pIGoS04lLO/jXQX7Z9omoNewYIVIxqZBd9Q==", - "dev": true - }, - "js-sdsl": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/js-sdsl/-/js-sdsl-4.2.0.tgz", - "integrity": "sha512-dyBIzQBDkCqCu+0upx25Y2jGdbTGxE9fshMsCdK0ViOongpV+n5tXRcZY9v7CaVQ79AGS9KA1KHtojxiM7aXSQ==", + "version": "4.13.1", + "resolved": "https://registry.npmjs.org/jose/-/jose-4.13.1.tgz", + "integrity": "sha512-MSJQC5vXco5Br38mzaQKiq9mwt7lwj2eXpgpRyQYNHYt2lq1PjkWa7DLXX0WVcQLE9HhMh3jPiufS7fhJf+CLQ==", "dev": true }, "js-tokens": { @@ -7667,29 +7952,15 @@ } }, "jsonwebtoken": { - "version": "8.5.1", - "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-8.5.1.tgz", - "integrity": "sha512-XjwVfRS6jTMsqYs0EsuJ4LGxXV14zQybNd4L2r0UvbVnSF9Af8x7p5MzbJ90Ioz/9TI41/hTCvznF/loiSzn8w==", + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-9.0.0.tgz", + "integrity": "sha512-tuGfYXxkQGDPnLJ7SibiQgVgeDgfbPq2k2ICcbgqW8WxWLBAxKQM/ZCu/IT8SOSwmaYl4dpTFCW5xZv7YbbWUw==", "dev": true, "requires": { "jws": "^3.2.2", - "lodash.includes": "^4.3.0", - "lodash.isboolean": "^3.0.3", - "lodash.isinteger": "^4.0.4", - "lodash.isnumber": "^3.0.3", - "lodash.isplainobject": "^4.0.6", - "lodash.isstring": "^4.0.1", - "lodash.once": "^4.0.0", + "lodash": "^4.17.21", "ms": "^2.1.1", - "semver": "^5.6.0" - }, - "dependencies": { - "semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", - "dev": true - } + "semver": "^7.3.8" } }, "jsprim": { @@ -7705,15 +7976,14 @@ } }, "jszip": { - "version": "3.7.1", - "resolved": "https://registry.npmjs.org/jszip/-/jszip-3.7.1.tgz", - "integrity": "sha512-ghL0tz1XG9ZEmRMcEN2vt7xabrDdqHHeykgARpmZ0BiIctWxM47Vt63ZO2dnp4QYt/xJVLLy5Zv1l/xRdh2byg==", - "dev": true, + "version": "3.10.1", + "resolved": "https://registry.npmjs.org/jszip/-/jszip-3.10.1.tgz", + "integrity": "sha512-xXDvecyTpGLrqFrvkrUSoxxfJI5AH7U8zxxtVclpsUtMCq4JQ290LY8AW5c7Ggnr/Y/oK+bQMbqK2qmtk3pN4g==", "requires": { "lie": "~3.3.0", "pako": "~1.0.2", "readable-stream": "~2.3.6", - "set-immediate-shim": "~1.0.1" + "setimmediate": "^1.0.5" } }, "jwa": { @@ -7738,9 +8008,9 @@ } }, "keyv": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.0.tgz", - "integrity": "sha512-2YvuMsA+jnFGtBareKqgANOEKe1mk3HKiXu2fRmAfyxG0MJAywNhi5ttWA3PMjl4NmpyjZNbFifR2vNjW1znfA==", + "version": "4.5.4", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", + "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", "dev": true, "requires": { "json-buffer": "3.0.1" @@ -7778,7 +8048,6 @@ "version": "3.3.0", "resolved": "https://registry.npmjs.org/lie/-/lie-3.3.0.tgz", "integrity": "sha512-UaiMJzeWRlEujzAuw5LokY1L5ecNQYZKfmyZ9L7wDHb/p5etKaxXhohBcrw0EYby+G/NA52vRSN4N39dxHAIwQ==", - "dev": true, "requires": { "immediate": "~3.0.5" } @@ -7825,40 +8094,10 @@ "p-locate": "^5.0.0" } }, - "lodash.includes": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/lodash.includes/-/lodash.includes-4.3.0.tgz", - "integrity": "sha512-W3Bx6mdkRTGtlJISOvVD/lbqjTlPPUDTMnlXZFnVwi9NKJ6tiAk6LVdlhZMm17VZisqhKcgzpO5Wz91PCt5b0w==", - "dev": true - }, - "lodash.isboolean": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz", - "integrity": "sha512-Bz5mupy2SVbPHURB98VAcw+aHh4vRV5IPNhILUCsOzRmsTmSQ17jIuqopAentWoehktxGd9e/hbIXq980/1QJg==", - "dev": true - }, - "lodash.isinteger": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz", - "integrity": "sha512-DBwtEWN2caHQ9/imiNeEA5ys1JoRtRfY3d7V9wkqtbycnAmTvRRmbHKDV4a0EYc678/dia0jrte4tjYwVBaZUA==", - "dev": true - }, - "lodash.isnumber": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/lodash.isnumber/-/lodash.isnumber-3.0.3.tgz", - "integrity": "sha512-QYqzpfwO3/CWf3XP+Z+tkQsfaLL/EnUlXWVkIk5FUPc4sBdTehEqZONuyRt2P67PXAk+NXmTBcc97zw9t1FQrw==", - "dev": true - }, - "lodash.isplainobject": { - "version": "4.0.6", - "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz", - "integrity": "sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==", - "dev": true - }, - "lodash.isstring": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/lodash.isstring/-/lodash.isstring-4.0.1.tgz", - "integrity": "sha512-0wJxfxH1wgO3GrbuP+dTTk7op+6L41QCXbGINEmD+ny/G/eCqGzxyCsh7159S+mgDDcoarnBw6PC1PS5+wUGgw==", + "lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", "dev": true }, "lodash.merge": { @@ -7867,12 +8106,6 @@ "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", "dev": true }, - "lodash.once": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz", - "integrity": "sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg==", - "dev": true - }, "lowercase-keys": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-3.0.0.tgz", @@ -7880,13 +8113,10 @@ "dev": true }, "lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "dev": true, - "requires": { - "yallist": "^4.0.0" - } + "version": "10.4.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", + "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", + "dev": true }, "make-error": { "version": "1.3.6", @@ -7968,6 +8198,12 @@ "integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==", "dev": true }, + "minipass": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz", + "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==", + "dev": true + }, "mkdirp": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", @@ -8073,12 +8309,6 @@ "dev": true, "optional": true }, - "nanoid": { - "version": "3.3.4", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.4.tgz", - "integrity": "sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw==", - "dev": true - }, "natural-compare": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", @@ -8099,9 +8329,9 @@ "dev": true }, "node-fetch": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-3.3.0.tgz", - "integrity": "sha512-BKwRP/O0UvoMKp7GNdwPlObhYGB5DQqwhEDQlNKuoqwVYSxkSZCSbHjnFFmUEtwSKRPU4kNK8PbDYYitwaE3QA==", + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-3.3.1.tgz", + "integrity": "sha512-cRVc/kyto/7E5shrWca1Wsea4y6tL9iYJE5FBCius3JQfb/4P4I295PfhgbJQBLTx6lATE4z+wK0rPM4VS2uow==", "dev": true, "requires": { "data-uri-to-buffer": "^4.0.0", @@ -8166,9 +8396,9 @@ "dev": true }, "on-exit-leak-free": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/on-exit-leak-free/-/on-exit-leak-free-2.1.0.tgz", - "integrity": "sha512-VuCaZZAjReZ3vUwgOB8LxAosIurDiAW0s13rI1YwmaP++jvcxP77AWoQvenZebpCA2m8WC1/EosPYPMjnRAp/w==", + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/on-exit-leak-free/-/on-exit-leak-free-2.1.2.tgz", + "integrity": "sha512-0eJJY6hXLGf1udHwfNftBqH+g73EU4B504nZeKpz1sYRKafAghwxEJunB2O7rDZkL4PGfsMVnTXZ2EjibbqcsA==", "dev": true }, "once": { @@ -8190,9 +8420,9 @@ } }, "open": { - "version": "8.4.0", - "resolved": "https://registry.npmjs.org/open/-/open-8.4.0.tgz", - "integrity": "sha512-XgFPPM+B28FtCCgSb9I+s9szOC1vZRSwgWsRUA5ylIxRTgKozqjOCrVOqGsYABPYK5qnfqClxZTFBa8PKt2v6Q==", + "version": "8.4.2", + "resolved": "https://registry.npmjs.org/open/-/open-8.4.2.tgz", + "integrity": "sha512-7x81NCL719oNbsq/3mh+hVrAWmFuEYUqrq/Iw3kUzH8ReypT9QQ0BLoJS7/G9k6N81XjW4qHWtjWwe/9eLy1EQ==", "dev": true, "requires": { "define-lazy-prop": "^2.0.0", @@ -8201,9 +8431,9 @@ } }, "optionator": { - "version": "0.9.1", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz", - "integrity": "sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==", + "version": "0.9.4", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", + "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==", "dev": true, "requires": { "deep-is": "^0.1.3", @@ -8211,7 +8441,7 @@ "levn": "^0.4.1", "prelude-ls": "^1.2.1", "type-check": "^0.4.0", - "word-wrap": "^1.2.3" + "word-wrap": "^1.2.5" } }, "os-locale": { @@ -8282,8 +8512,7 @@ "pako": { "version": "1.0.11", "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz", - "integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==", - "dev": true + "integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==" }, "parent-module": { "version": "1.0.1", @@ -8343,6 +8572,16 @@ "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", "dev": true }, + "path-scurry": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz", + "integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==", + "dev": true, + "requires": { + "lru-cache": "^10.2.0", + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" + } + }, "pend": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz", @@ -8355,35 +8594,29 @@ "integrity": "sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow==", "dev": true }, - "picocolors": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", - "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==", - "dev": true - }, "pino": { - "version": "8.7.0", - "resolved": "https://registry.npmjs.org/pino/-/pino-8.7.0.tgz", - "integrity": "sha512-l9sA5uPxmZzwydhMWUcm1gI0YxNnYl8MfSr2h8cwLvOAzQLBLewzF247h/vqHe3/tt6fgtXeG9wdjjoetdI/vA==", + "version": "8.20.0", + "resolved": "https://registry.npmjs.org/pino/-/pino-8.20.0.tgz", + "integrity": "sha512-uhIfMj5TVp+WynVASaVEJFTncTUe4dHBq6CWplu/vBgvGHhvBvQfxz+vcOrnnBQdORH3izaGEurLfNlq3YxdFQ==", "dev": true, "requires": { "atomic-sleep": "^1.0.0", "fast-redact": "^3.1.1", "on-exit-leak-free": "^2.1.0", - "pino-abstract-transport": "v1.0.0", + "pino-abstract-transport": "^1.1.0", "pino-std-serializers": "^6.0.0", - "process-warning": "^2.0.0", + "process-warning": "^3.0.0", "quick-format-unescaped": "^4.0.3", "real-require": "^0.2.0", "safe-stable-stringify": "^2.3.1", - "sonic-boom": "^3.1.0", + "sonic-boom": "^3.7.0", "thread-stream": "^2.0.0" } }, "pino-abstract-transport": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/pino-abstract-transport/-/pino-abstract-transport-1.0.0.tgz", - "integrity": "sha512-c7vo5OpW4wIS42hUVcT5REsL8ZljsUfBjqV/e2sFxmFEFZiq1XLUp5EYLtuDH6PEHq9W1egWqRbnLUP5FuZmOA==", + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/pino-abstract-transport/-/pino-abstract-transport-1.2.0.tgz", + "integrity": "sha512-Guhh8EZfPCfH+PMXAb6rKOjGQEoy0xlAIn+irODG5kgfYV+BQ0rGYYWTIel3P5mmyXqkYkPmdIkywsn6QKUR1Q==", "dev": true, "requires": { "readable-stream": "^4.0.0", @@ -8391,36 +8624,35 @@ }, "dependencies": { "readable-stream": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-4.2.0.tgz", - "integrity": "sha512-gJrBHsaI3lgBoGMW/jHZsQ/o/TIWiu5ENCJG1BB7fuCKzpFM8GaS2UoBVt9NO+oI+3FcrBNbUkl3ilDe09aY4A==", + "version": "4.5.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-4.5.2.tgz", + "integrity": "sha512-yjavECdqeZ3GLXNgRXgeQEdz9fvDDkNKyHnbHRFtOr7/LcfgBcmct7t/ET+HaCTqfh06OzoAxrkN/IfjJBVe+g==", "dev": true, "requires": { "abort-controller": "^3.0.0", "buffer": "^6.0.3", "events": "^3.3.0", - "process": "^0.11.10" + "process": "^0.11.10", + "string_decoder": "^1.3.0" + } + }, + "string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "dev": true, + "requires": { + "safe-buffer": "~5.2.0" } } } }, "pino-std-serializers": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/pino-std-serializers/-/pino-std-serializers-6.0.0.tgz", - "integrity": "sha512-mMMOwSKrmyl+Y12Ri2xhH1lbzQxwwpuru9VjyJpgFIH4asSj88F2csdMwN6+M5g1Ll4rmsYghHLQJw81tgZ7LQ==", + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/pino-std-serializers/-/pino-std-serializers-6.2.2.tgz", + "integrity": "sha512-cHjPPsE+vhj/tnhCy/wiMh3M3z3h/j15zHQX+S9GkTBgqJuTuJzYJ4gUyACLhDaJ7kk9ba9iRDmbH2tJU03OiA==", "dev": true }, - "postcss": { - "version": "8.4.19", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.19.tgz", - "integrity": "sha512-h+pbPsyhlYj6N2ozBmHhHrs9DzGmbaarbLvWipMRO7RLS+v4onj26MPFXA5OBYFxyqYhUJK456SwDcY9H2/zsA==", - "dev": true, - "requires": { - "nanoid": "^3.3.4", - "picocolors": "^1.0.0", - "source-map-js": "^1.0.2" - } - }, "prelude-ls": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", @@ -8436,13 +8668,12 @@ "process-nextick-args": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", - "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", - "dev": true + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==" }, "process-warning": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/process-warning/-/process-warning-2.0.0.tgz", - "integrity": "sha512-+MmoAXoUX+VTHAlwns0h+kFUWFs/3FZy+ZuchkgjyOu3oioLAo2LB5aCfKPh2+P9O18i3m43tUEv3YqttSy0Ww==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/process-warning/-/process-warning-3.0.0.tgz", + "integrity": "sha512-mqn0kFRl0EoqhnL0GQ0veqFHyIN1yig9RHh/InzORTUiZHFRAur+aMtRkELNwGs9aNwKS6tg/An4NYBPGwvtzQ==", "dev": true }, "promise-toolbox": { @@ -8477,9 +8708,9 @@ } }, "punycode": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", - "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", "dev": true }, "pupa": { @@ -8554,7 +8785,6 @@ "version": "2.3.7", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", - "dev": true, "requires": { "core-util-is": "~1.0.0", "inherits": "~2.0.3", @@ -8568,8 +8798,7 @@ "safe-buffer": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "dev": true + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" } } }, @@ -8585,12 +8814,6 @@ "integrity": "sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==", "dev": true }, - "regexpp": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz", - "integrity": "sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==", - "dev": true - }, "registry-auth-token": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/registry-auth-token/-/registry-auth-token-5.0.1.tgz", @@ -8790,9 +9013,9 @@ "optional": true }, "safe-stable-stringify": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/safe-stable-stringify/-/safe-stable-stringify-2.4.1.tgz", - "integrity": "sha512-dVHE6bMtS/bnL2mwualjc6IxEv1F+OCUpA46pKUj6F8uDbUM0jCCulPqRNPSnWwGNKx5etqMjZYdXtrm5KJZGA==", + "version": "2.4.3", + "resolved": "https://registry.npmjs.org/safe-stable-stringify/-/safe-stable-stringify-2.4.3.tgz", + "integrity": "sha512-e2bDA2WJT0wxseVd4lsDP4+3ONX6HpMXQa1ZhFQ7SU+GjvORCmShbCMltrtIDfkYhVHrOcPtj+KhmDBdPdZD1g==", "dev": true }, "safer-buffer": { @@ -8802,19 +9025,16 @@ "dev": true }, "sax": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", - "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==", + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/sax/-/sax-1.4.1.tgz", + "integrity": "sha512-+aWOz7yVScEGoKNd4PA10LZ8sk0A/z5+nXQG5giUO5rprX9jgYsTdov9qCchZiPIZezbZH+jRut8nPodFAX4Jg==", "dev": true }, "semver": { - "version": "7.3.8", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", - "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", - "dev": true, - "requires": { - "lru-cache": "^6.0.0" - } + "version": "7.6.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", + "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", + "dev": true }, "semver-diff": { "version": "4.0.0", @@ -8825,11 +9045,10 @@ "semver": "^7.3.5" } }, - "set-immediate-shim": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/set-immediate-shim/-/set-immediate-shim-1.0.1.tgz", - "integrity": "sha1-SysbJ+uAip+NzEgaWOXlb1mfP2E=", - "dev": true + "setimmediate": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz", + "integrity": "sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==" }, "sha.js": { "version": "2.4.11", @@ -8869,17 +9088,17 @@ "dev": true }, "sign-addon": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/sign-addon/-/sign-addon-5.1.0.tgz", - "integrity": "sha512-fag/csbsw25WpW+G+uWE6rRImSjlfwQNjuP28fFhvXpfW+kXccxl/o1QEW+hXtTidwpysksb7Y0B8UCeMkYkSA==", + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/sign-addon/-/sign-addon-5.3.0.tgz", + "integrity": "sha512-7nHlCzhQgVMLBNiXVEgbG/raq48awOW0lYMN5uo1BaB3mp0+k8M8pvDwbfTlr3apcxZJsk9HQsAW1POwoJugpQ==", "dev": true, "requires": { "common-tags": "1.8.2", - "core-js": "3.25.3", + "core-js": "3.29.0", "deepcopy": "2.1.0", "es6-error": "4.1.1", "es6-promisify": "7.0.0", - "jsonwebtoken": "8.5.1", + "jsonwebtoken": "9.0.0", "mz": "2.7.0", "request": "2.88.2", "source-map-support": "0.5.21", @@ -8893,9 +9112,9 @@ "dev": true }, "sonic-boom": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/sonic-boom/-/sonic-boom-3.2.0.tgz", - "integrity": "sha512-SbbZ+Kqj/XIunvIAgUZRlqd6CGQYq71tRRbXR92Za8J/R3Yh4Av+TWENiSiEgnlwckYLyP0YZQWVfyNC0dzLaA==", + "version": "3.8.1", + "resolved": "https://registry.npmjs.org/sonic-boom/-/sonic-boom-3.8.1.tgz", + "integrity": "sha512-y4Z8LCDBuum+PBP3lSV7RHrXscqksve/bi0as7mhwVnBW+/wUqKT/2Kb7um8yqcFy0duYbbPxzt89Zy2nOCaxg==", "dev": true, "requires": { "atomic-sleep": "^1.0.0" @@ -8907,12 +9126,6 @@ "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", "dev": true }, - "source-map-js": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz", - "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==", - "dev": true - }, "source-map-support": { "version": "0.5.21", "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", @@ -8943,15 +9156,15 @@ } }, "split2": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/split2/-/split2-4.1.0.tgz", - "integrity": "sha512-VBiJxFkxiXRlUIeyMQi8s4hgvKCSjtknJv/LVYbrgALPwf5zSKmEwV9Lst25AkvMDnvxODugjdl6KZgwKM1WYQ==", + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/split2/-/split2-4.2.0.tgz", + "integrity": "sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==", "dev": true }, "sshpk": { - "version": "1.17.0", - "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.17.0.tgz", - "integrity": "sha512-/9HIEs1ZXGhSPE8X6Ccm7Nam1z8KcoCqPdI7ecm1N33EzAetWahvQWVqLZtaZQ+IDKX4IyA2o0gBzqIMkAagHQ==", + "version": "1.18.0", + "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.18.0.tgz", + "integrity": "sha512-2p2KJZTSqQ/I3+HX42EpYOa2l3f8Erv8MWKsy2I9uf4wA7yFIkXRffYdsx86y6z4vHtV8u7g+pPlr8/4ouAxsQ==", "dev": true, "requires": { "asn1": "~0.2.3", @@ -8989,7 +9202,6 @@ "version": "1.1.1", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "dev": true, "requires": { "safe-buffer": "~5.1.0" }, @@ -8997,8 +9209,7 @@ "safe-buffer": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "dev": true + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" } } }, @@ -9030,6 +9241,25 @@ } } }, + "string-width-cjs": { + "version": "npm:string-width@4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "requires": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "dependencies": { + "emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true + } + } + }, "strip-ansi": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", @@ -9039,6 +9269,15 @@ "ansi-regex": "^5.0.1" } }, + "strip-ansi-cjs": { + "version": "npm:strip-ansi@6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "requires": { + "ansi-regex": "^5.0.1" + } + }, "strip-bom": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-5.0.0.tgz", @@ -9110,9 +9349,9 @@ } }, "thread-stream": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/thread-stream/-/thread-stream-2.2.0.tgz", - "integrity": "sha512-rUkv4/fnb4rqy/gGy7VuqK6wE1+1DOCOWy4RMeaV69ZHMP11tQKZvZSip1yTgrKCMZzEMcCL/bKfHvSfDHx+iQ==", + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/thread-stream/-/thread-stream-2.7.0.tgz", + "integrity": "sha512-qQiRWsU/wvNolI6tbbCKd9iKaTnCXsTwVxhhKM6nctPdujTyztjlbUkUTUymidWcMnZ5pWR0ej4a0tjsW021vw==", "dev": true, "requires": { "real-require": "^0.2.0" @@ -9182,9 +9421,9 @@ } }, "type-detect": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", - "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.1.0.tgz", + "integrity": "sha512-Acylog8/luQ8L7il+geoSxhEkazvkslg7PSNKOX59mbB9cOveP5aq9h74Y7YU8yDpJwetzQQrfIwtf4Wp4LKcw==", "dev": true }, "type-fest": { @@ -9218,9 +9457,9 @@ } }, "universalify": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz", - "integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", + "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", "dev": true }, "upath": { @@ -9271,8 +9510,7 @@ "util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=", - "dev": true + "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" }, "uuid": { "version": "8.3.2", @@ -9319,49 +9557,49 @@ } }, "web-ext": { - "version": "7.4.0", - "resolved": "https://registry.npmjs.org/web-ext/-/web-ext-7.4.0.tgz", - "integrity": "sha512-dT2HJaGNXxRNuOtzaVBtEULccL0kM2SN1ark1NnN/ZSlbucobBxCDj6119iki72YyuXpaXZCJGqfZtVf1Znocg==", + "version": "7.12.0", + "resolved": "https://registry.npmjs.org/web-ext/-/web-ext-7.12.0.tgz", + "integrity": "sha512-h+uWOYBlHlPKy5CqxuZKocgOdL8J7I4ctMw/rAGbQl7jq7tr+NmY/Lhh2FPMSlJ1Y0T2VeUqwBVighK0MM1+zA==", "dev": true, "requires": { - "@babel/runtime": "7.20.1", + "@babel/runtime": "7.21.0", "@devicefarmer/adbkit": "3.2.3", - "addons-linter": "5.23.0", + "addons-linter": "6.28.0", "bunyan": "1.8.15", - "camelcase": "7.0.0", + "camelcase": "7.0.1", "chrome-launcher": "0.15.1", "debounce": "1.2.1", "decamelize": "6.0.0", "es6-error": "4.1.1", - "firefox-profile": "4.2.2", - "fs-extra": "10.1.0", - "fx-runner": "1.3.0", + "firefox-profile": "4.3.2", + "fs-extra": "11.1.0", + "fx-runner": "1.4.0", "import-fresh": "3.3.0", - "jose": "4.11.1", + "jose": "4.13.1", "mkdirp": "1.0.4", "multimatch": "6.0.0", "mz": "2.7.0", - "node-fetch": "3.3.0", + "node-fetch": "3.3.1", "node-notifier": "10.0.1", - "open": "8.4.0", + "open": "8.4.2", "parse-json": "6.0.2", "promise-toolbox": "0.21.0", - "sign-addon": "5.1.0", + "sign-addon": "5.3.0", "source-map-support": "0.5.21", "strip-bom": "5.0.0", "strip-json-comments": "5.0.0", "tmp": "0.2.1", "update-notifier": "6.0.2", "watchpack": "2.4.0", - "ws": "8.11.0", - "yargs": "17.6.2", + "ws": "8.13.0", + "yargs": "17.7.1", "zip-dir": "2.0.0" } }, "web-streams-polyfill": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-3.2.1.tgz", - "integrity": "sha512-e0MO3wdXWKrLbL0DgGnUV7WHVuw9OUvL4hjgnPkIeEvESk74gAITi5G606JtZPp39cd8HA9VQzCIvA49LpPN5Q==", + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-3.3.3.tgz", + "integrity": "sha512-d2JWLCivmZYTSIoge9MsgFCZrt571BikcWGYkjC1khllbTeDlGqZ2D8vD8E/lJa8WGWbb7Plm8/XJYV7IJHZZw==", "dev": true }, "webidl-conversions": { @@ -9415,15 +9653,15 @@ "dev": true }, "word-wrap": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", - "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==", + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", + "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", "dev": true }, "wrap-ansi": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.0.1.tgz", - "integrity": "sha512-QFF+ufAqhoYHvoHdajT/Po7KoXVBPXS2bgjIam5isfWJPfIOnQZ50JtUiVvCv/sjgacf3yRrt2ZKUZ/V4itN4g==", + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", + "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", "dev": true, "requires": { "ansi-styles": "^6.1.0", @@ -9454,6 +9692,36 @@ } } }, + "wrap-ansi-cjs": { + "version": "npm:wrap-ansi@7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "requires": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "dependencies": { + "emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true + }, + "string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "requires": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + } + } + } + }, "wrappy": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", @@ -9473,9 +9741,9 @@ } }, "ws": { - "version": "8.11.0", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.11.0.tgz", - "integrity": "sha512-HPG3wQd9sNQoT9xHyNCXoDUa+Xw/VevmY9FoHyQ+g+rrMn4j6FB4np7Z0OhdTgjx6MgQLK7jwSy1YecU1+4Asg==", + "version": "8.13.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.13.0.tgz", + "integrity": "sha512-x9vcZYTrFPC7aSIbj7sRCYo7L/Xb8Iy+pW0ng0wt2vCJv7M9HOMy0UoN3rr+IFC7hb7vXoqS+P9ktyLLLhO+LA==", "dev": true, "requires": {} }, @@ -9486,9 +9754,9 @@ "dev": true }, "xml2js": { - "version": "0.4.23", - "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.4.23.tgz", - "integrity": "sha512-ySPiMjM0+pLDftHgXY4By0uswI3SPKLDw/i3UXbnO8M/p28zqexCUoPmQFrYD+/1BzhGJSs2i1ERWKJAtiLrug==", + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.5.0.tgz", + "integrity": "sha512-drPFnkQJik/O+uPKpqSgr22mpuFHqKdbS835iAQrUC73L2F5WkboIRd63ai/2Yg6I1jzifPFKH2NTK+cfglkIA==", "dev": true, "requires": { "sax": ">=0.6.0", @@ -9507,16 +9775,10 @@ "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", "dev": true }, - "yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true - }, "yargs": { - "version": "17.6.2", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.6.2.tgz", - "integrity": "sha512-1/9UrdHjDZc0eOU0HxOHoS78C69UD3JRMvzlJ7S79S2nTaWRA/whGCTV8o9e/N/1Va9YIV7Q4sOxD8VV4pCWOw==", + "version": "17.7.1", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.1.tgz", + "integrity": "sha512-cwiTb08Xuv5fqF4AovYacTFNxk62th7LKJ6BL9IGUpTJrWoU7/7WdQGTP2SjKf1dUNBGzDd28p/Yfs/GI6JrLw==", "dev": true, "requires": { "cliui": "^8.0.1", diff --git a/src/package.json b/src/package.json index 2231dc45..4b0a8349 100644 --- a/src/package.json +++ b/src/package.json @@ -9,5 +9,8 @@ }, "devDependencies": { "web-ext": "^7.4.0" + }, + "dependencies": { + "jszip": "^3.10.1" } } diff --git a/src/popup/popup.css b/src/popup/popup.css index 2d7ef0c7..9f2d2bb1 100644 --- a/src/popup/popup.css +++ b/src/popup/popup.css @@ -1,207 +1,1224 @@ :root { - --focus: orange; - --bg: #fff;/*#0A001F;*/ - --fg: #000; - --border: #eee; + /* Color Palette */ --primary: #4A90E2; - --fg-primary: #eee; - --bg-primary: #ECF5FF; - --border-primary: #4A90E2; - --font-size: 14px; + --primary-hover: #357ABD; + --primary-light: #ECF5FF; + --secondary: #6C757D; + --success: #28A745; + --warning: #FFC107; + --danger: #DC3545; + + /* Light Theme */ + --bg: #FFFFFF; + --bg-secondary: #F8F9FA; + --bg-tertiary: #E9ECEF; + --fg: #212529; + --fg-secondary: #6C757D; + --fg-muted: #ADB5BD; + --border: #DEE2E6; + --border-light: #E9ECEF; + --shadow: rgba(0, 0, 0, 0.1); + --shadow-hover: rgba(0, 0, 0, 0.15); + + /* Typography */ + --font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, sans-serif; + --font-size-xs: 11px; + --font-size-sm: 12px; + --font-size-base: 14px; + --font-size-lg: 16px; + --font-size-xl: 18px; + --font-weight-normal: 400; + --font-weight-medium: 500; + --font-weight-bold: 600; + + /* Spacing */ + --spacing-xs: 4px; + --spacing-sm: 8px; + --spacing-md: 12px; + --spacing-lg: 16px; + --spacing-xl: 20px; + --spacing-xxl: 24px; + + /* Border Radius */ + --radius-sm: 4px; + --radius-md: 8px; + --radius-lg: 12px; + --radius-xl: 16px; + + /* Transitions */ + --transition-fast: 0.15s ease; + --transition-normal: 0.3s ease; + --transition-slow: 0.5s ease; } -@media(prefers-color-scheme: dark) { +/* Dark Theme */ +@media (prefers-color-scheme: dark) { :root { - --focus: orange; - --bg: #2A2A2E; - --fg: #f8f8f8; - --border: #555; - --primary: #4A90E2; - --fg-primary: #eee; - --bg-primary: hsl(212, 80%, 30%); - --border-primary: #4A90E2; - --pre-bg: #474749; + --bg: #1A1D23; + --bg-secondary: #2D3139; + --bg-tertiary: #3A3F4A; + --fg: #FFFFFF; + --fg-secondary: #B8BCC5; + --fg-muted: #8B949E; + --border: #404956; + --border-light: #404956; + --shadow: rgba(0, 0, 0, 0.3); + --shadow-hover: rgba(0, 0, 0, 0.4); + --primary-light: rgba(74, 144, 226, 0.1); } + .cm-s-xq-dark.CodeMirror { - background-color: var(--bg); + background-color: var(--bg-secondary); + border-color: var(--border); } } -/* Works on Firefox */ +/* Base Styles */ +* { + margin: 0; + padding: 0; + box-sizing: border-box; +} + +*:focus { + outline: 2px solid var(--primary); + outline-offset: 2px; +} + +/* Scrollbar Styles */ * { scrollbar-width: thin; - scrollbar-color: var(--pre-bg) var(--bg); + scrollbar-color: var(--border) transparent; } -/* Works on Chrome, Edge, and Safari */ *::-webkit-scrollbar { - width: 12px; + width: 6px; + height: 6px; } *::-webkit-scrollbar-track { - background: var(--bg); + background: transparent; } *::-webkit-scrollbar-thumb { background-color: var(--border); border-radius: 20px; + border: none; } -* { - margin: 0; - padding: 0; - box-sizing: border-box; +*::-webkit-scrollbar-thumb:hover { + background-color: var(--fg-muted); } +/* Body */ body { - width: 350px; - height: 500px; - border-radius: 0.5em; + width: 500px; + height: 650px; + font-family: var(--font-family); + font-size: var(--font-size-base); + background: var(--bg); + color: var(--fg); overflow: hidden; - font-family: sans-serif; + position: relative; + margin: 0; + padding: 0; +} + +/* Loading Overlay */ +.loading-overlay { + position: absolute; + top: 0; + left: 0; + right: 0; + bottom: 0; background: var(--bg); - font-size: var(--font-size); + display: flex; + align-items: center; + justify-content: center; + z-index: 1000; + backdrop-filter: blur(4px); } -@keyframes spinner { - to { - transform: rotate(360deg); - } +.spinner-container { + text-align: center; } -* { - box-sizing: border-box; + +.spinner { + width: 32px; + height: 32px; + border: 3px solid var(--border-light); + border-top: 3px solid var(--primary); + border-radius: 50%; + animation: spin 1s linear infinite; + margin: 0 auto var(--spacing-md); } -*:focus { - border: 3px dotted var(--focus-color) !important; +.spinner-container p { + color: var(--fg-secondary); + font-size: var(--font-size-sm); + margin: 0; +} + +@keyframes spin { + 0% { transform: rotate(0deg); } + 100% { transform: rotate(360deg); } } -#spinner:before { +/* Main Container */ +.main-container { + display: none; + flex-direction: column; + height: 100vh; + max-height: 650px; + overflow: hidden; + position: relative; +} + +/* Header */ +.header { + display: flex; + align-items: center; + justify-content: space-between; + padding: var(--spacing-md) var(--spacing-lg) var(--spacing-sm); + background: linear-gradient(135deg, var(--primary) 0%, var(--primary-hover) 100%); + color: white; + position: relative; + overflow: hidden; + flex: 0 0 auto; /* fixed height section */ +} + +.header::before { content: ''; position: absolute; - top: 50%; - left: 50%; - width: 20px; - height: 20px; - margin-top: -10px; - margin-left: -10px; - border-radius: 50%; - border-top: 2px solid var(--primary); - border-right: 2px solid transparent; - animation: spinner .6s linear infinite; + top: -50%; + left: -50%; + width: 200%; + height: 200%; + background: radial-gradient(circle, rgba(255,255,255,0.1) 0%, transparent 70%); + animation: headerGlow 8s ease-in-out infinite alternate; } -.CodeMirror { - border: none; - padding: 0.5em; - flex: 1; +.header::after { + content: ''; + position: absolute; + bottom: 0; + left: 0; + right: 0; + height: 1px; + background: linear-gradient(90deg, transparent 0%, rgba(255,255,255,0.3) 50%, transparent 100%); + z-index: 1; } -input#title { - padding: 0.5em; - color: var(--fg); - background-color: var(--bg); - border: 1px solid var(--border); - font-size: 1.01em; +@keyframes headerGlow { + 0% { + transform: translate(-10%, -10%) rotate(0deg); + opacity: 0.5; + } + 100% { + transform: translate(10%, 10%) rotate(5deg); + opacity: 0.8; + } } +.logo { + position: relative; + z-index: 2; +} + +.header-actions { + position: relative; + z-index: 2; +} + +.logo h1 { + font-size: var(--font-size-xl); + font-weight: var(--font-weight-bold); + margin: 0; + letter-spacing: -0.5px; +} + +.logo .subtitle { + font-size: var(--font-size-xs); + opacity: 0.8; + font-weight: var(--font-weight-normal); + text-transform: uppercase; + letter-spacing: 0.5px; +} + +.header-actions { + display: flex; + align-items: center; + gap: var(--spacing-sm); +} + +.icon-button { + display: flex; + align-items: center; + justify-content: center; + width: 32px; + height: 32px; + background: rgba(255, 255, 255, 0.1); + border: 1px solid rgba(255, 255, 255, 0.2); + border-radius: var(--radius-md); + color: white; + text-decoration: none; + transition: var(--transition-fast); +} + +.icon-button:hover { + background: rgba(255, 255, 255, 0.2); + transform: translateY(-1px); +} + +/* --- Legacy structure compatibility (anchor-based UI) --- */ +/* Container + spinner for old markup */ #container { width: 100%; height: 100%; display: none; flex-direction: column; } + +/* Removed duplicate spinner - use .loading-overlay .spinner instead */ + .row { + display: flex; flex-direction: row; - display:flex; } +/* Anchor buttons */ a.button { display: block; - padding: 0.5em 0; + padding: 0.5em 0.75em; background-color: var(--primary); - color: var(--fg-primary); + color: #fff; text-align: center; text-decoration: none; - line-height: 1em; - border: 1px solid var(--bg); - border-collapse: collapse; + line-height: 1.2em; + border: 1px solid var(--primary); + border-radius: var(--radius-md); + margin: 6px 8px 0; + transition: var(--transition-fast); } +a.button:hover { + background-color: var(--primary-hover); + border-color: var(--primary-hover); +} + +/* Toggle anchors */ +.button.toggle { + position: relative; + background: var(--bg); + color: var(--fg); + border: 1px solid var(--border); + box-shadow: 0 2px 4px var(--shadow); +} + +.button.toggle:hover { + box-shadow: 0 4px 8px var(--shadow-hover); +} + +.button.toggle.checked { + background: var(--primary-light); + border-color: var(--primary); +} + +.button.toggle.active { + background: var(--primary-light); + border-color: var(--primary); +} + +/* Leading check dot inside toggle anchors */ +.check { + background: var(--border-light); + border-radius: 50%; + content: ''; + height: 18px; + left: 10px; + position: absolute; + top: calc(50% - 9px); + width: 18px; +} + +.checked .check { + background-color: var(--primary); + background-image: url('data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz48c3ZnIHdpZHRoPSIyNiIgaGVpZ2h0PSIyMCIgdmVyc2lvbj0iMS4xIiB2aWV3Qm94PSIyLjAyOTY4IC00MC4wOTAzIDI2IDIwIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPjxwYXRoIGQ9Ik0yNy45NzQzLC0zNi4xMjcyYzAsMC40NDY0MjggLTAuMTU2MjUsMC44MjU4OTMgLTAuNDY4NzUsMS4xMzgzOWwtMTIuMTIwNSwxMi4xMjA1bC0yLjI3Njc5LDIuMjc2NzljLTAuMzEyNSwwLjMxMjUgLTAuNjkxOTY0LDAuNDY4NzUgLTEuMTM4MzksMC40Njg3NWMtMC40NDY0MjgsMCAtMC44MjU4OTMsLTAuMTU2MjUgLTEuMTM4MzksLTAuNDY4NzVsLTIuMjc2NzksLTIuMjc2NzlMLTYuMDYwMjcsLTYuMDYwMjdjLTAuMzEyNSwtMC4zMTI1IC0wLjQ2ODc1LC0wLjY5MTk2NSAtMC40Njg3NSwtMS4xMzgzOWMwLC0wLjQ0NjQyOSAwLjE1NjI1LC0wLjgyNTg5MyAwLjQ2ODc1LC0xLjEzODM5bDIuMjc2NzksLTIuMjc2NzlDMTAuMzEyNSwtNDIuMzEyNSAxMC42ODc5LC00Mi40Njg3NSAxMS4xMzgzOSwtNDIuNDY4NzVjMC40NDY0MjksMCAwLjgyNTg5MywwLjE1NjI1IDEuMTM4MzksMC40Njg3NWw0LjkyMTg4LDQuOTM4NjJsMTAuOTgyMSwtMTAuOTk4OWMwLjMxMjUsLTAuMzEyNSAwLjY5MTk2NCwtMC40Njg3NSAxLjEzODM5LC0wLjQ2ODc1YzAuNDQ2NDI4LDAgMC44MjU4OTMsMC4xNTYyNSAxLjEzODM5LDAuNDY4NzVsMi4yNzY3OCwyLjI3Njc5YzAuMzEyNSwwLjMxMjUgMC40Njg3NSwwLjY5MTk2NCAwLjQ2ODc1LDEuMTM4MzlaIiBmaWxsPSIjZmZmIi8+PC9zdmc+'); + background-repeat: no-repeat; + background-position: center; + background-size: 12px; +} + +.active .check { + background-color: var(--primary); + background-image: url('data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz48c3ZnIHdpZHRoPSIyNiIgaGVpZ2h0PSIyMCIgdmVyc2lvbj0iMS4xIiB2aWV3Qm94PSIyLjAyOTY4IC00MC4wOTAzIDI2IDIwIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPjxwYXRoIGQ9Ik0yNy45NzQzLC0zNi4xMjcyYzAsMC40NDY0MjggLTAuMTU2MjUsMC44MjU4OTMgLTAuNDY4NzUsMS4xMzgzOWwtMTIuMTIwNSwxMi4xMjA1bC0yLjI3Njc5LDIuMjc2NzljLTAuMzEyNSwwLjMxMjUgLTAuNjkxOTY0LDAuNDY4NzUgLTEuMTM4MzksMC40Njg3NWMtMC40NDY0MjgsMCAtMC44MjU4OTMsLTAuMTU2MjUgLTEuMTM4MzksLTAuNDY4NzVsLTIuMjc2NzksLTIuMjc2NzlMLTYuMDYwMjcsLTYuMDYwMjdjLTAuMzEyNSwtMC4zMTI1IC0wLjQ2ODc1LC0wLjY5MTk2NSAtMC40Njg3NSwtMS4xMzgzOWMwLC0wLjQ0NjQyOSAwLjE1NjI1LC0wLjgyNTg5MyAwLjQ2ODc1LC0xLjEzODM5bDIuMjc2NzksLTIuMjc2NzlDMTAuMzEyNSwtNDIuMzEyNSAxMC42ODc5LC00Mi40Njg3NSAxMS4xMzgzOSwtNDIuNDY4NzVjMC40NDY0MjksMCAwLjgyNTg5MywwLjE1NjI1IDEuMTM4MzksMC40Njg3NWw0LjkyMTg4LDQuOTM4NjJsMTAuOTgyMSwtMTAuOTk4OWMwLjMxMjUsLTAuMzEyNSAwLjY5MTk2NCwtMC40Njg3NSAxLjEzODM5LC0wLjQ2ODc1YzAuNDQ2NDI4LDAgMC44MjU4OTMsMC4xNTYyNSAxLjEzODM5LDAuNDY4NzVsMi4yNzY3OCwyLjI3Njc5YzAuMzEyNSwwLjMxMjUgMC40Njg3NSwwLjY5MTk2NCAwLjQ2ODc1LDEuMTM4MzlaIiBmaWxsPSIjZmZmIi8+PC9zdmc+'); + background-repeat: no-repeat; + background-position: center; + background-size: 12px; +} + +/* Layout details for legacy */ +#selected, #document { flex: 1; } +#clipOption { display: none; } +#downloadSelection { display: none; background-color: var(--primary-light); color: var(--fg); border-color: var(--primary); } + +/* Gear options button in legacy UI */ #options { display: block; position: absolute; - top:2px; - right:2px; + top: 6px; + right: 6px; font-size: 0; text-decoration: none; background-color: var(--primary); - color: var(--fg-primary); - border-radius: 2rem; + color: #fff; + border-radius: 1rem; width: 2rem; height: 2rem; text-align: center; line-height: 2rem; - font-family: "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji", sans-serif; } -#options::before { - content: '⚙'; - font-size: 1rem; +#options::before { content: '⚙'; font-size: 1rem; } + +/* Title input in legacy UI */ +input#title { + margin: 8px; + padding: 0.5em; + color: var(--fg); + background-color: var(--bg); + border: 1px solid var(--border); + border-radius: var(--radius-md); + font-size: 1.01em; +} + +/* Quick Settings */ +.quick-settings { + background: var(--bg-secondary); + border-bottom: 1px solid var(--border); + padding: var(--spacing-sm) var(--spacing-md); + flex: 0 0 auto; /* fixed height section */ +} + +.quick-settings h3 { + font-size: var(--font-size-sm); + font-weight: var(--font-weight-medium); + margin-bottom: var(--spacing-sm); + color: var(--fg); +} + +.settings-grid { + display: flex; + flex-direction: column; + gap: var(--spacing-sm); } -#downloadSelection { - background-color: var(--bg-primary); +.setting-item { + display: flex; + flex-direction: column; + gap: var(--spacing-sm); +} + +.setting-item label:first-child { + font-size: var(--font-size-sm); + font-weight: var(--font-weight-medium); + color: var(--fg); +} + +/* Toggle Switch */ +.toggle-switch { + display: flex; + align-items: center; + gap: var(--spacing-md); + cursor: pointer; + user-select: none; +} + +.toggle-switch input[type="checkbox"] { display: none; } -#selected, #document { - flex:1; +.slider { + position: relative; + width: 44px; + height: 24px; + background: var(--border); + border-radius: 12px; + transition: var(--transition-normal); + flex-shrink: 0; +} + +.slider::before { + content: ''; + position: absolute; + top: 2px; + left: 2px; + width: 20px; + height: 20px; + background: white; + border-radius: 50%; + transition: var(--transition-normal); + box-shadow: 0 2px 4px var(--shadow); +} + +.toggle-switch input:checked + .slider { + background: var(--primary); } -#clipOption { - display:none; +.toggle-switch input:checked + .slider::before { + transform: translateX(20px); } +.toggle-switch .label { + font-size: var(--font-size-sm); + font-weight: var(--font-weight-normal); + color: var(--fg-secondary); +} +/* Button Group */ +.button-group { + display: flex; + border: 1px solid var(--border); + border-radius: var(--radius-md); + overflow: hidden; +} -.button.toggle { +.toggle-button { + flex: 1; + display: flex; + align-items: center; + justify-content: center; + gap: var(--spacing-sm); + padding: var(--spacing-sm) var(--spacing-md); + background: var(--bg); + border: none; + border-right: 1px solid var(--border); + font-size: var(--font-size-sm); + font-weight: var(--font-weight-medium); + color: var(--fg-secondary); + cursor: pointer; + transition: var(--transition-fast); +} + +.toggle-button:last-child { + border-right: none; +} + +.toggle-button:hover { + background: var(--bg-tertiary); +} + +.toggle-button.active { + background: var(--primary); + color: white; +} + +.toggle-button svg { + flex-shrink: 0; +} + +/* Format Preview Styles */ +.format-preview { + font-family: 'Monaco', 'Menlo', 'Ubuntu Mono', monospace; + font-size: 10px; + line-height: 1.2; + text-align: center; + white-space: nowrap; + overflow: hidden; +} + +/* Three-button groups */ +.button-group .toggle-button:first-child:nth-last-child(3), +.button-group .toggle-button:first-child:nth-last-child(3) ~ .toggle-button { + flex: 1; + font-size: var(--font-size-xs); + padding: var(--spacing-xs) var(--spacing-sm); +} + +/* Action Section - now at top */ +.action-section { + padding: var(--spacing-sm) var(--spacing-md); + background: var(--bg-secondary); + border-top: 1px solid var(--border); + border-bottom: 1px solid var(--border); + flex: 0 0 auto; /* fixed height section */ +} + +/* Content Section - contains title and preview */ +.content-section { + flex: 1 1 0; + display: flex; + flex-direction: column; + overflow: hidden; /* prevent page scroll */ + min-height: 200px; /* ensure content section is always visible */ + max-height: none; /* let it take remaining space */ +} + +/* Title Section - now inside content section */ +.title-section { + flex: 0 0 auto; + padding: var(--spacing-md) var(--spacing-md) var(--spacing-sm); + background: var(--bg); +} + +.content-header { + margin-bottom: var(--spacing-sm); +} + +.title-label { + display: block; + font-size: var(--font-size-sm); + font-weight: var(--font-weight-medium); + color: var(--fg); + margin-bottom: var(--spacing-sm); +} + +.title-input { + width: 100%; + padding: var(--spacing-md); + background: var(--bg); + border: 1px solid var(--border); + border-radius: var(--radius-md); + font-size: var(--font-size-base); + color: var(--fg); + transition: var(--transition-fast); +} + +.title-input:focus { + border-color: var(--primary); + box-shadow: 0 0 0 3px var(--primary-light); +} + +.title-input::placeholder { + color: var(--fg-muted); +} + +/* Editor Container */ +.editor-container { + flex: 1 1 0; + display: flex; + flex-direction: column; background: var(--bg); border: 1px solid var(--border); - box-shadow: 0 2px 4px rgba(0, 0, 0, 0.05); + border-radius: var(--radius-md); + overflow: hidden; + min-height: 180px; /* ensure preview always visible */ + max-height: none; /* let it expand */ position: relative; - color:var(--fg); + margin: 0 var(--spacing-md) var(--spacing-md); +} + +/* Make textarea/editor area scroll independently */ +.editor-container > textarea, +.editor-container > .CodeMirror { + min-height: 0; + flex: 1 1 auto; +} + +.editor-header { + display: flex; + align-items: center; + justify-content: space-between; + padding: var(--spacing-md) var(--spacing-lg); + background: var(--bg-secondary); + border-bottom: 1px solid var(--border); + flex: 0 0 auto; +} + +.editor-label { + font-size: var(--font-size-sm); + font-weight: var(--font-weight-medium); + color: var(--fg); +} + +.editor-actions { + display: flex; + gap: var(--spacing-sm); +} + +.action-button { + display: flex; + align-items: center; + gap: var(--spacing-xs); + padding: var(--spacing-xs) var(--spacing-sm); + background: transparent; + border: 1px solid var(--border); + border-radius: var(--radius-sm); + font-size: var(--font-size-xs); + color: var(--fg-secondary); cursor: pointer; - padding: 10px 10px 10px 30px; + transition: var(--transition-fast); +} + +.action-button:hover { + background: var(--bg-tertiary); + border-color: var(--primary); + color: var(--primary); +} + +.action-button.secondary { + background: var(--bg); +} + +/* Copy button text animation */ +#copy-text { + transition: all 0.2s ease-in-out; display: inline-block; - font-weight: 600; - transition: .3s ease all; } -.button.toggle:hover { - box-shadow: 0 4px 8px rgba(0, 0, 0, 0.05); +#copy-text.changing { + opacity: 0; + transform: translateY(-5px); } -.button.toggle.checked { - background: var(--bg-primary); - border-color: var(--border-primary); +/* Copy button hover effect */ +#copy:hover #copy-text { + transform: translateX(2px); } -.check { - background: var(--bg-primary); - border-radius: 50%; - content:''; - height: 20px; - left: 10px; +.markdown-editor { + flex: 1 1 0; + min-height: 0; /* let flex container control height */ + height: 100%; /* fill container */ + padding: var(--spacing-md); + background: var(--bg); + border: none; + font-family: 'Monaco', 'Menlo', 'Ubuntu Mono', monospace; + font-size: var(--font-size-sm); + line-height: 1.5; + color: var(--fg); + resize: none; + outline: none; + overflow-y: auto; /* enable vertical scrolling */ + overflow-x: hidden; + box-sizing: border-box; +} + +.markdown-editor::placeholder { + color: var(--fg-muted); + font-style: italic; +} + +/* CodeMirror Integration */ +.CodeMirror { + flex: 1 1 0; + height: 100% !important; /* fill container completely */ + border: none; + background: var(--bg); + font-family: 'Monaco', 'Menlo', 'Ubuntu Mono', monospace; + font-size: var(--font-size-sm); + line-height: 1.5; + overflow: hidden; /* let CodeMirror handle scrolling internally */ +} + +.CodeMirror-focused .CodeMirror-cursor { + border-left: 2px solid var(--primary); +} + +.CodeMirror-scroll { + height: 100% !important; + overflow-y: auto !important; + overflow-x: hidden !important; +} + +.CodeMirror-scrollbar-filler, .CodeMirror-gutter-filler { + background-color: var(--bg); +} + +/* Hide duplicate scrollbars */ +.CodeMirror-vscrollbar { + display: block !important; +} + +.CodeMirror-hscrollbar { + display: none !important; +} + +/* Ensure smooth scrolling */ +.CodeMirror-scroll { + scroll-behavior: smooth; +} + +.CodeMirror-selected { + background: var(--primary-light); +} + + +.button-row { + display: flex; + gap: var(--spacing-md); + align-items: center; +} + +/* Button with Overlay Help */ +.button-with-overlay-help { + position: relative; +} + +.button-with-overlay-help:hover .overlay-help-icon { + opacity: 1; + transform: scale(1.05); +} + +.overlay-help-icon { position: absolute; - top: calc(50% - 10px); - transition: .3s ease background-color; + top: 4px; + right: 4px; width: 20px; + height: 20px; + background: rgba(255, 255, 255, 0.9); + border-radius: 50%; + display: flex; + align-items: center; + justify-content: center; + cursor: pointer; + transition: all 0.2s ease; + opacity: 0.7; + color: var(--primary); + box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1); + backdrop-filter: blur(4px); } -.checked .check { - background-color: var(--primary); - background-image: url('data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz48c3ZnIHdpZHRoPSIyNiIgaGVpZ2h0PSIyMCIgdmVyc2lvbj0iMS4xIiB2aWV3Qm94PSIyLjAyOTY4IC00MC4wOTAzIDI2IDIwIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIj48IS0tR2VuZXJhdGVkIGJ5IElKU1ZHIChodHRwczovL2dpdGh1Yi5jb20vaWNvbmphci9JSlNWRyktLT48cGF0aCBkPSJNMjcuOTc0MywtMzYuMTI3MmMwLDAuNDQ2NDI4IC0wLjE1NjI1LDAuODI1ODkzIC0wLjQ2ODc1LDEuMTM4MzlsLTEyLjEyMDUsMTIuMTIwNWwtMi4yNzY3OSwyLjI3Njc5Yy0wLjMxMjUsMC4zMTI1IC0wLjY5MTk2NCwwLjQ2ODc1IC0xLjEzODM5LDAuNDY4NzVjLTAuNDQ2NDI4LDAgLTAuODI1ODkzLC0wLjE1NjI1IC0xLjEzODM5LC0wLjQ2ODc1bC0yLjI3Njc5LC0yLjI3Njc5bC02LjA2MDI3LC02LjA2MDI3Yy0wLjMxMjUsLTAuMzEyNSAtMC40Njg3NSwtMC42OTE5NjUgLTAuNDY4NzUsLTEuMTM4MzljMCwtMC40NDY0MjkgMC4xNTYyNSwtMC44MjU4OTMgMC40Njg3NSwtMS4xMzgzOWwyLjI3Njc5LC0yLjI3Njc5YzAuMzEyNSwtMC4zMTI1IDAuNjkxOTY1LC0wLjQ2ODc1IDEuMTM4MzksLTAuNDY4NzVjMC40NDY0MjksMCAwLjgyNTg5MywwLjE1NjI1IDEuMTM4MzksMC40Njg3NWw0LjkyMTg4LDQuOTM4NjJsMTAuOTgyMSwtMTAuOTk4OWMwLjMxMjUsLTAuMzEyNSAwLjY5MTk2NCwtMC40Njg3NSAxLjEzODM5LC0wLjQ2ODc1YzAuNDQ2NDI4LDAgMC44MjU4OTMsMC4xNTYyNSAxLjEzODM5LDAuNDY4NzVsMi4yNzY3OCwyLjI3Njc5YzAuMzEyNSwwLjMxMjUgMC40Njg3NSwwLjY5MTk2NCAwLjQ2ODc1LDEuMTM4MzlaIiB0cmFuc2Zvcm09InNjYWxlKDEuMDAxOTgpIiBmaWxsPSIjZmZmIj48L3BhdGg+PC9zdmc+'); - background-repeat: no-repeat; - background-position: center; - background-size: 12px; +.overlay-help-icon:hover { + opacity: 1; + transform: scale(1.1); + background: rgba(255, 255, 255, 0.95); + box-shadow: 0 2px 6px rgba(0, 0, 0, 0.15); +} + +/* Dark mode support for overlay help */ +@media (prefers-color-scheme: dark) { + .overlay-help-icon { + background: rgba(0, 0, 0, 0.8); + color: var(--primary-light); + } + + .overlay-help-icon:hover { + background: rgba(0, 0, 0, 0.9); + } +} + +/* Modal Styles */ +.modal-overlay { + position: fixed; + top: 0; + left: 0; + width: 100%; + height: 100%; + background: rgba(0, 0, 0, 0.5); + display: flex; + align-items: center; + justify-content: center; + z-index: 1000; + backdrop-filter: blur(4px); + animation: fadeIn 0.2s ease-out; +} + +.modal-content { + background: var(--bg); + border-radius: var(--radius-lg); + width: 90%; + max-width: 480px; + max-height: 80vh; + overflow-y: auto; + box-shadow: 0 20px 40px rgba(0, 0, 0, 0.3); + animation: slideUp 0.3s cubic-bezier(0.4, 0, 0.2, 1); +} + +.modal-header { + display: flex; + align-items: center; + justify-content: space-between; + padding: var(--spacing-lg); + border-bottom: 1px solid var(--border); + background: var(--bg-secondary); + border-radius: var(--radius-lg) var(--radius-lg) 0 0; +} + +.modal-header h3 { + margin: 0; + font-size: var(--font-size-lg); + font-weight: var(--font-weight-medium); + color: var(--fg); +} + +.close-button { + background: none; + border: none; + font-size: 24px; + cursor: pointer; + color: var(--fg-muted); + padding: var(--spacing-xs); + border-radius: var(--radius-sm); + transition: var(--transition-fast); + line-height: 1; +} + +.close-button:hover { + background: var(--bg-tertiary); + color: var(--fg); +} + +.modal-body { + padding: var(--spacing-lg); +} + +@keyframes fadeIn { + from { opacity: 0; } + to { opacity: 1; } +} + +@keyframes slideUp { + from { + opacity: 0; + transform: translateY(20px) scale(0.95); + } + to { + opacity: 1; + transform: translateY(0) scale(1); + } +} + +/* Setup Steps */ +.setup-step { + display: flex; + gap: var(--spacing-md); + margin-bottom: var(--spacing-lg); + align-items: flex-start; +} + +.step-number { + background: var(--primary); + color: white; + width: 28px; + height: 28px; + border-radius: 50%; + display: flex; + align-items: center; + justify-content: center; + font-weight: var(--font-weight-medium); + font-size: var(--font-size-sm); + flex-shrink: 0; +} + +.step-content { + flex: 1; +} + +.step-content h4 { + margin: 0 0 var(--spacing-sm) 0; + font-size: var(--font-size-base); + font-weight: var(--font-weight-medium); + color: var(--fg); +} + +.step-content p { + margin: 0; + color: var(--fg-muted); + line-height: 1.5; } + +.quick-setup { + margin-top: var(--spacing-md); + padding: var(--spacing-md); + background: var(--bg-secondary); + border-radius: var(--radius-md); + border: 1px solid var(--border); +} + +.quick-setup label { + display: block; + font-size: var(--font-size-sm); + font-weight: var(--font-weight-medium); + color: var(--fg); + margin-bottom: var(--spacing-xs); + margin-top: var(--spacing-sm); +} + +.quick-setup label:first-child { + margin-top: 0; +} + +.setup-input { + width: 100%; + padding: var(--spacing-sm); + border: 1px solid var(--border); + border-radius: var(--radius-sm); + background: var(--bg); + color: var(--fg); + font-size: var(--font-size-sm); + margin-bottom: var(--spacing-sm); + transition: var(--transition-fast); + box-sizing: border-box; +} + +.setup-input:focus { + outline: none; + border-color: var(--primary); + box-shadow: 0 0 0 2px var(--primary-light); +} + +.setup-button { + background: var(--primary); + color: white; + border: none; + padding: var(--spacing-sm) var(--spacing-lg); + border-radius: var(--radius-md); + font-size: var(--font-size-sm); + font-weight: var(--font-weight-medium); + cursor: pointer; + transition: var(--transition-fast); + margin-top: var(--spacing-sm); +} + +.setup-button:hover { + background: var(--primary-hover); + transform: translateY(-1px); +} + + +.primary-button { + flex: 1; + display: flex; + align-items: center; + justify-content: center; + gap: var(--spacing-sm); + padding: var(--spacing-lg) var(--spacing-xl); + background: var(--primary); + border: none; + border-radius: var(--radius-md); + font-size: var(--font-size-base); + font-weight: var(--font-weight-medium); + color: white; + cursor: pointer; + transition: var(--transition-fast); + box-shadow: 0 2px 4px var(--shadow); +} + +.primary-button:hover { + background: var(--primary-hover); + transform: translateY(-1px); + box-shadow: 0 4px 8px var(--shadow-hover); +} + +.primary-button:active { + transform: translateY(0); + box-shadow: 0 2px 4px var(--shadow); +} + +.secondary-button { + display: flex; + align-items: center; + justify-content: center; + gap: var(--spacing-sm); + padding: var(--spacing-lg) var(--spacing-xl); + background: var(--bg); + border: 1px solid var(--border); + border-radius: var(--radius-md); + font-size: var(--font-size-base); + font-weight: var(--font-weight-medium); + color: var(--fg); + cursor: pointer; + transition: var(--transition-fast); +} + +.secondary-button:hover { + background: var(--bg-tertiary); + border-color: var(--primary); + color: var(--primary); + transform: translateY(-1px); +} + +/* Status Bar - stays at bottom */ +.status-bar { + padding: var(--spacing-sm) var(--spacing-lg); + background: var(--bg-tertiary); + border-top: 1px solid var(--border); + text-align: center; + transition: var(--transition-fast); + flex: 0 0 auto; /* keep at bottom */ +} + +.status-bar.pulse { + animation: statusPulse 0.5s ease-out; +} + +#status-text { + font-size: var(--font-size-xs); + color: var(--fg-muted); + transition: var(--transition-fast); +} + +@keyframes statusPulse { + 0% { + transform: scale(1); + background: var(--bg-tertiary); + } + 50% { + transform: scale(1.02); + background: var(--primary-light); + } + 100% { + transform: scale(1); + background: var(--bg-tertiary); + } +} + +/* Button State Classes */ +.action-button.success, +.primary-button.success, +.secondary-button.success { + background: var(--success); + border-color: var(--success); + color: white; +} + +.action-button.error, +.primary-button.error, +.secondary-button.error { + background: var(--danger); + border-color: var(--danger); + color: white; +} + +.action-button.warning, +.primary-button.warning, +.secondary-button.warning { + background: var(--warning); + border-color: var(--warning); + color: white; +} + +/* Utility Classes */ +.hidden { + display: none !important; +} + +.success { + color: var(--success); +} + +.error { + color: var(--danger); +} + +.warning { + color: var(--warning); +} + +/* Loading state for buttons */ +.primary-button:disabled, +.secondary-button:disabled, +.action-button:disabled { + opacity: 0.6; + cursor: not-allowed; + transform: none; +} + +/* Animation Classes */ +@keyframes fadeIn { + from { + opacity: 0; + transform: translateY(10px); + } + to { + opacity: 1; + transform: translateY(0); + } +} + +@keyframes slideIn { + from { + opacity: 0; + transform: translateX(-10px); + } + to { + opacity: 1; + transform: translateX(0); + } +} + +.fade-in { + animation: fadeIn var(--transition-normal) ease-out; +} + +.slide-in { + animation: slideIn var(--transition-normal) ease-out; +} + +/* Responsive adjustments */ +@media (max-width: 480px) { + body { + width: 450px; + height: 600px; + } + + .header { + padding: var(--spacing-sm) var(--spacing-md); + } + + .quick-settings { + padding: var(--spacing-xs) var(--spacing-sm); + } + + .content-section { + padding: var(--spacing-sm); + min-height: 150px; + } + + .action-section { + padding: var(--spacing-xs) var(--spacing-sm); + } + + .button-row { + gap: var(--spacing-sm); + } +} + +/* Focus states for accessibility */ +.toggle-switch:focus-within .slider { + box-shadow: 0 0 0 3px var(--primary-light); +} + +.toggle-button:focus { + box-shadow: 0 0 0 3px var(--primary-light); +} + +/* High contrast mode support */ +@media (prefers-contrast: high) { + :root { + --border: #000000; + --shadow: rgba(0, 0, 0, 0.5); + } + + @media (prefers-color-scheme: dark) { + :root { + --border: #FFFFFF; + } + } +} + +/* Reduced motion support */ +@media (prefers-reduced-motion: reduce) { + * { + animation-duration: 0.01ms !important; + animation-iteration-count: 1 !important; + transition-duration: 0.01ms !important; + } + + .header::before { + animation: none !important; + opacity: 0.3; + } + + .status-bar.pulse { + animation: none !important; + } + + .primary-button:hover, + .secondary-button:hover, + .action-button:hover, + .toggle-button:hover, + .icon-button:hover { + transform: none !important; + } +} \ No newline at end of file diff --git a/src/popup/popup.html b/src/popup/popup.html index 54eaaee4..7d381fdc 100644 --- a/src/popup/popup.html +++ b/src/popup/popup.html @@ -1,32 +1,194 @@ - - - - - - - - - + + + + + MarkDownload + + + + + -
- - Download Images - open options -
- Selected Text - Entire Document + +
+
+
+

Processing page...

- Include front/back template - - - Download - Download selected
-
- + + +
+ +
+ + +
+ + +
+

Quick Settings

+
+
+ +
+
+ +
+
+ +
+ + +
+
+
+
+ + +
+
+ + +
+
+ + +
+ +
+
+ + +
+
+ + +
+
+ Markdown Preview +
+ +
+
+ +
+
+ + +
+ Ready +
+
+ + + + + diff --git a/src/popup/popup.js b/src/popup/popup.js index 773e857e..8d541aba 100644 --- a/src/popup/popup.js +++ b/src/popup/popup.js @@ -3,88 +3,372 @@ var selectedText = null; var imageList = null; var mdClipsFolder = ''; +var cm = null; const darkMode = window.matchMedia('(prefers-color-scheme: dark)').matches; -// set up event handlers -const cm = CodeMirror.fromTextArea(document.getElementById("md"), { - theme: darkMode ? "xq-dark" : "xq-light", - mode: "markdown", - lineWrapping: true -}); -cm.on("cursorActivity", (cm) => { - const somethingSelected = cm.somethingSelected(); - var a = document.getElementById("downloadSelection"); - if (somethingSelected) { - if(a.style.display != "block") a.style.display = "block"; +// Initialize CodeMirror when DOM is ready +const initializeCodeMirror = () => { + const textarea = document.getElementById("md"); + if (textarea && !cm) { + cm = CodeMirror.fromTextArea(textarea, { + theme: darkMode ? "xq-dark" : "xq-light", + mode: "markdown", + lineWrapping: true, + lineNumbers: false, + readOnly: false, + viewportMargin: Infinity, + scrollbarStyle: "native" + }); + + cm.on("cursorActivity", (cm) => { + const somethingSelected = cm.somethingSelected(); + const copyText = document.getElementById("copy-text"); + + if (somethingSelected) { + if (copyText && copyText.textContent !== "Copy Selection") { + animateTextChange(copyText, "Copy Selection"); + } + } else { + if (copyText && copyText.textContent !== "Copy") { + animateTextChange(copyText, "Copy"); + } + } + }); + + // Refresh CodeMirror after initialization + setTimeout(() => { + cm.refresh(); + }, 100); } - else { - if(a.style.display != "none") a.style.display = "none"; +}; + +// Animate text change with smooth transition +const animateTextChange = (element, newText) => { + if (!element) return; + + element.classList.add('changing'); + + setTimeout(() => { + element.textContent = newText; + element.classList.remove('changing'); + }, 100); +}; + +// Update status bar +const updateStatus = (message, type = 'info') => { + const statusText = document.getElementById('status-text'); + const statusBar = document.getElementById('status-bar'); + + if (statusText) { + statusText.textContent = message; + statusText.className = type; // success, error, warning + + // Add pulse animation for visual feedback + if (statusBar && !window.matchMedia('(prefers-reduced-motion: reduce)').matches) { + statusBar.classList.add('pulse'); + setTimeout(() => { + statusBar.classList.remove('pulse'); + }, 500); + } + + // Auto-clear status after 3 seconds for success messages + if (type === 'success') { + setTimeout(() => { + statusText.textContent = 'Ready'; + statusText.className = ''; + }, 3000); + } } +}; + +// Add basic event listeners (will be supplemented by setupEventListeners) +document.addEventListener('DOMContentLoaded', () => { + document.getElementById("download")?.addEventListener("click", download); + document.getElementById("copy")?.addEventListener("click", copyToClipboard); + document.getElementById("sendToObsidian")?.addEventListener("click", sendToObsidian); + document.getElementById("obsidianHelp")?.addEventListener("click", (e) => { + e.stopPropagation(); // 阻止事件冒泡到按钮 + e.preventDefault(); + showObsidianHelp(); + }); + document.getElementById("closeModal")?.addEventListener("click", hideObsidianHelp); + document.getElementById("saveObsidianSettings")?.addEventListener("click", saveObsidianSettings); + + // Close modal when clicking overlay + document.getElementById("obsidianHelpModal")?.addEventListener("click", (e) => { + if (e.target.id === "obsidianHelpModal") { + hideObsidianHelp(); + } + }); + + // Load existing Obsidian settings + loadObsidianSettings(); }); -document.getElementById("download").addEventListener("click", download); -document.getElementById("downloadSelection").addEventListener("click", downloadSelection); -const defaultOptions = { +// Provide a local defaultOptions fallback in case shared script isn't loaded +const localDefaultOptions = { + headingStyle: "atx", + hr: "___", + bulletListMarker: "-", + codeBlockStyle: "fenced", + fence: "```", + emDelimiter: "_", + strongDelimiter: "**", + linkStyle: "inlined", + linkReferenceStyle: "full", + imageStyle: "markdown", + imageRefStyle: "inlined", + frontmatter: "", + backmatter: "", + title: "{pageTitle}", includeTemplate: false, - clipSelection: true, - downloadImages: false + saveAs: false, + downloadImages: false, + imagePrefix: '{pageTitle}/', + imageFilenameTemplate: '{pageTitle:kebab}_{imageIndex}.{ext}', + mdClipsFolder: null, + disallowedChars: '[]#^', + downloadMode: 'downloadsApi', + turndownEscape: true, + contextMenus: true, + obsidianIntegration: false, + obsidianVault: "", + obsidianFolder: "" +}; + +// Use shared defaultOptions if present, otherwise fallback +const baseDefaults = (typeof defaultOptions !== 'undefined') ? defaultOptions : localDefaultOptions; + +// Add clipSelection to the default options +const popupDefaultOptions = { + ...baseDefaults, + clipSelection: true } const checkInitialSettings = options => { - if (options.includeTemplate) - document.querySelector("#includeTemplate").classList.add("checked"); + // Update includeTemplate state (supports input checkbox or legacy anchor) + const includeTemplateEl = document.querySelector("#includeTemplate"); + if (includeTemplateEl) { + if (includeTemplateEl.tagName === 'INPUT') { + includeTemplateEl.checked = !!options.includeTemplate; + } else { + includeTemplateEl.classList.toggle('checked', !!options.includeTemplate); + } + } - if (options.downloadImages) - document.querySelector("#downloadImages").classList.add("checked"); + // Update downloadImages state (supports input checkbox or legacy anchor) + const downloadImagesEl = document.querySelector("#downloadImages"); + if (downloadImagesEl) { + if (downloadImagesEl.tagName === 'INPUT') { + downloadImagesEl.checked = !!options.downloadImages; + } else { + downloadImagesEl.classList.toggle('checked', !!options.downloadImages); + } + } + + // Update toggle buttons for clip selection + const selectedBtn = document.querySelector("#selected"); + const documentBtn = document.querySelector("#document"); + + if (selectedBtn && documentBtn) { + if (options.clipSelection) { + selectedBtn.classList.add("active"); + documentBtn.classList.remove("active"); + } else { + selectedBtn.classList.remove("active"); + documentBtn.classList.add("active"); + } + } + + // Update heading style buttons + const atxBtn = document.querySelector("#heading-atx"); + const setextBtn = document.querySelector("#heading-setext"); + + if (atxBtn && setextBtn) { + if (options.headingStyle === 'atx') { + atxBtn.classList.add("active"); + setextBtn.classList.remove("active"); + } else { + atxBtn.classList.remove("active"); + setextBtn.classList.add("active"); + } + } - if (options.clipSelection) - document.querySelector("#selected").classList.add("checked"); - else - document.querySelector("#document").classList.add("checked"); + // Update link style buttons + const inlinedBtn = document.querySelector("#link-inlined"); + const referencedBtn = document.querySelector("#link-referenced"); + const stripBtn = document.querySelector("#link-strip"); + + [inlinedBtn, referencedBtn, stripBtn].forEach(btn => { + if (btn) btn.classList.remove("active"); + }); + + if (options.linkStyle === 'inlined' && inlinedBtn) { + inlinedBtn.classList.add("active"); + } else if (options.linkStyle === 'referenced' && referencedBtn) { + referencedBtn.classList.add("active"); + } else if (options.linkStyle === 'stripLinks' && stripBtn) { + stripBtn.classList.add("active"); + } } -const toggleClipSelection = options => { - options.clipSelection = !options.clipSelection; - document.querySelector("#selected").classList.toggle("checked"); - document.querySelector("#document").classList.toggle("checked"); - browser.storage.sync.set(options).then(() => clipSite()).catch((error) => { +const toggleClipSelection = (options, value) => { + options.clipSelection = (value === 'selection'); + + const selectedBtn = document.querySelector("#selected"); + const documentBtn = document.querySelector("#document"); + + if (selectedBtn && documentBtn) { + if (options.clipSelection) { + selectedBtn.classList.add("active"); + documentBtn.classList.remove("active"); + } else { + selectedBtn.classList.remove("active"); + documentBtn.classList.add("active"); + } + } + + updateStatus("Updating content selection...", "info"); + + chrome.storage.sync.set(options).then(() => { + // Get current tab ID and call clipSite + chrome.tabs.query({ currentWindow: true, active: true }).then(tabs => { + if (tabs[0]) { + clipSite(tabs[0].id); + } + }).catch(error => { + console.error('Failed to get tab ID:', error); + updateStatus("Error updating selection", "error"); + }); + }).catch((error) => { console.error(error); + updateStatus("Failed to save settings", "error"); }); } const toggleIncludeTemplate = options => { - options.includeTemplate = !options.includeTemplate; - document.querySelector("#includeTemplate").classList.toggle("checked"); - browser.storage.sync.set(options).then(() => { - browser.contextMenus.update("toggle-includeTemplate", { + const el = document.querySelector("#includeTemplate"); + if (!el) return; + + if (el.tagName === 'INPUT') { + options.includeTemplate = !!el.checked; + } else { + options.includeTemplate = !options.includeTemplate; + el.classList.toggle('checked', !!options.includeTemplate); + } + updateStatus("Updating template settings...", "info"); + + chrome.storage.sync.set(options).then(() => { + chrome.contextMenus.update("toggle-includeTemplate", { checked: options.includeTemplate }); - try { - browser.contextMenus.update("tabtoggle-includeTemplate", { - checked: options.includeTemplate - }); - } catch { } - return clipSite() + // Get current tab ID and call clipSite + chrome.tabs.query({ currentWindow: true, active: true }).then(tabs => { + if (tabs[0]) { + clipSite(tabs[0].id); + } + }).catch(error => { + console.error('Failed to get tab ID:', error); + updateStatus("Error updating content", "error"); + }); }).catch((error) => { console.error(error); + updateStatus("Failed to save settings", "error"); }); } const toggleDownloadImages = options => { - options.downloadImages = !options.downloadImages; - document.querySelector("#downloadImages").classList.toggle("checked"); - browser.storage.sync.set(options).then(() => { - browser.contextMenus.update("toggle-downloadImages", { + const el = document.querySelector("#downloadImages"); + if (!el) return; + + if (el.tagName === 'INPUT') { + options.downloadImages = !!el.checked; + } else { + options.downloadImages = !options.downloadImages; + el.classList.toggle('checked', !!options.downloadImages); + } + updateStatus("Updating image settings...", "info"); + + chrome.storage.sync.set(options).then(() => { + chrome.contextMenus.update("toggle-downloadImages", { checked: options.downloadImages }); - try { - browser.contextMenus.update("tabtoggle-downloadImages", { - checked: options.downloadImages - }); - } catch { } + updateStatus("Settings saved", "success"); + }).catch((error) => { + console.error(error); + updateStatus("Failed to save settings", "error"); + }); +} + +const toggleHeadingStyle = (options, value) => { + options.headingStyle = value; + + const atxBtn = document.querySelector("#heading-atx"); + const setextBtn = document.querySelector("#heading-setext"); + + if (atxBtn && setextBtn) { + if (value === 'atx') { + atxBtn.classList.add("active"); + setextBtn.classList.remove("active"); + } else { + atxBtn.classList.remove("active"); + setextBtn.classList.add("active"); + } + } + + updateStatus("Updating heading style...", "info"); + + chrome.storage.sync.set(options).then(() => { + // Get current tab ID and re-clip to show changes + chrome.tabs.query({ currentWindow: true, active: true }).then(tabs => { + if (tabs[0]) { + clipSite(tabs[0].id); + } + }).catch(error => { + console.error('Failed to get tab ID:', error); + }); + updateStatus("Heading style updated", "success"); + }).catch((error) => { + console.error(error); + updateStatus("Failed to save settings", "error"); + }); +} + +const toggleLinkStyle = (options, value) => { + options.linkStyle = value; + + const inlinedBtn = document.querySelector("#link-inlined"); + const referencedBtn = document.querySelector("#link-referenced"); + const stripBtn = document.querySelector("#link-strip"); + + [inlinedBtn, referencedBtn, stripBtn].forEach(btn => { + if (btn) btn.classList.remove("active"); + }); + + if (value === 'inlined' && inlinedBtn) { + inlinedBtn.classList.add("active"); + } else if (value === 'referenced' && referencedBtn) { + referencedBtn.classList.add("active"); + } else if (value === 'stripLinks' && stripBtn) { + stripBtn.classList.add("active"); + } + + updateStatus("Updating link style...", "info"); + + chrome.storage.sync.set(options).then(() => { + // Get current tab ID and re-clip to show changes + chrome.tabs.query({ currentWindow: true, active: true }).then(tabs => { + if (tabs[0]) { + clipSite(tabs[0].id); + } + }).catch(error => { + console.error('Failed to get tab ID:', error); + }); + updateStatus("Link style updated", "success"); }).catch((error) => { console.error(error); + updateStatus("Failed to save settings", "error"); }); } const showOrHideClipOption = selection => { @@ -97,102 +381,182 @@ const showOrHideClipOption = selection => { } const clipSite = id => { - return browser.tabs.executeScript(id, { code: "getSelectionAndDom()" }) - .then((result) => { - if (result && result[0]) { - showOrHideClipOption(result[0].selection); - let message = { - type: "clip", - dom: result[0].dom, - selection: result[0].selection - } - return browser.storage.sync.get(defaultOptions).then(options => { - browser.runtime.sendMessage({ - ...message, - ...options - }); - }).catch(err => { - console.error(err); - showError(err) - return browser.runtime.sendMessage({ - ...message, - ...defaultOptions - }); - }).catch(err => { - console.error(err); - showError(err) - }); + return chrome.scripting.executeScript({ + target: { tabId: id }, + func: () => { + return getSelectionAndDom(); + } + }).then((result) => { + if (result && result[0] && result[0].result) { + showOrHideClipOption(result[0].result.selection); + let message = { + type: "clip", + dom: result[0].result.dom, + selection: result[0].result.selection, + tabId: id } - }).catch(err => { - console.error(err); - showError(err) - }); + return chrome.storage.sync.get(popupDefaultOptions).then(options => { + chrome.runtime.sendMessage({ + ...message, + ...options + }); + }).catch(err => { + console.error(err); + showError(err) + return chrome.runtime.sendMessage({ + ...message, + ...popupDefaultOptions + }); + }).catch(err => { + console.error(err); + showError(err) + }); + } + }).catch(err => { + console.error(err); + showError(err) + }); } -// inject the necessary scripts -browser.storage.sync.get(defaultOptions).then(options => { - checkInitialSettings(options); - - document.getElementById("selected").addEventListener("click", (e) => { - e.preventDefault(); - toggleClipSelection(options); - }); - document.getElementById("document").addEventListener("click", (e) => { - e.preventDefault(); - toggleClipSelection(options); - }); - document.getElementById("includeTemplate").addEventListener("click", (e) => { - e.preventDefault(); - toggleIncludeTemplate(options); - }); - document.getElementById("downloadImages").addEventListener("click", (e) => { - e.preventDefault(); - toggleDownloadImages(options); - }); +// Initialize popup +const initializePopup = () => { + updateStatus("Loading settings...", "info"); - return browser.tabs.query({ - currentWindow: true, - active: true - }); -}).then((tabs) => { - var id = tabs[0].id; - var url = tabs[0].url; - browser.tabs.executeScript(id, { - file: "/browser-polyfill.min.js" - }) - .then(() => { - return browser.tabs.executeScript(id, { - file: "/contentScript/contentScript.js" - }); - }).then( () => { - console.info("Successfully injected MarkDownload content script"); - return clipSite(id); - }).catch( (error) => { + chrome.storage.sync.get(popupDefaultOptions).then(options => { + checkInitialSettings(options); + setupEventListeners(options); + + return chrome.tabs.query({ + currentWindow: true, + active: true + }); + }).then((tabs) => { + if (tabs && tabs[0]) { + const id = tabs[0].id; + const url = tabs[0].url; + + updateStatus("Processing page...", "info"); + console.info("MarkDownload popup: Content script should be available"); + return clipSite(id); + } else { + throw new Error("No active tab found"); + } + }).catch((error) => { console.error(error); showError(error); }); +}; + +// Setup event listeners +const setupEventListeners = (options) => { + // Toggle buttons for clip selection + const selectedBtn = document.getElementById("selected"); + const documentBtn = document.getElementById("document"); + + if (selectedBtn) { + selectedBtn.addEventListener("click", (e) => { + e.preventDefault(); + toggleClipSelection(options, 'selection'); + }); + } + + if (documentBtn) { + documentBtn.addEventListener("click", (e) => { + e.preventDefault(); + toggleClipSelection(options, 'document'); + }); + } + + // Heading style buttons + const headingAtxBtn = document.getElementById("heading-atx"); + const headingSetextBtn = document.getElementById("heading-setext"); + + if (headingAtxBtn) { + headingAtxBtn.addEventListener("click", (e) => { + e.preventDefault(); + toggleHeadingStyle(options, 'atx'); + }); + } + + if (headingSetextBtn) { + headingSetextBtn.addEventListener("click", (e) => { + e.preventDefault(); + toggleHeadingStyle(options, 'setext'); + }); + } + + // Link style buttons + const linkInlinedBtn = document.getElementById("link-inlined"); + const linkReferencedBtn = document.getElementById("link-referenced"); + const linkStripBtn = document.getElementById("link-strip"); + + if (linkInlinedBtn) { + linkInlinedBtn.addEventListener("click", (e) => { + e.preventDefault(); + toggleLinkStyle(options, 'inlined'); + }); + } + + if (linkReferencedBtn) { + linkReferencedBtn.addEventListener("click", (e) => { + e.preventDefault(); + toggleLinkStyle(options, 'referenced'); + }); + } + + if (linkStripBtn) { + linkStripBtn.addEventListener("click", (e) => { + e.preventDefault(); + toggleLinkStyle(options, 'stripLinks'); + }); + } + + // Checkbox event listeners + const includeTemplateEl = document.getElementById("includeTemplate"); + if (includeTemplateEl) { + const evt = (includeTemplateEl.tagName === 'INPUT') ? 'change' : 'click'; + includeTemplateEl.addEventListener(evt, (e) => { + e.preventDefault(); + toggleIncludeTemplate(options); + }); + } + + const downloadImagesEl = document.getElementById("downloadImages"); + if (downloadImagesEl) { + const evt2 = (downloadImagesEl.tagName === 'INPUT') ? 'change' : 'click'; + downloadImagesEl.addEventListener(evt2, (e) => { + e.preventDefault(); + toggleDownloadImages(options); + }); + } +}; + +// Call initialization when DOM is ready +document.addEventListener('DOMContentLoaded', () => { + initializeCodeMirror(); + initializePopup(); }); // listen for notifications from the background page -browser.runtime.onMessage.addListener(notify); +chrome.runtime.onMessage.addListener(notify); //function to send the download message to the background page function sendDownloadMessage(text) { if (text != null) { - - return browser.tabs.query({ + return chrome.tabs.query({ currentWindow: true, active: true }).then(tabs => { + const activeTab = tabs[0]; var message = { type: "download", markdown: text, title: document.getElementById("title").value, - tab: tabs[0], + tabId: activeTab?.id, imageList: imageList, mdClipsFolder: mdClipsFolder }; - return browser.runtime.sendMessage(message); + return chrome.runtime.sendMessage(message); }); } } @@ -204,11 +568,135 @@ async function download(e) { window.close(); } -// event handler for download selected button -async function downloadSelection(e) { + +// Obsidian Help Modal Functions +function showObsidianHelp() { + const modal = document.getElementById("obsidianHelpModal"); + if (modal) { + modal.style.display = "flex"; + document.body.style.overflow = "hidden"; + } +} + +function hideObsidianHelp() { + const modal = document.getElementById("obsidianHelpModal"); + if (modal) { + modal.style.display = "none"; + document.body.style.overflow = ""; + } +} + +async function loadObsidianSettings() { + try { + const result = await chrome.storage.sync.get(['obsidianVault', 'obsidianFolder']); + const vaultInput = document.getElementById("vaultName"); + const folderInput = document.getElementById("folderPath"); + + if (vaultInput && result.obsidianVault) { + vaultInput.value = result.obsidianVault; + } + if (folderInput && result.obsidianFolder) { + folderInput.value = result.obsidianFolder; + } + } catch (error) { + console.log("Could not load Obsidian settings:", error); + } +} + +async function saveObsidianSettings() { + const vaultInput = document.getElementById("vaultName"); + const folderInput = document.getElementById("folderPath"); + + if (!vaultInput) return; + + const vaultName = vaultInput.value.trim(); + const folderPath = folderInput.value.trim(); + + if (!vaultName) { + updateStatus("Please enter a vault name", "warning"); + return; + } + + try { + await chrome.storage.sync.set({ + obsidianVault: vaultName, + obsidianFolder: folderPath, + obsidianIntegration: true + }); + + updateStatus("Obsidian settings saved!", "success"); + + // Close modal after a short delay + setTimeout(() => { + hideObsidianHelp(); + }, 1000); + + } catch (error) { + console.error("Error saving Obsidian settings:", error); + updateStatus("Failed to save settings", "error"); + } +} + +// event handler for copy button +async function copyToClipboard(e) { e.preventDefault(); - if (cm.somethingSelected()) { - await sendDownloadMessage(cm.getSelection()); + if (!cm) { + updateStatus("Editor not initialized", "error"); + return; + } + + try { + // Check if there's a selection, if so copy selection, otherwise copy all + const hasSelection = cm.somethingSelected(); + const textToCopy = hasSelection ? cm.getSelection() : cm.getValue(); + + if (!textToCopy.trim()) { + updateStatus("No content to copy", "warning"); + return; + } + + await navigator.clipboard.writeText(textToCopy); + + // Show feedback to user + const copyButton = document.getElementById("copy"); + const originalHTML = copyButton.innerHTML; + const feedbackText = hasSelection ? "Selection Copied!" : "Copied!"; + + copyButton.innerHTML = ` + + + + ${feedbackText} + `; + copyButton.classList.add("success"); + updateStatus("Content copied to clipboard", "success"); + + // Reset button after 2 seconds + setTimeout(() => { + copyButton.innerHTML = originalHTML; + copyButton.classList.remove("success"); + }, 2000); + + } catch (error) { + console.error('Failed to copy text: ', error); + + // Show error feedback + const copyButton = document.getElementById("copy"); + const originalHTML = copyButton.innerHTML; + + copyButton.innerHTML = ` + + + + Failed + `; + copyButton.classList.add("error"); + updateStatus("Failed to copy content", "error"); + + setTimeout(() => { + copyButton.innerHTML = originalHTML; + copyButton.classList.remove("error"); + }, 2000); } } @@ -216,27 +704,154 @@ async function downloadSelection(e) { function notify(message) { // message for displaying markdown if (message.type == "display.md") { - - // set the values from the message - //document.getElementById("md").value = message.markdown; - cm.setValue(message.markdown); - document.getElementById("title").value = message.article.title; - imageList = message.imageList; - mdClipsFolder = message.mdClipsFolder; + if (!cm) { + // Initialize CodeMirror if not already done + initializeCodeMirror(); + } - // show the hidden elements - document.getElementById("container").style.display = 'flex'; - document.getElementById("spinner").style.display = 'none'; - // focus the download button - document.getElementById("download").focus(); - cm.refresh(); + if (cm && message.markdown) { + // set the values from the message + cm.setValue(message.markdown); + setTimeout(() => cm.refresh(), 50); + + // Set the title + const titleInput = document.getElementById("title"); + if (titleInput && message.article && message.article.title) { + titleInput.value = message.article.title; + } + + imageList = message.imageList; + mdClipsFolder = message.mdClipsFolder; + + // show the main container and hide spinner + const container = document.getElementById("container"); + const spinner = document.getElementById("spinner"); + + if (container) { + container.style.display = 'flex'; + container.classList.add('fade-in'); + } + if (spinner) { + spinner.style.display = 'none'; + } + + // focus the download button and refresh CodeMirror + const downloadBtn = document.getElementById("download"); + if (downloadBtn) { + downloadBtn.focus(); + } + + if (cm) { + setTimeout(() => cm.refresh(), 100); + } + + updateStatus("Page processed successfully", "success"); + } } } function showError(err) { - // show the hidden elements - document.getElementById("container").style.display = 'flex'; - document.getElementById("spinner").style.display = 'none'; - cm.setValue(`Error clipping the page\n\n${err}`) + console.error("MarkDownload Error:", err); + + // show the main container and hide spinner + const container = document.getElementById("container"); + const spinner = document.getElementById("spinner"); + + if (container) { + container.style.display = 'flex'; + container.classList.add('fade-in'); + } + if (spinner) { + spinner.style.display = 'none'; + } + + // Initialize CodeMirror if not already done + if (!cm) { + initializeCodeMirror(); + } + + // Show error message in editor + if (cm) { + const errorMessage = `# Error Processing Page\n\n**Error Details:**\n\`\`\`\n${err}\n\`\`\`\n\n**Troubleshooting:**\n- Try refreshing the page and clipping again\n- Check if the page has finished loading\n- Some pages may not be supported\n- Check browser console for more details`; + cm.setValue(errorMessage); + setTimeout(() => cm.refresh(), 100); + } + + updateStatus(`Error: ${err}`, "error"); +} + +// event handler for send to Obsidian button +async function sendToObsidian(e) { + e.preventDefault(); + if (!cm) { + updateStatus("Editor not initialized", "error"); + return; + } + try { + const markdownContent = cm.getValue(); + if (!markdownContent.trim()) { + updateStatus("No content to send", "warning"); + return; + } + + updateStatus("Sending to Obsidian...", "info"); + + const tabs = await chrome.tabs.query({ currentWindow: true, active: true }); + const options = await chrome.storage.sync.get(popupDefaultOptions); + if (!options.obsidianIntegration) { + updateStatus("Obsidian integration not enabled. Enable it in Options.", "error"); + return; + } + if (!tabs[0]) { + updateStatus("No active tab found", "error"); + return; + } + + const titleInput = document.getElementById("title"); + const title = titleInput ? titleInput.value.trim() : "Untitled"; + + const response = await chrome.runtime.sendMessage({ + type: "sendToObsidian", + markdown: markdownContent, + title: title, + tabId: tabs[0].id, + options: options + }); + + if (response && response.success) { + updateStatus("Successfully sent to Obsidian!", "success"); + const obsidianButton = document.getElementById("sendToObsidian"); + const originalHTML = obsidianButton.innerHTML; + obsidianButton.innerHTML = ` + + + + Sent! + `; + obsidianButton.classList.add("success"); + setTimeout(() => { + obsidianButton.innerHTML = originalHTML; + obsidianButton.classList.remove("success"); + }, 3000); + } else { + throw new Error(response?.error || "Failed to send to Obsidian"); + } + } catch (error) { + console.error('Failed to send to Obsidian: ', error); + updateStatus(`Failed to send to Obsidian: ${error.message}`, "error"); + const obsidianButton = document.getElementById("sendToObsidian"); + const originalHTML = obsidianButton.innerHTML; + obsidianButton.innerHTML = ` + + + + Failed + `; + obsidianButton.classList.add("error"); + setTimeout(() => { + obsidianButton.innerHTML = originalHTML; + obsidianButton.classList.remove("error"); + }, 3000); + } } diff --git a/src/shared/context-menus.js b/src/shared/context-menus.js deleted file mode 100644 index fd049aef..00000000 --- a/src/shared/context-menus.js +++ /dev/null @@ -1,174 +0,0 @@ -// create the context menus -async function createMenus() { - const options = await getOptions(); - - browser.contextMenus.removeAll(); - - if (options.contextMenus) { - - // tab menu (chrome does not support this) - try { - browser.contextMenus.create({ - id: "download-markdown-tab", - title: "Download Tab as Markdown", - contexts: ["tab"] - }, () => { }); - - browser.contextMenus.create({ - id: "tab-download-markdown-alltabs", - title: "Download All Tabs as Markdown", - contexts: ["tab"] - }, () => { }); - - browser.contextMenus.create({ - id: "copy-tab-as-markdown-link-tab", - title: "Copy Tab URL as Markdown Link", - contexts: ["tab"] - }, () => { }); - - browser.contextMenus.create({ - id: "copy-tab-as-markdown-link-all-tab", - title: "Copy All Tab URLs as Markdown Link List", - contexts: ["tab"] - }, () => { }); - - browser.contextMenus.create({ - id: "copy-tab-as-markdown-link-selected-tab", - title: "Copy Selected Tab URLs as Markdown Link List", - contexts: ["tab"] - }, () => { }); - - browser.contextMenus.create({ - id: "tab-separator-1", - type: "separator", - contexts: ["tab"] - }, () => { }); - - browser.contextMenus.create({ - id: "tabtoggle-includeTemplate", - type: "checkbox", - title: "Include front/back template", - contexts: ["tab"], - checked: options.includeTemplate - }, () => { }); - - browser.contextMenus.create({ - id: "tabtoggle-downloadImages", - type: "checkbox", - title: "Download Images", - contexts: ["tab"], - checked: options.downloadImages - }, () => { }); - } catch { - - } - // add the download all tabs option to the page context menu as well - browser.contextMenus.create({ - id: "download-markdown-alltabs", - title: "Download All Tabs as Markdown", - contexts: ["all"] - }, () => { }); - browser.contextMenus.create({ - id: "separator-0", - type: "separator", - contexts: ["all"] - }, () => { }); - - // download actions - browser.contextMenus.create({ - id: "download-markdown-selection", - title: "Download Selection As Markdown", - contexts: ["selection"] - }, () => { }); - browser.contextMenus.create({ - id: "download-markdown-all", - title: "Download Tab As Markdown", - contexts: ["all"] - }, () => { }); - - browser.contextMenus.create({ - id: "separator-1", - type: "separator", - contexts: ["all"] - }, () => { }); - - // copy to clipboard actions - browser.contextMenus.create({ - id: "copy-markdown-selection", - title: "Copy Selection As Markdown", - contexts: ["selection"] - }, () => { }); - browser.contextMenus.create({ - id: "copy-markdown-link", - title: "Copy Link As Markdown", - contexts: ["link"] - }, () => { }); - browser.contextMenus.create({ - id: "copy-markdown-image", - title: "Copy Image As Markdown", - contexts: ["image"] - }, () => { }); - browser.contextMenus.create({ - id: "copy-markdown-all", - title: "Copy Tab As Markdown", - contexts: ["all"] - }, () => { }); - browser.contextMenus.create({ - id: "copy-tab-as-markdown-link", - title: "Copy Tab URL as Markdown Link", - contexts: ["all"] - }, () => { }); - browser.contextMenus.create({ - id: "copy-tab-as-markdown-link-all", - title: "Copy All Tab URLs as Markdown Link List", - contexts: ["all"] - }, () => { }); - browser.contextMenus.create({ - id: "copy-tab-as-markdown-link-selected", - title: "Copy Selected Tab URLs as Markdown Link List", - contexts: ["all"] - }, () => { }); - - browser.contextMenus.create({ - id: "separator-2", - type: "separator", - contexts: ["all"] - }, () => { }); - - if(options.obsidianIntegration){ - // copy to clipboard actions - browser.contextMenus.create({ - id: "copy-markdown-obsidian", - title: "Send Text selection to Obsidian", - contexts: ["selection"] - }, () => { }); - browser.contextMenus.create({ - id: "copy-markdown-obsall", - title: "Send Tab to Obsidian", - contexts: ["all"] - }, () => { }); - } - browser.contextMenus.create({ - id: "separator-3", - type: "separator", - contexts: ["all"] - }, () => { }); - - // options - browser.contextMenus.create({ - id: "toggle-includeTemplate", - type: "checkbox", - title: "Include front/back template", - contexts: ["all"], - checked: options.includeTemplate - }, () => { }); - - browser.contextMenus.create({ - id: "toggle-downloadImages", - type: "checkbox", - title: "Download Images", - contexts: ["all"], - checked: options.downloadImages - }, () => { }); - } -} \ No newline at end of file diff --git a/src/shared/default-options.js b/src/shared/default-options.js index 6a309b3f..4e6664e7 100644 --- a/src/shared/default-options.js +++ b/src/shared/default-options.js @@ -18,6 +18,7 @@ const defaultOptions = { saveAs: false, downloadImages: false, imagePrefix: '{pageTitle}/', + imageFilenameTemplate: '{pageTitle:kebab}_{imageIndex}.{ext}', mdClipsFolder: null, disallowedChars: '[]#^', downloadMode: 'downloadsApi', @@ -32,10 +33,10 @@ const defaultOptions = { async function getOptions() { let options = defaultOptions; try { - options = await browser.storage.sync.get(defaultOptions); + options = await chrome.storage.sync.get(defaultOptions); } catch (err) { console.error(err); } - if (!browser.downloads) options.downloadMode = 'contentLink'; + if (!chrome.downloads) options.downloadMode = 'contentLink'; return options; } \ No newline at end of file diff --git a/xcode/MarkDownload - Markdown Web Clipper/MarkDownload - Markdown Web Clipper.xcodeproj/project.pbxproj b/xcode/MarkDownload - Markdown Web Clipper/MarkDownload - Markdown Web Clipper.xcodeproj/project.pbxproj index 6dbeea6c..b6ee2564 100644 --- a/xcode/MarkDownload - Markdown Web Clipper/MarkDownload - Markdown Web Clipper.xcodeproj/project.pbxproj +++ b/xcode/MarkDownload - Markdown Web Clipper/MarkDownload - Markdown Web Clipper.xcodeproj/project.pbxproj @@ -467,7 +467,7 @@ CODE_SIGN_ENTITLEMENTS = "MarkDownload - Markdown Web Clipper/MarkDownload___Markdown_Web_Clipper.entitlements"; CODE_SIGN_STYLE = Automatic; COMBINE_HIDPI_IMAGES = YES; - CURRENT_PROJECT_VERSION = 4; + CURRENT_PROJECT_VERSION = 4.0.1; DEVELOPMENT_TEAM = 4JYKNQ5WRZ; INFOPLIST_FILE = "MarkDownload - Markdown Web Clipper/Info.plist"; LD_RUNPATH_SEARCH_PATHS = ( @@ -475,7 +475,7 @@ "@executable_path/../Frameworks", ); MACOSX_DEPLOYMENT_TARGET = 10.14; - MARKETING_VERSION = 3.2.0; + MARKETING_VERSION = 3.4.0; PRODUCT_BUNDLE_IDENTIFIER = au.death.MarkDownload; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_VERSION = 5.0; @@ -491,7 +491,7 @@ CODE_SIGN_ENTITLEMENTS = "MarkDownload - Markdown Web Clipper/MarkDownload___Markdown_Web_Clipper.entitlements"; CODE_SIGN_STYLE = Automatic; COMBINE_HIDPI_IMAGES = YES; - CURRENT_PROJECT_VERSION = 4; + CURRENT_PROJECT_VERSION = 4.0.1; DEVELOPMENT_TEAM = 4JYKNQ5WRZ; INFOPLIST_FILE = "MarkDownload - Markdown Web Clipper/Info.plist"; LD_RUNPATH_SEARCH_PATHS = ( @@ -499,7 +499,7 @@ "@executable_path/../Frameworks", ); MACOSX_DEPLOYMENT_TARGET = 10.14; - MARKETING_VERSION = 3.2.0; + MARKETING_VERSION = 3.4.0; PRODUCT_BUNDLE_IDENTIFIER = au.death.MarkDownload; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_VERSION = 5.0;