fix(deps): resolve Dependabot security alerts (#591)

* fix(deps): resolve Dependabot security alerts

* fix(reader): scope PDF.js 6 integration

* fix(reader): address PDF.js compatibility gaps
This commit is contained in:
Quick
2026-08-11 09:59:30 -04:00
committed by GitHub
parent 881c96864b
commit 6b70edfa39
16 changed files with 984 additions and 687 deletions
@@ -4,7 +4,7 @@ go 1.26.4
require (
github.com/quic-go/quic-go v0.60.0
github.com/quic-go/webtransport-go v0.10.0
github.com/quic-go/webtransport-go v0.11.1
)
require (
@@ -10,8 +10,8 @@ github.com/quic-go/qpack v0.6.0 h1:g7W+BMYynC1LbYLSqRt8PBg5Tgwxn214ZZR34VIOjz8=
github.com/quic-go/qpack v0.6.0/go.mod h1:lUpLKChi8njB4ty2bFLX2x4gzDqXwUpaO1DP9qMDZII=
github.com/quic-go/quic-go v0.60.0 h1:xcQioE8OM66UQLeUMHltK1CCcOu3JbVB4JAQdDQSB+0=
github.com/quic-go/quic-go v0.60.0/go.mod h1:wpKpjmPpftl30sL6pFh7REVpjbcCVy4zt2vDyK1TuJk=
github.com/quic-go/webtransport-go v0.10.0 h1:LqXXPOXuETY5Xe8ITdGisBzTYmUOy5eSj+9n4hLTjHI=
github.com/quic-go/webtransport-go v0.10.0/go.mod h1:LeGIXr5BQKE3UsynwVBeQrU1TPrbh73MGoC6jd+V7ow=
github.com/quic-go/webtransport-go v0.11.1 h1:rrFQMO+7/52ZDJ04fsrjIaWqn6q1z1MYo9iVFq6JtbA=
github.com/quic-go/webtransport-go v0.11.1/go.mod h1:SHgEzUFVyj+9WUSuGB1P6Zd351Pww2leWV3SwlTovkA=
github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=
github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=
go.uber.org/mock v0.5.2 h1:LbtPTcP8A5k9WPXj54PPPbjcI4Y6lhyOZXn+VS7wNko=
+6 -6
View File
@@ -41,7 +41,7 @@
"jassub": "^2.5.6",
"lucide-react": "^0.576.0",
"node-unrar-js": "^2.0.2",
"pdfjs-dist": "^5.7.284",
"pdfjs-dist": "^6.2.108",
"radix-ui": "^1.4.3",
"react": "^19.0.0",
"react-day-picker": "^10.0.1",
@@ -81,13 +81,13 @@
],
"overrides": {
"@babel/core@<7.29.6": "7.29.6",
"brace-expansion@<1.1.13": "1.1.13",
"brace-expansion@>=4.0.0 <5.0.6": "5.0.6",
"brace-expansion@<1.1.18": "1.1.18",
"brace-expansion@>=4.0.0 <5.0.9": "5.0.9",
"flatted@<=3.4.1": "3.4.2",
"js-yaml@<4.2.0": "4.2.0",
"js-yaml@<4.3.1": "4.3.1",
"picomatch@>=4.0.0 <4.0.4": "4.0.4",
"postcss@<8.5.10": "8.5.10",
"undici@<7.28.0": "7.28.0",
"postcss@<8.5.23": "8.5.23",
"undici@<7.29.0": "7.29.0",
"vite@>=6.0.0 <6.4.2": "6.4.2"
}
}
+83 -83
View File
@@ -6,13 +6,13 @@ settings:
overrides:
'@babel/core@<7.29.6': 7.29.6
brace-expansion@<1.1.13: 1.1.13
brace-expansion@>=4.0.0 <5.0.6: 5.0.6
brace-expansion@<1.1.18: 1.1.18
brace-expansion@>=4.0.0 <5.0.9: 5.0.9
flatted@<=3.4.1: 3.4.2
js-yaml@<4.2.0: 4.2.0
js-yaml@<4.3.1: 4.3.1
picomatch@>=4.0.0 <4.0.4: 4.0.4
postcss@<8.5.10: 8.5.10
undici@<7.28.0: 7.28.0
postcss@<8.5.23: 8.5.23
undici@<7.29.0: 7.29.0
vite@>=6.0.0 <6.4.2: 6.4.2
importers:
@@ -95,8 +95,8 @@ importers:
specifier: ^2.0.2
version: 2.0.2
pdfjs-dist:
specifier: ^5.7.284
version: 5.7.284
specifier: ^6.2.108
version: 6.2.108
radix-ui:
specifier: ^1.4.3
version: 1.4.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)
@@ -689,79 +689,79 @@ packages:
'@marijn/find-cluster-break@1.0.3':
resolution: {integrity: sha512-FY+MKLBoTsLNJF/eLWaOsXGdz6uh3Iu1axjPf6TUq92IYumcTcXWHoS747JARLkcdlJ/Waiaxc5wQfFO8jC6NA==}
'@napi-rs/canvas-android-arm64@0.1.100':
resolution: {integrity: sha512-hjhCKhntPv9+t4ckHymdx0phYNcVW+GKQR6Lzw2zE+pOVjOplSmtx9nNNknTjbEDLcuLZqA1y8ufKg1XfgftzQ==}
'@napi-rs/canvas-android-arm64@1.0.5':
resolution: {integrity: sha512-ZzDlpKQocwFfCwhMh17UWre6Qt5yZN3kNIJoUpGfRZqwDDZ164IKOsPOHsRd3d8Tuj5KM6bDjGuPmZxuPuG3NQ==}
engines: {node: '>= 10'}
cpu: [arm64]
os: [android]
'@napi-rs/canvas-darwin-arm64@0.1.100':
resolution: {integrity: sha512-2PcswRaC7Ly645DGt88///zuFDhJxJYdKAs1uU3mfk1atYkXufgcgLfBpk6Tm12nCQBaNt1wpybuPZ4qOhTo8A==}
'@napi-rs/canvas-darwin-arm64@1.0.5':
resolution: {integrity: sha512-Hr8v6CA/TBe+OJOePdV3sXWxzQHQKfQsTKPbc8wG7iPqVeAx6MMdzKGXlYID6SVvpfwV/zqkvGcdImYWSlhrZg==}
engines: {node: '>= 10'}
cpu: [arm64]
os: [darwin]
'@napi-rs/canvas-darwin-x64@0.1.100':
resolution: {integrity: sha512-ePNZtj7pNIva/siZMg+HmbeozkIjqUIYdoymH8HaA3qK7LfzFN4WMBM8G6HQ9ZC+H3+Dnn5pqtiXpgLykaPOhw==}
'@napi-rs/canvas-darwin-x64@1.0.5':
resolution: {integrity: sha512-9BXlLHBXpYnK4jSae1MdFdyPq09Xi1I3PeCNpvRzqgmUUBhgJS7aC1z7SZEP8JUXDHtbfIrolCS3sFuT9IGP2A==}
engines: {node: '>= 10'}
cpu: [x64]
os: [darwin]
'@napi-rs/canvas-linux-arm-gnueabihf@0.1.100':
resolution: {integrity: sha512-d5cDB48oWFGU8/XPhUOFAlySgb/VAu7D+s8fi55K1Pcfg8aPplHWqMgibhVLU8ky7Pyg/fuiVLz4Nf3JrSTuUA==}
'@napi-rs/canvas-linux-arm-gnueabihf@1.0.5':
resolution: {integrity: sha512-zEW4fgvtYsOJ/N56Us4TQPfaFrUf0shGr9CgGSj3GACc+NHfUM3ci0YF9xFTjwJWGDmaEhYPL6KqCfFCxwm/qg==}
engines: {node: '>= 10'}
cpu: [arm]
os: [linux]
'@napi-rs/canvas-linux-arm64-gnu@0.1.100':
resolution: {integrity: sha512-rDxgxRu69RvDlX/bh9o22DxLsGr8EqsNgotL9+RwQE1S0b0cqeatqsw6aW45mukm0B42DIAaAacKaYQ8cqS1nw==}
'@napi-rs/canvas-linux-arm64-gnu@1.0.5':
resolution: {integrity: sha512-HFprwLspelJxCEtZvdMcz95Mwvfs63GzFVedLFmC/wslHnaOXhjXxgYxPCM/VdM4Jhx3CV4Lk0vVmh6hJv2etQ==}
engines: {node: '>= 10'}
cpu: [arm64]
os: [linux]
libc: [glibc]
'@napi-rs/canvas-linux-arm64-musl@0.1.100':
resolution: {integrity: sha512-K3mDW66N+xT2/V439u1alFANiBUjdEx2gLiNYnCmUsva5jZMxWTjafBYwTzYK+EMFMHrUoabuU+T1BIP5CgbYQ==}
'@napi-rs/canvas-linux-arm64-musl@1.0.5':
resolution: {integrity: sha512-FNMGFAx8DvtDwlLfWyBJ+oQjgPXoIAqCnNTJYqtJCFRwwzK3AyAe5B1Ll3NZ6hcOzqw7HylZsq4nQxVyPCQX1Q==}
engines: {node: '>= 10'}
cpu: [arm64]
os: [linux]
libc: [musl]
'@napi-rs/canvas-linux-riscv64-gnu@0.1.100':
resolution: {integrity: sha512-mooqUBTIsccZpnoQC4NgrC1v6C1vof39etLNMnBwCY+p0gajWJvAHLGQ6g/gGyS5YrpDW+GefSN4+Cvcr08UWw==}
'@napi-rs/canvas-linux-riscv64-gnu@1.0.5':
resolution: {integrity: sha512-2vd5v8Lui+37Hh/spITKIvTT384ip4dnUc5XBn0E+sMNS4b7au7IswyT5YDG2udPTjSh/eLUs3sGuB5YHooFOA==}
engines: {node: '>= 10'}
cpu: [riscv64]
os: [linux]
libc: [glibc]
'@napi-rs/canvas-linux-x64-gnu@0.1.100':
resolution: {integrity: sha512-1eCvkDCazm7FFhsT7DfGOdSaHgZVK3bt/dSBl5EWHOWmnz+I7j8tPseJqqD81NF+MH21jKUK4wQSDjN0mdhnTg==}
'@napi-rs/canvas-linux-x64-gnu@1.0.5':
resolution: {integrity: sha512-iQIPy+Uey0expZTOszLri5n8rY7x4WUpMaY82mcXNIgbil30iHvc01OsiizhZC1KQHTK90RFMFWSpwFU+ON3aA==}
engines: {node: '>= 10'}
cpu: [x64]
os: [linux]
libc: [glibc]
'@napi-rs/canvas-linux-x64-musl@0.1.100':
resolution: {integrity: sha512-20arT6lnI19S68qNlii73TSEDbECNgzMz2EpldC1V3mZFuRkeujXkcebRk0LRJe9SEUAooYiLokfMViY8IX7yA==}
'@napi-rs/canvas-linux-x64-musl@1.0.5':
resolution: {integrity: sha512-Npthji25t7FUqIAKsoEkFS0qY5CYVkHjvI3tuZjDTG92wX8g4dst+Lfb4hhubdqPazlDcIwalPzInsFCtf3FFg==}
engines: {node: '>= 10'}
cpu: [x64]
os: [linux]
libc: [musl]
'@napi-rs/canvas-win32-arm64-msvc@0.1.100':
resolution: {integrity: sha512-DZFFT1wIAg37LJw37yhMRFfjATd3vTQzjZ1Yki8u2vhO6Hi5VE6BVaGQ1aaDu7xb4iMErz+9EOwjpS7xcxFeBw==}
'@napi-rs/canvas-win32-arm64-msvc@1.0.5':
resolution: {integrity: sha512-bi+JsdCdbfVJDoAQybTYmkLKwh1xpYpptg5j/BNr2BB56u4/R26jrVvtjqff+CxYMXV6Kz1/jeDVhZCuj6bDng==}
engines: {node: '>= 10'}
cpu: [arm64]
os: [win32]
'@napi-rs/canvas-win32-x64-msvc@0.1.100':
resolution: {integrity: sha512-MyT1j3mHC2+Lu4pBi9mKyMJhtP6U7k7EldY7sj/uS5gJA65gTXt8MefJQXLJo5d/vZbuWmfxzkEUNc/urV3pHA==}
'@napi-rs/canvas-win32-x64-msvc@1.0.5':
resolution: {integrity: sha512-KQQwG9/sBmcGxqaLFIQf+k2OefREGoyEaIBmRuTM8bUuFKOEE9Xk5pel90hE6pmBwk/vo4RB0OdX+FxobJGMFw==}
engines: {node: '>= 10'}
cpu: [x64]
os: [win32]
'@napi-rs/canvas@0.1.100':
resolution: {integrity: sha512-xglYA6q3XO5P3BNJYxVZ1IV7DLVjp1Py6nwag88YntrS+3vKHyYcMqXVS4ZztJmwz2uGvz1FWhI/4LgbR5uQDA==}
'@napi-rs/canvas@1.0.5':
resolution: {integrity: sha512-GaPlicMtnvgPr5SowFRprkEJicDSrV3qCq17U4jiF5u0kNORZo3IbdN2Bk4SfcZJAMYFHbMVJ81O3w21CYxazg==}
engines: {node: '>= 10'}
'@radix-ui/number@1.1.1':
@@ -1960,12 +1960,12 @@ packages:
bidi-js@1.0.3:
resolution: {integrity: sha512-RKshQI1R3YQ+n9YJz2QQ147P66ELpa1FQEg20Dk8oW9t2KgLbpDLLp9aGZ7y8WHSshDknG0bknqGw5/tyCs5tw==}
brace-expansion@1.1.13:
resolution: {integrity: sha512-9ZLprWS6EENmhEOpjCYW2c8VkmOvckIJZfkr7rBW6dObmfgJ/L1GpSYW5Hpo9lDz4D1+n0Ckz8rU7FwHDQiG/w==}
brace-expansion@1.1.18:
resolution: {integrity: sha512-Edep/X9fGqVNmzKBVsDYIOtD+z1tuezV70LBjdCst9Tqu76lsnvRiZ6oTic1n+/BIwX6QDGAO94PN4N2SADvtw==}
brace-expansion@5.0.6:
resolution: {integrity: sha512-kLpxurY4Z4r9sgMsyG0Z9uzsBlgiU/EFKhj/h91/8yHu0edo7XuixOIH3VcJ8kkxs6/jPzoI6U9Vj3WqbMQ94g==}
engines: {node: 18 || 20 || >=22}
brace-expansion@5.0.9:
resolution: {integrity: sha512-ScQ4IuvIEF1TMlP7Zt+vjJ//9zlPb2SDcxWxM3bk8s6t6GGdJ7KO1dCcTidOPJKePW30LE/2cT7wCyPho9/Wxg==}
engines: {node: 20 || >=22}
browserslist@4.28.1:
resolution: {integrity: sha512-ZC5Bd0LgJXgwGqUknZY/vkUQ04r8NXnJZ3yYi4vDmSiZmC/pdSN0NbNRPxZpbtO4uAfDUAFffO8IZoM3Gj8IkA==}
@@ -2323,8 +2323,8 @@ packages:
js-tokens@4.0.0:
resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==}
js-yaml@4.2.0:
resolution: {integrity: sha512-ePWsvanv0DWuDRsW8dnt+R4jQ31SCRCQ7hhNcPXZPsoBZiemuZNYGf7adZdqX2D86j6rvKp3RpCxVTSb8WQlOw==}
js-yaml@4.3.1:
resolution: {integrity: sha512-CY6crGq313MX8GkwvB7tzgp99vjQxY1++5y10/BKN/GUfHqWaOGQMNZkBvqSzsZKWk/ijwHlWzzkLulsGHhjWQ==}
hasBin: true
jsdom@29.0.1:
@@ -2566,8 +2566,8 @@ packages:
ms@2.1.3:
resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==}
nanoid@3.3.12:
resolution: {integrity: sha512-ZB9RH/39qpq5Vu6Y+NmUaFhQR6pp+M2Xt76XBnEwDaGcVAqhlvxrl3B2bKS5D3NH3QR76v3aSrKaF/Kiy7lEtQ==}
nanoid@3.3.18:
resolution: {integrity: sha512-DTg4MJbGMWkfi6VZFdNt2/caMbQy4Ou+Op/hJQvGEWcnVfoA1QA+xzRKAzw9jD6+GVOOeYr/mIcuDSdug6F6+w==}
engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1}
hasBin: true
@@ -2618,8 +2618,8 @@ packages:
pathe@2.0.3:
resolution: {integrity: sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==}
pdfjs-dist@5.7.284:
resolution: {integrity: sha512-h4EdYQczmGhbOlqc3PPZwxevn7ApdWPbovAuWXOB/DjIyigSnwfy2oze7c6mRcSr9XgLp3eN3EeL4DyySTPMFw==}
pdfjs-dist@6.2.108:
resolution: {integrity: sha512-YxFb+SQcodN2rnX9Tn3dHYlqfb7NjlzzfONPpJd+AKoKtUjEdevTfbC07d5TcczzOK6261auRkP/M8OBHs9vFQ==}
engines: {node: '>=22.13.0 || >=24'}
picocolors@1.1.1:
@@ -2629,8 +2629,8 @@ packages:
resolution: {integrity: sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==}
engines: {node: '>=12'}
postcss@8.5.10:
resolution: {integrity: sha512-pMMHxBOZKFU6HgAZ4eyGnwXF/EvPGGqUr0MnZ5+99485wwW41kW91A4LOGxSHhgugZmSChL5AlElNdwlNgcnLQ==}
postcss@8.5.23:
resolution: {integrity: sha512-g50586zr4bZmwFiTlflMu8E0bDTb5I5gertgwAKmsdUlTQIhZtunzUlD1WSzwcVWPoAVpsrA6vlfCD7oXvRwgg==}
engines: {node: ^10 || ^12 || >=14}
prelude-ls@1.2.1:
@@ -2959,8 +2959,8 @@ packages:
undici-types@7.18.2:
resolution: {integrity: sha512-AsuCzffGHJybSaRrmr5eHr81mwJU3kjw6M+uprWvCXiNeN9SOGwQ3Jn8jb8m3Z6izVgknn1R0FTCEAP2QrLY/w==}
undici@7.28.0:
resolution: {integrity: sha512-cRZYrTDwWznlnRiPjggAGxZXanty6M8RV1ff8Wm4LWXBp7/IG8v5DnOm74DtUBp9OONpK75YlPnIjQqX0dBDtA==}
undici@7.29.0:
resolution: {integrity: sha512-IDxfleLmmbSskfWSUATiN1nfn2rDuvnMOqb5CWR92iIfojA0Ud+ulOAAEQ57LPr9rWmsreUyf5lwyao+7GNNVw==}
engines: {node: '>=20.18.1'}
update-browserslist-db@1.2.3:
@@ -3515,7 +3515,7 @@ snapshots:
globals: 14.0.0
ignore: 5.3.2
import-fresh: 3.3.1
js-yaml: 4.2.0
js-yaml: 4.3.1
minimatch: 3.1.5
strip-json-comments: 3.1.1
transitivePeerDependencies:
@@ -3605,52 +3605,52 @@ snapshots:
'@marijn/find-cluster-break@1.0.3': {}
'@napi-rs/canvas-android-arm64@0.1.100':
'@napi-rs/canvas-android-arm64@1.0.5':
optional: true
'@napi-rs/canvas-darwin-arm64@0.1.100':
'@napi-rs/canvas-darwin-arm64@1.0.5':
optional: true
'@napi-rs/canvas-darwin-x64@0.1.100':
'@napi-rs/canvas-darwin-x64@1.0.5':
optional: true
'@napi-rs/canvas-linux-arm-gnueabihf@0.1.100':
'@napi-rs/canvas-linux-arm-gnueabihf@1.0.5':
optional: true
'@napi-rs/canvas-linux-arm64-gnu@0.1.100':
'@napi-rs/canvas-linux-arm64-gnu@1.0.5':
optional: true
'@napi-rs/canvas-linux-arm64-musl@0.1.100':
'@napi-rs/canvas-linux-arm64-musl@1.0.5':
optional: true
'@napi-rs/canvas-linux-riscv64-gnu@0.1.100':
'@napi-rs/canvas-linux-riscv64-gnu@1.0.5':
optional: true
'@napi-rs/canvas-linux-x64-gnu@0.1.100':
'@napi-rs/canvas-linux-x64-gnu@1.0.5':
optional: true
'@napi-rs/canvas-linux-x64-musl@0.1.100':
'@napi-rs/canvas-linux-x64-musl@1.0.5':
optional: true
'@napi-rs/canvas-win32-arm64-msvc@0.1.100':
'@napi-rs/canvas-win32-arm64-msvc@1.0.5':
optional: true
'@napi-rs/canvas-win32-x64-msvc@0.1.100':
'@napi-rs/canvas-win32-x64-msvc@1.0.5':
optional: true
'@napi-rs/canvas@0.1.100':
'@napi-rs/canvas@1.0.5':
optionalDependencies:
'@napi-rs/canvas-android-arm64': 0.1.100
'@napi-rs/canvas-darwin-arm64': 0.1.100
'@napi-rs/canvas-darwin-x64': 0.1.100
'@napi-rs/canvas-linux-arm-gnueabihf': 0.1.100
'@napi-rs/canvas-linux-arm64-gnu': 0.1.100
'@napi-rs/canvas-linux-arm64-musl': 0.1.100
'@napi-rs/canvas-linux-riscv64-gnu': 0.1.100
'@napi-rs/canvas-linux-x64-gnu': 0.1.100
'@napi-rs/canvas-linux-x64-musl': 0.1.100
'@napi-rs/canvas-win32-arm64-msvc': 0.1.100
'@napi-rs/canvas-win32-x64-msvc': 0.1.100
'@napi-rs/canvas-android-arm64': 1.0.5
'@napi-rs/canvas-darwin-arm64': 1.0.5
'@napi-rs/canvas-darwin-x64': 1.0.5
'@napi-rs/canvas-linux-arm-gnueabihf': 1.0.5
'@napi-rs/canvas-linux-arm64-gnu': 1.0.5
'@napi-rs/canvas-linux-arm64-musl': 1.0.5
'@napi-rs/canvas-linux-riscv64-gnu': 1.0.5
'@napi-rs/canvas-linux-x64-gnu': 1.0.5
'@napi-rs/canvas-linux-x64-musl': 1.0.5
'@napi-rs/canvas-win32-arm64-msvc': 1.0.5
'@napi-rs/canvas-win32-x64-msvc': 1.0.5
optional: true
'@radix-ui/number@1.1.1': {}
@@ -4864,12 +4864,12 @@ snapshots:
dependencies:
require-from-string: 2.0.2
brace-expansion@1.1.13:
brace-expansion@1.1.18:
dependencies:
balanced-match: 1.0.2
concat-map: 0.0.1
brace-expansion@5.0.6:
brace-expansion@5.0.9:
dependencies:
balanced-match: 4.0.4
@@ -5226,7 +5226,7 @@ snapshots:
js-tokens@4.0.0: {}
js-yaml@4.2.0:
js-yaml@4.3.1:
dependencies:
argparse: 2.0.1
@@ -5247,7 +5247,7 @@ snapshots:
saxes: 6.0.0
symbol-tree: 3.2.4
tough-cookie: 6.0.1
undici: 7.28.0
undici: 7.29.0
w3c-xmlserializer: 5.0.0
webidl-conversions: 8.0.1
whatwg-mimetype: 5.0.0
@@ -5408,11 +5408,11 @@ snapshots:
minimatch@10.2.4:
dependencies:
brace-expansion: 5.0.6
brace-expansion: 5.0.9
minimatch@3.1.5:
dependencies:
brace-expansion: 1.1.13
brace-expansion: 1.1.18
motion-dom@12.38.0:
dependencies:
@@ -5422,7 +5422,7 @@ snapshots:
ms@2.1.3: {}
nanoid@3.3.12: {}
nanoid@3.3.18: {}
natural-compare@1.4.0: {}
@@ -5465,17 +5465,17 @@ snapshots:
pathe@2.0.3: {}
pdfjs-dist@5.7.284:
pdfjs-dist@6.2.108:
optionalDependencies:
'@napi-rs/canvas': 0.1.100
'@napi-rs/canvas': 1.0.5
picocolors@1.1.1: {}
picomatch@4.0.4: {}
postcss@8.5.10:
postcss@8.5.23:
dependencies:
nanoid: 3.3.12
nanoid: 3.3.18
picocolors: 1.1.1
source-map-js: 1.2.1
@@ -5772,7 +5772,7 @@ snapshots:
undici-types@7.18.2: {}
undici@7.28.0: {}
undici@7.29.0: {}
update-browserslist-db@1.2.3(browserslist@4.28.1):
dependencies:
@@ -5808,7 +5808,7 @@ snapshots:
esbuild: 0.25.12
fdir: 6.5.0(picomatch@4.0.4)
picomatch: 4.0.4
postcss: 8.5.10
postcss: 8.5.23
rollup: 4.62.0
tinyglobby: 0.2.17
optionalDependencies:
-407
View File
@@ -1,407 +0,0 @@
/* Copyright 2014 Mozilla Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
.annotationLayer {
color-scheme: only light;
--annotation-unfocused-field-background: url("data:image/svg+xml;charset=UTF-8,<svg width='1px' height='1px' xmlns='http://www.w3.org/2000/svg'><rect width='100%' height='100%' style='fill:rgba(0, 54, 255, 0.13);'/></svg>");
--input-focus-border-color: Highlight;
--input-focus-outline: 1px solid Canvas;
--input-unfocused-border-color: transparent;
--input-disabled-border-color: transparent;
--input-hover-border-color: black;
--link-outline: none;
@media screen and (forced-colors: active) {
--input-focus-border-color: CanvasText;
--input-unfocused-border-color: ActiveText;
--input-disabled-border-color: GrayText;
--input-hover-border-color: Highlight;
--link-outline: 1.5px solid LinkText;
.textWidgetAnnotation :is(input, textarea):required,
.choiceWidgetAnnotation select:required,
.buttonWidgetAnnotation:is(.checkBox, .radioButton) input:required {
outline: 1.5px solid selectedItem;
}
.linkAnnotation {
outline: var(--link-outline);
&:hover {
backdrop-filter: var(--hcm-highlight-filter);
}
& > a:hover {
opacity: 0 !important;
background: none !important;
box-shadow: none;
}
}
.popupAnnotation .popup {
outline: calc(1.5px * var(--total-scale-factor)) solid CanvasText !important;
background-color: ButtonFace !important;
color: ButtonText !important;
}
.highlightArea:hover::after {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
backdrop-filter: var(--hcm-highlight-filter);
content: "";
pointer-events: none;
}
.popupAnnotation.focused .popup {
outline: calc(3px * var(--total-scale-factor)) solid Highlight !important;
}
}
position: absolute;
top: 0;
left: 0;
pointer-events: none;
transform-origin: 0 0;
&[data-main-rotation="90"] .norotate {
transform: rotate(270deg) translateX(-100%);
}
&[data-main-rotation="180"] .norotate {
transform: rotate(180deg) translate(-100%, -100%);
}
&[data-main-rotation="270"] .norotate {
transform: rotate(90deg) translateY(-100%);
}
&.disabled {
section,
.popup {
pointer-events: none;
}
}
.annotationContent {
position: absolute;
width: 100%;
height: 100%;
pointer-events: none;
&.freetext {
background: transparent;
border: none;
inset: 0;
overflow: visible;
white-space: nowrap;
font: 10px sans-serif;
line-height: 1.35;
}
}
section {
position: absolute;
text-align: initial;
pointer-events: auto;
box-sizing: border-box;
transform-origin: 0 0;
user-select: none;
&:has(div.annotationContent) {
canvas.annotationContent {
display: none;
}
}
.overlaidText {
position: absolute;
top: 0;
left: 0;
width: 0;
height: 0;
display: inline-block;
overflow: hidden;
}
}
.textLayer.selecting ~ & section {
pointer-events: none;
}
:is(.linkAnnotation, .buttonWidgetAnnotation.pushButton) > a {
position: absolute;
font-size: 1em;
top: 0;
left: 0;
width: 100%;
height: 100%;
}
:is(.linkAnnotation, .buttonWidgetAnnotation.pushButton):not(.hasBorder)
> a:hover {
opacity: 0.2;
background-color: rgb(255 255 0);
}
.linkAnnotation.hasBorder:hover {
background-color: rgb(255 255 0 / 0.2);
}
.hasBorder {
background-size: 100% 100%;
}
.textAnnotation img {
position: absolute;
cursor: pointer;
width: 100%;
height: 100%;
top: 0;
left: 0;
}
.textWidgetAnnotation :is(input, textarea),
.choiceWidgetAnnotation select,
.buttonWidgetAnnotation:is(.checkBox, .radioButton) input {
background-image: var(--annotation-unfocused-field-background);
border: 2px solid var(--input-unfocused-border-color);
box-sizing: border-box;
font: calc(9px * var(--total-scale-factor)) sans-serif;
height: 100%;
margin: 0;
vertical-align: top;
width: 100%;
}
.textWidgetAnnotation :is(input, textarea):required,
.choiceWidgetAnnotation select:required,
.buttonWidgetAnnotation:is(.checkBox, .radioButton) input:required {
outline: 1.5px solid red;
}
.choiceWidgetAnnotation select option {
padding: 0;
}
.buttonWidgetAnnotation.radioButton input {
border-radius: 50%;
}
.textWidgetAnnotation textarea {
resize: none;
}
.textWidgetAnnotation :is(input, textarea)[disabled],
.choiceWidgetAnnotation select[disabled],
.buttonWidgetAnnotation:is(.checkBox, .radioButton) input[disabled] {
background: none;
border: 2px solid var(--input-disabled-border-color);
cursor: not-allowed;
}
.textWidgetAnnotation :is(input, textarea):hover,
.choiceWidgetAnnotation select:hover,
.buttonWidgetAnnotation:is(.checkBox, .radioButton) input:hover {
border: 2px solid var(--input-hover-border-color);
}
.textWidgetAnnotation :is(input, textarea):hover,
.choiceWidgetAnnotation select:hover,
.buttonWidgetAnnotation.checkBox input:hover {
border-radius: 2px;
}
.textWidgetAnnotation :is(input, textarea):focus,
.choiceWidgetAnnotation select:focus {
background: none;
border: 2px solid var(--input-focus-border-color);
border-radius: 2px;
outline: var(--input-focus-outline);
}
.buttonWidgetAnnotation:is(.checkBox, .radioButton) :focus {
background-image: none;
background-color: transparent;
}
.buttonWidgetAnnotation.checkBox :focus {
border: 2px solid var(--input-focus-border-color);
border-radius: 2px;
outline: var(--input-focus-outline);
}
.buttonWidgetAnnotation.radioButton :focus {
border: 2px solid var(--input-focus-border-color);
outline: var(--input-focus-outline);
}
.buttonWidgetAnnotation.checkBox input:checked::before,
.buttonWidgetAnnotation.checkBox input:checked::after,
.buttonWidgetAnnotation.radioButton input:checked::before {
background-color: CanvasText;
content: "";
display: block;
position: absolute;
}
.buttonWidgetAnnotation.checkBox input:checked::before,
.buttonWidgetAnnotation.checkBox input:checked::after {
height: 80%;
left: 45%;
width: 1px;
}
.buttonWidgetAnnotation.checkBox input:checked::before {
transform: rotate(45deg);
}
.buttonWidgetAnnotation.checkBox input:checked::after {
transform: rotate(-45deg);
}
.buttonWidgetAnnotation.radioButton input:checked::before {
border-radius: 50%;
height: 50%;
left: 25%;
top: 25%;
width: 50%;
}
.textWidgetAnnotation input.comb {
font-family: monospace;
padding-left: 2px;
padding-right: 0;
}
.textWidgetAnnotation input.comb:focus {
/*
* Letter spacing is placed on the right side of each character. Hence, the
* letter spacing of the last character may be placed outside the visible
* area, causing horizontal scrolling. We avoid this by extending the width
* when the element has focus and revert this when it loses focus.
*/
width: 103%;
}
.buttonWidgetAnnotation:is(.checkBox, .radioButton) input {
appearance: none;
}
.fileAttachmentAnnotation .popupTriggerArea {
height: 100%;
width: 100%;
}
.popupAnnotation {
position: absolute;
font-size: calc(9px * var(--total-scale-factor));
pointer-events: none;
width: max-content;
max-width: 45%;
height: auto;
}
.popup {
background-color: rgb(255 255 153);
color: black;
box-shadow: 0 calc(2px * var(--total-scale-factor))
calc(5px * var(--total-scale-factor)) rgb(136 136 136);
border-radius: calc(2px * var(--total-scale-factor));
outline: 1.5px solid rgb(255 255 74);
padding: calc(6px * var(--total-scale-factor));
cursor: pointer;
font: message-box;
white-space: normal;
word-wrap: break-word;
pointer-events: auto;
user-select: text;
}
.popupAnnotation.focused .popup {
outline-width: 3px;
}
.popup * {
font-size: calc(9px * var(--total-scale-factor));
}
.popup > .header {
display: inline-block;
}
.popup > .header > .title {
display: inline;
font-weight: bold;
}
.popup > .header .popupDate {
display: inline-block;
margin-left: calc(5px * var(--total-scale-factor));
width: fit-content;
}
.popupContent {
border-top: 1px solid rgb(51 51 51);
margin-top: calc(2px * var(--total-scale-factor));
padding-top: calc(2px * var(--total-scale-factor));
}
.richText > * {
white-space: pre-wrap;
font-size: calc(9px * var(--total-scale-factor));
}
.popupTriggerArea {
cursor: pointer;
&:hover {
backdrop-filter: var(--hcm-highlight-filter);
}
}
section svg {
position: absolute;
width: 100%;
height: 100%;
top: 0;
left: 0;
}
.annotationTextContent {
position: absolute;
width: 100%;
height: 100%;
opacity: 0;
color: transparent;
user-select: none;
pointer-events: none;
span {
width: 100%;
display: inline-block;
}
}
svg.quadrilateralsContainer {
contain: strict;
width: 0;
height: 0;
position: absolute;
top: 0;
left: 0;
z-index: -1;
}
}
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+640
View File
@@ -0,0 +1,640 @@
/* Copyright 2014 Mozilla Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*
* Extracted from pdfjs-dist 6.2.108 web/pdf_viewer.css for Silo's embedded
* reader. This file intentionally contains only the .textLayer,
* .textLayerImages, and .annotationLayer blocks used by foliate-js/pdf.js.
*/
.textLayer{
color-scheme:only light;
position:absolute;
text-align:initial;
inset:0;
overflow:clip;
opacity:1;
line-height:1;
letter-spacing:normal;
word-spacing:normal;
-webkit-text-size-adjust:none;
-moz-text-size-adjust:none;
text-size-adjust:none;
forced-color-adjust:none;
transform-origin:0 0;
caret-color:CanvasText;
z-index:0;
&.highlighting{
touch-action:none;
}
:is(span, br){
color:transparent;
position:absolute;
white-space:pre;
cursor:text;
transform-origin:0% 0%;
-webkit-user-select:text;
-moz-user-select:text;
user-select:text;
}
--min-font-size:1;
--text-scale-factor:calc(var(--total-scale-factor) * var(--min-font-size));
--min-font-size-inv:calc(1 / var(--min-font-size));
> :not(.markedContent),
.markedContent span:not(.markedContent){
z-index:1;
--font-height:0;
font-size:calc(var(--text-scale-factor) * var(--font-height));
--scale-x:1;
--rotate:0deg;
transform:rotate(var(--rotate)) scaleX(var(--scale-x)) scale(var(--min-font-size-inv));
}
.markedContent{
display:contents;
}
span[role="img"]{
-webkit-user-select:none;
-moz-user-select:none;
user-select:none;
cursor:default;
}
.highlight{
--highlight-bg-color:rgb(180 0 170 / 0.25);
--highlight-selected-bg-color:rgb(0 100 0 / 0.25);
--highlight-backdrop-filter:none;
--highlight-selected-backdrop-filter:none;
@media screen and (forced-colors: active){
--highlight-bg-color:transparent;
--highlight-selected-bg-color:transparent;
--highlight-backdrop-filter:var(--hcm-highlight-filter);
--highlight-selected-backdrop-filter:var(
--hcm-highlight-selected-filter
);
}
margin:-1px;
padding:1px;
background-color:var(--highlight-bg-color);
backdrop-filter:var(--highlight-backdrop-filter);
border-radius:4px;
&.appended{
position:initial;
}
&.begin{
border-radius:4px 0 0 4px;
}
&.end{
border-radius:0 4px 4px 0;
}
&.middle{
border-radius:0;
}
&.selected{
background-color:var(--highlight-selected-bg-color);
backdrop-filter:var(--highlight-selected-backdrop-filter);
scroll-margin-top:50px;
}
}
::-moz-selection{
background:rgba(0 0 255 / 0.25);
background:color-mix(in srgb, AccentColor, transparent 50%);
color:transparent;
}
::selection{
background:rgba(0 0 255 / 0.25);
background:color-mix(in srgb, AccentColor, transparent 50%);
color:transparent;
}
&.selectionRendering{
::-moz-selection{
background:transparent;
color:transparent;
}
::selection{
background:transparent;
color:transparent;
}
}
br::-moz-selection{
background:transparent;
}
br::selection{
background:transparent;
}
.endOfContent{
display:block;
position:absolute;
inset:100% 0 0;
z-index:0;
cursor:default;
-webkit-user-select:none;
-moz-user-select:none;
user-select:none;
}
&.selecting .endOfContent{
top:0;
}
}
.textLayerImages{
position:absolute;
inset:0;
-webkit-user-select:none;
-moz-user-select:none;
user-select:none;
canvas{
position:absolute;
transform-origin:0% 0%;
}
}
.annotationLayer{
color-scheme:only light;
--annotation-unfocused-field-background:url("data:image/svg+xml;charset=UTF-8,<svg width='1px' height='1px' xmlns='http://www.w3.org/2000/svg'><rect width='100%' height='100%' style='fill:rgba(0, 54, 255, 0.13);'/></svg>");
--annotation-unfocused-field-filter:url("data:image/svg+xml;charset=UTF-8,<svg xmlns='http://www.w3.org/2000/svg'><filter id='pdfjsFillableField' x='0%' y='0%' width='100%' height='100%' color-interpolation-filters='sRGB'><feFlood flood-color='rgb(0,54,255)' flood-opacity='0.13' result='f'/><feComposite in='f' in2='SourceGraphic' operator='over'/></filter></svg>#pdfjsFillableField");
--input-focus-border-color:Highlight;
--input-focus-outline:1px solid Canvas;
--input-unfocused-border-color:transparent;
--input-disabled-border-color:transparent;
--input-hover-border-color:black;
--link-outline:none;
@media screen and (forced-colors: active){
--input-focus-border-color:CanvasText;
--input-unfocused-border-color:ActiveText;
--input-disabled-border-color:GrayText;
--input-hover-border-color:Highlight;
--link-outline:1.5px solid LinkText;
.textWidgetAnnotation :is(input, textarea):required,
.choiceWidgetAnnotation select:required,
.buttonWidgetAnnotation:is(.checkBox, .radioButton) input:required{
outline:1.5px solid selectedItem;
}
.linkAnnotation{
outline:var(--link-outline);
&:hover{
backdrop-filter:var(--hcm-highlight-filter);
}
& > a:hover{
opacity:0 !important;
background:none !important;
box-shadow:none;
}
}
.popupAnnotation .popup{
outline:calc(1.5px * var(--total-scale-factor)) solid CanvasText !important;
background-color:ButtonFace !important;
color:ButtonText !important;
}
.highlightArea:hover::after{
position:absolute;
top:0;
left:0;
width:100%;
height:100%;
backdrop-filter:var(--hcm-highlight-filter);
content:"";
pointer-events:none;
}
.popupAnnotation.focused .popup{
outline:calc(3px * var(--total-scale-factor)) solid Highlight !important;
}
}
position:absolute;
top:0;
left:0;
pointer-events:none;
transform-origin:0 0;
&[data-main-rotation="90"] .norotate{
transform:rotate(270deg) translateX(-100%);
}
&[data-main-rotation="180"] .norotate{
transform:rotate(180deg) translate(-100%, -100%);
}
&[data-main-rotation="270"] .norotate{
transform:rotate(90deg) translateY(-100%);
}
&.disabled{
section,
.popup{
pointer-events:none;
}
}
.annotationContent{
position:absolute;
width:100%;
height:100%;
pointer-events:none;
&.freetext{
background:transparent;
border:none;
inset:0;
overflow:visible;
white-space:nowrap;
font:10px sans-serif;
line-height:1.35;
}
}
section{
position:absolute;
text-align:initial;
pointer-events:auto;
box-sizing:border-box;
transform-origin:0 0;
-webkit-user-select:none;
-moz-user-select:none;
user-select:none;
&:has(div.annotationContent){
canvas.annotationContent{
display:none;
}
}
.overlaidText{
position:absolute;
top:0;
left:0;
width:0;
height:0;
display:inline-block;
overflow:hidden;
}
}
.hasOwnCanvas:not(.sandboxModified) :is(input, textarea){
display:none;
}
.hasOwnCanvas.sandboxModified canvas.annotationContent{
display:none;
}
.textLayer.selecting ~ & section{
pointer-events:none;
}
:is(.linkAnnotation, .buttonWidgetAnnotation.pushButton) > a{
position:absolute;
font-size:1em;
top:0;
left:0;
width:100%;
height:100%;
}
:is(.linkAnnotation, .buttonWidgetAnnotation.pushButton):not(.hasBorder)
> a:hover{
opacity:0.2;
background-color:rgb(255 255 0);
}
.linkAnnotation.hasBorder:hover{
background-color:rgb(255 255 0 / 0.2);
}
.hasBorder{
background-size:100% 100%;
}
.textAnnotation img{
position:absolute;
cursor:pointer;
width:100%;
height:100%;
top:0;
left:0;
}
.textWidgetAnnotation :is(input, textarea),
.choiceWidgetAnnotation select,
.buttonWidgetAnnotation:is(.checkBox, .radioButton) input{
background-image:var(--annotation-unfocused-field-background);
border:2px solid var(--input-unfocused-border-color);
box-sizing:border-box;
font:calc(9px * var(--total-scale-factor)) sans-serif;
height:100%;
margin:0;
vertical-align:top;
width:100%;
}
.textWidgetAnnotation :is(input, textarea):required,
.choiceWidgetAnnotation select:required,
.buttonWidgetAnnotation:is(.checkBox, .radioButton) input:required{
outline:1.5px solid red;
}
.choiceWidgetAnnotation select option{
padding:0;
}
.textWidgetAnnotation textarea{
resize:none;
}
.textWidgetAnnotation :is(input, textarea)[disabled],
.choiceWidgetAnnotation select[disabled],
.buttonWidgetAnnotation:is(.checkBox, .radioButton) input[disabled]{
background:none;
border:2px solid var(--input-disabled-border-color);
cursor:not-allowed;
}
.textWidgetAnnotation :is(input, textarea):hover,
.choiceWidgetAnnotation select:hover,
.buttonWidgetAnnotation:is(.checkBox, .radioButton) input:hover{
border:2px solid var(--input-hover-border-color);
}
.textWidgetAnnotation :is(input, textarea):hover,
.choiceWidgetAnnotation select:hover,
.buttonWidgetAnnotation.checkBox input:hover{
border-radius:2px;
}
.textWidgetAnnotation :is(input, textarea):focus,
.choiceWidgetAnnotation select:focus{
background:none;
border:2px solid var(--input-focus-border-color);
border-radius:2px;
outline:var(--input-focus-outline);
}
.buttonWidgetAnnotation:is(.checkBox, .radioButton) :focus{
background-image:none;
background-color:transparent;
}
.buttonWidgetAnnotation.checkBox :focus{
border:2px solid var(--input-focus-border-color);
border-radius:2px;
outline:var(--input-focus-outline);
}
.buttonWidgetAnnotation.radioButton :focus{
border:2px solid var(--input-focus-border-color);
outline:var(--input-focus-outline);
}
.buttonWidgetAnnotation:is(.checkBox, .radioButton){
[data-canvas-name]{
filter:var(--annotation-unfocused-field-filter);
}
&:focus-within [data-canvas-name]{
filter:none;
}
[data-canvas-name="checked"]{
&:has(~ input:checked){
display:block;
}
&:has(~ input:not(:checked)){
display:none;
}
}
[data-canvas-name="unchecked"]{
&:has(~ input:checked){
display:none;
}
&:has(~ input:not(:checked)){
display:block;
}
}
}
.textWidgetAnnotation input.comb{
--comb-width:0px;
--comb-letter-spacing:calc(var(--comb-width) - 1ch);
font-family:monospace;
letter-spacing:var(--comb-letter-spacing);
overflow-x:hidden;
padding:0;
text-indent:calc(
var(--comb-offset, 0) * var(--comb-width) + var(--comb-letter-spacing) / 2
);
}
.textWidgetAnnotation input.comb:focus{
background-image:repeating-linear-gradient(
to right,
transparent 0 calc(var(--comb-width) - 1px),
var(--input-focus-border-color) calc(var(--comb-width) - 1px)
var(--comb-width)
);
}
.buttonWidgetAnnotation:is(.checkBox, .radioButton) input{
-webkit-appearance:none;
-moz-appearance:none;
appearance:none;
}
.buttonWidgetAnnotation:is(.checkBox, .radioButton):has(
[data-canvas-name="checked"]
)
input:checked,
.buttonWidgetAnnotation:is(.checkBox, .radioButton):has(
[data-canvas-name="unchecked"]
)
input:not(:checked){
background-image:none;
}
.fileAttachmentAnnotation .popupTriggerArea{
height:100%;
width:100%;
}
.mediaAnnotation{
pointer-events:auto;
.mediaContent{
width:100%;
}
video.mediaContent{
height:100%;
-o-object-fit:contain;
object-fit:contain;
}
audio.mediaContent{
position:absolute;
bottom:0;
}
.mediaPlayButton{
height:100%;
width:100%;
margin:0;
padding:0;
border:none;
cursor:pointer;
background-color:transparent;
background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 100 100'%3E%3Ccircle cx='50' cy='50' r='40' fill='rgba(0,0,0,0.55)'/%3E%3Cpath d='M40 32 L70 50 L40 68 Z' fill='white'/%3E%3C/svg%3E");
background-position:center;
background-repeat:no-repeat;
background-size:calc(48px * var(--total-scale-factor));
&:hover{
background-color:rgba(255 255 255 / 0.1);
}
}
}
.popupAnnotation{
position:absolute;
font-size:calc(9px * var(--total-scale-factor));
pointer-events:none;
width:-moz-max-content;
width:max-content;
max-width:45%;
height:auto;
}
.popup{
background-color:rgb(255 255 153);
color:black;
box-shadow:0 calc(2px * var(--total-scale-factor)) calc(5px * var(--total-scale-factor)) rgb(136 136 136);
border-radius:calc(2px * var(--total-scale-factor));
outline:1.5px solid rgb(255 255 74);
padding:calc(6px * var(--total-scale-factor));
cursor:pointer;
font:message-box;
white-space:normal;
word-wrap:break-word;
pointer-events:auto;
-webkit-user-select:text;
-moz-user-select:text;
user-select:text;
}
.popupAnnotation.focused .popup{
outline-width:3px;
}
.popup *{
font-size:calc(9px * var(--total-scale-factor));
}
.popup > .header{
display:inline-block;
}
.popup > .header > .title{
display:inline;
font-weight:bold;
}
.popup > .header .popupDate{
display:inline-block;
margin-left:calc(5px * var(--total-scale-factor));
width:-moz-fit-content;
width:fit-content;
}
.popupContent{
border-top:1px solid rgb(51 51 51);
margin-top:calc(2px * var(--total-scale-factor));
padding-top:calc(2px * var(--total-scale-factor));
}
.richText > *{
white-space:pre-wrap;
font-size:calc(9px * var(--total-scale-factor));
}
.popupTriggerArea{
cursor:pointer;
&:hover{
backdrop-filter:var(--hcm-highlight-filter);
}
}
section svg{
position:absolute;
width:100%;
height:100%;
top:0;
left:0;
}
.annotationTextContent{
position:absolute;
width:100%;
height:100%;
opacity:0;
color:transparent;
-webkit-user-select:none;
-moz-user-select:none;
user-select:none;
pointer-events:none;
span{
width:100%;
display:inline-block;
}
}
svg.quadrilateralsContainer{
contain:strict;
width:0;
height:0;
position:absolute;
top:0;
left:0;
z-index:-1;
}
}
-144
View File
@@ -1,144 +0,0 @@
/* Copyright 2014 Mozilla Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
.textLayer {
color-scheme: only light;
position: absolute;
text-align: initial;
inset: 0;
overflow: clip;
opacity: 1;
line-height: 1;
text-size-adjust: none;
forced-color-adjust: none;
transform-origin: 0 0;
caret-color: CanvasText;
z-index: 0;
&.highlighting {
touch-action: none;
}
:is(span, br) {
color: transparent;
position: absolute;
white-space: pre;
cursor: text;
transform-origin: 0% 0%;
}
/* We multiply the font size by --min-font-size, and then scale the text
* elements by 1/--min-font-size. This allows us to effectively ignore the
* minimum font size enforced by the browser, so that the text layer <span>s
* can always match the size of the text in the canvas. */
--min-font-size: 1;
--text-scale-factor: calc(var(--total-scale-factor) * var(--min-font-size));
--min-font-size-inv: calc(1 / var(--min-font-size));
> :not(.markedContent),
.markedContent span:not(.markedContent) {
z-index: 1;
--font-height: 0; /* set by text_layer.js */
font-size: calc(var(--text-scale-factor) * var(--font-height));
--scale-x: 1;
--rotate: 0deg;
transform: rotate(var(--rotate)) scaleX(var(--scale-x))
scale(var(--min-font-size-inv));
}
.markedContent {
display: contents;
}
span[role="img"] {
user-select: none;
cursor: default;
}
.highlight {
--highlight-bg-color: rgb(180 0 170 / 0.25);
--highlight-selected-bg-color: rgb(0 100 0 / 0.25);
--highlight-backdrop-filter: none;
--highlight-selected-backdrop-filter: none;
@media screen and (forced-colors: active) {
--highlight-bg-color: transparent;
--highlight-selected-bg-color: transparent;
--highlight-backdrop-filter: var(--hcm-highlight-filter);
--highlight-selected-backdrop-filter: var(
--hcm-highlight-selected-filter
);
}
margin: -1px;
padding: 1px;
background-color: var(--highlight-bg-color);
backdrop-filter: var(--highlight-backdrop-filter);
border-radius: 4px;
&.appended {
position: initial;
}
&.begin {
border-radius: 4px 0 0 4px;
}
&.end {
border-radius: 0 4px 4px 0;
}
&.middle {
border-radius: 0;
}
&.selected {
background-color: var(--highlight-selected-bg-color);
backdrop-filter: var(--highlight-selected-backdrop-filter);
}
}
::selection {
/* stylelint-disable declaration-block-no-duplicate-properties */
/*#if !MOZCENTRAL*/
background: rgba(0 0 255 / 0.25);
/*#endif*/
/* stylelint-enable declaration-block-no-duplicate-properties */
background: color-mix(in srgb, AccentColor, transparent 75%);
}
/* Avoids https://github.com/mozilla/pdf.js/issues/13840 in Chrome */
/*#if !MOZCENTRAL*/
br::selection {
background: transparent;
}
/*#endif*/
.endOfContent {
display: block;
position: absolute;
inset: 100% 0 0;
z-index: 0;
cursor: default;
user-select: none;
}
&.selecting .endOfContent {
top: 0;
}
}
Binary file not shown.
+10 -10
View File
@@ -2,15 +2,15 @@
async function QuickJS(moduleArg={}){var moduleRtn;var e=moduleArg,aa=import.meta.url,h="",m;try{h=(new URL(".",aa)).href}catch{}m=async a=>{a=await fetch(a,{credentials:"same-origin"});if(a.ok)return a.arrayBuffer();throw Error(a.status+" : "+a.url);};var q=console.error.bind(console),r,t=!1,u,v,w,x=!1;function y(){var a=z.buffer;A=new Int8Array(a);new Int16Array(a);B=new Uint8Array(a);new Uint16Array(a);C=new Int32Array(a);D=new Uint32Array(a);new Float32Array(a);new Float64Array(a);new BigInt64Array(a);new BigUint64Array(a)}
function E(a){e.onAbort?.(a);a=`Aborted(${a})`;q(a);t=!0;a=new WebAssembly.RuntimeError(a+". Build with -sASSERTIONS for more info.");w?.(a);throw a;}var F;async function ba(a){if(!r)try{var b=await m(a);return new Uint8Array(b)}catch{}if(a==F&&r)a=new Uint8Array(r);else throw"both async and sync fetching of the wasm failed";return a}async function ca(a,b){try{var c=await ba(a);return await WebAssembly.instantiate(c,b)}catch(d){q(`failed to asynchronously prepare wasm: ${d}`),E(d)}}
async function da(a){var b=F;if(!r)try{var c=fetch(b,{credentials:"same-origin"});return await WebAssembly.instantiateStreaming(c,a)}catch(d){q(`wasm streaming compile failed: ${d}`),q("falling back to ArrayBuffer instantiation")}return ca(b,a)}class G{name="ExitStatus";constructor(a){this.message=`Program terminated with exit(${a})`;this.status=a}}
var C,A,D,B,H=a=>{for(;0<a.length;)a.shift()(e)},I=[],J=[],ea=()=>{var a=e.preRun.shift();J.push(a)},K=!0,L=0,fa=[0,31,60,91,121,152,182,213,244,274,305,335],ha=[0,31,59,90,120,151,181,212,243,273,304,334],M={},N=a=>{if(!(a instanceof G||"unwind"==a))throw a;},O=a=>{u=a;K||0<L||(e.onExit?.(a),t=!0);throw new G(a);},ia=a=>{if(!t)try{a()}catch(b){N(b)}finally{if(!(K||0<L))try{u=a=u,O(a)}catch(b){N(b)}}},P=(a,b,c)=>{var d=B;if(0<c){c=b+c-1;for(var g=0;g<a.length;++g){var f=a.codePointAt(g);if(127>=f){if(b>=
c)break;d[b++]=f}else if(2047>=f){if(b+1>=c)break;d[b++]=192|f>>6;d[b++]=128|f&63}else if(65535>=f){if(b+2>=c)break;d[b++]=224|f>>12;d[b++]=128|f>>6&63;d[b++]=128|f&63}else{if(b+3>=c)break;d[b++]=240|f>>18;d[b++]=128|f>>12&63;d[b++]=128|f>>6&63;d[b++]=128|f&63;g++}}d[b]=0}},ja=new TextDecoder,Q=a=>{if(a){for(var b=a,c=B,d=b+void 0;c[b]&&!(b>=d);)++b;a=ja.decode(B.subarray(a,b))}else a="";return a},R=a=>{for(var b=0,c=0;c<a.length;++c){var d=a.charCodeAt(c);127>=d?b++:2047>=d?b+=2:55296<=d&&57343>=
d?(b+=4,++c):b+=3}return b},T=a=>{var b=R(a)+1,c=S(b);c&&P(a,c,b);return c};function U(){}var la=(a,b,c,d)=>{var g={string:k=>{var n=0;if(null!==k&&void 0!==k&&0!==k){n=R(k)+1;var X=V(n);P(k,X,n);n=X}return n},array:k=>{var n=V(k.length);A.set(k,n);return n}};a=e["_"+a];var f=[],p=0;if(d)for(var l=0;l<d.length;l++){var Y=g[c[l]];Y?(0===p&&(p=W()),f[l]=Y(d[l])):f[l]=d[l]}c=a(...f);return c=function(k){0!==p&&ka(p);return"string"===b?Q(k):"boolean"===b?!!k:k}(c)};
U=(a,b,c)=>{a=Q(a);b=null!==b?JSON.parse(Q(b)):[];try{const d=e.externalCall(a,b);return d?T(d):null}catch(d){return e.HEAPU8[c]=1,T(d.message)}};e.noExitRuntime&&(K=e.noExitRuntime);e.printErr&&(q=e.printErr);e.wasmBinary&&(r=e.wasmBinary);if(e.preInit)for("function"==typeof e.preInit&&(e.preInit=[e.preInit]);0<e.preInit.length;)e.preInit.shift()();e.ccall=la;e.cwrap=(a,b,c,d)=>{var g=!c||c.every(f=>"number"===f||"boolean"===f);return"string"!==b&&g&&!d?e["_"+a]:(...f)=>la(a,b,c,f,d)};
var C,A,D,B,H=a=>{for(;a.length>0;)a.shift()(e)},I=[],J=[],ea=()=>{var a=e.preRun.shift();J.push(a)},K=!0,L=0,fa=[0,31,60,91,121,152,182,213,244,274,305,335],ha=[0,31,59,90,120,151,181,212,243,273,304,334],M={},N=a=>{if(!(a instanceof G||a=="unwind"))throw a;},O=a=>{u=a;K||L>0||(e.onExit?.(a),t=!0);throw new G(a);},ia=a=>{if(!t)try{a()}catch(b){N(b)}finally{if(!(K||L>0))try{u=a=u,O(a)}catch(b){N(b)}}},P=(a,b,c)=>{var d=B;if(c>0){c=b+c-1;for(var g=0;g<a.length;++g){var f=a.codePointAt(g);if(f<=127){if(b>=
c)break;d[b++]=f}else if(f<=2047){if(b+1>=c)break;d[b++]=192|f>>6;d[b++]=128|f&63}else if(f<=65535){if(b+2>=c)break;d[b++]=224|f>>12;d[b++]=128|f>>6&63;d[b++]=128|f&63}else{if(b+3>=c)break;d[b++]=240|f>>18;d[b++]=128|f>>12&63;d[b++]=128|f>>6&63;d[b++]=128|f&63;g++}}d[b]=0}},ja=new TextDecoder,Q=a=>{if(a){for(var b=a,c=B,d=b+void 0;c[b]&&!(b>=d);)++b;a=ja.decode(B.subarray(a,b))}else a="";return a},R=a=>{for(var b=0,c=0;c<a.length;++c){var d=a.charCodeAt(c);d<=127?b++:d<=2047?b+=2:d>=55296&&d<=57343?
(b+=4,++c):b+=3}return b},T=a=>{var b=R(a)+1,c=S(b);c&&P(a,c,b);return c};function U(){}var la=(a,b,c,d)=>{var g={string:k=>{var n=0;if(k!==null&&k!==void 0&&k!==0){n=R(k)+1;var X=V(n);P(k,X,n);n=X}return n},array:k=>{var n=V(k.length);A.set(k,n);return n}};a=e["_"+a];var f=[],p=0;if(d)for(var l=0;l<d.length;l++){var Y=g[c[l]];Y?(p===0&&(p=W()),f[l]=Y(d[l])):f[l]=d[l]}c=a(...f);return c=function(k){p!==0&&ka(p);return b==="string"?Q(k):b==="boolean"?!!k:k}(c)};
U=(a,b,c)=>{a=Q(a);b=b!==null?JSON.parse(Q(b)):[];try{let d=e.externalCall(a,b);return d?T(d):null}catch(d){return e.HEAPU8[c]=1,T(d.message)}};e.noExitRuntime&&(K=e.noExitRuntime);e.printErr&&(q=e.printErr);e.wasmBinary&&(r=e.wasmBinary);if(e.preInit)for(typeof e.preInit=="function"&&(e.preInit=[e.preInit]);e.preInit.length>0;)e.preInit.shift()();e.ccall=la;e.cwrap=(a,b,c,d)=>{var g=!c||c.every(f=>f==="number"||f==="boolean");return b!=="string"&&g&&!d?e["_"+a]:(...f)=>la(a,b,c,f,d)};
e.stringToNewUTF8=T;
var S,ma,ka,V,W,z,na={e:()=>E(""),a:()=>{K=!1;L=0},b:function(a,b){a=-9007199254740992>a||9007199254740992<a?NaN:Number(a);a=new Date(1E3*a);C[b>>2]=a.getSeconds();C[b+4>>2]=a.getMinutes();C[b+8>>2]=a.getHours();C[b+12>>2]=a.getDate();C[b+16>>2]=a.getMonth();C[b+20>>2]=a.getFullYear()-1900;C[b+24>>2]=a.getDay();var c=a.getFullYear();C[b+28>>2]=(0!==c%4||0===c%100&&0!==c%400?ha:fa)[a.getMonth()]+a.getDate()-1|0;C[b+36>>2]=-(60*a.getTimezoneOffset());c=(new Date(a.getFullYear(),6,1)).getTimezoneOffset();
var d=(new Date(a.getFullYear(),0,1)).getTimezoneOffset();C[b+32>>2]=(c!=d&&a.getTimezoneOffset()==Math.min(d,c))|0},i:(a,b)=>{M[a]&&(clearTimeout(M[a].id),delete M[a]);if(!b)return 0;var c=setTimeout(()=>{delete M[a];ia(()=>ma(a,performance.now()))},b);M[a]={id:c,A:b};return 0},c:(a,b,c,d)=>{var g=(new Date).getFullYear(),f=(new Date(g,0,1)).getTimezoneOffset();g=(new Date(g,6,1)).getTimezoneOffset();D[a>>2]=60*Math.max(f,g);C[b>>2]=Number(f!=g);b=p=>{var l=Math.abs(p);return`UTC${0<=p?"-":"+"}${String(Math.floor(l/
60)).padStart(2,"0")}${String(l%60).padStart(2,"0")}`};a=b(f);b=b(g);g<f?(P(a,c,17),P(b,d,17)):(P(a,d,17),P(b,c,17))},g:U,f:function(a,b){a=Q(a);let c;try{c=window.JSON.parse(a)}catch(d){c=a}0!==b?window.alert(a):window.console.log("DUMP",c)},d:()=>Date.now(),j:a=>{var b=B.length;a>>>=0;if(2147483648<a)return!1;for(var c=1;4>=c;c*=2){var d=b*(1+.2/c);d=Math.min(d,a+100663296);a:{d=(Math.min(2147483648,65536*Math.ceil(Math.max(a,d)/65536))-z.buffer.byteLength+65535)/65536|0;try{z.grow(d);y();var g=
1;break a}catch(f){}g=void 0}if(g)return!0}return!1},m:function(a){a=Q(a);window.console.log(a)},h:function(a){a=Q(a);return Date.parse(a)},l:function(a,b,c,d){a=Q(a);b=Q(b);c=Q(c);c=`Quickjs -- ${a}: ${b}\n${c}`;0!==d?window.alert(c):window.console.error(c)},k:O},Z;
Z=await (async function(){function a(c){c=Z=c.exports;e._evalInSandbox=c.p;e._nukeSandbox=c.q;e._init=c.r;e._commFun=c.s;e._dumpMemoryUse=c.t;S=c.u;e._free=c.v;ma=c.w;ka=c.x;V=c.y;W=c.z;z=c.n;y();return Z}var b={a:na};if(e.instantiateWasm)return new Promise(c=>{e.instantiateWasm(b,(d,g)=>{c(a(d,g))})});F??=e.locateFile?e.locateFile?e.locateFile("quickjs-eval.wasm",h):h+"quickjs-eval.wasm":(new URL("quickjs-eval.wasm",import.meta.url)).href;return a((await da(b)).instance)}());
(function(){function a(){e.calledRun=!0;if(!t){x=!0;Z.o();v?.(e);e.onRuntimeInitialized?.();if(e.postRun)for("function"==typeof e.postRun&&(e.postRun=[e.postRun]);e.postRun.length;){var b=e.postRun.shift();I.push(b)}H(I)}}if(e.preRun)for("function"==typeof e.preRun&&(e.preRun=[e.preRun]);e.preRun.length;)ea();H(J);e.setStatus?(e.setStatus("Running..."),setTimeout(()=>{setTimeout(()=>e.setStatus(""),1);a()},1)):a()})();x?moduleRtn=e:moduleRtn=new Promise((a,b)=>{v=a;w=b});
var S,ma,ka,V,W,z,na={e:()=>E(""),a:()=>{K=!1;L=0},b:function(a,b){a=a<-9007199254740992||a>9007199254740992?NaN:Number(a);a=new Date(a*1E3);C[b>>2]=a.getSeconds();C[b+4>>2]=a.getMinutes();C[b+8>>2]=a.getHours();C[b+12>>2]=a.getDate();C[b+16>>2]=a.getMonth();C[b+20>>2]=a.getFullYear()-1900;C[b+24>>2]=a.getDay();var c=a.getFullYear();C[b+28>>2]=(c%4!==0||c%100===0&&c%400!==0?ha:fa)[a.getMonth()]+a.getDate()-1|0;C[b+36>>2]=-(a.getTimezoneOffset()*60);c=(new Date(a.getFullYear(),6,1)).getTimezoneOffset();
var d=(new Date(a.getFullYear(),0,1)).getTimezoneOffset();C[b+32>>2]=(c!=d&&a.getTimezoneOffset()==Math.min(d,c))|0},i:(a,b)=>{M[a]&&(clearTimeout(M[a].id),delete M[a]);if(!b)return 0;var c=setTimeout(()=>{delete M[a];ia(()=>ma(a,performance.now()))},b);M[a]={id:c,A:b};return 0},c:(a,b,c,d)=>{var g=(new Date).getFullYear(),f=(new Date(g,0,1)).getTimezoneOffset();g=(new Date(g,6,1)).getTimezoneOffset();D[a>>2]=Math.max(f,g)*60;C[b>>2]=Number(f!=g);b=p=>{var l=Math.abs(p);return`UTC${p>=0?"-":"+"}${String(Math.floor(l/
60)).padStart(2,"0")}${String(l%60).padStart(2,"0")}`};a=b(f);b=b(g);g<f?(P(a,c,17),P(b,d,17)):(P(a,d,17),P(b,c,17))},g:U,f:function(a,b){a=Q(a);try{var c=window.JSON.parse(a)}catch(d){c=a}b!==0?window.alert(a):window.console.log("DUMP",c)},d:()=>Date.now(),j:a=>{var b=B.length;a>>>=0;if(a>2147483648)return!1;for(var c=1;c<=4;c*=2){var d=b*(1+.2/c);d=Math.min(d,a+100663296);a:{d=(Math.min(2147483648,Math.ceil(Math.max(a,d)/65536)*65536)-z.buffer.byteLength+65535)/65536|0;try{z.grow(d);y();var g=1;
break a}catch(f){}g=void 0}if(g)return!0}return!1},m:function(a){a=Q(a);window.console.log(a)},h:function(a){a=Q(a);return Date.parse(a)},l:function(a,b,c,d){a=Q(a);b=Q(b);c=Q(c);c=`Quickjs -- ${a}: ${b}\n${c}`;d!==0?window.alert(c):window.console.error(c)},k:O},Z;
Z=await (async function(){function a(c){c=Z=c.exports;e._evalInSandbox=c.p;e._nukeSandbox=c.q;e._init=c.r;e._commFun=c.s;e._dumpMemoryUse=c.t;S=c.u;e._free=c.v;ma=c.w;ka=c.x;V=c.y;W=c.z;z=c.n;y();return Z}var b={a:na};if(e.instantiateWasm)return new Promise(c=>{e.instantiateWasm(b,(d,g)=>{c(a(d,g))})});F??=e.locateFile?e.locateFile?e.locateFile("quickjs-eval.wasm",h):h+"quickjs-eval.wasm":(new URL("quickjs-eval.wasm",import.meta.url)).href;return function(c){return a(c.instance)}(await da(b))}());
(function(){function a(){e.calledRun=!0;if(!t){x=!0;Z.o();v?.(e);e.onRuntimeInitialized?.();if(e.postRun)for(typeof e.postRun=="function"&&(e.postRun=[e.postRun]);e.postRun.length;){var b=e.postRun.shift();I.push(b)}H(I)}}if(e.preRun)for(typeof e.preRun=="function"&&(e.preRun=[e.preRun]);e.preRun.length;)ea();H(J);e.setStatus?(e.setStatus("Running..."),setTimeout(()=>{setTimeout(()=>e.setStatus(""),1);a()},1)):a()})();x?moduleRtn=e:moduleRtn=new Promise((a,b)=>{v=a;w=b});
;return moduleRtn}export default QuickJS;
Binary file not shown.
@@ -0,0 +1,29 @@
// @vitest-environment node
import { resolve } from "node:path";
import { pathToFileURL } from "node:url";
import { describe, expect, it } from "vitest";
describe("vendored PDF.js bundle compatibility", () => {
it("loads when the browser does not provide the global Iterator helper", async () => {
const descriptor = Object.getOwnPropertyDescriptor(globalThis, "Iterator");
Object.defineProperty(globalThis, "Iterator", {
configurable: true,
value: undefined,
writable: true,
});
try {
const bundleURL = pathToFileURL(resolve(process.cwd(), "public/vendor/pdfjs/pdf.min.mjs"));
bundleURL.searchParams.set("iterator-compat", String(Date.now()));
const pdfjs = await import(bundleURL.href);
expect(pdfjs.version).toBe("6.2.108");
} finally {
if (descriptor) Object.defineProperty(globalThis, "Iterator", descriptor);
else delete (globalThis as Record<string, unknown>).Iterator;
}
});
});
+179
View File
@@ -0,0 +1,179 @@
import { readFileSync } from "node:fs";
import { resolve } from "node:path";
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
const mocks = vi.hoisted(() => ({
annotationLayerConstructor: vi.fn(),
annotationLayerRender: vi.fn(),
getDocument: vi.fn(),
textLayerRender: vi.fn(),
}));
vi.mock("@pdfjs/pdf.min.mjs", () => {
class AnnotationLayer {
constructor(options: unknown) {
mocks.annotationLayerConstructor(options);
}
render(options: unknown) {
return mocks.annotationLayerRender(options);
}
}
class PDFDataRangeTransport {
requestDataRange?: (begin: number, end: number) => void;
onDataRange = vi.fn();
constructor(
readonly length: number,
readonly initialData: unknown[],
) {}
}
class TextLayer {
render() {
return mocks.textLayerRender();
}
}
(
globalThis as typeof globalThis & {
pdfjsLib?: Record<string, unknown>;
}
).pdfjsLib = {
AnnotationLayer,
GlobalWorkerOptions: {},
PDFDataRangeTransport,
TextLayer,
getDocument: mocks.getDocument,
};
return {};
});
// Import the vendored source directly so Vitest applies the app's @pdfjs alias
// instead of externalizing the local package through Node's module loader.
// @ts-expect-error The vendored JavaScript module does not ship TypeScript declarations.
import { makePDF } from "../../vendor/foliate-js/pdf.js";
describe("PDF reader security", () => {
beforeEach(() => {
mocks.annotationLayerConstructor.mockReset();
mocks.annotationLayerRender.mockReset().mockResolvedValue(undefined);
mocks.getDocument.mockReset();
mocks.textLayerRender.mockReset().mockResolvedValue(undefined);
});
afterEach(() => {
vi.unstubAllGlobals();
});
it("disables embedded PDF scripting at the PDF.js boundary", async () => {
const firstPage = {
getViewport: vi.fn(() => ({ height: 792, width: 612 })),
};
mocks.getDocument.mockReturnValue({
promise: Promise.resolve({
destroy: vi.fn(),
getMetadata: vi.fn(async () => ({ info: {}, metadata: null })),
getOutline: vi.fn(async () => null),
getPage: vi.fn(async () => firstPage),
numPages: 1,
}),
});
await makePDF(new File(["%PDF-1.7"], "safe.pdf", { type: "application/pdf" }));
expect(mocks.getDocument).toHaveBeenCalledWith(
expect.objectContaining({
enableScripting: false,
isEvalSupported: false,
}),
);
});
it("destroys the PDF.js loading task when the book closes", async () => {
const destroy = vi.fn();
const firstPage = {
getViewport: vi.fn(() => ({ height: 792, width: 612 })),
};
mocks.getDocument.mockReturnValue({
destroy,
promise: Promise.resolve({
getMetadata: vi.fn(async () => ({ info: {}, metadata: null })),
getOutline: vi.fn(async () => null),
getPage: vi.fn(async () => firstPage),
numPages: 1,
}),
});
const book = await makePDF(new File(["%PDF-1.7"], "safe.pdf", { type: "application/pdf" }));
await book.destroy();
expect(destroy).toHaveBeenCalledOnce();
});
it("provides PDF.js 6 annotation layers with attachment content", async () => {
vi.stubGlobal(
"fetch",
vi.fn(async () => ({ text: async () => ".textLayer{}.annotationLayer{}" })),
);
const attachment = new Uint8Array([1, 2, 3]);
const getAttachmentContent = vi.fn(async () => attachment);
const page = {
cleanup: vi.fn(),
getAnnotations: vi.fn(async () => []),
getViewport: vi.fn(() => ({ height: 792, width: 612 })),
render: vi.fn(() => ({ cancel: vi.fn(), promise: Promise.resolve() })),
streamTextContent: vi.fn(async () => ({})),
};
mocks.getDocument.mockReturnValue({
destroy: vi.fn(),
promise: Promise.resolve({
getAttachmentContent,
getMetadata: vi.fn(async () => ({ info: {}, metadata: null })),
getOutline: vi.fn(async () => null),
getPage: vi.fn(async () => page),
numPages: 1,
}),
});
const book = await makePDF(new File(["%PDF-1.7"], "safe.pdf", { type: "application/pdf" }));
const section = await book.sections[0].load();
const iframe = document.createElement("iframe");
document.body.append(iframe);
const doc = iframe.contentDocument;
if (!doc) throw new Error("missing iframe document");
doc.body.innerHTML =
'<div id="canvas"></div><div class="textLayer"></div><div class="annotationLayer"></div>';
await section.onZoom({ doc, scale: 1 });
const annotationOptions = mocks.annotationLayerConstructor.mock.calls[0]?.[0];
expect(annotationOptions).toBeDefined();
if (!annotationOptions) throw new Error("PDF.js did not construct an annotation layer");
const { linkService } = annotationOptions as {
linkService: { getAttachmentContent: (id: string) => Promise<Uint8Array | null> };
};
await expect(linkService.getAttachmentContent("attachment-1")).resolves.toBe(attachment);
expect(getAttachmentContent).toHaveBeenCalledWith("attachment-1");
iframe.remove();
await book.destroy();
});
it("ships only the PDF.js layers used by the embedded reader", () => {
const pdfLayerCSS = readFileSync(
resolve(process.cwd(), "public/vendor/pdfjs/pdf_layers.css"),
"utf8",
);
expect(pdfLayerCSS).toContain(".textLayer{");
expect(pdfLayerCSS).toContain(".textLayerImages{");
expect(pdfLayerCSS).toContain(".annotationLayer{");
expect(pdfLayerCSS).not.toMatch(
/\.(?:annotationEditorLayer|dialog|pdfViewer|sidebar|toolbar|xfaLayer)\b/,
);
});
});
+1 -1
View File
@@ -24,7 +24,7 @@
"fflate": "^0.8.2",
"fs-extra": "^11.2.0",
"globals": "^15.9.0",
"pdfjs-dist": "^5.4.530",
"pdfjs-dist": "^6.2.108",
"rollup": "^4.22.4"
},
"scripts": {
+25 -22
View File
@@ -6,8 +6,7 @@ pdfjsLib.GlobalWorkerOptions.workerSrc = pdfjsPath('pdf.worker.min.mjs')
const fetchText = async url => await (await fetch(url)).text()
let textLayerBuilderCSS = null
let annotationLayerBuilderCSS = null
let pdfLayerCSS = null
// Track active render tasks per iframe document to cancel superseded renders
const activeRenderTasks = new WeakMap()
@@ -130,7 +129,7 @@ const setupPanningEvents = (doc) => {
container.style.cursor = 'grab'
}
const render = async (page, doc, zoom, pageColors) => {
const render = async (page, doc, zoom, pageColors, getAttachmentContent) => {
if (!doc) return
// Increment generation to invalidate any in-progress render for this doc
@@ -158,8 +157,7 @@ const render = async (page, doc, zoom, pageColors) => {
const canvas = document.createElement('canvas')
canvas.height = viewport.height
canvas.width = viewport.width
const canvasContext = canvas.getContext('2d')
const renderTask = page.render({ canvasContext, viewport, pageColors })
const renderTask = page.render({ canvas, viewport, pageColors })
activeRenderTasks.set(doc, renderTask)
try {
@@ -237,20 +235,20 @@ const render = async (page, doc, zoom, pageColors) => {
goToDestination: () => {},
getDestinationHash: dest => JSON.stringify(dest),
addLinkAttributes: (link, url) => link.href = url,
getAttachmentContent,
}
await new pdfjsLib.AnnotationLayer({ page, viewport, div, linkService }).render({
annotations: await page.getAnnotations(),
})
}
const renderPage = async (page, getImageBlob) => {
const renderPage = async (page, getImageBlob, getAttachmentContent) => {
const viewport = page.getViewport({ scale: 1 })
if (getImageBlob) {
const canvas = document.createElement('canvas')
canvas.height = viewport.height
canvas.width = viewport.width
const canvasContext = canvas.getContext('2d')
await page.render({ canvasContext, viewport }).promise
await page.render({ canvas, viewport }).promise
return new Promise(resolve => canvas.toBlob(blob => {
// Release canvas bitmap memory after extracting the blob
canvas.width = 0
@@ -258,13 +256,8 @@ const renderPage = async (page, getImageBlob) => {
resolve(blob)
}))
}
// https://github.com/mozilla/pdf.js/blob/642b9a5ae67ef642b9a8808fd9efd447e8c350e2/web/text_layer_builder.css
if (textLayerBuilderCSS == null) {
textLayerBuilderCSS = await fetchText(pdfjsPath('text_layer_builder.css'))
}
// https://github.com/mozilla/pdf.js/blob/642b9a5ae67ef642b9a8808fd9efd447e8c350e2/web/annotation_layer_builder.css
if (annotationLayerBuilderCSS == null) {
annotationLayerBuilderCSS = await fetchText(pdfjsPath('annotation_layer_builder.css'))
if (pdfLayerCSS == null) {
pdfLayerCSS = await fetchText(pdfjsPath('pdf_layers.css'))
}
const data = `
<!DOCTYPE html>
@@ -276,15 +269,15 @@ const renderPage = async (page, getImageBlob) => {
margin: 0;
padding: 0;
}
${textLayerBuilderCSS}
${annotationLayerBuilderCSS}
${pdfLayerCSS}
</style>
<div id="canvas"></div>
<div class="textLayer"></div>
<div class="annotationLayer"></div>
`
const src = URL.createObjectURL(new Blob([data], { type: 'text/html' }))
const onZoom = ({ doc, scale, pageColors }) => render(page, doc, scale, pageColors)
const onZoom = ({ doc, scale, pageColors }) =>
render(page, doc, scale, pageColors, getAttachmentContent)
return { src, data, onZoom }
}
@@ -352,13 +345,23 @@ export const makePDF = async file => {
transport.onDataRange(begin, chunk)
})
}
const pdf = await pdfjsLib.getDocument({
const loadingTask = pdfjsLib.getDocument({
range: transport,
wasmUrl: pdfjsPath(''),
cMapUrl: pdfjsPath('cmaps/'),
standardFontDataUrl: pdfjsPath('standard_fonts/'),
enableScripting: false,
isEvalSupported: false,
}).promise
})
const pdf = await loadingTask.promise
const getAttachmentContent = async id => {
try {
return await pdf.getAttachmentContent(id)
} catch (error) {
console.warn(`Unable to load PDF attachment content: ${error}`)
return null
}
}
// Get viewport dimensions from first page for fixed-layout rendering
const firstPage = await pdf.getPage(1)
@@ -422,7 +425,7 @@ export const makePDF = async file => {
cache.set(i, cached)
return cached
}
const url = await renderPage(await getPage(i))
const url = await renderPage(await getPage(i), false, getAttachmentContent)
cache.set(i, url)
// Evict oldest render results when over limit
@@ -507,7 +510,7 @@ export const makePDF = async file => {
page?.cleanup()
}
pageCache.clear()
pdf.destroy()
return loadingTask.destroy()
}
return book
}