204 lines
5.7 KiB
TypeScript
204 lines
5.7 KiB
TypeScript
import { Hono } from "hono"
|
|
import { describeRoute, resolver, validator } from "hono-openapi"
|
|
import z from "zod"
|
|
import { listAdaptors } from "../../control-plane/adaptors"
|
|
import { Workspace } from "../../control-plane/workspace"
|
|
import { Instance } from "../../project/instance"
|
|
import { errors } from "../error"
|
|
import { lazy } from "../../util/lazy"
|
|
import { Log } from "@/util/log"
|
|
import { errorData } from "@/util/error"
|
|
|
|
const log = Log.create({ service: "server.workspace" })
|
|
|
|
export const WorkspaceRoutes = lazy(() =>
|
|
new Hono()
|
|
.get(
|
|
"/adaptor",
|
|
describeRoute({
|
|
summary: "List workspace adaptors",
|
|
description: "List all available workspace adaptors for the current project.",
|
|
operationId: "experimental.workspace.adaptor.list",
|
|
responses: {
|
|
200: {
|
|
description: "Workspace adaptors",
|
|
content: {
|
|
"application/json": {
|
|
schema: resolver(
|
|
z.array(
|
|
z.object({
|
|
type: z.string(),
|
|
name: z.string(),
|
|
description: z.string(),
|
|
}),
|
|
),
|
|
),
|
|
},
|
|
},
|
|
},
|
|
},
|
|
}),
|
|
async (c) => {
|
|
return c.json(await listAdaptors(Instance.project.id))
|
|
},
|
|
)
|
|
.post(
|
|
"/",
|
|
describeRoute({
|
|
summary: "Create workspace",
|
|
description: "Create a workspace for the current project.",
|
|
operationId: "experimental.workspace.create",
|
|
responses: {
|
|
200: {
|
|
description: "Workspace created",
|
|
content: {
|
|
"application/json": {
|
|
schema: resolver(Workspace.Info),
|
|
},
|
|
},
|
|
},
|
|
...errors(400),
|
|
},
|
|
}),
|
|
validator(
|
|
"json",
|
|
Workspace.create.schema.omit({
|
|
projectID: true,
|
|
}),
|
|
),
|
|
async (c) => {
|
|
const body = c.req.valid("json")
|
|
const workspace = await Workspace.create({
|
|
projectID: Instance.project.id,
|
|
...body,
|
|
})
|
|
return c.json(workspace)
|
|
},
|
|
)
|
|
.get(
|
|
"/",
|
|
describeRoute({
|
|
summary: "List workspaces",
|
|
description: "List all workspaces.",
|
|
operationId: "experimental.workspace.list",
|
|
responses: {
|
|
200: {
|
|
description: "Workspaces",
|
|
content: {
|
|
"application/json": {
|
|
schema: resolver(z.array(Workspace.Info)),
|
|
},
|
|
},
|
|
},
|
|
},
|
|
}),
|
|
async (c) => {
|
|
return c.json(Workspace.list(Instance.project))
|
|
},
|
|
)
|
|
.get(
|
|
"/status",
|
|
describeRoute({
|
|
summary: "Workspace status",
|
|
description: "Get connection status for workspaces in the current project.",
|
|
operationId: "experimental.workspace.status",
|
|
responses: {
|
|
200: {
|
|
description: "Workspace status",
|
|
content: {
|
|
"application/json": {
|
|
schema: resolver(z.array(Workspace.ConnectionStatus)),
|
|
},
|
|
},
|
|
},
|
|
},
|
|
}),
|
|
async (c) => {
|
|
const ids = new Set(Workspace.list(Instance.project).map((item) => item.id))
|
|
return c.json(Workspace.status().filter((item) => ids.has(item.workspaceID)))
|
|
},
|
|
)
|
|
.delete(
|
|
"/:id",
|
|
describeRoute({
|
|
summary: "Remove workspace",
|
|
description: "Remove an existing workspace.",
|
|
operationId: "experimental.workspace.remove",
|
|
responses: {
|
|
200: {
|
|
description: "Workspace removed",
|
|
content: {
|
|
"application/json": {
|
|
schema: resolver(Workspace.Info.optional()),
|
|
},
|
|
},
|
|
},
|
|
...errors(400),
|
|
},
|
|
}),
|
|
validator(
|
|
"param",
|
|
z.object({
|
|
id: Workspace.Info.shape.id,
|
|
}),
|
|
),
|
|
async (c) => {
|
|
const { id } = c.req.valid("param")
|
|
return c.json(await Workspace.remove(id))
|
|
},
|
|
)
|
|
.post(
|
|
"/:id/session-restore",
|
|
describeRoute({
|
|
summary: "Restore session into workspace",
|
|
description: "Replay a session's sync events into the target workspace in batches.",
|
|
operationId: "experimental.workspace.sessionRestore",
|
|
responses: {
|
|
200: {
|
|
description: "Session replay started",
|
|
content: {
|
|
"application/json": {
|
|
schema: resolver(
|
|
z.object({
|
|
total: z.number().int().min(0),
|
|
}),
|
|
),
|
|
},
|
|
},
|
|
},
|
|
...errors(400),
|
|
},
|
|
}),
|
|
validator("param", z.object({ id: Workspace.Info.shape.id })),
|
|
validator("json", Workspace.sessionRestore.schema.omit({ workspaceID: true })),
|
|
async (c) => {
|
|
const { id } = c.req.valid("param")
|
|
const body = c.req.valid("json")
|
|
log.info("session restore route requested", {
|
|
workspaceID: id,
|
|
sessionID: body.sessionID,
|
|
directory: Instance.directory,
|
|
})
|
|
try {
|
|
const result = await Workspace.sessionRestore({
|
|
workspaceID: id,
|
|
...body,
|
|
})
|
|
log.info("session restore route complete", {
|
|
workspaceID: id,
|
|
sessionID: body.sessionID,
|
|
total: result.total,
|
|
})
|
|
return c.json(result)
|
|
} catch (err) {
|
|
log.error("session restore route failed", {
|
|
workspaceID: id,
|
|
sessionID: body.sessionID,
|
|
error: errorData(err),
|
|
})
|
|
throw err
|
|
}
|
|
},
|
|
),
|
|
)
|