feat(workspace): add shared Drive browsing editing and Worker grants

This commit is contained in:
2026-10-09 16:40:50 +09:00
parent c79506b60f
commit e4daa4aaa7
46 changed files with 7957 additions and 35 deletions
+396
View File
@@ -0,0 +1,396 @@
// Browser-only, in-memory API fixture. This is NOT Backend authorization/storage evidence.
import type {
DriveEntry,
DriveEntryRef,
DriveGrantResponse,
DriveMutation,
DriveMutationResponse,
} from "../../../web/workspace/src/lib/generated/drive-api.ts";
import { fixturePng } from "./raster.ts";
type Node = { entry: DriveEntry; bytes: Uint8Array };
type Workspace = {
nodes: Map<string, Node>;
receipts: Map<string, DriveMutationResponse>;
grants: DriveGrantResponse[];
next: bigint;
};
export type FixtureLog = {
workspace: string;
path: string;
method: string;
requestId: string | null;
nodeId: string | null;
expectedRevision: string | null;
};
const encoder = new TextEncoder();
const rootId = "9007199254740993";
export const fixtureRootId = rootId;
const instant = "2026-01-02T00:00:00Z";
const errors = {
denied: 403,
not_found: 404,
conflict: 409,
invalid: 400,
limit: 413,
storage_unavailable: 503,
outcome_unknown: 503,
} as const;
function failure(code: keyof typeof errors): Response {
return Response.json({
code,
classification: code === "outcome_unknown" ? "unknown" : "not_committed",
message: `Drive fixture ${code}`,
}, { status: errors[code] });
}
export function createDriveFixture() {
const workspaces = new Map<string, Workspace>();
const log: FixtureLog[] = [];
const faults = new Map<string, string>();
function ws(id: string): Workspace {
let state = workspaces.get(id);
if (state) return state;
state = { nodes: new Map(), receipts: new Map(), grants: [], next: 100n };
workspaces.set(id, state);
const add = (
nodeId: string,
name: string,
kind: "folder" | "file",
parent: string | null,
contentType: string | null,
bytes = new Uint8Array(),
) => {
const ref = (n: string): DriveEntryRef => ({ workspace_id: id, node_id: n });
state!.nodes.set(nodeId, {
bytes,
entry: {
entry: ref(nodeId),
parent: parent === null ? null : ref(parent),
name,
kind,
revision: "1",
size: kind === "file" ? bytes.length : null,
content_type: contentType,
updated_by: "fixture-worker",
updated_at: instant,
latest_url: `/api/w/${encodeURIComponent(id)}/drive/${
kind === "file" ? "download" : "metadata"
}?entry_workspace_id=${encodeURIComponent(id)}&id=${nodeId}`,
},
});
};
add(rootId, "Drive", "folder", null, null);
if (id.includes("empty")) return state;
add("2", "資料", "folder", rootId, null);
add(
"3",
"README.md",
"file",
rootId,
"text/markdown",
encoder.encode(
`# Shared notes\n\nWorker-created latest-only document.\n\n[Local folder](/w/${
encodeURIComponent(id)
}/drive/2)\n\n[Unsafe](javascript:alert(1))\n\n<img src=x onerror=alert(1)>\n\n![External](https://example.invalid/credential-trap.png)\n\n![Image](/w/${
encodeURIComponent(id)
}/drive/5)\n`,
),
);
add("4", "notes.txt", "file", "2", "text/plain", encoder.encode("Second document — 日本語"));
add("5", "landscape.png", "file", rootId, "image/png", fixturePng);
add("6", "empty.txt", "file", rootId, "text/plain");
add("7", "broken.png", "file", rootId, "image/png", encoder.encode("not a valid PNG"));
add(
"8",
"unsafe.svg",
"file",
rootId,
"image/svg+xml",
encoder.encode('<svg onload="alert(1)"></svg>'),
);
add(
"9",
"large.txt",
"file",
rootId,
"text/plain",
encoder.encode("bounded preview\n".repeat(5000)),
);
add(
"10",
"長い名前 — 国際化された資料と分散開発の成果物 — ".repeat(2) + ".md",
"file",
rootId,
"text/markdown",
encoder.encode("# Long name"),
);
add("11", "escaped-64k.txt", "file", rootId, "text/plain", new Uint8Array(65536));
if (id.includes("paged")) {
for (let n = 20; n < 260; n++) {
add(
String(n),
`Document ${n}.txt`,
"file",
rootId,
"text/plain",
encoder.encode(String(n)),
);
}
}
state.next = id.includes("paged") ? 300n : 100n;
return state;
}
function bump(node: Node) {
node.entry.revision = String(BigInt(node.entry.revision) + 1n);
}
function mutate(id: string, mutation: DriveMutation): DriveEntry | null {
const state = ws(id);
const target = "id" in mutation ? state.nodes.get(mutation.id.node_id) : null;
if ("id" in mutation && (mutation.id.workspace_id !== id || !target)) throw "not_found";
if (
target && "expected_revision" in mutation &&
target.entry.revision !== mutation.expected_revision
) throw "conflict";
if ("parent" in mutation) {
const parent = state.nodes.get(mutation.parent.node_id);
if (mutation.parent.workspace_id !== id || parent?.entry.kind !== "folder") throw "not_found";
}
if ("name" in mutation) {
if (
!mutation.name || mutation.name.includes("/") || encoder.encode(mutation.name).length > 255
) throw "invalid";
if (
[...state.nodes.values()].some((n) =>
n !== target && n.entry.parent?.node_id === mutation.parent.node_id &&
n.entry.name === mutation.name
)
) throw "conflict";
}
if (mutation.operation === "delete") {
if (
target!.entry.parent === null ||
[...state.nodes.values()].some((n) => n.entry.parent?.node_id === mutation.id.node_id)
) throw "conflict";
state.nodes.delete(mutation.id.node_id);
return null;
}
if (mutation.operation === "relocate") {
target!.entry.parent = mutation.parent;
target!.entry.name = mutation.name;
bump(target!);
return target!.entry;
}
if (mutation.operation === "update_text") {
target!.bytes = encoder.encode(mutation.text);
target!.entry.size = target!.bytes.length;
target!.entry.content_type = mutation.content_type;
bump(target!);
return target!.entry;
}
const nodeId = String(state.next++);
const bytes = mutation.operation === "create_text"
? encoder.encode(mutation.text)
: new Uint8Array();
const entry: DriveEntry = {
entry: { workspace_id: id, node_id: nodeId },
parent: mutation.parent,
name: mutation.name,
kind: mutation.operation === "create_folder" ? "folder" : "file",
revision: "1",
size: mutation.operation === "create_folder" ? null : bytes.length,
content_type: mutation.operation === "create_text" ? mutation.content_type : null,
updated_by: "fixture-user",
updated_at: instant,
latest_url: `/api/w/${encodeURIComponent(id)}/drive/${
mutation.operation === "create_folder" ? "metadata" : "download"
}?entry_workspace_id=${encodeURIComponent(id)}&id=${nodeId}`,
};
state.nodes.set(nodeId, { entry, bytes });
return entry;
}
async function handler(request: Request): Promise<Response | null> {
const url = new URL(request.url);
if (url.pathname === "/__fixture/log") return Response.json(log);
if (url.pathname === "/__fixture/reset" && request.method === "POST") {
workspaces.clear();
faults.clear();
log.length = 0;
return Response.json({ ok: true });
}
if (url.pathname === "/__fixture/fault" && request.method === "POST") {
const body = await request.json();
faults.set(body.workspace, body.mode);
return Response.json({ ok: true });
}
const match = url.pathname.match(/^\/api\/w\/([^/]+)\/drive(\/.*)$/);
if (!match) return null;
const id = decodeURIComponent(match[1]), path = match[2];
const state = ws(id);
const mutationRoute = path === "/mutate" || path === "/upload";
const event: FixtureLog = {
workspace: id,
path,
method: request.method,
requestId: url.searchParams.get("request_id"),
nodeId: url.searchParams.get("id") ?? url.searchParams.get("parent_id"),
expectedRevision: url.searchParams.get("expected_revision"),
};
log.push(event);
if (id.includes("denied")) return failure("denied");
if (id.includes("offline") || id === "home-error") return failure("storage_unavailable");
if (mutationRoute && (id.includes("readonly") || id === "home-member")) {
return failure("denied");
}
if (path.startsWith("/requests/")) {
const requestId = decodeURIComponent(path.slice(10));
const response = state.receipts.get(requestId) ?? null;
return Response.json({
request_id: requestId,
state: response ? "committed" : "uncommitted",
response,
});
}
if (path === "/grants") {
if (id === "home-member") return failure("denied");
if (request.method === "POST") {
const input = await request.json();
const grant: DriveGrantResponse = {
...input,
grant_id: String(state.grants.length + 1),
workspace_id: id,
revoked: false,
created_by: "fixture-owner",
created_at: instant,
revoked_by: null,
revoked_at: null,
};
state.grants.push(grant);
return Response.json(grant);
}
return Response.json({ grants: state.grants, next_after: null });
}
if (/^\/grants\/\d+$/.test(path) && request.method === "DELETE") {
if (id === "home-member") return failure("denied");
const grant = state.grants.find((g) => g.grant_id === path.split("/")[2]);
if (!grant) return failure("not_found");
grant.revoked = true;
grant.revoked_at = instant;
grant.revoked_by = "fixture-owner";
return Response.json(grant);
}
if (mutationRoute) {
try {
const payload = path === "/mutate" ? await request.json() : null;
const requestId = path === "/upload"
? url.searchParams.get("request_id")!
: payload.request_id;
event.requestId = requestId;
if (payload) {
event.nodeId = payload.mutation.id?.node_id ?? payload.mutation.parent?.node_id ?? null;
event.expectedRevision = payload.mutation.expected_revision ?? null;
}
if (state.receipts.has(requestId)) return Response.json(state.receipts.get(requestId));
const fault = faults.get(id);
if (fault === "conflict") {
faults.delete(id);
return failure("conflict");
}
let entry: DriveEntry | null;
if (path === "/mutate") entry = mutate(id, payload.mutation);
else {
const bytes = new Uint8Array(await request.arrayBuffer());
if (bytes.length > 16 * 1024 * 1024) return failure("limit");
if (bytes.length !== Number(url.searchParams.get("size"))) return failure("invalid");
const digest = new Uint8Array(await crypto.subtle.digest("SHA-256", bytes));
if (
[...digest].map((n) => n.toString(16).padStart(2, "0")).join("") !==
url.searchParams.get("sha256")
) return failure("invalid");
const content_type = url.searchParams.get("content_type")!;
if (url.searchParams.get("operation") === "create") {
entry = mutate(id, {
operation: "create_text",
parent: { workspace_id: id, node_id: url.searchParams.get("parent_id")! },
name: url.searchParams.get("name")!,
text: "",
content_type,
});
} else {entry = mutate(id, {
operation: "update_text",
id: { workspace_id: id, node_id: url.searchParams.get("id")! },
expected_revision: url.searchParams.get("expected_revision")!,
text: "",
content_type,
});}
const node = state.nodes.get(entry!.entry.node_id)!;
node.bytes = bytes;
node.entry.size = bytes.length;
}
const response = structuredClone({ request_id: requestId, entry });
state.receipts.set(requestId, response);
if (fault === "unknown") {
faults.delete(id);
return failure("outcome_unknown");
}
return Response.json(response);
} catch (error) {
return failure(
typeof error === "string" && error in errors ? error as keyof typeof errors : "invalid",
);
}
}
const nodeId = path === "/root" ? rootId : url.searchParams.get("id");
if (nodeId !== null && path !== "/root" && url.searchParams.get("entry_workspace_id") !== id) {
return failure("invalid");
}
const node = nodeId ? state.nodes.get(nodeId) : null;
if (path === "/root" || path === "/metadata") {
return node ? Response.json(node.entry) : failure("not_found");
}
if (path === "/list" || path === "/search") {
if (path === "/list" && node?.entry.kind !== "folder") return failure("not_found");
const all = [...state.nodes.values()].filter((n) =>
path === "/search"
? n.entry.name.includes(url.searchParams.get("query") ?? "")
: n.entry.parent?.node_id === nodeId
).sort((a, b) => a.entry.name.localeCompare(b.entry.name));
const after = url.searchParams.get("after");
const start = after ? all.findIndex((n) => n.entry.entry.node_id === after) + 1 : 0;
const limit = Math.min(Number(url.searchParams.get("limit") ?? 50), 200);
const entries = all.slice(start, start + limit).map((n) => n.entry);
return Response.json({
entries,
next_after: start + limit < all.length ? entries.at(-1)!.entry.node_id : null,
});
}
if (!node || node.entry.kind !== "file") return failure("not_found");
if (path === "/read-text") {
const text = new TextDecoder().decode(node.bytes.slice(0, 65536));
return Response.json({ entry: node.entry, text, truncated: node.bytes.length > 65536 });
}
if (path === "/download" || path === "/read-chunk") {
if (
url.searchParams.has("expected_revision") &&
url.searchParams.get("expected_revision") !== node.entry.revision
) return failure("conflict");
if (faults.get(id) === "image_error" && node.entry.content_type?.startsWith("image/")) {
return failure("storage_unavailable");
}
const bytes = path === "/read-chunk"
? node.bytes.slice(
Number(url.searchParams.get("offset")),
Number(url.searchParams.get("offset")) + Number(url.searchParams.get("length")),
)
: node.bytes;
return new Response(new Uint8Array(bytes).buffer, {
headers: {
"content-type": node.entry.content_type!,
"content-disposition": "attachment",
"x-content-type-options": "nosniff",
},
});
}
return failure("not_found");
}
return { handler, log };
}
+54
View File
@@ -0,0 +1,54 @@
// Synthetic raster bytes only; no fixture CSS, DOM renderer, image URL or UI branch.
// A real PNG with 1200×800 natural dimensions and simple colored checker/landscape shapes.
import { deflateSync } from "node:zlib";
export const fixtureImageWidth = 1200;
export const fixtureImageHeight = 800;
function crc32(bytes: Uint8Array): number {
let crc = 0xffffffff;
for (const byte of bytes) {
crc ^= byte;
for (let bit = 0; bit < 8; bit++) crc = (crc >>> 1) ^ ((crc & 1) ? 0xedb88320 : 0);
}
return (crc ^ 0xffffffff) >>> 0;
}
function chunk(type: string, data: Uint8Array): Uint8Array {
const bytes = new Uint8Array(data.length + 12);
const view = new DataView(bytes.buffer);
view.setUint32(0, data.length);
bytes.set(new TextEncoder().encode(type), 4);
bytes.set(data, 8);
view.setUint32(data.length + 8, crc32(bytes.subarray(4, data.length + 8)));
return bytes;
}
const ihdr = new Uint8Array(13);
const dimensions = new DataView(ihdr.buffer);
dimensions.setUint32(0, fixtureImageWidth);
dimensions.setUint32(4, fixtureImageHeight);
ihdr[8] = 8;
ihdr[9] = 2; // 8-bit RGB, no interlacing.
const rowLength = fixtureImageWidth * 3 + 1;
const pixels = new Uint8Array(rowLength * fixtureImageHeight);
for (let y = 0; y < fixtureImageHeight; y++) {
for (let x = 0; x < fixtureImageWidth; x++) {
const checker = (Math.floor(x / 100) + Math.floor(y / 100)) % 2;
let rgb = checker ? [196, 221, 229] : [231, 240, 244];
if ((x - 930) ** 2 + (y - 170) ** 2 < 105 ** 2) rgb = [238, 175, 72];
const ridge = 480 - 150 * Math.sin(x / 210);
if (y > ridge) rgb = checker ? [42, 112, 123] : [52, 135, 141];
if (y > 650 + 55 * Math.cos(x / 140)) rgb = checker ? [25, 64, 83] : [34, 82, 100];
pixels.set(rgb, y * rowLength + 1 + x * 3);
}
}
const parts = [
new Uint8Array([137, 80, 78, 71, 13, 10, 26, 10]),
chunk("IHDR", ihdr),
chunk("IDAT", new Uint8Array(deflateSync(pixels, { level: 9 }))),
chunk("IEND", new Uint8Array()),
];
export const fixturePng = new Uint8Array(parts.reduce((sum, part) => sum + part.length, 0));
let offset = 0;
for (const part of parts) {
fixturePng.set(part, offset);
offset += part.length;
}
if (fixturePng.length >= 256 * 1024) throw new Error("Synthetic PNG exceeds raster byte cap");
+115
View File
@@ -0,0 +1,115 @@
// Serves the real static production shell. Drive is an in-memory fake API;
// other routes reuse the shared Home/settings fixtures via a loopback proxy.
import { dirname, fromFileUrl, join } from "jsr:@std/path@1.1.4";
import { createDriveFixture } from "./api.ts";
import { cleanupPlan, workerCatalog, workerSnapshot } from "./workers.ts";
const port = Number(Deno.args[0]);
const buildRoot = Deno.args[1];
if (!Number.isInteger(port) || !buildRoot) {
throw new Error("usage: server <port> <production-build-root>");
}
const root = join(dirname(fromFileUrl(import.meta.url)), "../../..");
const listener = Deno.listen({ hostname: "127.0.0.1", port: 0 });
const homePort = (listener.addr as Deno.NetAddr).port;
listener.close();
const home = new Deno.Command(Deno.execPath(), {
args: [
"run",
"--allow-net",
"--allow-read",
join(root, "tools/web-ux/browser-tests/workspace_home_fixture_server.ts"),
String(homePort),
buildRoot,
],
stdout: "null",
stderr: "inherit",
}).spawn();
let stopped = false;
function cleanup() {
if (!stopped) {
stopped = true;
try {
home.kill("SIGTERM");
} catch { /* already exited */ }
}
}
Deno.addSignalListener("SIGTERM", () => {
cleanup();
Deno.exit(0);
});
Deno.addSignalListener("SIGINT", () => {
cleanup();
Deno.exit(0);
});
const fixture = createDriveFixture();
const deadline = Date.now() + 10000;
while (true) {
try {
const response = await fetch(`http://127.0.0.1:${homePort}/health`);
await response.body?.cancel();
if (response.ok) break;
} catch { /* startup */ }
if (Date.now() > deadline) {
cleanup();
throw new Error("shared Home fixture failed to start");
}
await new Promise((resolve) => setTimeout(resolve, 30));
}
Deno.serve({ hostname: "127.0.0.1", port }, async (request) => {
const url = new URL(request.url);
if (url.pathname === "/health") {
return Response.json({ authority: "fixture, not actual Backend", ready: true });
}
const drive = await fixture.handler(request);
if (drive) return drive;
const api = url.pathname.match(/^\/api\/w\/([^/]+)(\/.*)$/);
if (api?.[2] === "/workers") {
if (api[1] === "workers-error") {
return Response.json({ error: "Worker fixture unavailable" }, { status: 503 });
}
return Response.json(workerCatalog(decodeURIComponent(api[1])));
}
if (api?.[2].match(/^\/runtimes\/[^/]+\/cleanup-plan$/)) {
return Response.json(cleanupPlan(decodeURIComponent(api[1]), api[2].split("/")[2]));
}
// Home fixture keeps the production WebSocket subscription flow intact.
if (api?.[2] === "/protocol/ws" && request.headers.get("upgrade") === "websocket") {
const { socket, response } = Deno.upgradeWebSocket(request);
socket.onmessage = (event) => {
const frame = JSON.parse(String(event.data));
if (frame?.message?.method !== "subscribe_events") return;
socket.send(JSON.stringify({
protocol_version: 2,
frame: "response",
message: {
result: "subscribed",
payload: {
request_id: frame.message.params.request_id,
subscription_id: "fixture-workers",
selector: { topic: "workspace_workers" },
snapshot: {
topic: "workers",
data: { workers: workerSnapshot(decodeURIComponent(api[1])) },
},
},
},
}));
};
return response;
}
const proxy = new URL(url.pathname + url.search, `http://127.0.0.1:${homePort}`);
const response = await fetch(proxy, {
method: request.method,
headers: request.headers,
body: request.method === "GET" || request.method === "HEAD"
? undefined
: await request.arrayBuffer(),
redirect: "manual",
});
if (api?.[2] === "/workspace") {
const body = await response.json();
body.display_name ??= `Drive ${decodeURIComponent(api[1])}`;
return Response.json(body, { status: response.status });
}
return response;
});
+74
View File
@@ -0,0 +1,74 @@
// One synthetic authoritative Worker catalog. Both REST and protocol projections
// derive from these same records; no grant-only Worker list or production override.
import type { WorkerListResponse } from "../../../web/workspace/src/lib/generated/worker-launch-api.ts";
import type { SubscriptionWorker } from "../../../web/workspace/src/lib/generated/protocol.ts";
import type { RuntimeCleanupPlanResponse } from "../../../web/workspace/src/lib/generated/runtime-api.ts";
export function workerCatalog(workspaceId: string): WorkerListResponse {
const representative = ["home-owner", "home-member", "home-long", "home-error"].includes(
workspaceId,
);
return {
workspace_id: workspaceId,
limit: 100,
source: "fixture",
diagnostics: [],
items: representative
? ["a", "b"].map((suffix, index) => ({
runtime_id: workspaceId === "home-long"
? `fixture-runtime-${"r".repeat(100)}`
: "fixture-runtime",
worker_id: workspaceId === "home-long"
? `fixture-worker-${suffix}-${"w".repeat(100)}`
: `fixture-worker-${suffix}`,
resource_key: `W-${801 + index}`,
host_id: "fixture-host",
display_name: workspaceId === "home-long"
? "Documentation and distributed development Worker — 国際化されたドキュメントを整理する長い表示名 — "
.repeat(2)
: index === 0
? "Documentation Worker"
: "画像・資料を整理する Worker — 長い名前",
label: `Fixture Worker ${suffix}`,
profile: "default",
workspace: { workspace_id: workspaceId, visibility: "workspace", identity: workspaceId },
availability: "observed",
state: "idle",
worker_state: { last_command_id: 0, state: { kind: "idle" } },
pinned: false,
retention_state: "active",
implementation: { kind: "builtin", display_hint: "fixture" },
tags: [],
diagnostics: [],
workdir_attachments: [],
last_seen_at: "2026-01-02T00:00:00Z",
}))
: [],
};
}
export function workerSnapshot(workspaceId: string): SubscriptionWorker[] {
return workerCatalog(workspaceId).items.map((worker) => ({
worker_id: worker.worker_id,
runtime_id: worker.runtime_id,
resource_key: worker.resource_key,
availability: worker.availability,
state: "idle",
worker_state: worker.worker_state,
workspace_id: workspaceId,
display_name: worker.display_name,
profile: worker.profile,
has_running_internal_workers: false,
workdir_attachments: [],
}));
}
export function cleanupPlan(workspaceId: string, runtimeId: string): RuntimeCleanupPlanResponse {
return {
workspace_id: workspaceId,
runtime_id: runtimeId,
diagnostics: [],
digest: "fixture-cleanup",
generated_at: "2026-01-02T00:00:00Z",
revision: "1",
workers: [],
workdirs: [],
};
}
+347
View File
@@ -0,0 +1,347 @@
// Development-only visual evidence over the real Workers route and loopback
// HTTP fixtures. No Backend/Runtime/account/grant state is mutated.
// Run from root: deno run --config tools/web-ux/deno.json -A tools/web-ux/drive-grants/visual-review.ts after
import { chromium } from "npm:playwright@1.59.1";
import { startOwnedProcesses, stopOwnedProcesses } from "../src/processes.ts";
const root = new URL("../../../", import.meta.url).pathname;
const run = Deno.args[0] ?? "after";
const before = run === "before";
const out = `${root}target/web-ux/t724-drive-grants/${run}`;
const listener = Deno.listen({ hostname: "127.0.0.1", port: 0 });
const port = (listener.addr as Deno.NetAddr).port;
listener.close();
const baseUrl = `http://127.0.0.1:${port}`;
const processes = await startOwnedProcesses(
[{
id: "vite",
command: "deno",
args: ["task", "dev", "--host", "127.0.0.1", "--port", String(port)],
cwd: `${root}web/workspace`,
readyUrl: baseUrl,
}],
import.meta.url,
`${out}/logs`,
[],
);
const worker = {
runtime_id: "runtime-a",
worker_id: "worker-a",
resource_key: "W-1",
host_id: "host-a",
display_name: "Documentation Worker",
label: "Worker",
profile: "builtin:coder",
tags: [],
workspace: {
visibility: "workspace",
identity: "space",
workspace_id: "space",
},
availability: "observed",
state: "stopped",
pinned: false,
retention_state: "normal",
implementation: { kind: "runtime", display_hint: "Runtime Worker" },
workdir_attachments: [],
diagnostics: [],
restore_observation_token: "observation-1",
};
const grant = {
grant_id: "1",
workspace_id: "space",
runtime_id: "runtime-a",
worker_id: "worker-a",
access: "read_only",
revoked: false,
created_by: "fixture-owner",
created_at: "2026-10-09",
revoked_by: null,
revoked_at: null,
};
const browser = await chromium.launch({ headless: true });
const longWorker = {
...worker,
runtime_id: `runtime-${"r".repeat(140)}`,
worker_id: `worker-${"w".repeat(140)}`,
display_name:
"Documentation and distributed development Worker with a long display name for international documentation review",
};
const captures: unknown[] = [];
try {
for (const persona of ["owner", "non-owner"]) {
for (const theme of ["light", "dark"] as const) {
for (const width of [1440, 768, 390]) {
const context = await browser.newContext({
viewport: { width, height: 900 },
colorScheme: theme,
reducedMotion: "reduce",
});
try {
const page = await context.newPage();
const errors: string[] = [];
page.on("pageerror", (error) => errors.push(error.message));
page.on("console", (message) => {
if (message.type() === "error") errors.push(message.text());
});
page.on("requestfailed", (request) =>
errors.push(
`${request.method()} ${
new URL(request.url()).pathname
}: ${request.failure()?.errorText}`,
));
let state = "active";
await page.routeWebSocket("**/api/w/space/protocol/ws", () => {});
await page.route("**/api/**", async (route) => {
const url = new URL(route.request().url()), path = url.pathname;
if (!path.startsWith("/api/")) {
return await route.continue();
}
const owner = persona === "owner";
let body: unknown;
if (path === "/api/workspaces") {
body = [{
workspace_id: "space",
display_name: "Drive review",
owner_account_id: "fixture-owner",
state: "active",
created_at: "2026-01-01",
updated_at: "2026-01-01",
}];
} else if (path.endsWith("/workspace")) {
body = {
workspace_id: "space",
display_name: "Drive review",
record_authority: "fixture",
schema_version: 1,
auth: {
Passkey: {
rp_id: "127.0.0.1",
origin: baseUrl,
public_base_url: baseUrl,
cookie_name: "fixture",
},
},
permissions: {
manage_repositories: owner,
manage_secrets: owner,
manage_runtimes: owner,
delete_workspace: owner,
},
extension_points: {
store: "fixture",
event_stream: {
status: "ready",
note: "fixture",
diagnostics: [],
},
host_worker_bridge: {
status: "ready",
note: "fixture",
diagnostics: [],
},
companion_console: {
status: "ready",
note: "fixture",
diagnostics: [],
},
},
};
} else if (path.endsWith("/workers")) {
body = {
workspace_id: "space",
limit: 100,
source: "fixture",
diagnostics: [],
items: [state === "long" ? longWorker : worker],
};
} else if (path.endsWith("/repositories")) {
body = {
workspace_id: "space",
items: [],
source: "fixture",
diagnostics: [],
};
} else if (path.endsWith("/cleanup-plan")) {
body = {
workspace_id: "space",
generated_at: "2026-10-09",
runtime_id: "runtime-a",
revision: "plan-1",
digest: "digest-1",
diagnostics: [],
workdirs: [],
workers: [],
};
} else if (path.endsWith("/drive/grants")) {
if (state === "loading") {
await new Promise<void>((resolve) => {
release = resolve;
});
}
if (state === "error") {
await route.fulfill({
status: 503,
json: {
code: "storage_unavailable",
classification: "not_committed",
message: `Drive storage unavailable. ${
"A long diagnostic requiring readable wrapping and an explicit refresh action. "
.repeat(12)
}`,
},
});
return;
}
body = {
grants: state === "empty" ? [] : [{
...grant,
runtime_id: state === "long" ? longWorker.runtime_id : worker.runtime_id,
worker_id: state === "long" ? longWorker.worker_id : worker.worker_id,
}],
next_after: null,
};
} else if (path.endsWith("/working-directories")) {
body = { workspace_id: "space", items: [], diagnostics: [] };
} else {
errors.push(`Unmatched fixture ${path}`);
body = {};
}
await route.fulfill({ json: body });
});
let release: (() => void) | undefined;
const response = await page.goto(`${baseUrl}/w/space/workers`);
await page.getByRole("heading", { name: "Workers", exact: true })
.waitFor().catch(async (cause) => {
console.log(errors, await page.locator("body").innerText());
throw cause;
});
await page.getByText("Documentation Worker", { exact: true }).first()
.waitFor().catch(async (cause) => {
console.log(errors, await page.locator("body").innerText());
throw cause;
});
async function capture(name: string) {
await Deno.mkdir(out, { recursive: true });
const filename = `${persona}-${theme}-${width}-${name}.png`;
const screenshot = await page.screenshot({
path: `${out}/${filename}`,
fullPage: true,
});
if (!before && persona === "owner") {
const clipped = await page.locator(".drive-grants").evaluate((
element,
) =>
[...element.querySelectorAll("button, select, summary")].some(
(control) => {
const box = control.getBoundingClientRect();
return box.left < 0 ||
box.right > element.ownerDocument.defaultView!.innerWidth;
},
)
);
if (clipped) {
throw new Error(
`Grant control clipped: ${persona} ${theme} ${width} ${name}`,
);
}
await page.locator(".drive-grants").screenshot({
path: `${out}/grants-${filename}`,
});
}
captures.push({
persona,
theme,
width,
state: name,
path: filename,
sha256: await sha256(screenshot),
documentStatus: response?.status(),
errors: [...errors],
visibleErrors: await page.locator("[role=alert]")
.allTextContents(),
overflow: await page.evaluate("document.documentElement.scrollWidth > innerWidth"),
accessibility: await page.locator("main").ariaSnapshot(),
});
}
if (before || !ownerPersona(persona)) await capture("workers");
else {
await page.getByRole("combobox", { name: "Worker", exact: true })
.selectOption(JSON.stringify(["runtime-a", "worker-a"]));
await page.getByRole("button", { name: "Revoke Drive grant 1" })
.waitFor();
await capture("active");
state = "empty";
await page.getByRole("button", { name: "Refresh grants" }).click();
await page.getByText("No active Drive grants for this Worker.")
.waitFor();
await page.getByRole("button", { name: "Add Drive grant" }).click();
await capture("empty-form");
state = "error";
await page.getByRole("button", { name: "Refresh grants" }).click();
await page.getByRole("alert").waitFor();
await capture("error");
state = "loading";
await page.getByRole("button", { name: "Refresh grants" }).click();
await page.getByText("Loading all grant pages…").waitFor();
await capture("loading");
release?.();
}
state = "long";
await page.reload();
await page.getByText(longWorker.display_name, { exact: true }).first()
.waitFor();
if (!before && persona === "owner") {
await page.getByRole("combobox", { name: "Worker", exact: true })
.selectOption(
JSON.stringify([longWorker.runtime_id, longWorker.worker_id]),
);
await page.getByRole("button", { name: "Revoke Drive grant 1" })
.waitFor();
await page.getByText("Worker identity", { exact: true }).click();
}
await capture("long-values");
} finally {
await context.close();
}
}
}
}
const pageSource = await Deno.readFile(
`${root}web/workspace/src/routes/w/[workspaceId]/workers/+page.svelte`,
);
const componentSource = await Deno.readFile(
`${root}web/workspace/src/lib/workspace/drive-grants/WorkerDriveGrants.svelte`,
);
const apiSource = await Deno.readFile(
`${root}web/workspace/src/lib/workspace/drive-grants/api.ts`,
);
await Deno.writeTextFile(
`${out}/review-context.json`,
JSON.stringify(
{
scenario: "real Workers route, loopback authoritative API projections",
run,
browserVersion: browser.version(),
workersPageSha256: await sha256(pageSource),
componentSha256: await sha256(componentSource),
apiSha256: await sha256(apiSource),
captures,
},
null,
2,
),
);
console.log(`Visual evidence: ${out}`);
} finally {
await browser.close();
await stopOwnedProcesses(processes);
}
function ownerPersona(persona: string) {
return persona === "owner";
}
async function sha256(bytes: Uint8Array) {
return [...new Uint8Array(await crypto.subtle.digest("SHA-256", Uint8Array.from(bytes).buffer))]
.map((
byte,
) => byte.toString(16).padStart(2, "0")).join("");
}