From dbb1a84dba09c773a67dd278e0d59c9ac98e0d12 Mon Sep 17 00:00:00 2001 From: saravanakumardb1 Date: Thu, 19 Mar 2026 07:20:28 -0700 Subject: [PATCH] fix(web): lazy-init extraction + blob clients, add use-client to notes-client - extraction-client.ts: lazy singleton (SSR crash fix) [A1] - blob-client.ts: lazy singleton + remove dead re-export [A1] - notes-client.ts: add "use client" directive [A6] - next.config.ts: add output: "standalone" [A2] - Delete mock-data.ts and review-data.ts (dead code) [D3, D4] --- web/next.config.ts | 1 + web/src/lib/blob-client.ts | 26 ++-- web/src/lib/extraction-client.ts | 16 ++- web/src/lib/mock-data.ts | 227 ------------------------------- web/src/lib/notes-client.ts | 2 + web/src/lib/review-data.ts | 45 ------ 6 files changed, 29 insertions(+), 288 deletions(-) delete mode 100644 web/src/lib/mock-data.ts delete mode 100644 web/src/lib/review-data.ts diff --git a/web/next.config.ts b/web/next.config.ts index d3d190a..a721737 100644 --- a/web/next.config.ts +++ b/web/next.config.ts @@ -21,6 +21,7 @@ const securityHeaders = [ ]; const nextConfig: NextConfig = { + output: "standalone", outputFileTracingRoot: path.join(process.cwd(), ".."), async headers() { return [ diff --git a/web/src/lib/blob-client.ts b/web/src/lib/blob-client.ts index 70e393b..80a4d66 100644 --- a/web/src/lib/blob-client.ts +++ b/web/src/lib/blob-client.ts @@ -8,19 +8,25 @@ function getAccessToken(): string | null { return localStorage.getItem(`${PRODUCT_ID}_access_token`); } -const blobClient = createBlobClient({ - baseUrl: PLATFORM_SERVICE_URL, - productId: PRODUCT_ID, - getAccessToken, -}); +let _blobClient: ReturnType | null = null; +function getBlobClient() { + if (!_blobClient) { + _blobClient = createBlobClient({ + baseUrl: PLATFORM_SERVICE_URL, + productId: PRODUCT_ID, + getAccessToken, + }); + } + return _blobClient; +} export async function getArtifactReadUrl(blobPath: string): Promise { - const sas = await blobClient.getSasUrl("attachments", blobPath, "r", 15); + const sas = await getBlobClient().getSasUrl("attachments", blobPath, "r", 15); return sas.sasUrl; } export async function getArtifactUploadUrl(blobPath: string): Promise { - const sas = await blobClient.getSasUrl("attachments", blobPath, "rw", 30); + const sas = await getBlobClient().getSasUrl("attachments", blobPath, "rw", 30); return sas.sasUrl; } @@ -28,7 +34,7 @@ export async function uploadArtifact( file: File, blobPath: string, ): Promise<{ blobPath: string; contentType: string; sizeBytes: number }> { - await blobClient.upload("attachments", file, { + await getBlobClient().upload("attachments", file, { contentType: file.type || "application/octet-stream", blobName: blobPath, }); @@ -41,8 +47,6 @@ export async function uploadArtifact( } export async function downloadArtifact(blobPath: string): Promise { - const response = await blobClient.download("attachments", blobPath); + const response = await getBlobClient().download("attachments", blobPath); return response.blob(); } - -export { blobClient }; diff --git a/web/src/lib/extraction-client.ts b/web/src/lib/extraction-client.ts index 8355347..0463e2d 100644 --- a/web/src/lib/extraction-client.ts +++ b/web/src/lib/extraction-client.ts @@ -22,10 +22,16 @@ function getAccessToken(): string | null { return localStorage.getItem(`${PRODUCT_ID}_access_token`); } -const extractionApi = createApiClient({ - baseUrl: EXTRACTION_SERVICE_URL, - getToken: getAccessToken, -}); +let _extractionApi: ReturnType | null = null; +function getExtractionApi() { + if (!_extractionApi) { + _extractionApi = createApiClient({ + baseUrl: EXTRACTION_SERVICE_URL, + getToken: getAccessToken, + }); + } + return _extractionApi; +} function slugify(value: string): string { return value @@ -36,7 +42,7 @@ function slugify(value: string): string { } export async function extractSuggestedTasks(text: string): Promise { - const response = await extractionApi.fetch("/api/extract", { + const response = await getExtractionApi().fetch("/api/extract", { method: "POST", body: JSON.stringify({ text, diff --git a/web/src/lib/mock-data.ts b/web/src/lib/mock-data.ts deleted file mode 100644 index ee44b82..0000000 --- a/web/src/lib/mock-data.ts +++ /dev/null @@ -1,227 +0,0 @@ -import type { - AgentTimelineItem, - NoteDetail, - NoteSummary, - OperatorWorkflowSummary, - SavedViewSummary, - WorkspaceSummary, -} from "@/lib/types"; - -export const mockWorkspaces: WorkspaceSummary[] = [ - { - id: "workspace-product", - name: "Product Strategy", - description: "PRDs, roadmap cuts, launch tradeoffs, and operating decisions.", - owner: "Product Lead", - noteCount: 18, - visibility: "shared", - updatedAt: "2026-03-10T14:35:00.000Z", - tags: ["strategy", "launch", "roadmap"], - }, - { - id: "workspace-research", - name: "Research Ops", - description: "Source notes, citations, summaries, and extracted action items.", - owner: "Research Lead", - noteCount: 42, - visibility: "private", - updatedAt: "2026-03-10T13:10:00.000Z", - tags: ["research", "sources", "agent-ready"], - }, - { - id: "workspace-platform", - name: "Platform Coordination", - description: "Shared-platform integration notes and handoffs for other agents.", - owner: "Platform Agent", - noteCount: 11, - visibility: "shared", - updatedAt: "2026-03-10T11:05:00.000Z", - tags: ["platform", "handoff", "integration"], - }, -]; - -export const mockNotes: NoteSummary[] = [ - { - id: "note-prd-cutline", - workspaceId: "workspace-product", - title: "MVP cut line for agentic notes launch", - excerpt: "Define which note, task, search, and approval flows must exist before wider rollout.", - status: "active", - tags: ["mvp", "launch", "scope"], - updatedAt: "2026-03-10T14:30:00.000Z", - updatedBy: "Product Lead", - }, - { - id: "note-web-shell", - workspaceId: "workspace-product", - title: "Web shell execution plan", - excerpt: "Scaffold authenticated layout, notes routes, search, settings, and operator affordances.", - status: "draft", - tags: ["web", "execution", "ui"], - updatedAt: "2026-03-10T14:10:00.000Z", - updatedBy: "Web Agent", - }, - { - id: "note-platform-deps", - workspaceId: "workspace-platform", - title: "Platform integration dependencies for v1", - excerpt: "Identify auth, telemetry, diagnostics, blob, and extraction dependencies that must be wired from day one.", - status: "active", - tags: ["platform", "telemetry", "auth"], - updatedAt: "2026-03-10T13:00:00.000Z", - updatedBy: "Platform Agent", - }, - { - id: "note-research-sources", - workspaceId: "workspace-research", - title: "Source summary ingestion workflow", - excerpt: "Map external research capture into note creation, citation linking, and downstream task extraction.", - status: "active", - tags: ["research", "sources", "workflow"], - updatedAt: "2026-03-10T12:15:00.000Z", - updatedBy: "Research Agent", - }, -]; - -export const mockSavedViews: SavedViewSummary[] = [ - { - id: "view-all-workspaces", - name: "All workspaces", - scope: "workspace", - description: "Default operational workspace listing across all note domains.", - query: "visibility:any sort:updated", - resultCount: 3, - }, - { - id: "view-launch-readiness", - name: "Launch readiness", - scope: "search", - description: "Notes tagged for launch, cut-line, approval, and release follow-up.", - query: "tag:launch tag:mvp status:active", - resultCount: 2, - }, - { - id: "view-agent-review", - name: "Agent review queue", - scope: "review", - description: "Proposals and approval items requiring operator attention.", - query: "review:proposed severity:medium+", - resultCount: 2, - }, -]; - -export const mockOperatorWorkflows: OperatorWorkflowSummary[] = [ - { - id: "workflow-approvals", - name: "Approval triage", - queueCount: 2, - owner: "Operator", - sla: "< 4h", - status: "healthy", - }, - { - id: "workflow-artifacts", - name: "Artifact follow-up", - queueCount: 3, - owner: "Knowledge Ops", - sla: "< 1d", - status: "at_risk", - }, - { - id: "workflow-search-gaps", - name: "Search quality review", - queueCount: 1, - owner: "Web Agent", - sla: "< 2d", - status: "healthy", - }, -]; - -const mockTimeline: AgentTimelineItem[] = [ - { - id: "event-1", - actor: "Research Agent", - action: "Proposed metadata enrichment", - timestamp: "2026-03-10 08:11", - status: "proposed", - summary: "Suggested new tags, source metadata, and a research confidence note.", - }, - { - id: "event-2", - actor: "Workflow Agent", - action: "Extracted task candidates", - timestamp: "2026-03-10 08:08", - status: "draft", - summary: "Produced three task candidates linked to the current note body.", - }, - { - id: "event-3", - actor: "Operator", - action: "Approved editorial summary", - timestamp: "2026-03-10 08:03", - status: "approved", - summary: "Accepted a summary rewrite and preserved original source wording in history.", - }, -]; - -export const mockNoteDetails: Record = { - "note-prd-cutline": { - ...mockNotes[0], - body: "# MVP Cut Line\n\nThe initial release must feel trustworthy for both humans and agents.\n\n## Must ship\n- Web authoring shell\n- Notes and workspace routes\n- Search and retrieval entry points\n- Agent review and approval placeholders\n\n## Defer if needed\n- Rich artifact upload orchestration\n- Advanced semantic ranking\n- Deep operator analytics", - metadata: { - owner: "Product Lead", - source: "manual", - reviewState: "approved", - taskCount: 3, - artifactCount: 2, - }, - linkedNotes: [ - { id: "note-web-shell", title: "Web shell execution plan", relationship: "implements" }, - { id: "note-platform-deps", title: "Platform integration dependencies for v1", relationship: "depends_on" }, - ], - tasks: [ - { id: "task-w0", title: "Stand up web shell", status: "in_progress", source: "manual" }, - { id: "task-w1", title: "Define backend integration boundary", status: "todo", source: "manual" }, - { id: "task-w2", title: "Review approval UX cut line", status: "todo", source: "agent" }, - ], - artifacts: [ - { id: "artifact-prd", name: "PRD v2.0", type: "document", status: "ready" }, - { id: "artifact-roadmap", name: "Roadmap execution sheet", type: "document", status: "ready" }, - ], - timeline: mockTimeline, - }, - "note-web-shell": { - ...mockNotes[1], - body: "# Web Shell Execution Plan\n\nUse existing ByteLyst web patterns.\n\n- App Router shell\n- Shared clients and tokens\n- Workspace-first navigation\n- Mock data until backend contracts stabilize", - metadata: { - owner: "Web Agent", - source: "agent", - reviewState: "proposed", - taskCount: 2, - artifactCount: 1, - }, - linkedNotes: [ - { id: "note-prd-cutline", title: "MVP cut line for agentic notes launch", relationship: "supports" }, - ], - tasks: [ - { id: "task-shell-1", title: "Create route skeleton", status: "done", source: "agent" }, - { id: "task-shell-2", title: "Wire providers", status: "in_progress", source: "agent" }, - ], - artifacts: [ - { id: "artifact-shell", name: "UI scaffold", type: "ui", status: "processing" }, - ], - timeline: mockTimeline, - }, -}; - -export function getWorkspaceById(id: string) { - return mockWorkspaces.find((workspace) => workspace.id === id) ?? null; -} - -export function getNoteById(id: string) { - return mockNoteDetails[id] ?? null; -} - -export function getNotesForWorkspace(workspaceId: string) { - return mockNotes.filter((note) => note.workspaceId === workspaceId); -} diff --git a/web/src/lib/notes-client.ts b/web/src/lib/notes-client.ts index 2c984f8..863f461 100644 --- a/web/src/lib/notes-client.ts +++ b/web/src/lib/notes-client.ts @@ -1,3 +1,5 @@ +"use client"; + import { extractSuggestedTasks } from "@/lib/extraction-client"; import { createNotesApiClient } from "@/lib/api-helpers"; import type { AgentTimelineItem, ArtifactSummary, LinkedNote, NoteDetail, NoteSummary, NoteTask, WorkspaceSummary } from "@/lib/types"; diff --git a/web/src/lib/review-data.ts b/web/src/lib/review-data.ts deleted file mode 100644 index 97ccb1d..0000000 --- a/web/src/lib/review-data.ts +++ /dev/null @@ -1,45 +0,0 @@ -import type { AgentTimelineItem } from "@/lib/types"; - -export const mockAgentTimeline: AgentTimelineItem[] = [ - { - id: "event-1", - actor: "Research Agent", - action: "Proposed metadata enrichment", - timestamp: "2026-03-10 08:11", - status: "proposed", - summary: "Suggested new tags, source metadata, and a research confidence note.", - }, - { - id: "event-2", - actor: "Workflow Agent", - action: "Extracted task candidates", - timestamp: "2026-03-10 08:08", - status: "draft", - summary: "Produced three task candidates linked to the current note body.", - }, - { - id: "event-3", - actor: "Operator", - action: "Approved editorial summary", - timestamp: "2026-03-10 08:03", - status: "approved", - summary: "Accepted a summary rewrite and preserved original source wording in history.", - }, -]; - -export const mockApprovalQueue = [ - { - id: "approval-1", - title: "Apply extracted task set to MVP cut line note", - owner: "Workflow Agent", - severity: "medium", - status: "awaiting_review", - }, - { - id: "approval-2", - title: "Approve note summary rewrite for Product Strategy workspace", - owner: "Research Agent", - severity: "low", - status: "awaiting_review", - }, -];