import { z } from "zod"; import type { AuditLogProtocol } from "@repo/core-shared/di/bind-protocols"; import { gitUrlSchema, workspaceSchema } from "../../entities/models/workspace"; import type { IWorkspaceRepository } from "../repositories/workspace.repository.interface"; // ── Input ──────────────────────────────────────────────────────────────── export const connectWorkspaceInputSchema = z .object({ name: z.string().min(1).max(128), gitUrl: gitUrlSchema, /** Repository personal access token. Write-only: encrypted at rest and never returned by any output. */ pat: z.string().min(1).max(4096), }) .strict(); export type ConnectWorkspaceInput = z.infer; // ── Output ─────────────────────────────────────────────────────────────── // The credential is deliberately absent: `workspaceSchema` has no credential // field, and `.parse` strips any unknown keys a repository might leak. export const connectWorkspaceOutputSchema = workspaceSchema; export type ConnectWorkspaceOutput = z.infer< typeof connectWorkspaceOutputSchema >; // ── Use case ───────────────────────────────────────────────────────────── export type IConnectWorkspaceUseCase = ReturnType< typeof connectWorkspaceUseCase >; export const connectWorkspaceUseCase = (workspaceRepository: IWorkspaceRepository, auditLog?: AuditLogProtocol) => async (input: ConnectWorkspaceInput): Promise => { const workspace = await workspaceRepository.createWorkspace({ name: input.name, gitUrl: input.gitUrl, credential: input.pat, }); // Audit event "workspace-connected" — declared in feature.manifest.ts // (useCases.connectWorkspace.audits). No session context exists at this // layer yet (auth wiring is a later story), so the system sentinels apply. await auditLog?.record({ actorId: "system", actorType: "system", actorRoles: [], action: "CREATE", resource: { type: "workspaces", id: workspace.id }, at: new Date(), scope: { feature: "workspaces", environment: process.env.NODE_ENV ?? "development", tenant: "default", }, from: { ipTruncated: "system", userAgent: "control-plane" }, containsPii: false, outcome: "success", reason: "workspace-connected", }); return connectWorkspaceOutputSchema.parse(workspace); };