Integrate group files: nullable room for uploads, archive class, claim idempotency, upload route

Wires the three parallel group-cloud tracks to one surface and fixes the
seams between them:

- chat_media_archive.room_id becomes nullable (direct web uploads have no
  Matrix room yet — the contract's null-event pattern extends to the room);
  core GroupFile.roomId and ArchiveEntryInput.roomId follow.
- mime_class gains 'archive' (zip) across the 029 CHECK, validation
  MIME_CLASSES and the bot classifier — one vocabulary everywhere.
- registerArchiveEntry claim keys are null-safe for room-less uploads.
- New: POST /files/groups/:groupId/upload — FileInterceptor (20 MiB) streams
  through magic-byte sniffing, library-safe naming, oCIS upload and the
  metadata index, behind group-membership ACL (Owner/Admin bypass).
- safeFileName/sniffMime promoted to packages/core (file-names.ts,
  file-mime.ts) so the bot and the api share one implementation; the bot's
  local modules become re-export shims; @types/node added to core.

Verified: api typecheck clean, group-files 22/22, bot 74/74, web typecheck
clean; 029 re-applied clean on a fresh scratch DB (room_id nullable,
archive class, claim_key unique all confirmed in the catalog).
This commit is contained in:
glass beadian 2026-10-11 10:09:24 +00:00
parent 688a2ce996
commit e7e703c105
21 changed files with 473 additions and 227 deletions

101
pnpm-lock.yaml generated
View file

@ -315,7 +315,7 @@ importers:
version: 5.9.3
vitest:
specifier: ^2.0.5
version: 2.1.9(@types/node@22.20.5)(lightningcss@1.32.0)(terser@5.51.2)
version: 2.1.9(@types/node@26.6.5)(lightningcss@1.32.0)(terser@5.51.2)
packages/connector-facebook:
dependencies:
@ -331,7 +331,7 @@ importers:
version: 5.9.3
vitest:
specifier: ^2.0.5
version: 2.1.9(@types/node@22.20.5)(lightningcss@1.32.0)(terser@5.51.2)
version: 2.1.9(@types/node@26.6.5)(lightningcss@1.32.0)(terser@5.51.2)
packages/connector-instagram:
dependencies:
@ -404,7 +404,7 @@ importers:
version: 5.9.3
vitest:
specifier: ^2.0.5
version: 2.1.9(@types/node@22.20.5)(lightningcss@1.32.0)(terser@5.51.2)
version: 2.1.9(@types/node@26.6.5)(lightningcss@1.32.0)(terser@5.51.2)
packages/connector-mock-social:
dependencies:
@ -420,7 +420,7 @@ importers:
version: 5.9.3
vitest:
specifier: ^2.0.5
version: 2.1.9(@types/node@22.20.5)(lightningcss@1.32.0)(terser@5.51.2)
version: 2.1.9(@types/node@26.6.5)(lightningcss@1.32.0)(terser@5.51.2)
packages/connector-mock-video:
dependencies:
@ -436,7 +436,7 @@ importers:
version: 5.9.3
vitest:
specifier: ^2.0.5
version: 2.1.9(@types/node@22.20.5)(lightningcss@1.32.0)(terser@5.51.2)
version: 2.1.9(@types/node@26.6.5)(lightningcss@1.32.0)(terser@5.51.2)
packages/connector-peertube:
dependencies:
@ -518,7 +518,7 @@ importers:
version: 5.9.3
vitest:
specifier: ^2.0.5
version: 2.1.9(@types/node@22.20.5)(lightningcss@1.32.0)(terser@5.51.2)
version: 2.1.9(@types/node@26.6.5)(lightningcss@1.32.0)(terser@5.51.2)
packages/connector-slack:
dependencies:
@ -598,12 +598,15 @@ importers:
packages/core:
devDependencies:
'@types/node':
specifier: ^26.6.5
version: 26.6.5
typescript:
specifier: ^5.5.4
version: 5.9.3
vitest:
specifier: ^2.0.5
version: 2.1.9(@types/node@22.20.5)(lightningcss@1.32.0)(terser@5.51.2)
version: 2.1.9(@types/node@26.6.5)(lightningcss@1.32.0)(terser@5.51.2)
packages/egress:
dependencies:
@ -2686,6 +2689,9 @@ packages:
'@types/node@22.20.5':
resolution: {integrity: sha512-U2+DNr+wSjpsTS/wZGYHq7GcwfuSmKiKvoPvK22zwTlRhU91yOniN4qRR5KhIjvif7ysw/dz/hKmfDH0Ris4aA==}
'@types/node@26.6.5':
resolution: {integrity: sha512-uMzsv9stDdofIZBx4UGh4Z9ZgXnGC9seRDscilBcTHAeOFk67MZg/k9bWVfO+bk4qZmG+l52hRnLwUiH2LnJTg==}
'@types/pg-pool@2.0.7':
resolution: {integrity: sha512-U4CwmGVQcbEuqpyju8/ptOKg6gEC+Tqsvj2xS9o1g71bUh8twxnC6ZL5rZKCsGN0iyH0CwgUyc9VR5owNQF9Ng==}
@ -4416,6 +4422,9 @@ packages:
undici-types@6.21.0:
resolution: {integrity: sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==}
undici-types@8.9.0:
resolution: {integrity: sha512-KTDyRTYX8sWmKXAikPHHSyc63CRPETMctyjKFupcC6OBLXT3xsN0e9aF7m+mIXutFWpUXuedtowG7iLOzp0kQg==}
unionfs@4.6.0:
resolution: {integrity: sha512-fJAy3gTHjFi5S3TP5EGdjs/OUMFFvI/ady3T8qVuZfkv8Qi8prV/Q8BuFEgODJslhZTT2z2qdD2lGdee9qjEnA==}
@ -6696,6 +6705,10 @@ snapshots:
dependencies:
undici-types: 6.21.0
'@types/node@26.6.5':
dependencies:
undici-types: 8.9.0
'@types/pg-pool@2.0.7':
dependencies:
'@types/pg': 8.23.1
@ -6850,6 +6863,14 @@ snapshots:
optionalDependencies:
vite: 5.4.21(@types/node@22.20.5)(lightningcss@1.32.0)(terser@5.51.2)
'@vitest/mocker@2.1.9(vite@5.4.21(@types/node@26.6.5)(lightningcss@1.32.0)(terser@5.51.2))':
dependencies:
'@vitest/spy': 2.1.9
estree-walker: 3.0.3
magic-string: 0.30.21
optionalDependencies:
vite: 5.4.21(@types/node@26.6.5)(lightningcss@1.32.0)(terser@5.51.2)
'@vitest/pretty-format@2.1.9':
dependencies:
tinyrainbow: 1.2.0
@ -8508,6 +8529,8 @@ snapshots:
undici-types@6.21.0: {}
undici-types@8.9.0: {}
unionfs@4.6.0:
dependencies:
fs-monkey: 1.1.0
@ -8569,6 +8592,24 @@ snapshots:
- supports-color
- terser
vite-node@2.1.9(@types/node@26.6.5)(lightningcss@1.32.0)(terser@5.51.2):
dependencies:
cac: 6.7.14
debug: 4.4.3
es-module-lexer: 1.7.0
pathe: 1.1.2
vite: 5.4.21(@types/node@26.6.5)(lightningcss@1.32.0)(terser@5.51.2)
transitivePeerDependencies:
- '@types/node'
- less
- lightningcss
- sass
- sass-embedded
- stylus
- sugarss
- supports-color
- terser
vite@5.4.21(@types/node@22.20.5)(lightningcss@1.32.0)(terser@5.51.2):
dependencies:
esbuild: 0.21.5
@ -8580,6 +8621,17 @@ snapshots:
lightningcss: 1.32.0
terser: 5.51.2
vite@5.4.21(@types/node@26.6.5)(lightningcss@1.32.0)(terser@5.51.2):
dependencies:
esbuild: 0.21.5
postcss: 8.5.29
rollup: 4.64.0
optionalDependencies:
'@types/node': 26.6.5
fsevents: 2.3.3
lightningcss: 1.32.0
terser: 5.51.2
vitest@2.1.9(@types/node@22.20.5)(lightningcss@1.32.0)(terser@5.51.2):
dependencies:
'@vitest/expect': 2.1.9
@ -8615,6 +8667,41 @@ snapshots:
- supports-color
- terser
vitest@2.1.9(@types/node@26.6.5)(lightningcss@1.32.0)(terser@5.51.2):
dependencies:
'@vitest/expect': 2.1.9
'@vitest/mocker': 2.1.9(vite@5.4.21(@types/node@26.6.5)(lightningcss@1.32.0)(terser@5.51.2))
'@vitest/pretty-format': 2.1.9
'@vitest/runner': 2.1.9
'@vitest/snapshot': 2.1.9
'@vitest/spy': 2.1.9
'@vitest/utils': 2.1.9
chai: 5.3.3
debug: 4.4.3
expect-type: 1.4.0
magic-string: 0.30.21
pathe: 1.1.2
std-env: 3.10.0
tinybench: 2.9.0
tinyexec: 0.3.2
tinypool: 1.1.1
tinyrainbow: 1.2.0
vite: 5.4.21(@types/node@26.6.5)(lightningcss@1.32.0)(terser@5.51.2)
vite-node: 2.1.9(@types/node@26.6.5)(lightningcss@1.32.0)(terser@5.51.2)
why-is-node-running: 2.3.0
optionalDependencies:
'@types/node': 26.6.5
transitivePeerDependencies:
- less
- lightningcss
- msw
- sass
- sass-embedded
- stylus
- sugarss
- supports-color
- terser
w3c-keyname@2.2.8: {}
watchpack@2.5.2: