92 lines
3.3 KiB
TypeScript
92 lines
3.3 KiB
TypeScript
import { NonNegativeInt } from "@/util/schema"
|
|
import { Schema } from "effect"
|
|
import { HttpApi, HttpApiEndpoint, HttpApiError, HttpApiGroup, OpenApi } from "effect/unstable/httpapi"
|
|
import { Authorization } from "../middleware/authorization"
|
|
import { InstanceContextMiddleware } from "../middleware/instance-context"
|
|
import { WorkspaceRoutingMiddleware } from "../middleware/workspace-routing"
|
|
import { described } from "./metadata"
|
|
|
|
const root = "/sync"
|
|
export const ReplayEvent = Schema.Struct({
|
|
id: Schema.String,
|
|
aggregateID: Schema.String,
|
|
seq: NonNegativeInt,
|
|
type: Schema.String,
|
|
data: Schema.Record(Schema.String, Schema.Unknown),
|
|
})
|
|
export const ReplayPayload = Schema.Struct({
|
|
directory: Schema.String,
|
|
events: Schema.NonEmptyArray(ReplayEvent),
|
|
})
|
|
export const ReplayResponse = Schema.Struct({
|
|
sessionID: Schema.String,
|
|
})
|
|
export const HistoryPayload = Schema.Record(Schema.String, NonNegativeInt)
|
|
export const HistoryEvent = Schema.Struct({
|
|
id: Schema.String,
|
|
aggregate_id: Schema.String,
|
|
seq: NonNegativeInt,
|
|
type: Schema.String,
|
|
data: Schema.Record(Schema.String, Schema.Unknown),
|
|
})
|
|
|
|
export const SyncPaths = {
|
|
start: `${root}/start`,
|
|
replay: `${root}/replay`,
|
|
history: `${root}/history`,
|
|
} as const
|
|
|
|
export const SyncApi = HttpApi.make("sync")
|
|
.add(
|
|
HttpApiGroup.make("sync")
|
|
.add(
|
|
HttpApiEndpoint.post("start", SyncPaths.start, {
|
|
success: described(Schema.Boolean, "Workspace sync started"),
|
|
}).annotateMerge(
|
|
OpenApi.annotations({
|
|
identifier: "sync.start",
|
|
summary: "Start workspace sync",
|
|
description: "Start sync loops for workspaces in the current project that have active sessions.",
|
|
}),
|
|
),
|
|
HttpApiEndpoint.post("replay", SyncPaths.replay, {
|
|
payload: ReplayPayload,
|
|
success: described(ReplayResponse, "Replayed sync events"),
|
|
error: HttpApiError.BadRequest,
|
|
}).annotateMerge(
|
|
OpenApi.annotations({
|
|
identifier: "sync.replay",
|
|
summary: "Replay sync events",
|
|
description: "Validate and replay a complete sync event history.",
|
|
}),
|
|
),
|
|
HttpApiEndpoint.post("history", SyncPaths.history, {
|
|
payload: HistoryPayload,
|
|
success: described(Schema.Array(HistoryEvent), "Sync events"),
|
|
error: HttpApiError.BadRequest,
|
|
}).annotateMerge(
|
|
OpenApi.annotations({
|
|
identifier: "sync.history.list",
|
|
summary: "List sync events",
|
|
description:
|
|
"List sync events for all aggregates. Keys are aggregate IDs the client already knows about, values are the last known sequence ID. Events with seq > value are returned for those aggregates. Aggregates not listed in the input get their full history.",
|
|
}),
|
|
),
|
|
)
|
|
.annotateMerge(
|
|
OpenApi.annotations({
|
|
title: "sync",
|
|
description: "Experimental HttpApi sync routes.",
|
|
}),
|
|
)
|
|
.middleware(InstanceContextMiddleware)
|
|
.middleware(WorkspaceRoutingMiddleware)
|
|
.middleware(Authorization),
|
|
)
|
|
.annotateMerge(
|
|
OpenApi.annotations({
|
|
title: "opencode experimental HttpApi",
|
|
version: "0.0.1",
|
|
description: "Experimental HttpApi surface for selected instance routes.",
|
|
}),
|
|
)
|