+{
+ const [collections] = await getCollections();
+ const lines: string[] = [
+ "",
+ "",
+ "",
+ "Bookmarks",
+ "Bookmarks
",
+ ""
+ ];
+
+ for (const collection of collections)
+ lines.push(...createFolder(collection));
+
+ lines.push("
");
+
+ const data: string = lines.join("\n");
+
+ const blob: Blob = new Blob([data], { type: "text/html" });
+
+ const element: HTMLAnchorElement = document.createElement("a");
+ element.style.display = "none";
+ element.href = URL.createObjectURL(blob);
+ element.setAttribute("download", "collections.html");
+
+ document.body.appendChild(element);
+ element.click();
+
+ URL.revokeObjectURL(element.href);
+ document.body.removeChild(element);
+}
+
+function createFolder(item: CollectionItem | GroupItem): string[]
+{
+ const lines: string[] = [];
+ const title: string = item.type === "collection" ?
+ (item.title ?? getCollectionTitle(item)) :
+ (item.pinned ? i18n.t("groups.pinned") : (item.title ?? ""));
+
+ lines.push(`
${sanitizeString(title)}
`);
+ lines.push("");
+
+ for (const subItem of item.items)
+ {
+ if (subItem.type === "tab")
+ lines.push(`
- ${sanitizeString(subItem.title || subItem.url)}`);
+ else if (subItem.type === "group")
+ lines.push(...createFolder(subItem));
+ }
+
+ lines.push("
");
+ return lines;
+}
+
+function sanitizeString(str: string): string
+{
+ return str.replace(/&/g, "&").replace(//g, ">");
+}
diff --git a/features/netscapeBookmarks/utils/importBookmarks.ts b/features/netscapeBookmarks/utils/importBookmarks.ts
new file mode 100644
index 0000000..5729663
--- /dev/null
+++ b/features/netscapeBookmarks/utils/importBookmarks.ts
@@ -0,0 +1,52 @@
+import { getCollections, saveCollections } from "@/features/collectionStorage";
+import { sendMessage } from "@/utils/messaging";
+import parse from "node-bookmarks-parser";
+import { Bookmark } from "node-bookmarks-parser/build/interfaces/bookmark";
+import convertBookmarks from "./convertBookmarks";
+
+export default async function importBookmarks(): Promise
+{
+ const element: HTMLInputElement = document.createElement("input");
+ element.style.display = "none";
+ element.hidden = true;
+ element.type = "file";
+ element.accept = ".html";
+
+ document.body.appendChild(element);
+ element.click();
+
+ await new Promise(resolve =>
+ {
+ const listener = () =>
+ {
+ element.removeEventListener("input", listener);
+ resolve(null);
+ };
+ element.addEventListener("input", listener);
+ });
+
+ if (!element.files || element.files.length < 1)
+ return null;
+
+ const file: File = element.files[0];
+ const content: string = await file.text();
+
+ document.body.removeChild(element);
+
+ try
+ {
+ const bookmarks: Bookmark[] = parse(content);
+ const [data, graphics, tabCount] = convertBookmarks(bookmarks);
+ const [collections, cloudIssues] = await getCollections();
+
+ await saveCollections([...data, ...collections], cloudIssues === null, graphics);
+ sendMessage("refreshCollections", undefined);
+
+ return tabCount;
+ }
+ catch (error)
+ {
+ console.error("Failed to parse bookmarks file", error);
+ return -1;
+ }
+}
diff --git a/locales/en.yml b/locales/en.yml
index bc2c6ae..9c22fae 100644
--- a/locales/en.yml
+++ b/locales/en.yml
@@ -46,6 +46,17 @@ features:
p3_text: "See the full list of what we collect"
p3_link: "here"
+ netscape_bookmarks:
+ title: "Browser bookmarks"
+ export: "Export collections as bookmarks"
+ import: "Import from bookmarks file"
+ import_dialog:
+ title: "Import bookmarks"
+ content: "Import bookmarks from a Netscape-format bookmarks file exported from your browser."
+ import_result:
+ success: "Successfully imported $1 bookmarks."
+ error: "Failed to import bookmarks. Please ensure the file is a valid bookmarks file."
+
notifications:
tabs_saved:
title: "New collection created"
@@ -114,6 +125,8 @@ options_page:
restore: "Open tabs and remove the collection"
storage:
title: "Storage"
+ manage_title: "Storage management"
+ thumbnails_title: "Thumbnails & icons"
capacity:
title: "Cloud storage capacity"
description: "$1 of $2 KiB"
diff --git a/locales/es.yml b/locales/es.yml
index 0ade1e4..4d63dd5 100644
--- a/locales/es.yml
+++ b/locales/es.yml
@@ -46,6 +46,17 @@ features:
p3_text: "Ver la lista completa de lo que recopilamos"
p3_link: "aquí"
+ netscape_bookmarks:
+ title: "Marcadores del navegador"
+ export: "Exportar colecciones como marcadores"
+ import: "Importar desde archivo de marcadores"
+ import_dialog:
+ title: "Importar marcadores"
+ content: "Importa marcadores desde un archivo de marcadores en formato Netscape exportado desde tu navegador."
+ import_result:
+ success: "Se importaron correctamente $1 marcadores."
+ error: "No se pudieron importar los marcadores. Asegúrate de que el archivo sea un archivo de marcadores válido."
+
notifications:
tabs_saved:
title: "Nueva colección creada"
@@ -114,6 +125,8 @@ options_page:
restore: "Abrir pestañas y eliminar la colección"
storage:
title: "Almacenamiento"
+ manage_title: "Administrar almacenamiento"
+ thumbnails_title: "Miniaturas e íconos"
capacity:
title: "Capacidad de almacenamiento en la nube"
description: "$1 de $2 KiB"
diff --git a/locales/it.yml b/locales/it.yml
index 6c0942f..515f93a 100644
--- a/locales/it.yml
+++ b/locales/it.yml
@@ -46,6 +46,17 @@ features:
p3_text: "Vedi l'elenco completo di ciò che raccogliamo"
p3_link: "qui"
+ netscape_bookmarks:
+ title: "Segnalibri del browser"
+ export: "Esporta collezioni come segnalibri"
+ import: "Importa da file di segnalibri"
+ import_dialog:
+ title: "Importa segnalibri"
+ content: "Importa segnalibri da un file di segnalibri in formato Netscape esportato dal tuo browser."
+ import_result:
+ success: "Importati con successo $1 segnalibri."
+ error: "Impossibile importare i segnalibri. Assicurati che il file sia un file di segnalibri valido."
+
notifications:
tabs_saved:
title: "Nuova collezione creata"
@@ -114,6 +125,8 @@ options_page:
restore: "Apri le schede e rimuovi la collezione"
storage:
title: "Archiviazione"
+ manage_title: "Gestisci archiviazione"
+ thumbnails_title: "Miniature e icone"
capacity:
title: "Capacità di archiviazione cloud"
description: "$1 di $2 KiB"
diff --git a/locales/pl.yml b/locales/pl.yml
index d413f2a..702da79 100644
--- a/locales/pl.yml
+++ b/locales/pl.yml
@@ -46,6 +46,17 @@ features:
p3_text: "Pełną listę zbieranych danych można zobaczyć"
p3_link: "tutaj"
+ netscape_bookmarks:
+ title: "Import/eksport zakładek"
+ export: "Eksportuj kolekcje jako plik zakładek"
+ import: "Importuj z pliku zakładek"
+ import_dialog:
+ title: "Import zakładek"
+ content: "Importuj zakładki z pliku zakładek w formacie Netscape wyeksportowanego z przeglądarki."
+ import_result:
+ success: "Zakładki zostały pomyślnie zaimportowane ($1)"
+ error: "Nie udało się zaimportować zakładek. Upewnij się, że plik jest poprawnym plikiem zakładek."
+
notifications:
tabs_saved:
title: "Utworzono nową kolekcję"
@@ -114,6 +125,8 @@ options_page:
restore: "Otwórz karty i usuń kolekcję"
storage:
title: "Magazyn"
+ manage_title: "Zarządzaj magazynem"
+ thumbnails_title: "Podglądy i ikony"
capacity:
title: "Magazyn w chmurze"
description: "$1 z $2 KiB"
diff --git a/locales/pt_BR.yml b/locales/pt_BR.yml
index ec231df..544a307 100644
--- a/locales/pt_BR.yml
+++ b/locales/pt_BR.yml
@@ -46,6 +46,17 @@ features:
p3_text: "Veja a lista completa do que coletamos"
p3_link: "aqui"
+ netscape_bookmarks:
+ title: "Favoritos do navegador"
+ export: "Exportar coleções como favoritos"
+ import: "Importar de arquivo de favoritos"
+ import_dialog:
+ title: "Importar favoritos"
+ content: "Importe favoritos de um arquivo de favoritos no formato Netscape exportado do seu navegador."
+ import_result:
+ success: "Importados com sucesso $1 favoritos."
+ error: "Falha ao importar favoritos. Por favor, certifique-se de que o arquivo é um arquivo de favoritos válido."
+
notifications:
tabs_saved:
title: "Nova coleção criada"
@@ -114,6 +125,8 @@ options_page:
restore: "Abrir abas e remover a coleção"
storage:
title: "Armazenamento"
+ manage_title: "Gerenciar armazenamento"
+ thumbnails_title: "Miniaturas e ícones"
capacity:
title: "Capacidade de armazenamento na nuvem"
description: "$1 de $2 KiB"
diff --git a/locales/ru.yml b/locales/ru.yml
index a61f4c1..9aec98e 100644
--- a/locales/ru.yml
+++ b/locales/ru.yml
@@ -46,6 +46,17 @@ features:
p3_text: "Полный список собираемых данных можно посмотреть"
p3_link: "здесь"
+ netscape_bookmarks:
+ title: "Импорт/экспорт закладок"
+ export: "Экспортировать коллекции как файл закладок"
+ import: "Импорт из файла закладок"
+ import_dialog:
+ title: "Импорт закладок"
+ content: "Импортируйте закладки из файла закладок в формате Netscape, экспортированного из вашего браузера."
+ import_result:
+ success: "Закладки успешно импортированы ($1 шт.)"
+ error: "Не удалось импортировать закладки. Пожалуйста, убедитесь, что файл является допустимым файлом закладок."
+
notifications:
tabs_saved:
title: "Создана новая коллекция"
@@ -114,6 +125,8 @@ options_page:
restore: "Открыть вкладки и удалить коллекцию"
storage:
title: "Хранилище"
+ manage_title: "Управление хранилищем"
+ thumbnails_title: "Превью и иконки"
capacity:
title: "Объём облачного хранилища"
description: "$1 из $2 КиБ"
diff --git a/locales/uk.yml b/locales/uk.yml
index 4ff8342..d4fc708 100644
--- a/locales/uk.yml
+++ b/locales/uk.yml
@@ -46,6 +46,17 @@ features:
p3_text: "Повний список зібраних даних можна подивитися"
p3_link: "тут"
+ netscape_bookmarks:
+ title: "Імпорт/експорт закладок"
+ export: "Експортувати колекції як файл закладок"
+ import: "Імпорт із файлу закладок"
+ import_dialog:
+ title: "Імпорт закладок"
+ content: "Імпортуйте закладки з файлу закладок у форматі Netscape, експортованого з вашого браузера."
+ import_result:
+ success: "Закладки успішно імпортовані ($1 шт.)"
+ error: "Не вдалося імпортувати закладки. Будь ласка, переконайтеся, що файл є коректним файлом закладок."
+
notifications:
tabs_saved:
title: "Створено нову колекцію"
@@ -114,6 +125,8 @@ options_page:
restore: "Відкрити вкладки та видалити колекцію"
storage:
title: "Сховище"
+ manage_title: "Керування сховищем"
+ thumbnails_title: "Прев'ю та іконки"
capacity:
title: "Хмарне сховище"
description: "$1 з $2 КіБ"
@@ -132,13 +145,13 @@ options_page:
disable_prompt:
text: "Ця дія вимкне синхронізацію колекцій між вашими пристроями. Налаштування продовжать зберігатися у хмарі."
action: "Вимкнути та перезавантажити розширення"
- thumbnail_capture: "Зберігати превью і іконки для збережених вкладок"
+ thumbnail_capture: "Зберігати прев'ю і іконки для збережених вкладок"
thumbnail_capture_notice1: "Необхідний доступ до вмісту відвіданих веб-сайтів"
thumbnail_capture_notice2: "Вимкнення цієї функції може покращити продуктивність при великій кількості збережених вкладок"
clear_thumbnails:
action: "Видалити збережені іконки"
- title: "Видалити превью і іконки?"
- prompt: "Ця дія видалить всі превью і іконки у ваших збережених вкладках. Цю дію не можна скасувати."
+ title: "Видалити прев'ю і іконки?"
+ prompt: "Ця дія видалить всі прев'ю і іконки у ваших збережених вкладках. Цю дію не можна скасувати."
about:
title: "О розширенні"
developed_by: "Розробник: Євген Лис"
diff --git a/locales/zh_CN.yml b/locales/zh_CN.yml
index 4ecc1e5..82cb6b1 100644
--- a/locales/zh_CN.yml
+++ b/locales/zh_CN.yml
@@ -46,6 +46,17 @@ features:
p3_text: "请参阅我们收集内容的"
p3_link: "完整列表"
+ netscape_bookmarks:
+ title: "浏览器书签"
+ export: "将收藏导出为书签"
+ import: "从书签文件导入"
+ import_dialog:
+ title: "导入书签"
+ content: "从您的浏览器导出的 Netscape 格式书签文件中导入书签。"
+ import_result:
+ success: "成功导入 $1 个书签。"
+ error: "导入书签失败。请确保该文件是有效的书签文件。"
+
notifications:
tabs_saved:
title: "已创建新收藏"
@@ -114,6 +125,8 @@ options_page:
restore: "打开标签页并删除收藏"
storage:
title: "存储"
+ manage_title: "存储管理"
+ thumbnails_title: "缩略图和图标"
capacity:
title: "云存储容量"
description: "$1 / $2 KiB"
diff --git a/package-lock.json b/package-lock.json
index 091687b..5350e41 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -19,6 +19,7 @@
"@wxt-dev/analytics": "^0.5.1",
"@wxt-dev/i18n": "^0.2.4",
"lzutf8": "^0.6.3",
+ "node-bookmarks-parser": "^2.0.0",
"react": "^19.2.1",
"react-dom": "^19.2.1"
},
@@ -4595,6 +4596,48 @@
"url": "https://github.com/chalk/chalk?sponsor=1"
}
},
+ "node_modules/cheerio": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/cheerio/-/cheerio-1.1.2.tgz",
+ "integrity": "sha512-IkxPpb5rS/d1IiLbHMgfPuS0FgiWTtFIm/Nj+2woXDLTZ7fOT2eqzgYbdMlLweqlHbsZjxEChoVK+7iph7jyQg==",
+ "license": "MIT",
+ "dependencies": {
+ "cheerio-select": "^2.1.0",
+ "dom-serializer": "^2.0.0",
+ "domhandler": "^5.0.3",
+ "domutils": "^3.2.2",
+ "encoding-sniffer": "^0.2.1",
+ "htmlparser2": "^10.0.0",
+ "parse5": "^7.3.0",
+ "parse5-htmlparser2-tree-adapter": "^7.1.0",
+ "parse5-parser-stream": "^7.1.2",
+ "undici": "^7.12.0",
+ "whatwg-mimetype": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=20.18.1"
+ },
+ "funding": {
+ "url": "https://github.com/cheeriojs/cheerio?sponsor=1"
+ }
+ },
+ "node_modules/cheerio-select": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/cheerio-select/-/cheerio-select-2.1.0.tgz",
+ "integrity": "sha512-9v9kG0LvzrlcungtnJtpGNxY+fzECQKhK4EGJX2vByejiMX84MFNQw4UxPJl3bFbTMw+Dfs37XaIkCwTZfLh4g==",
+ "license": "BSD-2-Clause",
+ "dependencies": {
+ "boolbase": "^1.0.0",
+ "css-select": "^5.1.0",
+ "css-what": "^6.1.0",
+ "domelementtype": "^2.3.0",
+ "domhandler": "^5.0.3",
+ "domutils": "^3.0.1"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/fb55"
+ }
+ },
"node_modules/chokidar": {
"version": "4.0.3",
"resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.3.tgz",
@@ -5412,6 +5455,19 @@
"integrity": "sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A==",
"license": "MIT"
},
+ "node_modules/encoding-sniffer": {
+ "version": "0.2.1",
+ "resolved": "https://registry.npmjs.org/encoding-sniffer/-/encoding-sniffer-0.2.1.tgz",
+ "integrity": "sha512-5gvq20T6vfpekVtqrYQsSCFZ1wEg5+wW0/QaZMWkFr6BqD3NfKs0rLCx4rrVlSWJeZb5NBJgVLswK/w2MWU+Gw==",
+ "license": "MIT",
+ "dependencies": {
+ "iconv-lite": "^0.6.3",
+ "whatwg-encoding": "^3.1.1"
+ },
+ "funding": {
+ "url": "https://github.com/fb55/encoding-sniffer?sponsor=1"
+ }
+ },
"node_modules/entities": {
"version": "4.5.0",
"resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz",
@@ -6675,6 +6731,18 @@
"url": "https://github.com/fb55/entities?sponsor=1"
}
},
+ "node_modules/iconv-lite": {
+ "version": "0.6.3",
+ "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz",
+ "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==",
+ "license": "MIT",
+ "dependencies": {
+ "safer-buffer": ">= 2.1.2 < 3.0.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
"node_modules/ieee754": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz",
@@ -8080,6 +8148,15 @@
"dev": true,
"license": "MIT"
},
+ "node_modules/node-bookmarks-parser": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/node-bookmarks-parser/-/node-bookmarks-parser-2.0.0.tgz",
+ "integrity": "sha512-BHQpogPEifFP+eToF+GS6cP9DInDsh++c3PFtMiH0oJ1ByeEXcoZw0joDio1sIpm1lJAFyY6msguZ5ZJTEueZg==",
+ "license": "MIT",
+ "dependencies": {
+ "cheerio": "^1.0.0-rc.3"
+ }
+ },
"node_modules/node-fetch-native": {
"version": "1.6.7",
"resolved": "https://registry.npmjs.org/node-fetch-native/-/node-fetch-native-1.6.7.tgz",
@@ -8550,6 +8627,55 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
+ "node_modules/parse5": {
+ "version": "7.3.0",
+ "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.3.0.tgz",
+ "integrity": "sha512-IInvU7fabl34qmi9gY8XOVxhYyMyuH2xUNpb2q8/Y+7552KlejkRvqvD19nMoUW/uQGGbqNpA6Tufu5FL5BZgw==",
+ "license": "MIT",
+ "dependencies": {
+ "entities": "^6.0.0"
+ },
+ "funding": {
+ "url": "https://github.com/inikulin/parse5?sponsor=1"
+ }
+ },
+ "node_modules/parse5-htmlparser2-tree-adapter": {
+ "version": "7.1.0",
+ "resolved": "https://registry.npmjs.org/parse5-htmlparser2-tree-adapter/-/parse5-htmlparser2-tree-adapter-7.1.0.tgz",
+ "integrity": "sha512-ruw5xyKs6lrpo9x9rCZqZZnIUntICjQAd0Wsmp396Ul9lN/h+ifgVV1x1gZHi8euej6wTfpqX8j+BFQxF0NS/g==",
+ "license": "MIT",
+ "dependencies": {
+ "domhandler": "^5.0.3",
+ "parse5": "^7.0.0"
+ },
+ "funding": {
+ "url": "https://github.com/inikulin/parse5?sponsor=1"
+ }
+ },
+ "node_modules/parse5-parser-stream": {
+ "version": "7.1.2",
+ "resolved": "https://registry.npmjs.org/parse5-parser-stream/-/parse5-parser-stream-7.1.2.tgz",
+ "integrity": "sha512-JyeQc9iwFLn5TbvvqACIF/VXG6abODeB3Fwmv/TGdLk2LfbWkaySGY72at4+Ty7EkPZj854u4CrICqNk2qIbow==",
+ "license": "MIT",
+ "dependencies": {
+ "parse5": "^7.0.0"
+ },
+ "funding": {
+ "url": "https://github.com/inikulin/parse5?sponsor=1"
+ }
+ },
+ "node_modules/parse5/node_modules/entities": {
+ "version": "6.0.1",
+ "resolved": "https://registry.npmjs.org/entities/-/entities-6.0.1.tgz",
+ "integrity": "sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g==",
+ "license": "BSD-2-Clause",
+ "engines": {
+ "node": ">=0.12"
+ },
+ "funding": {
+ "url": "https://github.com/fb55/entities?sponsor=1"
+ }
+ },
"node_modules/path-exists": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz",
@@ -9287,6 +9413,12 @@
"node": ">=10"
}
},
+ "node_modules/safer-buffer": {
+ "version": "2.1.2",
+ "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
+ "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==",
+ "license": "MIT"
+ },
"node_modules/sax": {
"version": "1.4.3",
"resolved": "https://registry.npmjs.org/sax/-/sax-1.4.3.tgz",
@@ -10201,6 +10333,15 @@
"url": "https://github.com/sponsors/ljharb"
}
},
+ "node_modules/undici": {
+ "version": "7.16.0",
+ "resolved": "https://registry.npmjs.org/undici/-/undici-7.16.0.tgz",
+ "integrity": "sha512-QEg3HPMll0o3t2ourKwOeUAZ159Kn9mx5pnzHRQO8+Wixmh88YdZRiIwat0iNzNNXn0yoEtXJqFpyW7eM8BV7g==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=20.18.1"
+ }
+ },
"node_modules/undici-types": {
"version": "7.16.0",
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.16.0.tgz",
@@ -10526,6 +10667,27 @@
"integrity": "sha512-66/V2i5hQanC51vBQKPH4aI8NMAcBW59FVBs+rC7eGHupMyfn34q7rZIE+ETlJ+XTevqfUhVVBgSUNSW2flEUQ==",
"license": "MIT"
},
+ "node_modules/whatwg-encoding": {
+ "version": "3.1.1",
+ "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-3.1.1.tgz",
+ "integrity": "sha512-6qN4hJdMwfYBtE3YBTTHhoeuUrDBPZmbQaxWAqSALV/MeEnR5z1xd8UKud2RAkFoPkmB+hli1TZSnyi84xz1vQ==",
+ "license": "MIT",
+ "dependencies": {
+ "iconv-lite": "0.6.3"
+ },
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/whatwg-mimetype": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-4.0.0.tgz",
+ "integrity": "sha512-QaKxh0eNIi2mE9p2vEdzfagOKHCcj1pJ56EEHGQOVxp8r9/iszLUUV7v89x9O1p/T+NlTM5W7jW6+cz4Fq1YVg==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=18"
+ }
+ },
"node_modules/when": {
"version": "3.7.7",
"resolved": "https://registry.npmjs.org/when/-/when-3.7.7.tgz",
diff --git a/package.json b/package.json
index e68e7ff..54d8593 100644
--- a/package.json
+++ b/package.json
@@ -22,6 +22,7 @@
"@wxt-dev/analytics": "^0.5.1",
"@wxt-dev/i18n": "^0.2.4",
"lzutf8": "^0.6.3",
+ "node-bookmarks-parser": "^2.0.0",
"react": "^19.2.1",
"react-dom": "^19.2.1"
},