|
@@ -2,15 +2,28 @@ import { listAdaptors } from "@/control-plane/adaptors"
|
|
|
import { Workspace } from "@/control-plane/workspace"
|
|
import { Workspace } from "@/control-plane/workspace"
|
|
|
import { WorkspaceAdaptorEntry } from "@/control-plane/types"
|
|
import { WorkspaceAdaptorEntry } from "@/control-plane/types"
|
|
|
import * as InstanceState from "@/effect/instance-state"
|
|
import * as InstanceState from "@/effect/instance-state"
|
|
|
-import { Effect, Layer, Schema } from "effect"
|
|
|
|
|
|
|
+import { Instance } from "@/project/instance"
|
|
|
|
|
+import { Effect, Layer, Schema, Struct } from "effect"
|
|
|
import { HttpApi, HttpApiBuilder, HttpApiEndpoint, HttpApiGroup, OpenApi } from "effect/unstable/httpapi"
|
|
import { HttpApi, HttpApiBuilder, HttpApiEndpoint, HttpApiGroup, OpenApi } from "effect/unstable/httpapi"
|
|
|
import { Authorization } from "./auth"
|
|
import { Authorization } from "./auth"
|
|
|
|
|
|
|
|
const root = "/experimental/workspace"
|
|
const root = "/experimental/workspace"
|
|
|
|
|
+const CreatePayload = Schema.Struct(Struct.omit(Workspace.CreateInput.fields, ["projectID"])).annotate({
|
|
|
|
|
+ identifier: "WorkspaceCreateInput",
|
|
|
|
|
+})
|
|
|
|
|
+const SessionRestorePayload = Schema.Struct(Struct.omit(Workspace.SessionRestoreInput.fields, ["workspaceID"])).annotate({
|
|
|
|
|
+ identifier: "WorkspaceSessionRestoreInput",
|
|
|
|
|
+})
|
|
|
|
|
+const SessionRestoreResponse = Schema.Struct({
|
|
|
|
|
+ total: Schema.Number,
|
|
|
|
|
+}).annotate({ identifier: "WorkspaceSessionRestoreResponse" })
|
|
|
|
|
+
|
|
|
export const WorkspacePaths = {
|
|
export const WorkspacePaths = {
|
|
|
adaptors: `${root}/adaptor`,
|
|
adaptors: `${root}/adaptor`,
|
|
|
list: root,
|
|
list: root,
|
|
|
status: `${root}/status`,
|
|
status: `${root}/status`,
|
|
|
|
|
+ remove: `${root}/:id`,
|
|
|
|
|
+ sessionRestore: `${root}/:id/session-restore`,
|
|
|
} as const
|
|
} as const
|
|
|
|
|
|
|
|
export const WorkspaceApi = HttpApi.make("workspace")
|
|
export const WorkspaceApi = HttpApi.make("workspace")
|
|
@@ -35,6 +48,16 @@ export const WorkspaceApi = HttpApi.make("workspace")
|
|
|
description: "List all workspaces.",
|
|
description: "List all workspaces.",
|
|
|
}),
|
|
}),
|
|
|
),
|
|
),
|
|
|
|
|
+ HttpApiEndpoint.post("create", WorkspacePaths.list, {
|
|
|
|
|
+ payload: CreatePayload,
|
|
|
|
|
+ success: Workspace.Info,
|
|
|
|
|
+ }).annotateMerge(
|
|
|
|
|
+ OpenApi.annotations({
|
|
|
|
|
+ identifier: "experimental.workspace.create",
|
|
|
|
|
+ summary: "Create workspace",
|
|
|
|
|
+ description: "Create a workspace for the current project.",
|
|
|
|
|
+ }),
|
|
|
|
|
+ ),
|
|
|
HttpApiEndpoint.get("status", WorkspacePaths.status, {
|
|
HttpApiEndpoint.get("status", WorkspacePaths.status, {
|
|
|
success: Schema.Array(Workspace.ConnectionStatus),
|
|
success: Schema.Array(Workspace.ConnectionStatus),
|
|
|
}).annotateMerge(
|
|
}).annotateMerge(
|
|
@@ -44,6 +67,27 @@ export const WorkspaceApi = HttpApi.make("workspace")
|
|
|
description: "Get connection status for workspaces in the current project.",
|
|
description: "Get connection status for workspaces in the current project.",
|
|
|
}),
|
|
}),
|
|
|
),
|
|
),
|
|
|
|
|
+ HttpApiEndpoint.delete("remove", WorkspacePaths.remove, {
|
|
|
|
|
+ params: { id: Workspace.Info.fields.id },
|
|
|
|
|
+ success: Schema.UndefinedOr(Workspace.Info),
|
|
|
|
|
+ }).annotateMerge(
|
|
|
|
|
+ OpenApi.annotations({
|
|
|
|
|
+ identifier: "experimental.workspace.remove",
|
|
|
|
|
+ summary: "Remove workspace",
|
|
|
|
|
+ description: "Remove an existing workspace.",
|
|
|
|
|
+ }),
|
|
|
|
|
+ ),
|
|
|
|
|
+ HttpApiEndpoint.post("sessionRestore", WorkspacePaths.sessionRestore, {
|
|
|
|
|
+ params: { id: Workspace.Info.fields.id },
|
|
|
|
|
+ payload: SessionRestorePayload,
|
|
|
|
|
+ success: SessionRestoreResponse,
|
|
|
|
|
+ }).annotateMerge(
|
|
|
|
|
+ OpenApi.annotations({
|
|
|
|
|
+ identifier: "experimental.workspace.sessionRestore",
|
|
|
|
|
+ summary: "Restore session into workspace",
|
|
|
|
|
+ description: "Replay a session's sync events into the target workspace in batches.",
|
|
|
|
|
+ }),
|
|
|
|
|
+ ),
|
|
|
)
|
|
)
|
|
|
.annotateMerge(
|
|
.annotateMerge(
|
|
|
OpenApi.annotations({
|
|
OpenApi.annotations({
|
|
@@ -72,13 +116,51 @@ export const workspaceHandlers = Layer.unwrap(
|
|
|
return Workspace.list((yield* InstanceState.context).project)
|
|
return Workspace.list((yield* InstanceState.context).project)
|
|
|
})
|
|
})
|
|
|
|
|
|
|
|
|
|
+ const create = Effect.fn("WorkspaceHttpApi.create")(function* (ctx: { payload: typeof CreatePayload.Type }) {
|
|
|
|
|
+ const instance = yield* InstanceState.context
|
|
|
|
|
+ return yield* Effect.promise(() =>
|
|
|
|
|
+ Instance.restore(instance, () =>
|
|
|
|
|
+ Workspace.create({
|
|
|
|
|
+ ...Schema.decodeUnknownSync(CreatePayload)(ctx.payload),
|
|
|
|
|
+ projectID: instance.project.id,
|
|
|
|
|
+ }),
|
|
|
|
|
+ ),
|
|
|
|
|
+ )
|
|
|
|
|
+ })
|
|
|
|
|
+
|
|
|
const status = Effect.fn("WorkspaceHttpApi.status")(function* () {
|
|
const status = Effect.fn("WorkspaceHttpApi.status")(function* () {
|
|
|
const ids = new Set(Workspace.list((yield* InstanceState.context).project).map((item) => item.id))
|
|
const ids = new Set(Workspace.list((yield* InstanceState.context).project).map((item) => item.id))
|
|
|
return Workspace.status().filter((item) => ids.has(item.workspaceID))
|
|
return Workspace.status().filter((item) => ids.has(item.workspaceID))
|
|
|
})
|
|
})
|
|
|
|
|
|
|
|
|
|
+ const remove = Effect.fn("WorkspaceHttpApi.remove")(function* (ctx: { params: { id: Workspace.Info["id"] } }) {
|
|
|
|
|
+ const instance = yield* InstanceState.context
|
|
|
|
|
+ return yield* Effect.promise(() => Instance.restore(instance, () => Workspace.remove(ctx.params.id)))
|
|
|
|
|
+ })
|
|
|
|
|
+
|
|
|
|
|
+ const sessionRestore = Effect.fn("WorkspaceHttpApi.sessionRestore")(function* (ctx: {
|
|
|
|
|
+ params: { id: Workspace.Info["id"] }
|
|
|
|
|
+ payload: typeof SessionRestorePayload.Type
|
|
|
|
|
+ }) {
|
|
|
|
|
+ const instance = yield* InstanceState.context
|
|
|
|
|
+ return yield* Effect.promise(() =>
|
|
|
|
|
+ Instance.restore(instance, () =>
|
|
|
|
|
+ Workspace.sessionRestore({
|
|
|
|
|
+ workspaceID: ctx.params.id,
|
|
|
|
|
+ sessionID: ctx.payload.sessionID,
|
|
|
|
|
+ }),
|
|
|
|
|
+ ),
|
|
|
|
|
+ )
|
|
|
|
|
+ })
|
|
|
|
|
+
|
|
|
return HttpApiBuilder.group(WorkspaceApi, "workspace", (handlers) =>
|
|
return HttpApiBuilder.group(WorkspaceApi, "workspace", (handlers) =>
|
|
|
- handlers.handle("adaptors", adaptors).handle("list", list).handle("status", status),
|
|
|
|
|
|
|
+ handlers
|
|
|
|
|
+ .handle("adaptors", adaptors)
|
|
|
|
|
+ .handle("list", list)
|
|
|
|
|
+ .handle("create", create)
|
|
|
|
|
+ .handle("status", status)
|
|
|
|
|
+ .handle("remove", remove)
|
|
|
|
|
+ .handle("sessionRestore", sessionRestore),
|
|
|
)
|
|
)
|
|
|
}),
|
|
}),
|
|
|
)
|
|
)
|