feat: retire oCIS — the hub runs entirely on R2 object storage

Files payloads moved to R2 in 041; this removes the remaining oCIS coupling:
- delete the oCIS WebDAV client; verifyWhileStreaming moves to its own
  storage-agnostic module (verify-stream.ts)
- group-files: storage_key is the only payload source; legacy rows answer
  'retired storage' instead of touching oCIS
- collective share: the ocis-resource item kind is gone (peertube links stay);
  share-into-library was R2-backed since the previous commit
- import-drive endpoint removed (no web caller); import-chat (homeserver) stays
- web: Drive tab + embedded oCIS page removed; Library is the Files view
Legacy e2e rows (2) deleted; every remaining archive row is R2-backed.
This commit is contained in:
glass beadian 2026-10-16 01:32:56 +00:00
parent 4cbb63920a
commit e7bf870de9
13 changed files with 88 additions and 750 deletions

View file

@ -31,26 +31,13 @@ import type { MimeClass as ValidationMimeClass } from "./group-files.validation.
export const SHARE_TARGETS = ["library", "open-room", "both"] as const;
export type ShareTarget = (typeof SHARE_TARGETS)[number];
export const SHARE_ITEM_KINDS = ["ocis-resource", "peertube-video"] as const;
export const SHARE_ITEM_KINDS = ["peertube-video"] as const;
export type ShareItemKind = (typeof SHARE_ITEM_KINDS)[number];
/** Per-request caps; a share is a person acting on a handful of items, not a bulk ingest. */
export const MAX_SHARE_ITEMS = 20;
export const MAX_NOTE_LENGTH = 500;
export const MAX_TITLE_LENGTH = 200;
/** Collision suffix ceiling: stem-1 … stem-100, then a per-item error. */
export const MAX_COLLISION_ATTEMPTS = 100;
export interface OcisResourceItem {
readonly kind: "ocis-resource";
/**
* dav path RELATIVE to /remote.php/dav/files/<FILES_OCID_USER>/ — the hub's
* own conventions: `hub-resources/<resourceId>` (a row of the group files
* index) or a group folder path `hub-groups/<groupId>/<name>`.
*/
readonly path: string;
}
export interface PeertubeVideoItem {
readonly kind: "peertube-video";
/** Canonical video URL (…/w/:id, /videos/watch/:id or /videos/embed/:id). */
@ -58,7 +45,7 @@ export interface PeertubeVideoItem {
readonly title: string;
}
export type CollectiveShareItem = OcisResourceItem | PeertubeVideoItem;
export type CollectiveShareItem = PeertubeVideoItem;
export interface CollectiveShareInput {
readonly target: ShareTarget;
@ -148,14 +135,6 @@ function parseItem(value: unknown, index: number): CollectiveShareItem {
}
const record = value as Record<string, unknown>;
const kind = record.kind;
if (kind === "ocis-resource") {
if (typeof record.path !== "string" || record.path.trim() === "") {
throw new BadRequestException(`items[${index}].path must be a non-empty string`);
}
// Segment shape is validated here so a traversal attempt never reaches the service.
davSegments(record.path, `items[${index}].path`);
return { kind, path: record.path.trim() };
}
if (kind === "peertube-video") {
const title = boundedText(record.title, `items[${index}].title`, MAX_TITLE_LENGTH);
if (title === null) throw new BadRequestException(`items[${index}].title must be a non-empty string`);