diff --git a/package.json b/package.json index 8da4fc97..a3f006bf 100644 --- a/package.json +++ b/package.json @@ -42,9 +42,11 @@ "start": "electron-vite preview", "dev": "node scripts/prepare-better-sqlite3-native.mjs ensure electron && node scripts/prepare-node-pty-native.mjs ensure electron && node scripts/ensure-web-crawler-sidecar.mjs && electron-vite dev", "dev:no-sidecar": "node scripts/prepare-better-sqlite3-native.mjs ensure electron && node scripts/prepare-node-pty-native.mjs ensure electron && electron-vite dev", - "build": "node scripts/prepare-better-sqlite3-native.mjs ensure node && node scripts/prepare-node-pty-native.mjs ensure node && tsc --noEmit -p tsconfig.node.json --composite false && tsc --noEmit -p tsconfig.web.json --composite false && node scripts/build-web-crawler-sidecar.mjs && node scripts/prepare-better-sqlite3-native.mjs export-electron-resource && electron-vite build && node scripts/verify-runtime-bundles.mjs && node scripts/prepare-node-pty-native.mjs ensure electron && node scripts/prepare-package-stage.mjs", + "build": "node scripts/prepare-better-sqlite3-native.mjs ensure node && node scripts/prepare-node-pty-native.mjs ensure node && tsc --noEmit -p tsconfig.node.json --composite false && tsc --noEmit -p tsconfig.web.json --composite false && node scripts/build-web-crawler-sidecar.mjs && node scripts/prepare-better-sqlite3-native.mjs export-electron-resource && electron-vite build && node scripts/verify-runtime-bundles.mjs && node scripts/prepare-node-pty-native.mjs ensure electron && node scripts/prepare-package-stage.mjs && node scripts/obfuscate-package-main.mjs && node scripts/verify-package-main-obfuscation.mjs && node scripts/audit-package-stage.mjs", "postinstall": "node scripts/postinstall.mjs", "package:audit:stage": "node scripts/audit-package-stage.mjs", + "package:obfuscate:main": "node scripts/obfuscate-package-main.mjs", + "package:obfuscation:verify": "node scripts/verify-package-main-obfuscation.mjs", "package:audit": "node scripts/audit-packaged-app.mjs dist", "package:audit:summary": "node scripts/print-package-audit-summary.mjs dist/package-audit.json", "build:unpack": "pnpm run build && electron-builder --dir && pnpm run package:audit", @@ -141,6 +143,7 @@ "eslint-plugin-react": "^7.37.5", "eslint-plugin-react-hooks": "^7.0.1", "eslint-plugin-react-refresh": "^0.4.24", + "javascript-obfuscator": "5.5.0", "jsdom": "^26.1.0", "less": "^4.5.1", "prettier": "^3.7.4", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index f1bb97d7..1acf43f4 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -234,6 +234,9 @@ importers: eslint-plugin-react-refresh: specifier: ^0.4.24 version: 0.4.26(eslint@9.39.2(jiti@2.6.1)) + javascript-obfuscator: + specifier: 5.5.0 + version: 5.5.0 jsdom: specifier: ^26.1.0 version: 26.1.0(bufferutil@4.1.0)(utf-8-validate@6.0.5) @@ -1122,89 +1125,105 @@ packages: resolution: {integrity: sha512-excjX8DfsIcJ10x1Kzr4RcWe1edC9PquDRRPx3YVCvQv+U5p7Yin2s32ftzikXojb1PIFc/9Mt28/y+iRklkrw==} cpu: [arm64] os: [linux] + libc: [glibc] '@img/sharp-libvips-linux-arm@1.2.4': resolution: {integrity: sha512-bFI7xcKFELdiNCVov8e44Ia4u2byA+l3XtsAj+Q8tfCwO6BQ8iDojYdvoPMqsKDkuoOo+X6HZA0s0q11ANMQ8A==} cpu: [arm] os: [linux] + libc: [glibc] '@img/sharp-libvips-linux-ppc64@1.2.4': resolution: {integrity: sha512-FMuvGijLDYG6lW+b/UvyilUWu5Ayu+3r2d1S8notiGCIyYU/76eig1UfMmkZ7vwgOrzKzlQbFSuQfgm7GYUPpA==} cpu: [ppc64] os: [linux] + libc: [glibc] '@img/sharp-libvips-linux-riscv64@1.2.4': resolution: {integrity: sha512-oVDbcR4zUC0ce82teubSm+x6ETixtKZBh/qbREIOcI3cULzDyb18Sr/Wcyx7NRQeQzOiHTNbZFF1UwPS2scyGA==} cpu: [riscv64] os: [linux] + libc: [glibc] '@img/sharp-libvips-linux-s390x@1.2.4': resolution: {integrity: sha512-qmp9VrzgPgMoGZyPvrQHqk02uyjA0/QrTO26Tqk6l4ZV0MPWIW6LTkqOIov+J1yEu7MbFQaDpwdwJKhbJvuRxQ==} cpu: [s390x] os: [linux] + libc: [glibc] '@img/sharp-libvips-linux-x64@1.2.4': resolution: {integrity: sha512-tJxiiLsmHc9Ax1bz3oaOYBURTXGIRDODBqhveVHonrHJ9/+k89qbLl0bcJns+e4t4rvaNBxaEZsFtSfAdquPrw==} cpu: [x64] os: [linux] + libc: [glibc] '@img/sharp-libvips-linuxmusl-arm64@1.2.4': resolution: {integrity: sha512-FVQHuwx1IIuNow9QAbYUzJ+En8KcVm9Lk5+uGUQJHaZmMECZmOlix9HnH7n1TRkXMS0pGxIJokIVB9SuqZGGXw==} cpu: [arm64] os: [linux] + libc: [musl] '@img/sharp-libvips-linuxmusl-x64@1.2.4': resolution: {integrity: sha512-+LpyBk7L44ZIXwz/VYfglaX/okxezESc6UxDSoyo2Ks6Jxc4Y7sGjpgU9s4PMgqgjj1gZCylTieNamqA1MF7Dg==} cpu: [x64] os: [linux] + libc: [musl] '@img/sharp-linux-arm64@0.34.5': resolution: {integrity: sha512-bKQzaJRY/bkPOXyKx5EVup7qkaojECG6NLYswgktOZjaXecSAeCWiZwwiFf3/Y+O1HrauiE3FVsGxFg8c24rZg==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [arm64] os: [linux] + libc: [glibc] '@img/sharp-linux-arm@0.34.5': resolution: {integrity: sha512-9dLqsvwtg1uuXBGZKsxem9595+ujv0sJ6Vi8wcTANSFpwV/GONat5eCkzQo/1O6zRIkh0m/8+5BjrRr7jDUSZw==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [arm] os: [linux] + libc: [glibc] '@img/sharp-linux-ppc64@0.34.5': resolution: {integrity: sha512-7zznwNaqW6YtsfrGGDA6BRkISKAAE1Jo0QdpNYXNMHu2+0dTrPflTLNkpc8l7MUP5M16ZJcUvysVWWrMefZquA==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [ppc64] os: [linux] + libc: [glibc] '@img/sharp-linux-riscv64@0.34.5': resolution: {integrity: sha512-51gJuLPTKa7piYPaVs8GmByo7/U7/7TZOq+cnXJIHZKavIRHAP77e3N2HEl3dgiqdD/w0yUfiJnII77PuDDFdw==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [riscv64] os: [linux] + libc: [glibc] '@img/sharp-linux-s390x@0.34.5': resolution: {integrity: sha512-nQtCk0PdKfho3eC5MrbQoigJ2gd1CgddUMkabUj+rBevs8tZ2cULOx46E7oyX+04WGfABgIwmMC0VqieTiR4jg==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [s390x] os: [linux] + libc: [glibc] '@img/sharp-linux-x64@0.34.5': resolution: {integrity: sha512-MEzd8HPKxVxVenwAa+JRPwEC7QFjoPWuS5NZnBt6B3pu7EG2Ge0id1oLHZpPJdn3OQK+BQDiw9zStiHBTJQQQQ==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [x64] os: [linux] + libc: [glibc] '@img/sharp-linuxmusl-arm64@0.34.5': resolution: {integrity: sha512-fprJR6GtRsMt6Kyfq44IsChVZeGN97gTD331weR1ex1c1rypDEABN6Tm2xa1wE6lYb5DdEnk03NZPqA7Id21yg==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [arm64] os: [linux] + libc: [musl] '@img/sharp-linuxmusl-x64@0.34.5': resolution: {integrity: sha512-Jg8wNT1MUzIvhBFxViqrEhWDGzqymo3sV7z7ZsaWbZNDLXRJZoRGrjulp60YYtV4wfY8VIKcWidjojlLcWrd8Q==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [x64] os: [linux] + libc: [musl] '@img/sharp-wasm32@0.34.5': resolution: {integrity: sha512-OdWTEiVkY2PHwqkbBI8frFxQQFekHaSSkUIJkwzclWZe64O1X4UlUjqqqLaPbUpMOQk6FBu/HtlGXNblIs0huw==} @@ -1229,6 +1248,28 @@ packages: cpu: [x64] os: [win32] + '@inversifyjs/common@1.5.2': + resolution: {integrity: sha512-WlzR9xGadABS9gtgZQ+luoZ8V6qm4Ii6RQfcfC9Ho2SOlE6ZuemFo7PKJvKI0ikm8cmKbU8hw5UK6E4qovH21w==} + + '@inversifyjs/container@1.15.0': + resolution: {integrity: sha512-U2xYsPrJTz5za2TExi5lg8qOWf8TEVBpN+pQM7B8BVA2rajtbRE9A66SLRHk8c1eGXmg+0K4Hdki6tWAsSQBUA==} + peerDependencies: + reflect-metadata: ~0.2.2 + + '@inversifyjs/core@9.2.0': + resolution: {integrity: sha512-Nm7BR6KmpgshIHpVQWuEDehqRVb6GBm8LFEuhc2s4kSZWrArZ15RmXQzROLk4m+hkj4kMXgvMm5Qbopot/D6Sg==} + + '@inversifyjs/plugin@0.2.0': + resolution: {integrity: sha512-R/JAdkTSD819pV1zi0HP54mWHyX+H2m8SxldXRgPQarS3ySV4KPyRdosWcfB8Se0JJZWZLHYiUNiS6JvMWSPjw==} + + '@inversifyjs/prototype-utils@0.1.3': + resolution: {integrity: sha512-EzRamZzNgE9Sn3QtZ8NncNa2lpPMZfspqbK6BWFguWnOpK8ymp2TUuH46ruFHZhrHKnknPd7fG22ZV7iF517TQ==} + + '@inversifyjs/reflect-metadata-utils@1.4.1': + resolution: {integrity: sha512-Cp77C4d2wLaHXiUB7iH6Cxb7i1lD/YDuTIHLTDzKINqGSz0DCSoL/Dg2wVkW/6Qx03r/yQMLJ+32Agl32N2X8g==} + peerDependencies: + reflect-metadata: ~0.2.2 + '@isaacs/balanced-match@4.0.1': resolution: {integrity: sha512-yzMTt9lEb8Gv7zRioUilSglI0c0smZ9k5D65677DLWLtWJaXIS3CqcGyUFByYKlnUj6TkjLVs54fBl6+TiGQDQ==} engines: {node: 20 || >=22} @@ -1245,6 +1286,14 @@ packages: resolution: {integrity: sha512-wgm9Ehl2jpeqP3zw/7mo3kRHFp5MEDhqAdwy1fTGkHAwnkGOVsgpvQhL8B5n1qlb01jV3n/bI0ZfZp5lWA1k4w==} engines: {node: '>=18.0.0'} + '@javascript-obfuscator/escodegen@2.4.2': + resolution: {integrity: sha512-3N7EUdYxuldwvtOtZIlAxNwPW1qTUFwWt3PxNkik6hB1uSSXLXj9JMlSyUbTCXK3Osjn0Nu0s/aa4mbvkGouXQ==} + engines: {node: '>=6.0'} + + '@javascript-obfuscator/estraverse@5.4.0': + resolution: {integrity: sha512-CZFX7UZVN9VopGbjTx4UXaXsi9ewoM1buL0kY7j1ftYdSs7p2spv9opxFjHlQ/QGTgh4UqufYqJJ0WKLml7b6w==} + engines: {node: '>=4.0'} + '@jridgewell/gen-mapping@0.3.13': resolution: {integrity: sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==} @@ -1283,24 +1332,28 @@ packages: engines: {node: '>= 18'} cpu: [arm64] os: [linux] + libc: [glibc] '@lancedb/lancedb-linux-arm64-musl@0.22.3': resolution: {integrity: sha512-jVRMtXxxYaDlZSaclCIHB2N+NJvQ1Fj9EaPeBx+HxG2VqUg0vXKef+yiaD2aGo9sAH6mMmkKJsrPhwABpUC4rQ==} engines: {node: '>= 18'} cpu: [arm64] os: [linux] + libc: [musl] '@lancedb/lancedb-linux-x64-gnu@0.22.3': resolution: {integrity: sha512-co7idTwvNAtbFoFHojhHlTpKsydOm5sZfbtAsQRdoa7g6a61yIrqrMm8D7Ngh756JfzZLFQBMkDUZEW3X4vP/g==} engines: {node: '>= 18'} cpu: [x64] os: [linux] + libc: [glibc] '@lancedb/lancedb-linux-x64-musl@0.22.3': resolution: {integrity: sha512-+ipFsn5PCODK7mOMq1gZ5OAZWks5YlgmjAlnYMmU8XxvaK0b6lZdA3s1hTmBaBO9+wv+31ulO55oBN4/U8Yldg==} engines: {node: '>= 18'} cpu: [x64] os: [linux] + libc: [musl] '@lancedb/lancedb-win32-arm64-msvc@0.22.3': resolution: {integrity: sha512-E0XywJYnelIe4pzOlvog+aMHKt5ChW27tgmT2V80Z6PXcX6eN9I69Fj0Q6DK6z1YCTPIPu6Na1Hd6d4GqUNKPw==} @@ -1317,6 +1370,7 @@ packages: '@lancedb/lancedb@0.22.3': resolution: {integrity: sha512-nRC0fkg+d7dzCtudKHT+VH7znk6KUXRZyuS6HJYNnIrbvXBxaT6wAPjEbf70KTuqvP2znj48Zg+kiwRqkRnAJw==} engines: {node: '>= 18'} + cpu: [x64, arm64] os: [darwin, linux, win32] peerDependencies: apache-arrow: '>=15.0.0 <=18.1.0' @@ -1809,30 +1863,35 @@ packages: engines: {node: '>= 10'} cpu: [arm64] os: [linux] + libc: [glibc] '@napi-rs/canvas-linux-arm64-musl@0.1.80': resolution: {integrity: sha512-1XbCOz/ymhj24lFaIXtWnwv/6eFHXDrjP0jYkc6iHQ9q8oXKzUX1Lc6bu+wuGiLhGh2GS/2JlfORC5ZcXimRcg==} engines: {node: '>= 10'} cpu: [arm64] os: [linux] + libc: [musl] '@napi-rs/canvas-linux-riscv64-gnu@0.1.80': resolution: {integrity: sha512-XTzR125w5ZMs0lJcxRlS1K3P5RaZ9RmUsPtd1uGt+EfDyYMu4c6SEROYsxyatbbu/2+lPe7MPHOO/0a0x7L/gw==} engines: {node: '>= 10'} cpu: [riscv64] os: [linux] + libc: [glibc] '@napi-rs/canvas-linux-x64-gnu@0.1.80': resolution: {integrity: sha512-BeXAmhKg1kX3UCrJsYbdQd3hIMDH/K6HnP/pG2LuITaXhXBiNdh//TVVVVCBbJzVQaV5gK/4ZOCMrQW9mvuTqA==} engines: {node: '>= 10'} cpu: [x64] os: [linux] + libc: [glibc] '@napi-rs/canvas-linux-x64-musl@0.1.80': resolution: {integrity: sha512-x0XvZWdHbkgdgucJsRxprX/4o4sEed7qo9rCQA9ugiS9qE2QvP0RIiEugtZhfLH3cyI+jIRFJHV4Fuz+1BHHMg==} engines: {node: '>= 10'} cpu: [x64] os: [linux] + libc: [musl] '@napi-rs/canvas-win32-x64-msvc@0.1.80': resolution: {integrity: sha512-Z8jPsM6df5V8B1HrCHB05+bDiCxjE9QA//3YrkKIdVDEwn5RKaqOxCJDRJkl48cJbylcrJbW4HxZbTte8juuPg==} @@ -1888,24 +1947,28 @@ packages: engines: {node: '>= 10'} cpu: [arm64] os: [linux] + libc: [glibc] '@node-rs/jieba-linux-arm64-musl@2.0.1': resolution: {integrity: sha512-K4EDyNixSLVdTNYnHwD+7I/ytvzpo7tt+vdCLqwQViiek2PMpL/FFRvA39uU2tk99jXIxvkczdxARG20BRZppg==} engines: {node: '>= 10'} cpu: [arm64] os: [linux] + libc: [musl] '@node-rs/jieba-linux-x64-gnu@2.0.1': resolution: {integrity: sha512-sq3J6L2ANTE25I9eVFq/nb57OtXcvUIeUD1CTKJxwgTKIVmcB2LyOZpWf20AjHRUfbMER9Klqg5dgyyO+Six+w==} engines: {node: '>= 10'} cpu: [x64] os: [linux] + libc: [glibc] '@node-rs/jieba-linux-x64-musl@2.0.1': resolution: {integrity: sha512-0zfP9Qy68yEXrhBFknfhF6WUJDPU/8eRuyIrkMGdMjfRpxhpSbr2fMfnsqhOQLvhuK4w3iDFvTy4t5d0s6JKMA==} engines: {node: '>= 10'} cpu: [x64] os: [linux] + libc: [musl] '@node-rs/jieba-wasm32-wasi@2.0.1': resolution: {integrity: sha512-7I5rJya5rlQNJIhv8PvPzIVT1/gVc0vFzHmlfRGwCPGDJ3tHVxkSPW34dDx3OgDmbIeadNpmgIyC1RaS9djPJg==} @@ -2132,24 +2195,28 @@ packages: engines: {node: '>= 10'} cpu: [arm64] os: [linux] + libc: [glibc] '@resvg/resvg-js-linux-arm64-musl@2.6.2': resolution: {integrity: sha512-3h3dLPWNgSsD4lQBJPb4f+kvdOSJHa5PjTYVsWHxLUzH4IFTJUAnmuWpw4KqyQ3NA5QCyhw4TWgxk3jRkQxEKg==} engines: {node: '>= 10'} cpu: [arm64] os: [linux] + libc: [musl] '@resvg/resvg-js-linux-x64-gnu@2.6.2': resolution: {integrity: sha512-IVUe+ckIerA7xMZ50duAZzwf1U7khQe2E0QpUxu5MBJNao5RqC0zwV/Zm965vw6D3gGFUl7j4m+oJjubBVoftw==} engines: {node: '>= 10'} cpu: [x64] os: [linux] + libc: [glibc] '@resvg/resvg-js-linux-x64-musl@2.6.2': resolution: {integrity: sha512-UOf83vqTzoYQO9SZ0fPl2ZIFtNIz/Rr/y+7X8XRX1ZnBYsQ/tTb+cj9TE+KHOdmlTFBxhYzVkP2lRByCzqi4jQ==} engines: {node: '>= 10'} cpu: [x64] os: [linux] + libc: [musl] '@resvg/resvg-js-win32-arm64-msvc@2.6.2': resolution: {integrity: sha512-7C/RSgCa+7vqZ7qAbItfiaAWhyRSoD4l4BQAbVDqRRsRgY+S+hgS3in0Rxr7IorKUpGE69X48q6/nOAuTJQxeQ==} @@ -2210,66 +2277,79 @@ packages: resolution: {integrity: sha512-Rn3n+FUk2J5VWx+ywrG/HGPTD9jXNbicRtTM11e/uorplArnXZYsVifnPPqNNP5BsO3roI4n8332ukpY/zN7rQ==} cpu: [arm] os: [linux] + libc: [glibc] '@rollup/rollup-linux-arm-musleabihf@4.55.1': resolution: {integrity: sha512-grPNWydeKtc1aEdrJDWk4opD7nFtQbMmV7769hiAaYyUKCT1faPRm2av8CX1YJsZ4TLAZcg9gTR1KvEzoLjXkg==} cpu: [arm] os: [linux] + libc: [musl] '@rollup/rollup-linux-arm64-gnu@4.55.1': resolution: {integrity: sha512-a59mwd1k6x8tXKcUxSyISiquLwB5pX+fJW9TkWU46lCqD/GRDe9uDN31jrMmVP3feI3mhAdvcCClhV8V5MhJFQ==} cpu: [arm64] os: [linux] + libc: [glibc] '@rollup/rollup-linux-arm64-musl@4.55.1': resolution: {integrity: sha512-puS1MEgWX5GsHSoiAsF0TYrpomdvkaXm0CofIMG5uVkP6IBV+ZO9xhC5YEN49nsgYo1DuuMquF9+7EDBVYu4uA==} cpu: [arm64] os: [linux] + libc: [musl] '@rollup/rollup-linux-loong64-gnu@4.55.1': resolution: {integrity: sha512-r3Wv40in+lTsULSb6nnoudVbARdOwb2u5fpeoOAZjFLznp6tDU8kd+GTHmJoqZ9lt6/Sys33KdIHUaQihFcu7g==} cpu: [loong64] os: [linux] + libc: [glibc] '@rollup/rollup-linux-loong64-musl@4.55.1': resolution: {integrity: sha512-MR8c0+UxAlB22Fq4R+aQSPBayvYa3+9DrwG/i1TKQXFYEaoW3B5b/rkSRIypcZDdWjWnpcvxbNaAJDcSbJU3Lw==} cpu: [loong64] os: [linux] + libc: [musl] '@rollup/rollup-linux-ppc64-gnu@4.55.1': resolution: {integrity: sha512-3KhoECe1BRlSYpMTeVrD4sh2Pw2xgt4jzNSZIIPLFEsnQn9gAnZagW9+VqDqAHgm1Xc77LzJOo2LdigS5qZ+gw==} cpu: [ppc64] os: [linux] + libc: [glibc] '@rollup/rollup-linux-ppc64-musl@4.55.1': resolution: {integrity: sha512-ziR1OuZx0vdYZZ30vueNZTg73alF59DicYrPViG0NEgDVN8/Jl87zkAPu4u6VjZST2llgEUjaiNl9JM6HH1Vdw==} cpu: [ppc64] os: [linux] + libc: [musl] '@rollup/rollup-linux-riscv64-gnu@4.55.1': resolution: {integrity: sha512-uW0Y12ih2XJRERZ4jAfKamTyIHVMPQnTZcQjme2HMVDAHY4amf5u414OqNYC+x+LzRdRcnIG1YodLrrtA8xsxw==} cpu: [riscv64] os: [linux] + libc: [glibc] '@rollup/rollup-linux-riscv64-musl@4.55.1': resolution: {integrity: sha512-u9yZ0jUkOED1BFrqu3BwMQoixvGHGZ+JhJNkNKY/hyoEgOwlqKb62qu+7UjbPSHYjiVy8kKJHvXKv5coH4wDeg==} cpu: [riscv64] os: [linux] + libc: [musl] '@rollup/rollup-linux-s390x-gnu@4.55.1': resolution: {integrity: sha512-/0PenBCmqM4ZUd0190j7J0UsQ/1nsi735iPRakO8iPciE7BQ495Y6msPzaOmvx0/pn+eJVVlZrNrSh4WSYLxNg==} cpu: [s390x] os: [linux] + libc: [glibc] '@rollup/rollup-linux-x64-gnu@4.55.1': resolution: {integrity: sha512-a8G4wiQxQG2BAvo+gU6XrReRRqj+pLS2NGXKm8io19goR+K8lw269eTrPkSdDTALwMmJp4th2Uh0D8J9bEV1vg==} cpu: [x64] os: [linux] + libc: [glibc] '@rollup/rollup-linux-x64-musl@4.55.1': resolution: {integrity: sha512-bD+zjpFrMpP/hqkfEcnjXWHMw5BIghGisOKPj+2NaNDuVT+8Ds4mPf3XcPHuat1tz89WRL+1wbcxKY3WSbiT7w==} cpu: [x64] os: [linux] + libc: [musl] '@rollup/rollup-openbsd-x64@4.55.1': resolution: {integrity: sha512-eLXw0dOiqE4QmvikfQ6yjgkg/xDM+MdU9YJuP4ySTibXU0oAvnEWXt7UDJmD4UkYialMfOGFPJnIHSe/kdzPxg==} @@ -2381,24 +2461,28 @@ packages: engines: {node: '>= 10'} cpu: [arm64] os: [linux] + libc: [glibc] '@tailwindcss/oxide-linux-arm64-musl@4.1.18': resolution: {integrity: sha512-1px92582HkPQlaaCkdRcio71p8bc8i/ap5807tPRDK/uw953cauQBT8c5tVGkOwrHMfc2Yh6UuxaH4vtTjGvHg==} engines: {node: '>= 10'} cpu: [arm64] os: [linux] + libc: [musl] '@tailwindcss/oxide-linux-x64-gnu@4.1.18': resolution: {integrity: sha512-v3gyT0ivkfBLoZGF9LyHmts0Isc8jHZyVcbzio6Wpzifg/+5ZJpDiRiUhDLkcr7f/r38SWNe7ucxmGW3j3Kb/g==} engines: {node: '>= 10'} cpu: [x64] os: [linux] + libc: [glibc] '@tailwindcss/oxide-linux-x64-musl@4.1.18': resolution: {integrity: sha512-bhJ2y2OQNlcRwwgOAGMY0xTFStt4/wyU6pvI6LSuZpRgKQwxTec0/3Scu91O8ir7qCR3AuepQKLU/kX99FouqQ==} engines: {node: '>= 10'} cpu: [x64] os: [linux] + libc: [musl] '@tailwindcss/oxide-wasm32-wasi@4.1.18': resolution: {integrity: sha512-LffYTvPjODiP6PT16oNeUQJzNVyJl1cjIebq/rWWBF+3eDst5JGEFSc5cWxyRCJ0Mxl+KyIkqRxk1XPEs9x8TA==} @@ -2531,6 +2615,9 @@ packages: '@types/mdast@4.0.4': resolution: {integrity: sha512-kGaNbPh1k7AFzgpud/gMdvIm5xuECykRR+JnWKQno9TAXVa6WIVCGTPvYGekIDL4uwCZQSYbUxNBSb1aUo79oA==} + '@types/minimatch@3.0.5': + resolution: {integrity: sha512-Klz949h02Gz2uZCMGwDUSDS1YBlTdDDgbWHi+81l29tQALUtvz4rAYi5uoVhE5Lagoq6DeqAUlbrHvW/mXDgdQ==} + '@types/ms@2.1.0': resolution: {integrity: sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA==} @@ -2581,6 +2668,9 @@ packages: '@types/uuid@10.0.0': resolution: {integrity: sha512-7gqG38EyHgyP1S+7+xomFtL+ZNHcKv6DwNaCZmJmo1vgMugyF3TCnXVg4t1uk89mLNwnLtnY3TpOpCOyp1/xHQ==} + '@types/validator@13.15.10': + resolution: {integrity: sha512-T8L6i7wCuyoK8A/ZeLYt1+q0ty3Zb9+qbSSvrIVitzT3YjZqkTZ40IbRsPanlB4h1QB3JVL1SYCdR6ngtFYcuA==} + '@types/verror@1.10.11': resolution: {integrity: sha512-RlDm9K7+o5stv0Co8i8ZRGxDbrTxhJtgjqjFyVh/tXQyl/rYtTKlnTvZ88oSTeYREWurwx20Js4kTuKCsFkUtg==} @@ -2649,10 +2739,25 @@ packages: '@ungap/structured-clone@1.3.0': resolution: {integrity: sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g==} + '@vercel/blob@2.6.1': + resolution: {integrity: sha512-KTJytw85j1XQBxjN5d6UXI7fIWNQe1jotn4nWN+0hePqLs+Qi1B3jHdQcSKFGF0m2rsy9uhPT6GOXMtHe3qNzg==} + engines: {node: '>=20.0.0'} + + '@vercel/cli-config@0.2.0': + resolution: {integrity: sha512-fJRRRB7734BDuXZ89yBEaA2ncYhH7bWX30mk04W80J6VAfQc+4iB8lyzAdaGpFV3/vNlkt9VZt+/uoQoWX6UsQ==} + + '@vercel/cli-exec@1.0.0': + resolution: {integrity: sha512-kQF8LGie/Hbdq9/psJxLE7owRTcqMQMhgybU04gCeR7cbQAr5t8OrjefDNColJv1QSSucFt4pLwRiARVmlOnug==} + engines: {node: '>= 18'} + '@vercel/oidc@3.1.0': resolution: {integrity: sha512-Fw28YZpRnA3cAHHDlkt7xQHiJ0fcL+NRcIqsocZQUSmbzeIKRpwttJjik5ZGanXP+vlA4SbTg+AbA3bP363l+w==} engines: {node: '>= 20'} + '@vercel/oidc@3.8.0': + resolution: {integrity: sha512-r00laGW6Pv778RoR6M2NxX91ycSj+PBwVo+fOb9Bif+F0IyUKt25zrvBzfEzQpeAzbqOgPZyQibEWDdDFApd+A==} + engines: {node: '>= 20'} + '@vitejs/plugin-react@5.1.2': resolution: {integrity: sha512-EcA07pHJouywpzsoTUqNh5NwGayl2PPVEJKUSinGGSxFGYn+shYbqMGBg6FXDqgXum9Ou/ecb+411ssw8HImJQ==} engines: {node: ^20.19.0 || >=22.12.0} @@ -2710,6 +2815,11 @@ packages: resolution: {integrity: sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng==} engines: {node: '>= 0.6'} + acorn-import-attributes@1.9.5: + resolution: {integrity: sha512-n02Vykv5uA3eHGM/Z2dQrcD56kL8TyDb2p1+0P83PClMnC/nc+anbQRhIOWnSq4Ke/KvDPrY3C9hDtC/A3eHnQ==} + peerDependencies: + acorn: ^8 + acorn-jsx@5.3.2: resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==} peerDependencies: @@ -2830,10 +2940,18 @@ packages: resolution: {integrity: sha512-LHE+8BuR7RYGDKvnrmcuSq3tDcKv9OFEXQt/HpbZhY7V6h0zlUXutnAD82GiFx9rdieCMjkvtcsPqBwgUl1Iiw==} engines: {node: '>= 0.4'} + array-differ@3.0.0: + resolution: {integrity: sha512-THtfYS6KtME/yIAhKjZ2ul7XI96lQGHRputJQHO80LAWQnuGP4iCIN8vdMRboGbIEYBwU33q8Tch1os2+X0kMg==} + engines: {node: '>=8'} + array-includes@3.1.9: resolution: {integrity: sha512-FmeCCAenzH0KH381SPT5FZmiA/TmpndpcaShhfgEN9eCVjnFBqq3l1xrI42y8+PPLI6hypzou4GXw00WHmPBLQ==} engines: {node: '>= 0.4'} + array-union@2.1.0: + resolution: {integrity: sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==} + engines: {node: '>=8'} + array.prototype.findlast@1.2.5: resolution: {integrity: sha512-CVvd6FHg1Z3POpBLxO6E6zr+rSKEQ9L6rZHAaY7lLfhKsWYUBBOuMs0e9o24oopj6H+geRCX0YJ+TJLBK2eHyQ==} engines: {node: '>= 0.4'} @@ -2854,10 +2972,17 @@ packages: resolution: {integrity: sha512-BNoCY6SXXPQ7gF2opIP4GBE+Xw7U+pHMYKuzjgCN3GwiaIR09UUeKfheyIry77QtrCBlC0KK0q5/TER/tYh3PQ==} engines: {node: '>= 0.4'} + arrify@2.0.1: + resolution: {integrity: sha512-3duEwti880xqi4eAMN8AyR4a0ByT90zoYdLlevfrvU43vb0YZwZVfxOgxWrLXXXpyugL0hNZc9G6BiB5B3nUug==} + engines: {node: '>=8'} + assert-plus@1.0.0: resolution: {integrity: sha512-NfJ4UzBCcQGLDlQq7nHxH+tv3kyZ0hHQqF5BO6J7tNJeP5do1llPr8dZ8zHonfhAu0PHAdMkSo+8o0wxg9lZWw==} engines: {node: '>=0.8'} + assert@2.1.0: + resolution: {integrity: sha512-eLHpSK/Y4nhMJ07gDaAzoX/XAKS8PSaojml3M0DM4JpV1LAi5JOJ/p6H/XWrl8L+DzVEvVCW1z3vWAaB9oTsQw==} + assertion-error@2.0.1: resolution: {integrity: sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==} engines: {node: '>=12'} @@ -2874,6 +2999,9 @@ packages: resolution: {integrity: sha512-hsU18Ae8CDTR6Kgu9DYf0EbCr/a5iGL0rytQDobUcdpYOKokk8LEjVphnXkDkgpi0wYVsqrXuP0bZxJaTqdgoA==} engines: {node: '>= 0.4'} + async-retry@1.3.3: + resolution: {integrity: sha512-wfr/jstw9xNi/0teMHrRW7dsz3Lt5ARhYNZ2ewpadnhaIp5mbALhOAP+EAdsC7t4Z6wqsDVv9+W6gm1Dk9mEyw==} + async@3.2.6: resolution: {integrity: sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA==} @@ -3066,6 +3194,13 @@ packages: resolution: {integrity: sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA==} engines: {node: ^12.17.0 || ^14.13 || >=16.0.0} + chance@1.1.13: + resolution: {integrity: sha512-V6lQCljcLznE7tUYUM9EOAnnKXbctE6j/rdQkYOHIWbfGQbrzTsAXNW9CdU5XCo4ArXQCj/rb6HgxPlmGJcaUg==} + + char-regex@1.0.2: + resolution: {integrity: sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==} + engines: {node: '>=10'} + character-entities-html4@2.1.0: resolution: {integrity: sha512-1v7fgQRj6hnSwFpq1Eu0ynr/CDEw0rXo2B61qXrLNdHZmPKgb7fqS1a2JwF0rISo9q77jDI8VMEHoApn8qDoZA==} @@ -3078,6 +3213,9 @@ packages: character-reference-invalid@2.0.1: resolution: {integrity: sha512-iBZ4F4wRbyORVsu0jPV7gXkOsGYjGHPmAyv+HiHG8gi5PtC9KI2j1+v8/tlibRvjoWX027ypmG/n0HtO5t7unw==} + charenc@0.0.2: + resolution: {integrity: sha512-yrLQ/yVUFXkzg7EDQsPieE/53+0RlaWTs+wBrvW36cyilJ2SaDWfl4Yj7MtLTXleV9uEKefbAGUPv2/iWSooRA==} + cheerio-select@2.1.0: resolution: {integrity: sha512-9v9kG0LvzrlcungtnJtpGNxY+fzECQKhK4EGJX2vByejiMX84MFNQw4UxPJl3bFbTMw+Dfs37XaIkCwTZfLh4g==} @@ -3113,6 +3251,9 @@ packages: resolution: {integrity: sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==} engines: {node: '>=8'} + class-validator@0.14.3: + resolution: {integrity: sha512-rXXekcjofVN1LTOSw+u4u9WXVEUvNBVjORW154q/IdmYWy1nMbOU9aNtZB0t8m+FJQ9q91jlr2f9CwwUFdFMRA==} + classnames@2.5.1: resolution: {integrity: sha512-saHYOzhIQs6wy2sVxTM6bUDsQO4F50V9RQ22qBpEdCW+I+/Wmke2HOl6lS6dTpdxVhb88/I6+Hs+438c3lfUow==} @@ -3183,6 +3324,10 @@ packages: resolution: {integrity: sha512-PqMLy5+YGwhMh1wS04mVG44oqDsgyLRSKJBdOo1bnYhMKBW65gZF1dRp2OZRhiTjgUHljy99qkO7bsctLaw35Q==} engines: {node: '>=12.20.0'} + commander@12.1.0: + resolution: {integrity: sha512-Vw8qHK3bZM9y/P10u3Vib8o/DdkvA2OtPtZvD871QKjy74Wj1WSKFILMPRPSdUSx5RFK1arlJzEtA4PkFgnbuA==} + engines: {node: '>=18'} + commander@13.1.0: resolution: {integrity: sha512-/rFeCpNJQbhSZjGVwO9RFV3xPqbnERS8MmIQzCtD/zl6gpJuV/bMLuN92oG3F7d8oDEHHRrujSXNUr8fpjntKw==} engines: {node: '>=18'} @@ -3274,6 +3419,9 @@ packages: resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==} engines: {node: '>= 8'} + crypt@0.0.2: + resolution: {integrity: sha512-mCxBlsHFYh9C+HVpiEacem8FEBnMXgU9gy4zmNC+SXAZNB/1idgp/aulFJ4FgCi7GPEVbfyng092GqL2k2rmow==} + crypto-js@4.2.0: resolution: {integrity: sha512-KALDyEYgpY+Rlob/iriUtjV6d5Eq+Y191A5g4UqLAi8CyGP9N1+FdVbkc1SxKc2r4YAYqG8JzO2KGL+AizD70Q==} @@ -3563,6 +3711,10 @@ packages: resolution: {integrity: sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==} engines: {node: '>=6'} + env-paths@4.0.0: + resolution: {integrity: sha512-pxP8eL2SwwaTRi/KHYwLYXinDs7gL3jxFcBYmEdYfZmZXbaVDvdppd0XBU8qVz03rDfKZMXg1omHCbsJjZrMsw==} + engines: {node: '>=20'} + err-code@2.0.3: resolution: {integrity: sha512-2bmlRpNKBxT/CRmPOlyISQpNj+qSeYvcym/uT0Jx2bMOlKLtSy1ZmLuVxSEKKyor/N5yhvp/ZiG1oE3DEYMSFA==} @@ -3700,6 +3852,11 @@ packages: resolution: {integrity: sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + esprima@4.0.1: + resolution: {integrity: sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==} + engines: {node: '>=4'} + hasBin: true + esquery@1.7.0: resolution: {integrity: sha512-Ap6G0WQwcU/LHsvLwON1fAQX9Zp0A2Y6Y/cJBl9r/JbW90Zyg4/zbG6zzKa2OTALELarYHmKu0GhpM5EO+7T0g==} engines: {node: '>=0.10'} @@ -3748,6 +3905,10 @@ packages: resolution: {integrity: sha512-CRT1WTyuQoD771GW56XEZFQ/ZoSfWid1alKGDYMmkt2yl8UXrVR4pspqWNEcqKvVIzg6PAltWjxcSSPrboA4iA==} engines: {node: '>=18.0.0'} + execa@5.1.1: + resolution: {integrity: sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==} + engines: {node: '>=10'} + expand-template@2.0.3: resolution: {integrity: sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg==} engines: {node: '>=6'} @@ -4004,6 +4165,10 @@ packages: resolution: {integrity: sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==} engines: {node: '>=8'} + get-stream@6.0.1: + resolution: {integrity: sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==} + engines: {node: '>=10'} + get-symbol-description@1.1.0: resolution: {integrity: sha512-w9UMqWwJxHNOvoNzSJ2oPF5wvYcvP7jUvYzhp67yEhTi17ZDBBC1z9pTdGuzjD+EFIqLSYRweZjqfiPzQ06Ebg==} engines: {node: '>= 0.4'} @@ -4027,7 +4192,7 @@ packages: glob@8.1.0: resolution: {integrity: sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==} engines: {node: '>=12'} - deprecated: Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me + deprecated: Glob versions prior to v9 are no longer supported global-agent@3.0.0: resolution: {integrity: sha512-PT6XReJ+D07JvGoxQMkT6qji/jVNfX/h364XHZOWeRzy64sSFr+xJ5OX7LI3b4MPQzdL4H8Y8M0xzPpsVMwA8Q==} @@ -4208,6 +4373,10 @@ packages: resolution: {integrity: sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==} engines: {node: '>= 14'} + human-signals@2.1.0: + resolution: {integrity: sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==} + engines: {node: '>=10.17.0'} + humanize-ms@1.2.1: resolution: {integrity: sha512-Fl70vYtsAFb/C06PTS9dZBo7ihau+Tu/DNCk/OyHhea07S+aeMWpFFkUaXRa8fI+ScZbEI8dfSxwY7gxZ9SAVQ==} @@ -4282,6 +4451,9 @@ packages: resolution: {integrity: sha512-4gd7VpWNQNB4UKKCFFVcp1AVv+FMOgs9NKzjHKusc8jTMhd5eL1NqQqOpE0KzMds804/yHlglp3uxgluOqAPLw==} engines: {node: '>= 0.4'} + inversify@7.11.0: + resolution: {integrity: sha512-yZDprSSr8TyVeMGI/AOV4ws6gwjX22hj9Z8/oHAVpJORY6WRFTcUzhnZtibBUHEw2U8ArvHcR+i863DplQ3Cwg==} + ip-address@10.2.0: resolution: {integrity: sha512-/+S6j4E9AHvW9SWMSEY9Xfy66O5PWvVEJ08O0y5JGyEKQpojb0K0GKpz/v5HJ/G0vi3D2sjGK78119oXZeE0qA==} engines: {node: '>= 12'} @@ -4296,6 +4468,10 @@ packages: is-alphanumerical@2.0.1: resolution: {integrity: sha512-hmbYhX/9MUMF5uh7tOXyK/n0ZvWpad5caBA17GsC6vyuCqaWliRG5K1qS9inmUhEMaOBIW7/whAnSwveW/LtZw==} + is-arguments@1.2.0: + resolution: {integrity: sha512-7bVbi0huj/wrIAOzb8U1aszg9kdi3KN/CyU19CTI7tAoZYEZoL9yCDXpbXN+uPsuWnP02cyug1gleqq+TU+YCA==} + engines: {node: '>= 0.4'} + is-array-buffer@3.0.5: resolution: {integrity: sha512-DDfANUiiG2wC1qawP66qlTugJeL5HyzMpfr8lLK+jMQirGzNod0B12cFB/9q838Ru27sBwfw78/rdoU7RERz6A==} engines: {node: '>= 0.4'} @@ -4315,6 +4491,13 @@ packages: resolution: {integrity: sha512-wa56o2/ElJMYqjCjGkXri7it5FbebW5usLw/nPmCMs5DeZ7eziSYZhSmPRn0txqeW4LnAmQQU7FgqLpsEFKM4A==} engines: {node: '>= 0.4'} + is-buffer@1.1.6: + resolution: {integrity: sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==} + + is-buffer@2.0.5: + resolution: {integrity: sha512-i2R6zNFDwgEHJyQUtJEk0XFi1i0dPFn/oqjK3/vPCcDeJvW5NQ83V8QbicfF1SupOaB0h8ntgBC2YiE7dfyctQ==} + engines: {node: '>=4'} + is-callable@1.2.7: resolution: {integrity: sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==} engines: {node: '>= 0.4'} @@ -4380,6 +4563,10 @@ packages: is-mobile@5.0.0: resolution: {integrity: sha512-Tz/yndySvLAEXh+Uk8liFCxOwVH6YutuR74utvOcu7I9Di+DwM0mtdPVZNaVvvBUM2OXxne/NhOs1zAO7riusQ==} + is-nan@1.3.2: + resolution: {integrity: sha512-E+zBKpQ2t6MEo1VsonYmluk9NxGrbzpeeLC2xIViuO2EjU2xsXsBPwTr3Ykv9l08UYEVEdWeRZNouaZqF6RN0w==} + engines: {node: '>= 0.4'} + is-negative-zero@2.0.3: resolution: {integrity: sha512-5KoIu2Ngpyek75jXodFvnafB6DJgr3u8uuK0LEZJjrU19DrMD3EVERaR8sjz8CCGgpZvxPl9SuE1GMVPFHx1mw==} engines: {node: '>= 0.4'} @@ -4388,6 +4575,9 @@ packages: resolution: {integrity: sha512-6oIwpsgRfnDiyEDLMay/GqCl3HoAtH5+RUKW29gYkL0QA+ipzpDLA16yQs7/RHCSu+BwgbJaOUqa4A99qNVQVw==} engines: {node: '>=16'} + is-node-process@1.2.0: + resolution: {integrity: sha512-Vg4o6/fqPxIjtxgUH5QLJhwZ7gW5diGCVlXpuUfELC62CuxM1iHcRe51f2W1FDy04Ai4KJkagKjx3XaqyfRKXw==} + is-number-object@1.1.1: resolution: {integrity: sha512-lZhclumE1G6VYD8VHe35wFaIif+CTy5SJIi5+3y4psDgWu4wPDoBhF8NxUOinEc7pHgiTsT6MaBb92rKhhD+Xw==} engines: {node: '>= 0.4'} @@ -4406,6 +4596,10 @@ packages: resolution: {integrity: sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g==} engines: {node: '>= 0.4'} + is-safe-filename@0.1.1: + resolution: {integrity: sha512-4SrR7AdnY11LHfDKTZY1u6Ga3RuxZdl3YKWWShO5iyuG5h8QS4GD2tOb04peBJ5I7pXbR+CGBNEhTcwK+FzN3g==} + engines: {node: '>=20'} + is-set@2.0.3: resolution: {integrity: sha512-iPAjerrse27/ygGLxw+EBR9agv9Y6uLeYVJMu+QNCoouJ1/1ri0mGrcWpfCqFZuzzx3WjtwxG098X+n4OuRkPg==} engines: {node: '>= 0.4'} @@ -4414,6 +4608,10 @@ packages: resolution: {integrity: sha512-ISWac8drv4ZGfwKl5slpHG9OwPNty4jOWPRIhBpxOoD+hqITiwuipOQ2bNthAzwA3B4fIjO4Nln74N0S9byq8A==} engines: {node: '>= 0.4'} + is-stream@2.0.1: + resolution: {integrity: sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==} + engines: {node: '>=8'} + is-string@1.1.1: resolution: {integrity: sha512-BtEeSsoaQjlSPBemMQIrY1MY0uM6vnS1g5fmufYOtnxLGUZM2178PKbhsk7Ffv58IX+ZtcvoGwccYsh0PglkAA==} engines: {node: '>= 0.4'} @@ -4484,6 +4682,11 @@ packages: engines: {node: '>=10'} hasBin: true + javascript-obfuscator@5.5.0: + resolution: {integrity: sha512-YBkZLadMb0ynLQKKMj8urk+NPsglWa4Upwm/kd6x65gyY6YkNkCJi40OOdGDQa1bVGixgRAmVINwODkLnmiJNw==} + engines: {node: '>=18.0.0'} + hasBin: true + jay-peg@1.1.1: resolution: {integrity: sha512-D62KEuBxz/ip2gQKOEhk/mx14o7eiFRaU+VNNSP4MOiIkwb/D6B3G1Mfas7C/Fit8EsSV2/IWjZElx/Gs6A4ww==} @@ -4491,6 +4694,9 @@ packages: resolution: {integrity: sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ==} hasBin: true + jose@5.10.0: + resolution: {integrity: sha512-s+3Al/p9g32Iq+oqXxkW//7jk2Vig6FF1CFqzVXoTUXt2qz89YWbL+OwS17NFYEvxC35n0FKeGO2LGYSxeM2Gg==} + jose@6.2.3: resolution: {integrity: sha512-YYVDInQKFJfR/xa3ojUTl8c2KoTwiL1R5Wg9YCydwH0x0B9grbzlg5HC7mMjCtUJjbQ/YnGEZIhI5tCgfTb4Hw==} @@ -4498,6 +4704,10 @@ packages: resolution: {integrity: sha512-34wB/Y7MW7bzjKRjUKTa46I2Z7eV62Rkhva+KkopW7Qvv/OSWBqvkSY7vusOPrNuZcUG3tApvdVgNB8POj3SPw==} engines: {node: '>=10'} + js-string-escape@1.0.1: + resolution: {integrity: sha512-Smw4xcfIQ5LVjAOuJCvN/zIodzA/BBSsluuoSykP+lUvScIi4U6RJLfwHet5cxFnCswUjISV8oAXaqaJDY3chg==} + engines: {node: '>= 0.8'} + js-tiktoken@1.0.21: resolution: {integrity: sha512-biOj/6M5qdgx5TKjDnFT1ymSpM5tbd3ylwDtrQvFQSu0Z7bBYko2dF+W/aUkXUPuk6IVpRxk/3Q2sHOzGlS36g==} @@ -4638,10 +4848,17 @@ packages: engines: {node: '>=14'} hasBin: true + levn@0.3.0: + resolution: {integrity: sha512-0OO4y2iOHix2W6ujICbKIaEQXvFQHue65vUG3pb5EUomzPI90z9hsA1VsO/dbIIpC53J8gxM9Q4Oho0jrCM/yA==} + engines: {node: '>= 0.8.0'} + levn@0.4.1: resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==} engines: {node: '>= 0.8.0'} + libphonenumber-js@1.13.9: + resolution: {integrity: sha512-VNS5vWMM7r0P66BYv+TQJATxExEgLxN+34hfHDVhDkUsGAE4cRg0shCNSLTXNKm7nIUscC7AfB51TjxEeF7msQ==} + lie@3.3.0: resolution: {integrity: sha512-UaiMJzeWRlEujzAuw5LokY1L5ecNQYZKfmyZ9L7wDHb/p5etKaxXhohBcrw0EYby+G/NA52vRSN4N39dxHAIwQ==} @@ -4683,24 +4900,28 @@ packages: engines: {node: '>= 12.0.0'} cpu: [arm64] os: [linux] + libc: [glibc] lightningcss-linux-arm64-musl@1.30.2: resolution: {integrity: sha512-5Vh9dGeblpTxWHpOx8iauV02popZDsCYMPIgiuw97OJ5uaDsL86cnqSFs5LZkG3ghHoX5isLgWzMs+eD1YzrnA==} engines: {node: '>= 12.0.0'} cpu: [arm64] os: [linux] + libc: [musl] lightningcss-linux-x64-gnu@1.30.2: resolution: {integrity: sha512-Cfd46gdmj1vQ+lR6VRTTadNHu6ALuw2pKR9lYq4FnhvgBc4zWY1EtZcAc6EffShbb1MFrIPfLDXD6Xprbnni4w==} engines: {node: '>= 12.0.0'} cpu: [x64] os: [linux] + libc: [glibc] lightningcss-linux-x64-musl@1.30.2: resolution: {integrity: sha512-XJaLUUFXb6/QG2lGIW6aIk6jKdtjtcffUT0NKvIqhSBY3hh9Ch+1LCeH80dR9q9LBjG3ewbDjnumefsLsP6aiA==} engines: {node: '>= 12.0.0'} cpu: [x64] os: [linux] + libc: [musl] lightningcss-win32-arm64-msvc@1.30.2: resolution: {integrity: sha512-FZn+vaj7zLv//D/192WFFVA0RgHawIcHqLX9xuWiQt7P0PtdFEVaxgF9rjM/IRYHQXNnk61/H/gb2Ei+kUQ4xQ==} @@ -4860,6 +5081,9 @@ packages: resolution: {integrity: sha512-+LfG9Fik+OuI8SLwsiR02IVdjcnRCy5MufYLi0C3TdMT56L/pjB0alMVGgoWJF8pN9Rc7FESycZB9BMNWIid5w==} deprecated: Version 4 replaces this package with the scoped package @mathjax/src + md5@2.3.0: + resolution: {integrity: sha512-T1GITYmFaKuO91vxyoQMFETst+O71VUPEU3ze5GNzDm0OWdP8v1ziTaAEPUr/3kLsY3Sftgz242A1SetQiDL7g==} + mdast-util-find-and-replace@3.0.2: resolution: {integrity: sha512-Tmd1Vg/m3Xz43afeNxDIhWRtFZgM2VLyaf4vSTYwudTyeuTneoL3qtWMA5jeLyz/O1vDJmmV4QuScFCA2tBPwg==} @@ -4935,6 +5159,9 @@ packages: '@types/react': optional: true + merge-stream@2.0.0: + resolution: {integrity: sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==} + mhchemparser@4.2.1: resolution: {integrity: sha512-kYmyrCirqJf3zZ9t/0wGgRZ4/ZJw//VwaRVGA75C4nhE60vtnIzhl9J9ndkX/h6hxSN7pjg/cE0VxbnNM+bnDQ==} @@ -5149,6 +5376,10 @@ packages: ms@2.1.3: resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} + multimatch@5.0.0: + resolution: {integrity: sha512-ypMKuglUrZUD99Tk2bUQ+xNQj43lPEfAeX2o9cTteAmShXy2VHDJpuwu1o0xqoKCt9jLVAvwyFKdLTPXKAfJyA==} + engines: {node: '>=10'} + mustache@4.2.0: resolution: {integrity: sha512-71ippSywq5Yb7/tVYyGbkBggbU8H3u5Rz56fH60jGFgr8uHwxs+aSKeqmluIVzM0m0kB7xQjKS6qPfd0b2ZoqQ==} hasBin: true @@ -5249,6 +5480,10 @@ packages: resolution: {integrity: sha512-DlL+XwOy3NxAQ8xuC0okPgK46iuVNAK01YN7RueYBqqFeGsBjV9XmCAzAdgt+667bCl5kPh9EqKKDwnaPG1I7A==} engines: {node: '>=10'} + npm-run-path@4.0.1: + resolution: {integrity: sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==} + engines: {node: '>=8'} + npmlog@5.0.1: resolution: {integrity: sha512-AqZtDUWOMKs1G/8lwylVjrdYgqA4d9nu8hc+0gzRxlDb1I10+FHBGMXs6aiQHFdCUUlqH99MUMuLfzWDNDtfxw==} deprecated: This package is no longer supported. @@ -5267,6 +5502,10 @@ packages: resolution: {integrity: sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==} engines: {node: '>= 0.4'} + object-is@1.1.6: + resolution: {integrity: sha512-F8cZ+KfGlSGi09lJT7/Nd6KJZ9ygtvYC0/UYYLI9nmQKLMnydpB9yvbv9K1uSkEu7FU9vYPmVwLg328tX+ot3Q==} + engines: {node: '>= 0.4'} + object-keys@1.1.1: resolution: {integrity: sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==} engines: {node: '>= 0.4'} @@ -5366,6 +5605,10 @@ packages: option@0.2.4: resolution: {integrity: sha512-pkEqbDyl8ou5cpq+VsnQbe/WlEy5qS7xPzMS1U55OCG9KPvwFD46zDbxQIj3egJSFc3D+XhYOPUzz49zQAVy7A==} + optionator@0.8.3: + resolution: {integrity: sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA==} + engines: {node: '>= 0.8.0'} + optionator@0.9.4: resolution: {integrity: sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==} engines: {node: '>= 0.8.0'} @@ -5374,6 +5617,10 @@ packages: resolution: {integrity: sha512-5b6Y85tPxZZ7QytO+BQzysW31HJku27cRIlkbAXaNx+BdcVi+LlRFmVXzeF6a7JCwJpyw5c4b+YSVImQIrBpuQ==} engines: {node: '>=10'} + os-paths@4.4.0: + resolution: {integrity: sha512-wrAwOeXp1RRMFfQY8Sy7VaGVmPocaLwSFOYCGKSyo8qmJ+/yaafCl5BCA1IQZWqFSRBrKDYFeR9d/VyQzfH/jg==} + engines: {node: '>= 6.0'} + own-keys@1.0.1: resolution: {integrity: sha512-qFOyK5PjiWZd+QQIh+1jhdb9LpxTF0qs7Pm8o5QHYZ0M3vKqSqzsZaEB6oWlxZ+q2sJBMI/Ktgd2N5ZwQoRHfg==} engines: {node: '>= 0.4'} @@ -5599,6 +5846,10 @@ packages: deprecated: No longer maintained. Please contact the author of the relevant native addon; alternatives are available. hasBin: true + prelude-ls@1.1.2: + resolution: {integrity: sha512-ESF23V4SKG6lVSGZgYNpbsiaAkdab6ZgOxe52p7+Kid3W3u3bxR4Vfd/o21dmN7jSt0IwgZ4v5MUd26FEtXE9w==} + engines: {node: '>= 0.8.0'} + prelude-ls@1.2.1: resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==} engines: {node: '>= 0.8.0'} @@ -6385,6 +6636,9 @@ packages: string-convert@0.2.1: resolution: {integrity: sha512-u/1tdPl4yQnPBjnVrmdLo9gtuLvELKsAoRapekWggdiQNvvvum+jYF329d84NAa660KQw7pB2n36KrIKVoXa3A==} + string-template@1.0.0: + resolution: {integrity: sha512-SLqR3GBUXuoPP5MmYtD7ompvXiG87QjT6lzOszyXjTM86Uu7At7vNnt2xgyTLq5o9T4IxTYFyGxcULqpsmsfdg==} + string-width@4.2.3: resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==} engines: {node: '>=8'} @@ -6421,6 +6675,9 @@ packages: stringify-entities@4.0.4: resolution: {integrity: sha512-IwfBptatlO+QCJUo19AqvrPNqlVMpW9YEL2LIVY+Rpv2qsjCGxaDLNRgeGsQWJhfItebuJhsGSLjaBbNSQ+ieg==} + stringz@2.1.0: + resolution: {integrity: sha512-KlywLT+MZ+v0IRepfMxRtnSvDCMc3nR1qqCs3m/qIbSOWkNZYT8XHQA31rS3TnKp0c5xjZu3M4GY/2aRKSi/6A==} + strip-ansi@6.0.1: resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==} engines: {node: '>=8'} @@ -6429,6 +6686,10 @@ packages: resolution: {integrity: sha512-gmBGslpoQJtgnMAvOVqGZpEz9dyoKTCzy2nfz/n8aIFhN/jCE/rCmcxabB6jOOHV+0WNnylOxaxBQPSvcWklhA==} engines: {node: '>=12'} + strip-final-newline@2.0.0: + resolution: {integrity: sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==} + engines: {node: '>=6'} + strip-json-comments@2.0.1: resolution: {integrity: sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==} engines: {node: '>=0.10.0'} @@ -6528,6 +6789,10 @@ packages: resolution: {integrity: sha512-B71/4oyj61iNH0KeCamLuE2rmKuTO5byTOSVwECM5FA7TiAiAW+UqTKZ9ERueC4qvgSttUhdmq1mXC3kJqGX7A==} engines: {node: '>=12.22'} + throttleit@2.1.0: + resolution: {integrity: sha512-nt6AMGKW1p/70DF/hGBdJB57B8Tspmbp5gfJ8ilhLnt7kkr2ye7hzD6NVG8GGErk2HWF34igrL2CXmNIkzKqKw==} + engines: {node: '>=18'} + tiny-async-pool@1.3.0: resolution: {integrity: sha512-01EAw5EDrcVrdgyCLgoSPvqznC0sVxDSVeiOz09FUpjh71G79VCqneOr+xvt7T1r76CF6ZZfPjHorN2+d+3mqA==} @@ -6627,6 +6892,10 @@ packages: tunnel-agent@0.6.0: resolution: {integrity: sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==} + type-check@0.3.2: + resolution: {integrity: sha512-ZCmOJdvOWDBYJlzAoFkC+Q0+bUyEOS1ltgp1MGU03fqHG+dbi9tBFU2Rd9QKiDZFAYrhPh2JUf7rZRIuHRKtOg==} + engines: {node: '>= 0.8.0'} + type-check@0.4.0: resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==} engines: {node: '>= 0.8.0'} @@ -6696,6 +6965,10 @@ packages: undici-types@7.18.2: resolution: {integrity: sha512-AsuCzffGHJybSaRrmr5eHr81mwJU3kjw6M+uprWvCXiNeN9SOGwQ3Jn8jb8m3Z6izVgknn1R0FTCEAP2QrLY/w==} + undici@6.27.0: + resolution: {integrity: sha512-YmfV3YnEDzXRC5lZ2jWtWWHKGUm1zIt8AhesR1tens+HTNv+YZlN/dp6G727LOvMJ8xjP9Be7Y2Sdr96LDm+pg==} + engines: {node: '>=18.17'} + undici@7.21.0: resolution: {integrity: sha512-Hn2tCQpoDt1wv23a68Ctc8Cr/BHpUSfaPYrkajTXOS9IKpxVRx/X5m1K2YkbK2ipgZgxXSgsUinl3x+2YdSSfg==} engines: {node: '>=20.18.1'} @@ -6779,6 +7052,9 @@ packages: util-deprecate@1.0.2: resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} + util@0.12.5: + resolution: {integrity: sha512-kZf/K6hEIrWHI6XqOFUiiMa+79wE/D8Q+NCNAWclkyg3b4d2k7s0QGepNjiABc+aR3N1PAyHL7p6UcLY6LmrnA==} + uuid@10.0.0: resolution: {integrity: sha512-8XkAphELsDnEGrDxUOHB3RGvXz6TeuYSGEZBOjtTtPm2lwhGBjLgOzLHB63IUWfBpNucQjND6d3AOudO+H3RWQ==} hasBin: true @@ -6791,6 +7067,10 @@ packages: resolution: {integrity: sha512-XQegIaBTVUjSHliKqcnFqYypAd4S+WCYt5NIeRs6w/UAry7z8Y9j5ZwRRL4kzq9U3sD6v+85er9FvkEaBpji2w==} hasBin: true + validator@13.15.35: + resolution: {integrity: sha512-TQ5pAGhd5whStmqWvYF4OjQROlmv9SMFVt37qoCBdqRffuuklWYQlCNnEs2ZaIBD1kZRNnikiZOS1eqgkar0iw==} + engines: {node: '>= 0.10'} + vary@1.1.2: resolution: {integrity: sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==} engines: {node: '>= 0.8'} @@ -7014,6 +7294,14 @@ packages: utf-8-validate: optional: true + xdg-app-paths@5.5.1: + resolution: {integrity: sha512-hI3flOB4PLZIy5prbtTpirobtPE2ZtZ52szO+2mM9Efp6ErM398La+C1lIpNWDfNoQk+6Lsi6nMcCwVB7pxeMQ==} + engines: {node: '>= 6.0'} + + xdg-portable@7.3.0: + resolution: {integrity: sha512-sqMMuL1rc0FmMBOzCpd0yuy9trqF2yTTVe+E9ogwCSWQCdDEtQUwrZPT6AxqtsFGRNxycgncbP/xmOOSPw5ZUw==} + engines: {node: '>= 6.0'} + xml-js@1.6.11: resolution: {integrity: sha512-7rVi2KMfwfWFl+GpPg6m80IVMWXLRjO+PxTq7V2CDhoGak0wzYzFgUY2m4XJ47OGdXd8eLE8EmwfAmdjw7lC1g==} hasBin: true @@ -7091,6 +7379,9 @@ packages: zod@3.23.8: resolution: {integrity: sha512-XBx9AXhXktjUqnepgTiE5flcKIYWi/rme0Eaj+5Y0lftuGBq+jyRu/md4WnuxqgP1ubdpNCsYEYPxrzVHD8d6g==} + zod@4.1.11: + resolution: {integrity: sha512-WPsqwxITS2tzx1bzhIKsEs19ABD5vmCVa4xBo2tq/SrV4RNZtfws1EnCWQXM6yh8bD08a1idvkB5MZSBiZsjwg==} + zod@4.3.6: resolution: {integrity: sha512-rftlrkhHZOcjDwkGlnUtZZkvaPHCsDATp4pGpuOOMDaTdDDXF91wuVDJoWoPsKX/3YPQ5fHuF3STjcYyKr+Qhg==} @@ -8061,6 +8352,34 @@ snapshots: '@img/sharp-win32-x64@0.34.5': optional: true + '@inversifyjs/common@1.5.2': {} + + '@inversifyjs/container@1.15.0(reflect-metadata@0.2.2)': + dependencies: + '@inversifyjs/common': 1.5.2 + '@inversifyjs/core': 9.2.0(reflect-metadata@0.2.2) + '@inversifyjs/plugin': 0.2.0 + '@inversifyjs/reflect-metadata-utils': 1.4.1(reflect-metadata@0.2.2) + reflect-metadata: 0.2.2 + + '@inversifyjs/core@9.2.0(reflect-metadata@0.2.2)': + dependencies: + '@inversifyjs/common': 1.5.2 + '@inversifyjs/prototype-utils': 0.1.3 + '@inversifyjs/reflect-metadata-utils': 1.4.1(reflect-metadata@0.2.2) + transitivePeerDependencies: + - reflect-metadata + + '@inversifyjs/plugin@0.2.0': {} + + '@inversifyjs/prototype-utils@0.1.3': + dependencies: + '@inversifyjs/common': 1.5.2 + + '@inversifyjs/reflect-metadata-utils@1.4.1(reflect-metadata@0.2.2)': + dependencies: + reflect-metadata: 0.2.2 + '@isaacs/balanced-match@4.0.1': {} '@isaacs/brace-expansion@5.0.0': @@ -8080,6 +8399,17 @@ snapshots: dependencies: minipass: 7.1.2 + '@javascript-obfuscator/escodegen@2.4.2': + dependencies: + '@javascript-obfuscator/estraverse': 5.4.0 + esprima: 4.0.1 + esutils: 2.0.3 + optionator: 0.8.3 + optionalDependencies: + source-map: 0.6.1 + + '@javascript-obfuscator/estraverse@5.4.0': {} + '@jridgewell/gen-mapping@0.3.13': dependencies: '@jridgewell/sourcemap-codec': 1.5.5 @@ -9026,6 +9356,8 @@ snapshots: dependencies: '@types/unist': 3.0.3 + '@types/minimatch@3.0.5': {} + '@types/ms@2.1.0': {} '@types/node-fetch@2.6.13': @@ -9079,6 +9411,8 @@ snapshots: '@types/uuid@10.0.0': {} + '@types/validator@13.15.10': {} + '@types/verror@1.10.11': optional: true @@ -9180,8 +9514,32 @@ snapshots: '@ungap/structured-clone@1.3.0': {} + '@vercel/blob@2.6.1': + dependencies: + '@vercel/oidc': 3.8.0 + async-retry: 1.3.3 + is-buffer: 2.0.5 + is-node-process: 1.2.0 + throttleit: 2.1.0 + undici: 6.27.0 + + '@vercel/cli-config@0.2.0': + dependencies: + xdg-app-paths: 5.5.1 + zod: 4.1.11 + + '@vercel/cli-exec@1.0.0': + dependencies: + execa: 5.1.1 + '@vercel/oidc@3.1.0': {} + '@vercel/oidc@3.8.0': + dependencies: + '@vercel/cli-config': 0.2.0 + '@vercel/cli-exec': 1.0.0 + jose: 5.10.0 + '@vitejs/plugin-react@5.1.2(vite@7.3.0(@types/node@22.19.3)(jiti@2.6.1)(less@4.5.1)(lightningcss@1.30.2)(yaml@2.8.2))': dependencies: '@babel/core': 7.28.5 @@ -9250,6 +9608,10 @@ snapshots: mime-types: 3.0.2 negotiator: 1.0.0 + acorn-import-attributes@1.9.5(acorn@8.15.0): + dependencies: + acorn: 8.15.0 + acorn-jsx@5.3.2(acorn@8.15.0): dependencies: acorn: 8.15.0 @@ -9456,6 +9818,8 @@ snapshots: call-bound: 1.0.4 is-array-buffer: 3.0.5 + array-differ@3.0.0: {} + array-includes@3.1.9: dependencies: call-bind: 1.0.8 @@ -9467,6 +9831,8 @@ snapshots: is-string: 1.1.1 math-intrinsics: 1.1.0 + array-union@2.1.0: {} + array.prototype.findlast@1.2.5: dependencies: call-bind: 1.0.8 @@ -9508,9 +9874,19 @@ snapshots: get-intrinsic: 1.3.0 is-array-buffer: 3.0.5 + arrify@2.0.1: {} + assert-plus@1.0.0: optional: true + assert@2.1.0: + dependencies: + call-bind: 1.0.8 + is-nan: 1.3.2 + object-is: 1.1.6 + object.assign: 4.1.7 + util: 0.12.5 + assertion-error@2.0.1: {} astral-regex@2.0.0: @@ -9520,6 +9896,10 @@ snapshots: async-function@1.0.0: {} + async-retry@1.3.3: + dependencies: + retry: 0.13.1 + async@3.2.6: {} asynckit@0.4.0: {} @@ -9772,6 +10152,10 @@ snapshots: chalk@5.6.2: {} + chance@1.1.13: {} + + char-regex@1.0.2: {} + character-entities-html4@2.1.0: {} character-entities-legacy@3.0.0: {} @@ -9780,6 +10164,8 @@ snapshots: character-reference-invalid@2.0.1: {} + charenc@0.0.2: {} + cheerio-select@2.1.0: dependencies: boolbase: 1.0.0 @@ -9830,6 +10216,12 @@ snapshots: ci-info@3.9.0: {} + class-validator@0.14.3: + dependencies: + '@types/validator': 13.15.10 + libphonenumber-js: 1.13.9 + validator: 13.15.35 + classnames@2.5.1: {} clean-stack@2.2.0: {} @@ -9898,6 +10290,8 @@ snapshots: table-layout: 4.1.1 typical: 7.3.0 + commander@12.1.0: {} + commander@13.1.0: {} commander@5.1.0: {} @@ -9973,6 +10367,8 @@ snapshots: shebang-command: 2.0.0 which: 2.0.2 + crypt@0.0.2: {} + crypto-js@4.2.0: {} css-color-keywords@1.0.0: {} @@ -10318,6 +10714,10 @@ snapshots: env-paths@2.2.1: {} + env-paths@4.0.0: + dependencies: + is-safe-filename: 0.1.1 + err-code@2.0.3: {} errno@0.1.8: @@ -10604,6 +11004,8 @@ snapshots: acorn-jsx: 5.3.2(acorn@8.15.0) eslint-visitor-keys: 4.2.1 + esprima@4.0.1: {} + esquery@1.7.0: dependencies: estraverse: 5.3.0 @@ -10638,6 +11040,18 @@ snapshots: dependencies: eventsource-parser: 3.1.0 + execa@5.1.1: + dependencies: + cross-spawn: 7.0.6 + get-stream: 6.0.1 + human-signals: 2.1.0 + is-stream: 2.0.1 + merge-stream: 2.0.0 + npm-run-path: 4.0.1 + onetime: 5.1.2 + signal-exit: 3.0.7 + strip-final-newline: 2.0.0 + expand-template@2.0.3: {} expect-type@1.3.0: {} @@ -10949,6 +11363,8 @@ snapshots: dependencies: pump: 3.0.3 + get-stream@6.0.1: {} + get-symbol-description@1.1.0: dependencies: call-bound: 1.0.4 @@ -11244,6 +11660,8 @@ snapshots: transitivePeerDependencies: - supports-color + human-signals@2.1.0: {} + humanize-ms@1.2.1: dependencies: ms: 2.1.3 @@ -11265,7 +11683,7 @@ snapshots: isstream: 0.1.2 jsonwebtoken: 9.0.3 mime-types: 2.1.35 - retry-axios: 2.6.0(axios@1.13.2) + retry-axios: 2.6.0(axios@1.13.2(debug@4.4.3)) tough-cookie: 4.1.4 transitivePeerDependencies: - supports-color @@ -11323,6 +11741,14 @@ snapshots: hasown: 2.0.2 side-channel: 1.1.0 + inversify@7.11.0(reflect-metadata@0.2.2): + dependencies: + '@inversifyjs/common': 1.5.2 + '@inversifyjs/container': 1.15.0(reflect-metadata@0.2.2) + '@inversifyjs/core': 9.2.0(reflect-metadata@0.2.2) + transitivePeerDependencies: + - reflect-metadata + ip-address@10.2.0: {} ipaddr.js@1.9.1: {} @@ -11334,6 +11760,11 @@ snapshots: is-alphabetical: 2.0.1 is-decimal: 2.0.1 + is-arguments@1.2.0: + dependencies: + call-bound: 1.0.4 + has-tostringtag: 1.0.2 + is-array-buffer@3.0.5: dependencies: call-bind: 1.0.8 @@ -11359,6 +11790,10 @@ snapshots: call-bound: 1.0.4 has-tostringtag: 1.0.2 + is-buffer@1.1.6: {} + + is-buffer@2.0.5: {} + is-callable@1.2.7: {} is-ci@3.0.1: @@ -11415,10 +11850,17 @@ snapshots: is-mobile@5.0.0: {} + is-nan@1.3.2: + dependencies: + call-bind: 1.0.8 + define-properties: 1.2.1 + is-negative-zero@2.0.3: {} is-network-error@1.3.0: {} + is-node-process@1.2.0: {} + is-number-object@1.1.1: dependencies: call-bound: 1.0.4 @@ -11437,12 +11879,16 @@ snapshots: has-tostringtag: 1.0.2 hasown: 2.0.2 + is-safe-filename@0.1.1: {} + is-set@2.0.3: {} is-shared-array-buffer@1.0.4: dependencies: call-bound: 1.0.4 + is-stream@2.0.1: {} + is-string@1.1.1: dependencies: call-bound: 1.0.4 @@ -11513,16 +11959,46 @@ snapshots: filelist: 1.0.4 picocolors: 1.1.1 + javascript-obfuscator@5.5.0: + dependencies: + '@javascript-obfuscator/escodegen': 2.4.2 + '@javascript-obfuscator/estraverse': 5.4.0 + '@vercel/blob': 2.6.1 + acorn: 8.15.0 + acorn-import-attributes: 1.9.5(acorn@8.15.0) + assert: 2.1.0 + chalk: 4.1.2 + chance: 1.1.13 + class-validator: 0.14.3 + commander: 12.1.0 + env-paths: 4.0.0 + eslint-scope: 8.4.0 + eslint-visitor-keys: 4.2.1 + fast-deep-equal: 3.1.3 + inversify: 7.11.0(reflect-metadata@0.2.2) + js-string-escape: 1.0.1 + md5: 2.3.0 + multimatch: 5.0.0 + process: 0.11.10 + reflect-metadata: 0.2.2 + string-template: 1.0.0 + stringz: 2.1.0 + tslib: 2.8.1 + jay-peg@1.1.1: dependencies: restructure: 3.0.2 jiti@2.6.1: {} + jose@5.10.0: {} + jose@6.2.3: {} joycon@3.1.1: {} + js-string-escape@1.0.1: {} + js-tiktoken@1.0.21: dependencies: base64-js: 1.5.1 @@ -11689,11 +12165,18 @@ snapshots: needle: 3.3.1 source-map: 0.6.1 + levn@0.3.0: + dependencies: + prelude-ls: 1.1.2 + type-check: 0.3.2 + levn@0.4.1: dependencies: prelude-ls: 1.2.1 type-check: 0.4.0 + libphonenumber-js@1.13.9: {} + lie@3.3.0: dependencies: immediate: 3.0.6 @@ -11908,6 +12391,12 @@ snapshots: mj-context-menu: 0.6.1 speech-rule-engine: 4.1.4 + md5@2.3.0: + dependencies: + charenc: 0.0.2 + crypt: 0.0.2 + is-buffer: 1.1.6 + mdast-util-find-and-replace@3.0.2: dependencies: '@types/mdast': 4.0.4 @@ -12087,6 +12576,8 @@ snapshots: optionalDependencies: '@types/react': 19.2.7 + merge-stream@2.0.0: {} + mhchemparser@4.2.1: {} micromark-core-commonmark@2.0.3: @@ -12391,6 +12882,14 @@ snapshots: ms@2.1.3: {} + multimatch@5.0.0: + dependencies: + '@types/minimatch': 3.0.5 + array-differ: 3.0.0 + array-union: 2.1.0 + arrify: 2.0.1 + minimatch: 3.1.2 + mustache@4.2.0: {} nan@2.24.0: @@ -12468,6 +12967,10 @@ snapshots: normalize-url@6.1.0: {} + npm-run-path@4.0.1: + dependencies: + path-key: 3.1.1 + npmlog@5.0.1: dependencies: are-we-there-yet: 2.0.0 @@ -12486,6 +12989,11 @@ snapshots: object-inspect@1.13.4: {} + object-is@1.1.6: + dependencies: + call-bind: 1.0.8 + define-properties: 1.2.1 + object-keys@1.1.1: {} object.assign@4.1.7: @@ -12589,6 +13097,15 @@ snapshots: option@0.2.4: {} + optionator@0.8.3: + dependencies: + deep-is: 0.1.4 + fast-levenshtein: 2.0.6 + levn: 0.3.0 + prelude-ls: 1.1.2 + type-check: 0.3.2 + word-wrap: 1.2.5 + optionator@0.9.4: dependencies: deep-is: 0.1.4 @@ -12610,6 +13127,8 @@ snapshots: strip-ansi: 6.0.1 wcwidth: 1.0.1 + os-paths@4.4.0: {} + own-keys@1.0.1: dependencies: get-intrinsic: 1.3.0 @@ -12852,6 +13371,8 @@ snapshots: tar-fs: 2.1.5 tunnel-agent: 0.6.0 + prelude-ls@1.1.2: {} + prelude-ls@1.2.1: {} prettier-linter-helpers@1.0.1: @@ -13537,7 +14058,7 @@ snapshots: restructure@3.0.2: {} - retry-axios@2.6.0(axios@1.13.2): + retry-axios@2.6.0(axios@1.13.2(debug@4.4.3)): dependencies: axios: 1.13.2(debug@4.4.3) @@ -13890,6 +14411,8 @@ snapshots: string-convert@0.2.1: {} + string-template@1.0.0: {} + string-width@4.2.3: dependencies: emoji-regex: 8.0.0 @@ -13959,6 +14482,10 @@ snapshots: character-entities-html4: 2.1.0 character-entities-legacy: 3.0.0 + stringz@2.1.0: + dependencies: + char-regex: 1.0.2 + strip-ansi@6.0.1: dependencies: ansi-regex: 5.0.1 @@ -13967,6 +14494,8 @@ snapshots: dependencies: ansi-regex: 6.2.2 + strip-final-newline@2.0.0: {} + strip-json-comments@2.0.1: {} strip-json-comments@3.1.1: {} @@ -14087,6 +14616,8 @@ snapshots: throttle-debounce@5.0.2: {} + throttleit@2.1.0: {} + tiny-async-pool@1.3.0: dependencies: semver: 5.7.2 @@ -14174,6 +14705,10 @@ snapshots: dependencies: safe-buffer: 5.2.1 + type-check@0.3.2: + dependencies: + prelude-ls: 1.1.2 + type-check@0.4.0: dependencies: prelude-ls: 1.2.1 @@ -14254,6 +14789,8 @@ snapshots: undici-types@7.18.2: {} + undici@6.27.0: {} + undici@7.21.0: {} unicode-properties@1.4.1: @@ -14350,12 +14887,22 @@ snapshots: util-deprecate@1.0.2: {} + util@0.12.5: + dependencies: + inherits: 2.0.4 + is-arguments: 1.2.0 + is-generator-function: 1.1.2 + is-typed-array: 1.1.15 + which-typed-array: 1.1.19 + uuid@10.0.0: {} uuid@11.1.1: {} uuid@13.0.0: {} + validator@13.15.35: {} + vary@1.1.2: {} verror@1.10.1: @@ -14573,6 +15120,15 @@ snapshots: bufferutil: 4.1.0 utf-8-validate: 6.0.5 + xdg-app-paths@5.5.1: + dependencies: + os-paths: 4.4.0 + xdg-portable: 7.3.0 + + xdg-portable@7.3.0: + dependencies: + os-paths: 4.4.0 + xml-js@1.6.11: dependencies: sax: 1.4.3 @@ -14630,6 +15186,8 @@ snapshots: zod@3.23.8: {} + zod@4.1.11: {} + zod@4.3.6: {} zwitch@2.0.4: {} diff --git a/scripts/audit-packaged-app.mjs b/scripts/audit-packaged-app.mjs index 72a0ab0b..d1678145 100644 --- a/scripts/audit-packaged-app.mjs +++ b/scripts/audit-packaged-app.mjs @@ -9,6 +9,7 @@ import { normalizeRelativePath, scanTextForSecrets } from './package-content-policy.mjs' +import { assertProtectedMainPlaintextAbsent } from './package-main-obfuscation.mjs' import { evaluatePackageSizeBudget, loadPackageSizeBudgetConfig } from './package-size-budget.mjs' const inputDirectory = path.resolve(process.argv[2] || 'dist') @@ -107,6 +108,9 @@ for (const archivePath of archives) { if (!/\.(?:js|cjs|mjs|json|html|css)$/u.test(item.relativePath)) continue const source = extractArchiveFile(archivePath, item.relativePath).toString('utf8') scanTextForSecrets(source, `${archivePath}:${item.relativePath}`) + if (item.relativePath.startsWith('out/main/')) { + assertProtectedMainPlaintextAbsent(source, `${archivePath}:${item.relativePath}`) + } } const appRoot = findApplicationRoot(archivePath) diff --git a/scripts/obfuscate-package-main.mjs b/scripts/obfuscate-package-main.mjs new file mode 100644 index 00000000..c9ad3d85 --- /dev/null +++ b/scripts/obfuscate-package-main.mjs @@ -0,0 +1,18 @@ +import path from 'node:path' +import process from 'node:process' +import { fileURLToPath } from 'node:url' +import { obfuscatePackageMain } from './package-main-obfuscation.mjs' + +const root = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..') +const stageDirectory = path.resolve(process.argv[2] || path.join(root, 'release-stage', 'app')) +const reportPath = path.resolve( + process.argv[3] || path.join(root, 'release-stage', 'main-obfuscation-report.json') +) + +const report = obfuscatePackageMain({ stageDirectory, reportPath }) +process.stdout.write( + `[package] main obfuscation passed: ${String(report.totals.files)} files, ` + + `${(report.totals.originalBytes / 1024 / 1024).toFixed(1)} MiB -> ` + + `${(report.totals.obfuscatedBytes / 1024 / 1024).toFixed(1)} MiB\n` +) +process.stdout.write(`[package] main obfuscation report: ${reportPath}\n`) diff --git a/scripts/package-main-obfuscation.mjs b/scripts/package-main-obfuscation.mjs new file mode 100644 index 00000000..02b7691a --- /dev/null +++ b/scripts/package-main-obfuscation.mjs @@ -0,0 +1,309 @@ +import crypto from 'node:crypto' +import fs from 'node:fs' +import { createRequire } from 'node:module' +import path from 'node:path' +import process from 'node:process' +import { spawnSync } from 'node:child_process' +import JavaScriptObfuscator from 'javascript-obfuscator' + +const require = createRequire(import.meta.url) +const obfuscatorPackage = require('javascript-obfuscator/package.json') + +export const MAIN_OBFUSCATION_SCHEMA_VERSION = 1 +export const MAIN_OBFUSCATION_CONFIGURATION_VERSION = 1 +export const MAX_MAIN_OBFUSCATION_GROWTH_BYTES = 3 * 1024 * 1024 + +export const PROTECTED_MAIN_PLAINTEXT_MARKERS = [ + { + id: 'brain-system-prompt', + value: '像一个判断稳定的人类执行者一样工作' + }, + { + id: 'mouth-system-prompt', + value: '你的职责是基于已经提供的信息,面向用户交付最终结果' + } +] + +const JAVASCRIPT_EXTENSIONS = new Set(['.js', '.cjs', '.mjs']) + +const normalizeRelativePath = (value) => value.replaceAll(path.sep, '/') + +const sha256 = (value) => crypto.createHash('sha256').update(value).digest('hex') + +const deriveSeed = (relativePath) => { + const digest = crypto + .createHash('sha256') + .update(`ncurator-main-obfuscation-v1\0${normalizeRelativePath(relativePath)}`) + .digest() + return Math.max(1, digest.readUInt32BE(0) & 0x7fffffff) +} + +export const createMainObfuscationOptions = (relativePath) => ({ + compact: true, + target: 'node', + identifierNamesGenerator: 'hexadecimal', + renameGlobals: false, + renameProperties: false, + transformObjectKeys: false, + stringArray: true, + stringArrayThreshold: 1, + stringArrayEncoding: ['rc4'], + stringArrayRotate: true, + stringArrayShuffle: true, + splitStrings: true, + splitStringsChunkLength: 8, + controlFlowFlattening: false, + deadCodeInjection: false, + debugProtection: false, + selfDefending: false, + disableConsoleOutput: false, + numbersToExpressions: false, + unicodeEscapeSequence: false, + sourceMap: false, + seed: deriveSeed(relativePath) +}) + +export const obfuscateMainJavaScript = (source, relativePath) => + JavaScriptObfuscator.obfuscate( + source, + createMainObfuscationOptions(relativePath) + ).getObfuscatedCode() + +const listJavaScriptFiles = (rootDirectory) => { + const result = [] + const walk = (directory) => { + for (const entry of fs.readdirSync(directory, { withFileTypes: true })) { + const absolutePath = path.join(directory, entry.name) + if (entry.isDirectory()) { + walk(absolutePath) + continue + } + if (entry.isFile() && JAVASCRIPT_EXTENSIONS.has(path.extname(entry.name).toLowerCase())) { + result.push(absolutePath) + } + } + } + walk(rootDirectory) + return result.sort((left, right) => left.localeCompare(right)) +} + +const assertJavaScriptSyntax = (filePath) => { + const result = spawnSync(process.execPath, ['--check', filePath], { + encoding: 'utf8', + stdio: ['ignore', 'pipe', 'pipe'] + }) + if (result.error) throw result.error + if (result.status !== 0) { + throw new Error( + `obfuscated JavaScript syntax check failed for ${filePath}:\n${String(result.stderr || result.stdout).trim()}` + ) + } +} + +const assertProtectedMarkersPresent = (sources) => { + const missing = PROTECTED_MAIN_PLAINTEXT_MARKERS.filter( + (marker) => !sources.some((source) => source.includes(marker.value)) + ) + if (missing.length > 0) { + throw new Error( + `main obfuscation protection markers were not found before obfuscation: ${missing + .map((marker) => marker.id) + .join(', ')}` + ) + } +} + +export const assertProtectedMainPlaintextAbsent = (source, sourceLabel) => { + const exposed = PROTECTED_MAIN_PLAINTEXT_MARKERS.filter((marker) => source.includes(marker.value)) + if (exposed.length > 0) { + throw new Error( + `${sourceLabel} exposes protected main-process plaintext: ${exposed + .map((marker) => marker.id) + .join(', ')}` + ) + } +} + +const writeJsonAtomically = (filePath, value) => { + fs.mkdirSync(path.dirname(filePath), { recursive: true }) + const temporaryPath = `${filePath}.tmp-${String(process.pid)}` + try { + fs.writeFileSync(temporaryPath, `${JSON.stringify(value, null, 2)}\n`, 'utf8') + fs.renameSync(temporaryPath, filePath) + } finally { + fs.rmSync(temporaryPath, { force: true }) + } +} + +export const obfuscatePackageMain = ({ stageDirectory, reportPath }) => { + const stageRoot = path.resolve(stageDirectory) + const mainDirectory = path.join(stageRoot, 'out', 'main') + const resolvedReportPath = path.resolve(reportPath) + fs.rmSync(resolvedReportPath, { force: true }) + + if (!fs.existsSync(mainDirectory) || !fs.statSync(mainDirectory).isDirectory()) { + throw new Error(`staged main-process directory not found: ${mainDirectory}`) + } + + const packageJsonPath = path.join(stageRoot, 'package.json') + const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf8')) + const files = listJavaScriptFiles(mainDirectory) + if (files.length === 0) + throw new Error(`no staged main-process JavaScript found: ${mainDirectory}`) + + const originalSources = files.map((filePath) => fs.readFileSync(filePath, 'utf8')) + assertProtectedMarkersPresent(originalSources) + + const pending = [] + let originalBytes = 0 + let obfuscatedBytes = 0 + let growthBytes = 0 + try { + for (let index = 0; index < files.length; index += 1) { + const filePath = files[index] + const relativePath = normalizeRelativePath(path.relative(stageRoot, filePath)) + const originalSource = originalSources[index] + const obfuscatedSource = obfuscateMainJavaScript(originalSource, relativePath) + if (!obfuscatedSource || obfuscatedSource === originalSource) { + throw new Error(`main-process JavaScript was not transformed: ${relativePath}`) + } + assertProtectedMainPlaintextAbsent(obfuscatedSource, relativePath) + if ( + /(?:\/\/[#@]\s*sourceMappingURL\s*=|\/\*[#@]\s*sourceMappingURL\s*=)/u.test( + obfuscatedSource + ) + ) { + throw new Error( + `obfuscated main-process JavaScript references a source map: ${relativePath}` + ) + } + + const extension = path.extname(filePath) + const temporaryPath = path.join( + path.dirname(filePath), + `.${path.basename(filePath, extension)}.obfuscating-${String(process.pid)}${extension}` + ) + fs.writeFileSync(temporaryPath, obfuscatedSource, 'utf8') + pending.push({ + filePath, + temporaryPath, + relativePath, + originalBytes: Buffer.byteLength(originalSource), + obfuscatedBytes: Buffer.byteLength(obfuscatedSource), + originalSha256: sha256(originalSource), + obfuscatedSha256: sha256(obfuscatedSource) + }) + assertJavaScriptSyntax(temporaryPath) + } + + originalBytes = pending.reduce((sum, item) => sum + item.originalBytes, 0) + obfuscatedBytes = pending.reduce((sum, item) => sum + item.obfuscatedBytes, 0) + growthBytes = obfuscatedBytes - originalBytes + if (growthBytes > MAX_MAIN_OBFUSCATION_GROWTH_BYTES) { + throw new Error( + `main-process obfuscation grew by ${(growthBytes / 1024 / 1024).toFixed(1)} MiB; limit is ${(MAX_MAIN_OBFUSCATION_GROWTH_BYTES / 1024 / 1024).toFixed(1)} MiB` + ) + } + + for (const item of pending) fs.renameSync(item.temporaryPath, item.filePath) + } finally { + for (const item of pending) fs.rmSync(item.temporaryPath, { force: true }) + } + + const report = { + schemaVersion: MAIN_OBFUSCATION_SCHEMA_VERSION, + configurationVersion: MAIN_OBFUSCATION_CONFIGURATION_VERSION, + status: 'passed', + generatedAt: new Date().toISOString(), + packageVersion: String(packageJson.version || ''), + tool: { + name: 'javascript-obfuscator', + version: String(obfuscatorPackage.version) + }, + protectedMarkers: PROTECTED_MAIN_PLAINTEXT_MARKERS.map((marker) => marker.id), + totals: { + files: pending.length, + originalBytes, + obfuscatedBytes, + growthBytes, + growthPercent: originalBytes > 0 ? (growthBytes / originalBytes) * 100 : 0 + }, + files: pending.map((item) => ({ + path: item.relativePath, + originalBytes: item.originalBytes, + obfuscatedBytes: item.obfuscatedBytes, + originalSha256: item.originalSha256, + obfuscatedSha256: item.obfuscatedSha256 + })) + } + writeJsonAtomically(resolvedReportPath, report) + return report +} + +export const verifyPackageMainObfuscation = ({ stageDirectory, reportPath }) => { + const stageRoot = path.resolve(stageDirectory) + const mainDirectory = path.join(stageRoot, 'out', 'main') + const resolvedReportPath = path.resolve(reportPath) + if (!fs.existsSync(resolvedReportPath)) { + throw new Error(`main-process obfuscation report not found: ${resolvedReportPath}`) + } + + const report = JSON.parse(fs.readFileSync(resolvedReportPath, 'utf8')) + if ( + report.schemaVersion !== MAIN_OBFUSCATION_SCHEMA_VERSION || + report.configurationVersion !== MAIN_OBFUSCATION_CONFIGURATION_VERSION || + report.status !== 'passed' + ) { + throw new Error('main-process obfuscation report has an unsupported or failed status') + } + if ( + report.tool?.name !== 'javascript-obfuscator' || + report.tool?.version !== String(obfuscatorPackage.version) || + JSON.stringify(report.protectedMarkers) !== + JSON.stringify(PROTECTED_MAIN_PLAINTEXT_MARKERS.map((marker) => marker.id)) + ) { + throw new Error('main-process obfuscation report does not match the active protection policy') + } + + const packageJson = JSON.parse(fs.readFileSync(path.join(stageRoot, 'package.json'), 'utf8')) + if (report.packageVersion !== String(packageJson.version || '')) { + throw new Error('main-process obfuscation report does not match the staged package version') + } + + const currentFiles = listJavaScriptFiles(mainDirectory).map((filePath) => + normalizeRelativePath(path.relative(stageRoot, filePath)) + ) + const reportedFiles = report.files.map((item) => item.path) + if (JSON.stringify(currentFiles) !== JSON.stringify(reportedFiles)) { + throw new Error('main-process obfuscation report does not match the staged JavaScript files') + } + + for (const item of report.files) { + const filePath = path.join(stageRoot, item.path) + const source = fs.readFileSync(filePath, 'utf8') + if (sha256(source) !== item.obfuscatedSha256 || item.originalSha256 === item.obfuscatedSha256) { + throw new Error(`main-process obfuscation hash mismatch: ${item.path}`) + } + assertProtectedMainPlaintextAbsent(source, item.path) + assertJavaScriptSyntax(filePath) + } + + const originalBytes = report.files.reduce((sum, item) => sum + Number(item.originalBytes || 0), 0) + const obfuscatedBytes = report.files.reduce( + (sum, item) => sum + Number(item.obfuscatedBytes || 0), + 0 + ) + if ( + report.totals.files !== report.files.length || + report.totals.originalBytes !== originalBytes || + report.totals.obfuscatedBytes !== obfuscatedBytes || + report.totals.growthBytes !== obfuscatedBytes - originalBytes + ) { + throw new Error('main-process obfuscation report totals are inconsistent') + } + if (report.totals.growthBytes > MAX_MAIN_OBFUSCATION_GROWTH_BYTES) { + throw new Error('main-process obfuscation report exceeds the allowed growth budget') + } + + return report +} diff --git a/scripts/verify-package-main-obfuscation.mjs b/scripts/verify-package-main-obfuscation.mjs new file mode 100644 index 00000000..475e1801 --- /dev/null +++ b/scripts/verify-package-main-obfuscation.mjs @@ -0,0 +1,16 @@ +import path from 'node:path' +import process from 'node:process' +import { fileURLToPath } from 'node:url' +import { verifyPackageMainObfuscation } from './package-main-obfuscation.mjs' + +const root = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..') +const stageDirectory = path.resolve(process.argv[2] || path.join(root, 'release-stage', 'app')) +const reportPath = path.resolve( + process.argv[3] || path.join(root, 'release-stage', 'main-obfuscation-report.json') +) + +const report = verifyPackageMainObfuscation({ stageDirectory, reportPath }) +process.stdout.write( + `[package] main obfuscation verified: ${String(report.totals.files)} files, ` + + `growth ${(report.totals.growthBytes / 1024 / 1024).toFixed(1)} MiB\n` +) diff --git a/tests/case/settings/update/package-content-policy.test.ts b/tests/case/settings/update/package-content-policy.test.ts index 53ca8082..e787622e 100644 --- a/tests/case/settings/update/package-content-policy.test.ts +++ b/tests/case/settings/update/package-content-policy.test.ts @@ -6,6 +6,7 @@ import { promisify } from 'node:util' import { createPackage } from '@electron/asar' import { afterEach, describe, expect, it } from 'vitest' import { normalizeRelativePath } from '../../../../scripts/package-content-policy.mjs' +import { PROTECTED_MAIN_PLAINTEXT_MARKERS } from '../../../../scripts/package-main-obfuscation.mjs' const execFileAsync = promisify(execFile) let temporaryDirectory = '' @@ -66,4 +67,39 @@ describe('package content policy paths', () => { expect.objectContaining({ root: 'win-unpacked', archiveFileCount: 2 }) ]) }) + + it('rejects a packaged app that exposes protected main-process prompts', async () => { + temporaryDirectory = await mkdtemp(path.join(os.tmpdir(), 'ncurator-package-audit-')) + const appSource = path.join(temporaryDirectory, 'app-source') + const packagedApp = path.join(temporaryDirectory, 'package', 'win-unpacked') + const archivePath = path.join(packagedApp, 'resources', 'app.asar') + await mkdir(path.join(appSource, 'out', 'main'), { recursive: true }) + await mkdir(path.dirname(archivePath), { recursive: true }) + await writeFile( + path.join(appSource, 'out', 'main', 'index.js'), + `const prompt = ${JSON.stringify(PROTECTED_MAIN_PLAINTEXT_MARKERS[0].value)}\n` + ) + await writeFile( + path.join(appSource, 'package.json'), + `${JSON.stringify({ + name: 'ncurator-audit-fixture', + version: '1.0.0', + main: './out/main/index.js', + private: true, + dependencies: {} + })}\n` + ) + await createPackage(appSource, archivePath) + + let stderr = '' + try { + await execFileAsync(process.execPath, [ + path.resolve('scripts/audit-packaged-app.mjs'), + path.join(temporaryDirectory, 'package') + ]) + } catch (error) { + stderr = String((error as { stderr?: string }).stderr || error) + } + expect(stderr).toContain('exposes protected main-process plaintext') + }) }) diff --git a/tests/case/settings/update/package-main-obfuscation.test.ts b/tests/case/settings/update/package-main-obfuscation.test.ts new file mode 100644 index 00000000..08463803 --- /dev/null +++ b/tests/case/settings/update/package-main-obfuscation.test.ts @@ -0,0 +1,122 @@ +import { mkdtemp, mkdir, readFile, rm, writeFile } from 'node:fs/promises' +import os from 'node:os' +import path from 'node:path' +import vm from 'node:vm' +import { afterEach, describe, expect, it } from 'vitest' +import { + MAX_MAIN_OBFUSCATION_GROWTH_BYTES, + PROTECTED_MAIN_PLAINTEXT_MARKERS, + obfuscateMainJavaScript, + obfuscatePackageMain, + verifyPackageMainObfuscation +} from '../../../../scripts/package-main-obfuscation.mjs' + +let temporaryDirectory = '' + +afterEach(async () => { + if (temporaryDirectory) await rm(temporaryDirectory, { recursive: true, force: true }) + temporaryDirectory = '' +}) + +const fixtureSource = ` +'use strict' +const path = require('node:path') +const buildPrompt = (input) => [ + '', + '像一个判断稳定的人类执行者一样工作', + '你的职责是基于已经提供的信息,面向用户交付最终结果', + JSON.stringify({ input, schema: { type: 'object', required: ['answer'] } }, null, 2), + '', + path.sep +].join('\\n') +globalThis.__ncuratorPromptResult = buildPrompt('中文、emoji 🚀、换行\\n保持一致') +` + +const executeFixture = (source: string): string => { + const requiredSpecifiers: string[] = [] + const context: Record = { + require: (specifier: string) => { + requiredSpecifiers.push(specifier) + return { sep: '/' } + } + } + vm.runInNewContext(source, context, { timeout: 10_000 }) + return JSON.stringify({ + prompt: String(context.__ncuratorPromptResult || ''), + requiredSpecifiers + }) +} + +describe('package-main-obfuscation main-process release protection', () => { + it('preserves the exact runtime prompt while hiding protected plaintext', () => { + const originalPrompt = executeFixture(fixtureSource) + const obfuscated = obfuscateMainJavaScript(fixtureSource, 'out/main/index.js') + const repeated = obfuscateMainJavaScript(fixtureSource, 'out/main/index.js') + const otherFile = obfuscateMainJavaScript(fixtureSource, 'out/main/worker.js') + const obfuscatedPrompt = executeFixture(obfuscated) + + expect(obfuscatedPrompt).toBe(originalPrompt) + expect(obfuscated).not.toBe(fixtureSource) + expect(repeated).toBe(obfuscated) + expect(otherFile).not.toBe(obfuscated) + for (const marker of PROTECTED_MAIN_PLAINTEXT_MARKERS) { + expect(fixtureSource).toContain(marker.value) + expect(obfuscated).not.toContain(marker.value) + } + }) + + it('writes and verifies a report tied to every staged main-process file', async () => { + temporaryDirectory = await mkdtemp(path.join(os.tmpdir(), 'ncurator-main-obfuscation-')) + const stageDirectory = path.join(temporaryDirectory, 'app') + const mainDirectory = path.join(stageDirectory, 'out', 'main') + const reportPath = path.join(temporaryDirectory, 'main-obfuscation-report.json') + await mkdir(mainDirectory, { recursive: true }) + await writeFile( + path.join(stageDirectory, 'package.json'), + `${JSON.stringify({ name: 'fixture', version: '1.2.3' })}\n`, + 'utf8' + ) + await writeFile(path.join(mainDirectory, 'index.js'), fixtureSource, 'utf8') + await writeFile( + path.join(mainDirectory, 'worker.js'), + `'use strict'; globalThis.__workerReady = true\n`, + 'utf8' + ) + + const report = obfuscatePackageMain({ stageDirectory, reportPath }) + const verified = verifyPackageMainObfuscation({ stageDirectory, reportPath }) + const stagedSource = await readFile(path.join(mainDirectory, 'index.js'), 'utf8') + + expect(report.status).toBe('passed') + expect(verified.packageVersion).toBe('1.2.3') + expect(verified.files.map((item: { path: string }) => item.path)).toEqual([ + 'out/main/index.js', + 'out/main/worker.js' + ]) + expect(verified.totals.growthBytes).toBeLessThanOrEqual(MAX_MAIN_OBFUSCATION_GROWTH_BYTES) + for (const marker of PROTECTED_MAIN_PLAINTEXT_MARKERS) { + expect(stagedSource).not.toContain(marker.value) + } + + await writeFile(path.join(mainDirectory, 'index.js'), `${stagedSource}\n// tampered\n`, 'utf8') + expect(() => verifyPackageMainObfuscation({ stageDirectory, reportPath })).toThrow( + 'hash mismatch' + ) + }) + + it('runs only after dependency collection and keeps packaged-app protection auditing', async () => { + const packageJson = JSON.parse(await readFile(path.resolve('package.json'), 'utf8')) + const buildScript = String(packageJson.scripts.build || '') + const prepareIndex = buildScript.indexOf('prepare-package-stage.mjs') + const obfuscateIndex = buildScript.indexOf('obfuscate-package-main.mjs') + const verifyIndex = buildScript.indexOf('verify-package-main-obfuscation.mjs') + const auditIndex = buildScript.lastIndexOf('audit-package-stage.mjs') + const packagedAudit = await readFile(path.resolve('scripts/audit-packaged-app.mjs'), 'utf8') + + expect(prepareIndex).toBeGreaterThanOrEqual(0) + expect(obfuscateIndex).toBeGreaterThan(prepareIndex) + expect(verifyIndex).toBeGreaterThan(obfuscateIndex) + expect(auditIndex).toBeGreaterThan(verifyIndex) + expect(packagedAudit).toContain('assertProtectedMainPlaintextAbsent') + }) +})