feat(browser-ext): move browser extension to browser-ext/ and update API client to tRPC

- Create browser-ext/ with full extension code (MV3 manifest, background
  service worker, content script, popup, options page)
- Add tRPC API client that communicates with unified monolith endpoints
- Implement cache, settings, and phishing detection utilities
- Create extension tRPC router in web app (getAuthStatus, linkDevice,
  reportPhishing)
- Configure Vite build with manifest V3 support
- Write unit tests for cache, phishing detector, and API client
- All 20 tests passing, TypeScript lint clean
This commit is contained in:
2026-05-25 18:13:44 -04:00
parent 20dc5bf785
commit b03096f19d
30 changed files with 1474 additions and 5 deletions

166
pnpm-lock.yaml generated
View File

@@ -24,7 +24,30 @@ importers:
specifier: ^4.1.5
version: 4.1.7(@opentelemetry/api@1.9.1)(@types/node@25.9.1)(@vitest/coverage-v8@4.1.7)(jsdom@29.1.1)(vite@7.3.3(@types/node@25.9.1)(jiti@2.7.0)(lightningcss@1.32.0)(terser@5.48.0)(tsx@4.22.3))
browser-ext: {}
browser-ext:
dependencies:
'@trpc/client':
specifier: ^10.45.2
version: 10.45.4(@trpc/server@10.45.4)
'@trpc/server':
specifier: ^10.45.2
version: 10.45.4
superjson:
specifier: ^2.2.1
version: 2.2.6
devDependencies:
'@types/chrome':
specifier: ^0.0.280
version: 0.0.280
typescript:
specifier: ^5.7.0
version: 5.9.3
vite:
specifier: ^6.0.0
version: 6.4.2(@types/node@25.9.1)(jiti@2.7.0)(lightningcss@1.32.0)(terser@5.48.0)(tsx@4.22.3)
vitest:
specifier: ^4.1.5
version: 4.1.7(@opentelemetry/api@1.9.1)(@types/node@25.9.1)(@vitest/coverage-v8@4.1.7)(jsdom@29.1.1)(vite@6.4.2(@types/node@25.9.1)(jiti@2.7.0)(lightningcss@1.32.0)(terser@5.48.0)(tsx@4.22.3))
web:
dependencies:
@@ -1824,6 +1847,9 @@ packages:
'@types/chai@5.2.3':
resolution: {integrity: sha512-Mw558oeA9fFbv65/y4mHtXDs9bPnFMZAL/jxdPFUpOHHIXX91mcgEHbS5Lahr+pwZFR8A7GQleRWeI6cGFC2UA==}
'@types/chrome@0.0.280':
resolution: {integrity: sha512-AotSmZrL9bcZDDmSI1D9dE7PGbhOur5L0cKxXd7IqbVizQWCY4gcvupPUVsQ4FfDj3V2tt/iOpomT9EY0s+w1g==}
'@types/deep-eql@4.0.2':
resolution: {integrity: sha512-c9h9dVVMigMPc4bwTvC5dxqtqJZwQPePsWjPlpSOnojbor6pGqdk541lfA7AqFQr5pB1BRdq0juY9db81BwyFw==}
@@ -1833,6 +1859,15 @@ packages:
'@types/estree@1.0.9':
resolution: {integrity: sha512-GhdPgy1el4/ImP05X05Uw4cw2/M93BCUmnEvWZNStlCzEKME4Fkk+YpoA5OiHNQmoS7Cafb8Xa3Pya8m1Qrzeg==}
'@types/filesystem@0.0.36':
resolution: {integrity: sha512-vPDXOZuannb9FZdxgHnqSwAG/jvdGM8Wq+6N4D/d80z+D4HWH+bItqsZaVRQykAn6WEVeEkLm2oQigyHtgb0RA==}
'@types/filewriter@0.0.33':
resolution: {integrity: sha512-xFU8ZXTw4gd358lb2jw25nxY9QAgqn2+bKKjKOYfNCzN4DKCFetK7sPtrlpg66Ywe3vWY9FNxprZawAh9wfJ3g==}
'@types/har-format@1.2.16':
resolution: {integrity: sha512-fluxdy7ryD3MV6h8pTfTYpy/xQzCFC7m89nOH9y94cNqJ1mDIDPut7MnRHI3F6qRmh/cT2fUjG1MLdCNb4hE9A==}
'@types/hast@3.0.4':
resolution: {integrity: sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ==}
@@ -2301,6 +2336,10 @@ packages:
resolution: {integrity: sha512-9Kr/j4O16ISv8zBBhJoi4bXOYNTkFLOqSL3UDB0njXxCXNezjeyVrJyGOWtgfs/q2km1gwBcfH8q1yEGoMYunA==}
engines: {node: '>=18'}
copy-anything@4.0.5:
resolution: {integrity: sha512-7Vv6asjS4gMOuILabD3l739tsaxFQmC+a7pLZm02zyvs8p977bL3zEgq3yDk5rn9B0PbYgIv++jmHcuUab4RhA==}
engines: {node: '>=18'}
core-util-is@1.0.3:
resolution: {integrity: sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==}
@@ -3066,6 +3105,10 @@ packages:
resolution: {integrity: sha512-ZhMwEosbFJkA0YhFnNDgTM4ZxDRsS6HqTo7qsZM08fehyRYIYa0yHu5R6mgo1n/8MgaPBXiPimPD77baVFYg+A==}
engines: {node: '>=12.13'}
is-what@5.5.0:
resolution: {integrity: sha512-oG7cgbmg5kLYae2N5IVd3jm2s+vldjxJzK1pcu9LfpGuQ93MQSzo0okvRna+7y5ifrD+20FE8FvjusyGaz14fw==}
engines: {node: '>=18'}
is-wsl@3.1.1:
resolution: {integrity: sha512-e6rvdUCiQCAuumZslxRJWR/Doq4VpPR82kqclvcS0efgt430SlGIk05vdCN58+VrzgtIcfNODjozVielycD4Sw==}
engines: {node: '>=16'}
@@ -4097,6 +4140,10 @@ packages:
stubs@3.0.0:
resolution: {integrity: sha512-PdHt7hHUJKxvTCgbKX9C1V/ftOcjJQgz8BZwNfV5c4B6dcGqlpelTbJ999jBGZ2jYiPAwcX5dP6oBwVlBlUbxw==}
superjson@2.2.6:
resolution: {integrity: sha512-H+ue8Zo4vJmV2nRjpx86P35lzwDT3nItnIsocgumgr0hHMQ+ZGq5vrERg9kJBo5AWGmxZDhzDo+WVIJqkB0cGA==}
engines: {node: '>=16'}
supports-color@10.2.2:
resolution: {integrity: sha512-SS+jx45GF1QjgEXQx4NJZV9ImqmO2NPz5FNsIHrsDjh2YsHnawpan7SNQ1o8NuhrbHZy9AZhIoCUiCeaW/C80g==}
engines: {node: '>=18'}
@@ -4434,6 +4481,46 @@ packages:
'@testing-library/jest-dom':
optional: true
vite@6.4.2:
resolution: {integrity: sha512-2N/55r4JDJ4gdrCvGgINMy+HH3iRpNIz8K6SFwVsA+JbQScLiC+clmAxBgwiSPgcG9U15QmvqCGWzMbqda5zGQ==}
engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0}
hasBin: true
peerDependencies:
'@types/node': ^18.0.0 || ^20.0.0 || >=22.0.0
jiti: '>=1.21.0'
less: '*'
lightningcss: ^1.21.0
sass: '*'
sass-embedded: '*'
stylus: '*'
sugarss: '*'
terser: ^5.16.0
tsx: ^4.8.1
yaml: ^2.4.2
peerDependenciesMeta:
'@types/node':
optional: true
jiti:
optional: true
less:
optional: true
lightningcss:
optional: true
sass:
optional: true
sass-embedded:
optional: true
stylus:
optional: true
sugarss:
optional: true
terser:
optional: true
tsx:
optional: true
yaml:
optional: true
vite@7.3.3:
resolution: {integrity: sha512-/4XH147Ui7OGTjg3HbdWe5arnZQSbfuRzdr9Ec7TQi5I7R+ir0Rlc9GIvD4v0XZurELqA035KVXJXpR61xhiTA==}
engines: {node: ^20.19.0 || >=22.12.0}
@@ -6138,12 +6225,25 @@ snapshots:
'@types/deep-eql': 4.0.2
assertion-error: 2.0.1
'@types/chrome@0.0.280':
dependencies:
'@types/filesystem': 0.0.36
'@types/har-format': 1.2.16
'@types/deep-eql@4.0.2': {}
'@types/estree@1.0.8': {}
'@types/estree@1.0.9': {}
'@types/filesystem@0.0.36':
dependencies:
'@types/filewriter': 0.0.33
'@types/filewriter@0.0.33': {}
'@types/har-format@1.2.16': {}
'@types/hast@3.0.4':
dependencies:
'@types/unist': 3.0.3
@@ -6264,6 +6364,14 @@ snapshots:
chai: 6.2.2
tinyrainbow: 3.1.0
'@vitest/mocker@4.1.7(vite@6.4.2(@types/node@25.9.1)(jiti@2.7.0)(lightningcss@1.32.0)(terser@5.48.0)(tsx@4.22.3))':
dependencies:
'@vitest/spy': 4.1.7
estree-walker: 3.0.3
magic-string: 0.30.21
optionalDependencies:
vite: 6.4.2(@types/node@25.9.1)(jiti@2.7.0)(lightningcss@1.32.0)(terser@5.48.0)(tsx@4.22.3)
'@vitest/mocker@4.1.7(vite@7.3.3(@types/node@25.9.1)(jiti@2.7.0)(lightningcss@1.32.0)(terser@5.48.0)(tsx@4.22.3))':
dependencies:
'@vitest/spy': 4.1.7
@@ -6645,6 +6753,10 @@ snapshots:
cookie@1.0.2: {}
copy-anything@4.0.5:
dependencies:
is-what: 5.5.0
core-util-is@1.0.3: {}
cosmiconfig@9.0.1(typescript@5.9.3):
@@ -7439,6 +7551,8 @@ snapshots:
is-what@4.1.16: {}
is-what@5.5.0: {}
is-wsl@3.1.1:
dependencies:
is-inside-container: 1.0.0
@@ -8626,6 +8740,10 @@ snapshots:
stubs@3.0.0:
optional: true
superjson@2.2.6:
dependencies:
copy-anything: 4.0.5
supports-color@10.2.2: {}
supports-color@7.2.0:
@@ -8966,6 +9084,22 @@ snapshots:
transitivePeerDependencies:
- supports-color
vite@6.4.2(@types/node@25.9.1)(jiti@2.7.0)(lightningcss@1.32.0)(terser@5.48.0)(tsx@4.22.3):
dependencies:
esbuild: 0.25.12
fdir: 6.5.0(picomatch@4.0.4)
picomatch: 4.0.4
postcss: 8.5.15
rollup: 4.60.4
tinyglobby: 0.2.16
optionalDependencies:
'@types/node': 25.9.1
fsevents: 2.3.3
jiti: 2.7.0
lightningcss: 1.32.0
terser: 5.48.0
tsx: 4.22.3
vite@7.3.3(@types/node@25.9.1)(jiti@2.7.0)(lightningcss@1.32.0)(terser@5.48.0)(tsx@4.22.3):
dependencies:
esbuild: 0.27.7
@@ -8986,6 +9120,36 @@ snapshots:
optionalDependencies:
vite: 7.3.3(@types/node@25.9.1)(jiti@2.7.0)(lightningcss@1.32.0)(terser@5.48.0)(tsx@4.22.3)
vitest@4.1.7(@opentelemetry/api@1.9.1)(@types/node@25.9.1)(@vitest/coverage-v8@4.1.7)(jsdom@29.1.1)(vite@6.4.2(@types/node@25.9.1)(jiti@2.7.0)(lightningcss@1.32.0)(terser@5.48.0)(tsx@4.22.3)):
dependencies:
'@vitest/expect': 4.1.7
'@vitest/mocker': 4.1.7(vite@6.4.2(@types/node@25.9.1)(jiti@2.7.0)(lightningcss@1.32.0)(terser@5.48.0)(tsx@4.22.3))
'@vitest/pretty-format': 4.1.7
'@vitest/runner': 4.1.7
'@vitest/snapshot': 4.1.7
'@vitest/spy': 4.1.7
'@vitest/utils': 4.1.7
es-module-lexer: 2.1.0
expect-type: 1.3.0
magic-string: 0.30.21
obug: 2.1.1
pathe: 2.0.3
picomatch: 4.0.4
std-env: 4.1.0
tinybench: 2.9.0
tinyexec: 1.2.2
tinyglobby: 0.2.16
tinyrainbow: 3.1.0
vite: 6.4.2(@types/node@25.9.1)(jiti@2.7.0)(lightningcss@1.32.0)(terser@5.48.0)(tsx@4.22.3)
why-is-node-running: 2.3.0
optionalDependencies:
'@opentelemetry/api': 1.9.1
'@types/node': 25.9.1
'@vitest/coverage-v8': 4.1.7(vitest@4.1.7)
jsdom: 29.1.1
transitivePeerDependencies:
- msw
vitest@4.1.7(@opentelemetry/api@1.9.1)(@types/node@25.9.1)(@vitest/coverage-v8@4.1.7)(jsdom@29.1.1)(vite@7.3.3(@types/node@25.9.1)(jiti@2.7.0)(lightningcss@1.32.0)(terser@5.48.0)(tsx@4.22.3)):
dependencies:
'@vitest/expect': 4.1.7