Skip to content

feat: implement mock API layer and real-time SSE transfer progress si… - #52

Merged
allenjose24 merged 2 commits into
devfrom
feat/mock-api-layer
Jul 6, 2026
Merged

feat: implement mock API layer and real-time SSE transfer progress si…#52
allenjose24 merged 2 commits into
devfrom
feat/mock-api-layer

Conversation

@allenjose24

Copy link
Copy Markdown
Member

This PR implements the mock API handlers matching docs/API_CONTRACT.md responses, along with an in-memory session database and background transfer progress simulation.

Closes #9

Changes:

  • Mock Store (frontend/lib/mocks/store.ts): Simulates drive connection status, tree structures, folder creation, quota availability, and background transfer task progress.
  • Next.js API Route Handlers:
    • Auth Router: /auth/login, /auth/callback, /auth/logout, /auth/connect/*, /auth/callback/drive to simulate Google OAuth.
    • Drive Router: /api/drive/source/tree, /api/drive/target/folders, /api/drive/target/quota for listing and folder creation.
    • Jobs Router: /api/jobs (POST to create), /api/jobs/[id] (GET status), and /api/jobs/[id]/stream (Server-Sent Events progress stream).
    • Job Actions: /pause, /resume, /cancel, /retry-failed to control the background simulation engine.

Copilot AI review requested due to automatic review settings July 6, 2026 06:35

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR adds a frontend-only mock API layer (via Next.js App Router route handlers) backed by an in-memory mockStore, including simulated transfer jobs with an SSE progress stream. This is intended to let the UI be developed without a running backend and to follow docs/API_CONTRACT.md.

Changes:

  • Introduces frontend/lib/mocks/store.ts as an in-memory mock “backend” for drive items, quota, and simulated transfer jobs (including SSE listeners).
  • Adds mock Auth routes for login/callback/logout and Source drive connection.
  • Adds mock Transfer Jobs routes: create job, read job status, SSE stream, and pause/resume/cancel/retry-failed actions; plus a Source tree browsing route.

Reviewed changes

Copilot reviewed 14 out of 14 changed files in this pull request and generated 14 comments.

Show a summary per file
File Description
frontend/lib/mocks/store.ts In-memory mock store for drive items, quota, and simulated transfer jobs with progress broadcasting.
frontend/app/auth/login/route.ts Mock OAuth entrypoint redirecting into the callback flow.
frontend/app/auth/callback/route.ts Mock OAuth callback; sets a session cookie and marks mock login state.
frontend/app/auth/logout/route.ts Clears the mock session and resets the in-memory store.
frontend/app/auth/connect/source/route.ts Mock connect flow entrypoint for Source drive.
frontend/app/auth/callback/drive/route.ts Shared drive connection callback toggling Source/Target connected flags.
frontend/app/api/drive/source/tree/route.ts Mock Source drive tree listing endpoint.
frontend/app/api/jobs/route.ts Creates a mock transfer job and starts background progress simulation.
frontend/app/api/jobs/[id]/route.ts Retrieves a mock transfer job status payload.
frontend/app/api/jobs/[id]/stream/route.ts SSE endpoint streaming mock job progress events.
frontend/app/api/jobs/[id]/pause/route.ts Pauses a running mock job.
frontend/app/api/jobs/[id]/resume/route.ts Resumes a paused mock job.
frontend/app/api/jobs/[id]/cancel/route.ts Cancels a running/paused/pending mock job.
frontend/app/api/jobs/[id]/retry-failed/route.ts Retries failed items for a failed/completed-with-errors mock job.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

if (item.type === "file") totalFiles++;
else {
totalFolders++;
// Add children recursively in simulation
Comment on lines +196 to +206
if (job && (job.status === "running" || job.status === "paused" || job.status === "pending")) {
job.status = "cancelled";
job.updatedAt = new Date().toISOString();
this.broadcastToJob(id, "done", {
status: "cancelled",
filesCompleted: job.filesCompleted,
filesFailed: job.filesFailed,
totalFiles: job.totalFiles
});
return true;
}
Comment on lines +303 to +314
} else {
// Simulation completed
clearInterval(interval);
job.status = job.filesFailed > 0 ? "completed_with_errors" : "completed";
job.updatedAt = new Date().toISOString();
this.broadcastToJob(id, "done", {
status: job.status,
filesCompleted: job.filesCompleted,
filesFailed: job.filesFailed,
totalFiles: job.totalFiles
});
}
Comment on lines +9 to +22
// Validate parameters
if (!transferMode || !conflictPolicy || !sourceItemIds || !targetParentId) {
return NextResponse.json(
{ error: "bad_request", message: "Missing required parameters in request body" },
{ status: 400 }
);
}

if (transferMode !== "COPY" && transferMode !== "MOVE") {
return NextResponse.json(
{ error: "invalid_mode", message: "transferMode must be COPY or MOVE" },
{ status: 400 }
);
}
Comment thread frontend/app/auth/logout/route.ts Outdated
import { cookies } from "next/headers";
import { mockStore } from "@/lib/mocks/store";

export async function POST(request: NextRequest) {
Comment on lines +4 to +9
export async function POST(
request: NextRequest,
context: { params: Promise<{ id: string }> }
) {
const { id } = await context.params;
const itemsRequeued = mockStore.retryFailedJob(id);
Comment on lines +4 to +10
export async function GET(
request: NextRequest,
context: { params: Promise<{ id: string }> }
) {
const { id } = await context.params;
const job = mockStore.getJob(id);

Comment on lines +13 to +15
const searchParams = request.nextUrl.searchParams;
const folderId = searchParams.get("folderId") || undefined;

Comment on lines +3 to +7
export async function GET(request: NextRequest) {
// Redirect to callback/drive simulating permission authorization for Source drive
const targetUrl = new URL("/auth/callback/drive?state=source", request.url);
return NextResponse.redirect(targetUrl);
}
Comment on lines +81 to +87
// Get target directories (only folders)
public getTargetFolders(parentId?: string) {
const targetParentId = parentId || "root";
const breadcrumb = this.getBreadcrumbs(this.targetItems, targetParentId);
const items = this.targetItems.filter(item => item.parentId === targetParentId && item.type === "folder");
return { folderId: targetParentId, breadcrumb, items };
}
@allenjose24
allenjose24 merged commit b1f29c5 into dev Jul 6, 2026
1 check passed
@allenjose24
allenjose24 deleted the feat/mock-api-layer branch July 6, 2026 06:56
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants