feat(drive): expose authorized typed Workspace Drive API

T-722: reuse T-721 storage/CAS/receipts with clone-bound transaction authorization against attached Server authority. Add migration 84 audited Worker read_only/read_write grants and removal/deletion fencing, member-facing ordinary access, owner-controlled grant settings, Workspace-bound decimal entry references, bounded text/binary chunks, streamed HTTP receive/download with integrity and safe headers, typed errors and generated Rust/OpenAPI/TypeScript contracts.

Validation: root cargo check; server-api 83 default / 91 typescript tests; FeatureStorage 16; Drive 31 unit + 12 integration; Workspace Server 691 library + 11 binary tests (--test-threads=4), including 9 real DB/LocalFileSystem HTTP tests for two Workers/non-owner usage, revoke during reception, concurrent CAS, response-loss receipts, chunk expiry and safe binary media. cargo fmt --all -- --check and git diff --check HEAD passed. Existing OpenAPI schemas/routes semantically unchanged; dependent TS digest projections regenerated.
This commit is contained in:
2026-10-09 00:02:09 +09:00
parent 9da79ab9f0
commit b5ea162f83
25 changed files with 6416 additions and 16 deletions
@@ -1,6 +1,6 @@
// @generated by yoi-companion-openapi-typescript@1. Do not edit.
// Input: openapi/server-api.json
// Input contract: 0.1.0 (sha256:16796bde0da04973310a14f90cf6eac14b2580bbe184c7c12afde3b6225ce933)
// Input contract: 0.1.0 (sha256:5f767ab90e6507d2e9486cd2efe74f62d613912ffa830ad617a088b2848f20da)
// Options: companion-operation-schema-closure,openapi-3.1,strict-integer-ranges,sorted-output
// Output: web/workspace/src/lib/generated/companion-api.ts
// Regenerate/check: cargo run -q -p server-api --example generate_companion_api_types -- --check
@@ -0,0 +1,203 @@
// Generated from server-api. Do not edit by hand.
// Regenerate: cargo run -q -p server-api --features typescript --example generate_drive_api_types > web/workspace/src/lib/generated/drive-api.ts
export type DriveEntryRef = { workspace_id: string; node_id: string };
export type DriveEntryKind = "folder" | "file";
export type DriveEntry = {
entry: DriveEntryRef;
parent: DriveEntryRef | null;
name: string;
kind: DriveEntryKind;
revision: string;
/**
* File length in bytes; absent for folders.
*/
size: number | null;
content_type: string | null;
updated_by: string;
/**
* Timestamp projected from storage's updated_at_ms; not a creation time.
*/
updated_at: string;
/**
* Stable relative authenticated URL in this same Workspace. No bearer token
* or cross-Workspace link is embedded in this metadata.
*/
latest_url: string;
};
export type DriveEntryQuery = { entry_workspace_id: string; id: string };
export type DriveListQuery = {
entry_workspace_id: string;
/**
* Folder to list.
*/
id: string;
limit: number | null;
/**
* Opaque service-issued page cursor, not a bare node ID.
*/
after: string | null;
};
export type DriveSearchQuery = {
query: string;
/**
* Search file text as well as names only when explicitly requested.
*/
include_text: boolean;
limit: number | null;
after: string | null;
};
export type DriveListResponse = {
entries: Array<DriveEntry>;
next_after: string | null;
};
export type DriveReadTextQuery = {
entry_workspace_id: string;
id: string;
max_bytes: number;
};
export type DriveReadTextResponse = {
entry: DriveEntry;
text: string;
truncated: boolean;
};
export type DriveReadChunkQuery = {
entry_workspace_id: string;
id: string;
/**
* Bind a multi-chunk read to the same file revision.
*/
expected_revision: string;
offset: number;
length: number;
};
export type DriveDownloadQuery = {
entry_workspace_id: string;
id: string;
expected_revision: string | null;
};
export type DriveMutation = {
"operation": "create_folder";
parent: DriveEntryRef;
name: string;
} | {
"operation": "create_text";
parent: DriveEntryRef;
name: string;
text: string;
content_type: string;
} | {
"operation": "update_text";
id: DriveEntryRef;
expected_revision: string;
text: string;
content_type: string;
} | {
"operation": "relocate";
id: DriveEntryRef;
expected_revision: string;
parent: DriveEntryRef;
name: string;
} | { "operation": "delete"; id: DriveEntryRef; expected_revision: string };
export type DriveMutationRequest = {
request_id: string;
mutation: DriveMutation;
};
export type DriveMutationResponse = {
request_id: string;
/**
* A deleted entry has no live metadata.
*/
entry: DriveEntry | null;
};
export type DriveUploadOperation = "create" | "update";
export type DriveUploadQuery = {
operation: DriveUploadOperation;
request_id: string;
entry_workspace_id: string;
parent_id: string | null;
name: string | null;
id: string | null;
expected_revision: string | null;
content_type: string;
/**
* Values above the file limit still decode as u32 so the service returns
* typed Limit rather than a generic request-decoding error.
*/
size: number;
sha256: string;
};
export type DriveRequestState = "uncommitted" | "committed";
export type DriveRequestStatusResponse = {
request_id: string;
state: DriveRequestState;
response: DriveMutationResponse | null;
};
export type DriveAccess = "read_only" | "read_write";
export type DriveGrantCreateRequest = {
runtime_id: string;
worker_id: string;
access: DriveAccess;
};
export type DriveGrantResponse = {
grant_id: string;
workspace_id: string;
runtime_id: string;
worker_id: string;
access: DriveAccess;
revoked: boolean;
created_by: string;
created_at: string;
revoked_by: string | null;
revoked_at: string | null;
};
export type DriveGrantListQuery = {
limit: number | null;
/**
* Canonical grant ID cursor within this Workspace.
*/
after: string | null;
};
export type DriveGrantListResponse = {
grants: Array<DriveGrantResponse>;
next_after: string | null;
};
export type DriveApiErrorCode =
| "denied"
| "not_found"
| "conflict"
| "invalid"
| "limit"
| "storage_unavailable"
| "outcome_unknown";
export type DriveFailureClassification = "not_committed" | "unknown";
export type DriveApiError = {
code: DriveApiErrorCode;
classification: DriveFailureClassification;
message: string;
};
@@ -1,6 +1,6 @@
// @generated by yoi-repository-openapi-typescript@1. Do not edit.
// Input: openapi/server-api.json
// Input contract: 0.1.0 (sha256:16796bde0da04973310a14f90cf6eac14b2580bbe184c7c12afde3b6225ce933)
// Input contract: 0.1.0 (sha256:5f767ab90e6507d2e9486cd2efe74f62d613912ffa830ad617a088b2848f20da)
// Options: repository-operation-schema-closure,openapi-3.1,format:uint64=safe-number,strict-safe-integers,sorted-output
// Output: web/workspace/src/lib/generated/repository-api.ts
// Regenerate/check: cargo run -q -p server-api --example generate_repository_openapi_types -- --check
@@ -1,6 +1,6 @@
// @generated by yoi-runtime-openapi-typescript@1. Do not edit.
// Input: openapi/server-api.json
// Input contract: 0.1.0 (sha256:16796bde0da04973310a14f90cf6eac14b2580bbe184c7c12afde3b6225ce933)
// Input contract: 0.1.0 (sha256:5f767ab90e6507d2e9486cd2efe74f62d613912ffa830ad617a088b2848f20da)
// Options: runtime-operation-schema-closure,openapi-3.1,strict-integer-ranges,sorted-output
// Output: web/workspace/src/lib/generated/runtime-api.ts
// Regenerate/check: cargo run -q -p server-api --example generate_runtime_api_types -- --check
@@ -1,6 +1,6 @@
// @generated by yoi-ticket-browser-openapi-typescript@1. Do not edit.
// Input: openapi/server-api.json
// Input contract: 0.1.0 (sha256:16796bde0da04973310a14f90cf6eac14b2580bbe184c7c12afde3b6225ce933)
// Input contract: 0.1.0 (sha256:5f767ab90e6507d2e9486cd2efe74f62d613912ffa830ad617a088b2848f20da)
// Options: ticket-objective-merge-request-browser-operation-schema-closure,openapi-3.1,strict-integer-ranges,sorted-output
// Output: web/workspace/src/lib/generated/ticket-api.ts
// Regenerate/check: cargo run -q -p server-api --example generate_ticket_api_types -- --check
@@ -1,6 +1,6 @@
// @generated by yoi-worker-openapi-typescript@1. Do not edit.
// Input: openapi/server-api.json
// Input contract: 0.1.0 (sha256:16796bde0da04973310a14f90cf6eac14b2580bbe184c7c12afde3b6225ce933)
// Input contract: 0.1.0 (sha256:5f767ab90e6507d2e9486cd2efe74f62d613912ffa830ad617a088b2848f20da)
// Options: worker-operation-schema-closure,openapi-3.1,strict-integer-ranges,sorted-output
// Output: web/workspace/src/lib/generated/worker-launch-api.ts
// Regenerate/check: cargo run -q -p server-api --example generate_worker_launch_api_types -- --check