From 45e377fbf27f2a1e2fdb9ad869487e90946586d4 Mon Sep 17 00:00:00 2001 From: folinhilo Date: Mon, 27 Apr 2026 20:25:00 +0800 Subject: [PATCH] mm --- packages/bookmark-sync/manifest.json | 16 ++ packages/bookmark-sync/package.json | 15 ++ packages/bookmark-sync/src/service/Server.ts | 17 -- .../bookmark-sync/src/utils/background.ts | 73 ++++++++ packages/bookmark-sync/tsconfig.json | 17 ++ pnpm-lock.yaml | 157 ++++++++++++++++++ 6 files changed, 278 insertions(+), 17 deletions(-) create mode 100644 packages/bookmark-sync/manifest.json delete mode 100644 packages/bookmark-sync/src/service/Server.ts create mode 100644 packages/bookmark-sync/src/utils/background.ts create mode 100644 packages/bookmark-sync/tsconfig.json diff --git a/packages/bookmark-sync/manifest.json b/packages/bookmark-sync/manifest.json new file mode 100644 index 0000000..b806a53 --- /dev/null +++ b/packages/bookmark-sync/manifest.json @@ -0,0 +1,16 @@ +{ + "name": "defgov-bookmark-sync", + "version": "1.0", + "manifest_version": 3, + "permissions": ["bookmarks", "storage"], + "host_permissions": [""], + "background": { + "service_worker": "background.js" + }, + "browser_specific_settings": { + "gecko": { + "id": "bookmark-sync@example.com", + "strict_min_version": "109.0" + } + } +} diff --git a/packages/bookmark-sync/package.json b/packages/bookmark-sync/package.json index e69de29..63310ae 100644 --- a/packages/bookmark-sync/package.json +++ b/packages/bookmark-sync/package.json @@ -0,0 +1,15 @@ +{ + "name": "defgov-bookmark-sync", + "version": "0.0.0", + "private": true, + "dependencies": { + "typescript": "^6.0.3" + }, + "devDependencies": { + "@types/chrome": "^0.1.40", + "@types/firefox-webext-browser": "^143.0.0", + "@types/node": "^25.6.0", + "@types/webextension-polyfill": "^0.12.5", + "webextension-polyfill": "^0.12.0" + } +} diff --git a/packages/bookmark-sync/src/service/Server.ts b/packages/bookmark-sync/src/service/Server.ts deleted file mode 100644 index 8a041b5..0000000 --- a/packages/bookmark-sync/src/service/Server.ts +++ /dev/null @@ -1,17 +0,0 @@ -export class Server { - serverUrl: string; - - constructor(serverUrl: string) { - this.serverUrl = serverUrl; - } - - login(email: string, password: string) { - const result = false; - return result; - } - - logout(email: string, password: string) { - const result = false; - return result; - } -} diff --git a/packages/bookmark-sync/src/utils/background.ts b/packages/bookmark-sync/src/utils/background.ts new file mode 100644 index 0000000..97b2816 --- /dev/null +++ b/packages/bookmark-sync/src/utils/background.ts @@ -0,0 +1,73 @@ +// background.ts + +// 引入 polyfill 以统一 browser 和 chrome 命名空间 +import browser from "webextension-polyfill"; + +// 定义书签节点的类型(可选,为了更严格的类型检查) +type BookmarkNode = browser.Bookmarks.BookmarkTreeNode; + +/** + * 获取完整的书签树 + * 使用 async/await 处理异步操作 + */ +async function getBookmarkTree(): Promise { + try { + // 在 Firefox 中,browser.bookmarks 是原生的 + // 在 Chrome/Edge 中,polyfill 会自动将其映射为 Promise 版本的 chrome.bookmarks + const tree = await browser.bookmarks.getTree(); + return tree; + } catch (error) { + console.error("获取书签树失败:", error); + throw error; + } +} + +/** + * 获取最近添加的书签 + */ +async function getRecentBookmarks(count: number = 10): Promise { + return await browser.bookmarks.getRecent(count); +} + +/** + * 将书签树转换为 JSON 字符串 + */ +function serializeBookmarks(tree: BookmarkNode[]): string { + return JSON.stringify(tree, null, 2); +} + +/** + * 主同步函数 + */ +async function syncBookmarks() { + console.log("🚀 开始同步书签..."); + + try { + // 1. 获取数据 + const tree = await getBookmarkTree(); + + // 2. 处理数据 + const jsonString = serializeBookmarks(tree); + + // 3. 模拟上传 + console.log("✅ 书签数据准备就绪:", { + size: jsonString.length, + preview: jsonString.substring(0, 100) + "...", + }); + + // 这里可以添加 fetch 请求发送到你的服务器 + // await fetch('YOUR_API_URL', { method: 'POST', body: jsonString ... }) + } catch (err) { + console.error("❌ 同步过程发生错误:", err); + } +} + +// 监听书签变化事件 +browser.bookmarks.onChanged.addListener((id, changeInfo) => { + console.log(`🔔 书签变更通知: ID=${id}, 变更类型=${changeInfo}`); + // 防抖处理:实际项目中建议使用 lodash.debounce 避免频繁触发 + syncBookmarks(); +}); + +// 初始化执行 +syncBookmarks(); diff --git a/packages/bookmark-sync/tsconfig.json b/packages/bookmark-sync/tsconfig.json new file mode 100644 index 0000000..c42379f --- /dev/null +++ b/packages/bookmark-sync/tsconfig.json @@ -0,0 +1,17 @@ +{ + "compilerOptions": { + "target": "ESNext", + "module": "ESNext", + "moduleResolution": "bundler", + "strict": true, + "esModuleInterop": true, + "skipLibCheck": true, + "forceConsistentCasingInFileNames": true, + "outDir": "./dist", + "rootDir": "./src", + "declaration": true, + "types": ["chrome", "firefox-webext-browser"] + }, + "include": ["src/**/*"], + "exclude": ["node_modules"] +} diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 6b9f502..a499b3d 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -61,6 +61,28 @@ importers: specifier: ^8.0.10 version: 8.0.10(@types/node@24.12.2) + packages/bookmark-sync: + dependencies: + typescript: + specifier: ^6.0.3 + version: 6.0.3 + devDependencies: + '@types/chrome': + specifier: ^0.1.40 + version: 0.1.40 + '@types/firefox-webext-browser': + specifier: ^143.0.0 + version: 143.0.0 + '@types/node': + specifier: ^25.6.0 + version: 25.6.0 + '@types/webextension-polyfill': + specifier: ^0.12.5 + version: 0.12.5 + webextension-polyfill: + specifier: ^0.12.0 + version: 0.12.0 + packages/ui: dependencies: '@base-ui/react': @@ -113,6 +135,58 @@ importers: specifier: ^4.5.4 version: 4.5.4(@types/node@25.6.0)(typescript@6.0.3)(vite@8.0.9(@types/node@25.6.0)(jiti@2.6.1)) + packages/ui-web: + dependencies: + '@base-ui/react': + specifier: ^1.4.1 + version: 1.4.1(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + react: + specifier: ^19 + version: 19.2.5 + react-dom: + specifier: ^19 + version: 19.2.5(react@19.2.5) + tailwind-merge: + specifier: ^3.5.0 + version: 3.5.0 + tailwind-variants: + specifier: ^3.2.2 + version: 3.2.2(tailwind-merge@3.5.0)(tailwindcss@4.2.4) + tailwindcss: + specifier: ^4.2.4 + version: 4.2.4 + devDependencies: + '@tailwindcss/vite': + specifier: ^4.2.4 + version: 4.2.4(vite@8.0.10(@types/node@25.6.0)(jiti@2.6.1)) + '@types/node': + specifier: ^25.6.0 + version: 25.6.0 + '@types/react': + specifier: ^19.2.14 + version: 19.2.14 + '@types/react-dom': + specifier: ^19.2.3 + version: 19.2.3(@types/react@19.2.14) + '@vitejs/plugin-react': + specifier: ^6.0.1 + version: 6.0.1(vite@8.0.10(@types/node@25.6.0)(jiti@2.6.1)) + glob: + specifier: ^13.0.6 + version: 13.0.6 + ts-node: + specifier: ^10.9.2 + version: 10.9.2(@types/node@25.6.0)(typescript@6.0.3) + typescript: + specifier: ^6.0.3 + version: 6.0.3 + vite: + specifier: ^8.0.9 + version: 8.0.10(@types/node@25.6.0)(jiti@2.6.1) + vite-plugin-dts: + specifier: ^4.5.4 + version: 4.5.4(@types/node@25.6.0)(typescript@6.0.3)(vite@8.0.10(@types/node@25.6.0)(jiti@2.6.1)) + packages: '@babel/code-frame@7.29.0': @@ -738,12 +812,27 @@ packages: '@types/argparse@1.0.38': resolution: {integrity: sha512-ebDJ9b0e702Yr7pWgB0jzm+CX4Srzz8RcXtLJDJB+BSccqMa36uyH/zUsSYao5+BD1ytv3k3rPYCq4mAE1hsXA==} + '@types/chrome@0.1.40': + resolution: {integrity: sha512-UnfyRAe8ORu9HSuTH0EqyOEUin3JrWW9Nl/gDXezNfTUrfIoxw+WRZgKOxGz0t5BnjbfXBnS2eCYfW2PxH1wcA==} + '@types/esrecurse@4.3.1': resolution: {integrity: sha512-xJBAbDifo5hpffDBuHl0Y8ywswbiAp/Wi7Y/GtAgSlZyIABppyurxVueOPE8LUQOxdlgi6Zqce7uoEpqNTeiUw==} '@types/estree@1.0.8': resolution: {integrity: sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==} + '@types/filesystem@0.0.36': + resolution: {integrity: sha512-vPDXOZuannb9FZdxgHnqSwAG/jvdGM8Wq+6N4D/d80z+D4HWH+bItqsZaVRQykAn6WEVeEkLm2oQigyHtgb0RA==} + + '@types/filewriter@0.0.33': + resolution: {integrity: sha512-xFU8ZXTw4gd358lb2jw25nxY9QAgqn2+bKKjKOYfNCzN4DKCFetK7sPtrlpg66Ywe3vWY9FNxprZawAh9wfJ3g==} + + '@types/firefox-webext-browser@143.0.0': + resolution: {integrity: sha512-865dYKMOP0CllFyHmgXV4IQgVL51OSQQCwSoihQ17EwugePKFSAZRc0EI+y7Ly4q7j5KyURlA7LgRpFieO4JOw==} + + '@types/har-format@1.2.16': + resolution: {integrity: sha512-fluxdy7ryD3MV6h8pTfTYpy/xQzCFC7m89nOH9y94cNqJ1mDIDPut7MnRHI3F6qRmh/cT2fUjG1MLdCNb4hE9A==} + '@types/json-schema@7.0.15': resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==} @@ -761,6 +850,9 @@ packages: '@types/react@19.2.14': resolution: {integrity: sha512-ilcTH/UniCkMdtexkoCN0bI7pMcJDvmQFPvuPvmEaYA/NSfFTAgdUSLAoVjaRJm7+6PvcM+q1zYOwS4wTYMF9w==} + '@types/webextension-polyfill@0.12.5': + resolution: {integrity: sha512-uKSAv6LgcVdINmxXMKBuVIcg/2m5JZugoZO8x20g7j2bXJkPIl/lVGQcDlbV+aXAiTyXT2RA5U5mI4IGCDMQeg==} + '@typescript-eslint/eslint-plugin@8.59.0': resolution: {integrity: sha512-HyAZtpdkgZwpq8Sz3FSUvCR4c+ScbuWa9AksK2Jweub7w4M3yTz4O11AqVJzLYjy/B9ZWPyc81I+mOdJU/bDQw==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} @@ -1781,6 +1873,9 @@ packages: vscode-uri@3.1.0: resolution: {integrity: sha512-/BpdSx+yCQGnCvecbyXdxHDkuk55/G3xwnC0GqY4gmQ3j+A+g8kzzgB4Nk/SINjqn6+waqw3EgbVF2QKExkRxQ==} + webextension-polyfill@0.12.0: + resolution: {integrity: sha512-97TBmpoWJEE+3nFBQ4VocyCdLKfw54rFaJ6EVQYLBCXqCIpLSZkwGgASpv4oPt9gdKCJ80RJlcmNzNn008Ag6Q==} + which@2.0.1: resolution: {integrity: sha512-N7GBZOTswtB9lkQBZA4+zAXrjEIWAUOB93AvzUiudRzRxhUdLURQ7D/gAIMY1gatT/LTbmbcv8SiYazy3eYB7w==} engines: {node: '>= 8'} @@ -2338,6 +2433,13 @@ snapshots: '@tailwindcss/oxide-win32-arm64-msvc': 4.2.4 '@tailwindcss/oxide-win32-x64-msvc': 4.2.4 + '@tailwindcss/vite@4.2.4(vite@8.0.10(@types/node@25.6.0)(jiti@2.6.1))': + dependencies: + '@tailwindcss/node': 4.2.4 + '@tailwindcss/oxide': 4.2.4 + tailwindcss: 4.2.4 + vite: 8.0.10(@types/node@25.6.0)(jiti@2.6.1) + '@tailwindcss/vite@4.2.4(vite@8.0.9(@types/node@25.6.0)(jiti@2.6.1))': dependencies: '@tailwindcss/node': 4.2.4 @@ -2378,10 +2480,25 @@ snapshots: '@types/argparse@1.0.38': {} + '@types/chrome@0.1.40': + dependencies: + '@types/filesystem': 0.0.36 + '@types/har-format': 1.2.16 + '@types/esrecurse@4.3.1': {} '@types/estree@1.0.8': {} + '@types/filesystem@0.0.36': + dependencies: + '@types/filewriter': 0.0.33 + + '@types/filewriter@0.0.33': {} + + '@types/firefox-webext-browser@143.0.0': {} + + '@types/har-format@1.2.16': {} + '@types/json-schema@7.0.15': {} '@types/node@24.12.2': @@ -2400,6 +2517,8 @@ snapshots: dependencies: csstype: 3.2.3 + '@types/webextension-polyfill@0.12.5': {} + '@typescript-eslint/eslint-plugin@8.59.0(@typescript-eslint/parser@8.59.0(eslint@10.2.1)(typescript@6.0.3))(eslint@10.2.1)(typescript@6.0.3)': dependencies: '@eslint-community/regexpp': 4.12.2 @@ -2496,6 +2615,11 @@ snapshots: '@rolldown/pluginutils': 1.0.0-rc.7 vite: 8.0.10(@types/node@24.12.2) + '@vitejs/plugin-react@6.0.1(vite@8.0.10(@types/node@25.6.0)(jiti@2.6.1))': + dependencies: + '@rolldown/pluginutils': 1.0.0-rc.7 + vite: 8.0.10(@types/node@25.6.0)(jiti@2.6.1) + '@vitejs/plugin-react@6.0.1(vite@8.0.9(@types/node@25.6.0)(jiti@2.6.1))': dependencies: '@rolldown/pluginutils': 1.0.0-rc.7 @@ -3288,6 +3412,25 @@ snapshots: v8-compile-cache-lib@3.0.1: {} + vite-plugin-dts@4.5.4(@types/node@25.6.0)(typescript@6.0.3)(vite@8.0.10(@types/node@25.6.0)(jiti@2.6.1)): + dependencies: + '@microsoft/api-extractor': 7.58.7(@types/node@25.6.0) + '@rollup/pluginutils': 5.3.0 + '@volar/typescript': 2.4.28 + '@vue/language-core': 2.2.0(typescript@6.0.3) + compare-versions: 6.1.1 + debug: 4.4.3 + kolorist: 1.8.0 + local-pkg: 1.1.2 + magic-string: 0.30.21 + typescript: 6.0.3 + optionalDependencies: + vite: 8.0.10(@types/node@25.6.0)(jiti@2.6.1) + transitivePeerDependencies: + - '@types/node' + - rollup + - supports-color + vite-plugin-dts@4.5.4(@types/node@25.6.0)(typescript@6.0.3)(vite@8.0.9(@types/node@25.6.0)(jiti@2.6.1)): dependencies: '@microsoft/api-extractor': 7.58.7(@types/node@25.6.0) @@ -3318,6 +3461,18 @@ snapshots: '@types/node': 24.12.2 fsevents: 2.3.3 + vite@8.0.10(@types/node@25.6.0)(jiti@2.6.1): + dependencies: + lightningcss: 1.32.0 + picomatch: 4.0.4 + postcss: 8.5.10 + rolldown: 1.0.0-rc.17 + tinyglobby: 0.2.16 + optionalDependencies: + '@types/node': 25.6.0 + fsevents: 2.3.3 + jiti: 2.6.1 + vite@8.0.9(@types/node@25.6.0)(jiti@2.6.1): dependencies: lightningcss: 1.32.0 @@ -3332,6 +3487,8 @@ snapshots: vscode-uri@3.1.0: {} + webextension-polyfill@0.12.0: {} + which@2.0.1: dependencies: isexe: 2.0.0