fix(opencode): restore global sync event compatibility
This commit is contained in:
@@ -291,7 +291,7 @@ export const { use: useSyncV2, provider: SyncProviderV2 } = createSimpleContext(
|
||||
message: {
|
||||
async sync(sessionID: string) {
|
||||
const response = await sdk.client.v2.session.messages({ sessionID })
|
||||
setStore("messages", sessionID, reconcile(response.data?.items ?? []))
|
||||
setStore("messages", sessionID, reconcile(response.data?.data.items ?? []))
|
||||
},
|
||||
fromSession(sessionID: string) {
|
||||
const messages = store.messages[sessionID]
|
||||
|
||||
@@ -44,6 +44,21 @@ export const layer = Layer.effect(
|
||||
workspace: workspaceID,
|
||||
payload: { id: event.id, type: event.type, properties: event.data },
|
||||
})
|
||||
if (!event.sync || event.version === undefined) return
|
||||
GlobalBus.emit("event", {
|
||||
directory: event.location?.directory ?? ctx?.directory,
|
||||
project: ctx?.project.id,
|
||||
workspace: workspaceID,
|
||||
payload: {
|
||||
type: "sync",
|
||||
syncEvent: {
|
||||
id: event.id,
|
||||
type: EventV2.versionedType(event.type, event.version),
|
||||
...event.sync,
|
||||
data: event.data,
|
||||
},
|
||||
},
|
||||
})
|
||||
}),
|
||||
)
|
||||
yield* Effect.addFinalizer(() => unsubscribe)
|
||||
|
||||
@@ -20,11 +20,14 @@ const SyncEventSchemas = EventV2.registry
|
||||
return [
|
||||
Schema.Struct({
|
||||
type: Schema.Literal("sync"),
|
||||
name: Schema.Literal(EventV2.versionedType(definition.type, definition.sync.version)),
|
||||
id: Schema.String,
|
||||
seq: Schema.Finite,
|
||||
aggregateID: Schema.Literal(definition.sync.aggregate),
|
||||
data: definition.data,
|
||||
syncEvent: Schema.Struct({
|
||||
type: Schema.Literal(EventV2.versionedType(definition.type, definition.sync.version)),
|
||||
id: Schema.String,
|
||||
seq: Schema.Finite,
|
||||
aggregateID: Schema.String,
|
||||
data: definition.data,
|
||||
}),
|
||||
}).annotate({ identifier: `SyncEvent.${definition.type}` }),
|
||||
]
|
||||
})
|
||||
|
||||
@@ -3,7 +3,13 @@ import { OpenApi } from "effect/unstable/httpapi"
|
||||
import { PublicApi } from "../../src/server/routes/instance/httpapi/public"
|
||||
|
||||
type Method = "get" | "post" | "put" | "delete" | "patch"
|
||||
type OpenApiSchema = { readonly $ref?: string }
|
||||
type OpenApiSchema = {
|
||||
readonly $ref?: string
|
||||
readonly type?: string
|
||||
readonly enum?: readonly unknown[]
|
||||
readonly properties?: Record<string, OpenApiSchema>
|
||||
readonly required?: readonly string[]
|
||||
}
|
||||
type OpenApiResponse = {
|
||||
readonly description?: string
|
||||
readonly content?: Record<string, { readonly schema?: OpenApiSchema }>
|
||||
@@ -19,7 +25,10 @@ type OpenApiOperation = {
|
||||
readonly security?: unknown
|
||||
}
|
||||
type OpenApiPathItem = Partial<Record<Method, OpenApiOperation>>
|
||||
type OpenApiSpec = { readonly paths: Record<string, OpenApiPathItem> }
|
||||
type OpenApiSpec = {
|
||||
readonly paths: Record<string, OpenApiPathItem>
|
||||
readonly components: { readonly schemas: Record<string, OpenApiSchema> }
|
||||
}
|
||||
|
||||
const methods = ["get", "post", "put", "delete", "patch"] as const
|
||||
|
||||
@@ -49,6 +58,23 @@ function isBuiltInEndpointError(name: string) {
|
||||
}
|
||||
|
||||
describe("PublicApi OpenAPI v2 errors", () => {
|
||||
test("documents nested legacy global sync events", () => {
|
||||
const spec = OpenApi.fromApi(PublicApi) as OpenApiSpec
|
||||
const schema = spec.components.schemas.SyncEventSessionCreated
|
||||
|
||||
expect(schema?.required).toEqual(["type", "id", "syncEvent"])
|
||||
expect(schema?.properties?.type?.enum).toEqual(["sync"])
|
||||
expect(schema?.properties?.syncEvent).toMatchObject({
|
||||
required: ["type", "id", "seq", "aggregateID", "data"],
|
||||
properties: {
|
||||
type: { enum: ["session.created.1"] },
|
||||
id: { type: "string" },
|
||||
seq: { type: "number" },
|
||||
aggregateID: { type: "string" },
|
||||
},
|
||||
})
|
||||
})
|
||||
|
||||
test("preserves /api auth responses", () => {
|
||||
const spec = OpenApi.fromApi(PublicApi) as OpenApiSpec
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { describe, expect } from "bun:test"
|
||||
import { SessionV1 } from "@opencode-ai/core/v1/session"
|
||||
import { Database } from "@opencode-ai/core/database/database"
|
||||
import { EventV2 } from "@opencode-ai/core/event"
|
||||
import { SessionProjector } from "@opencode-ai/core/session/projector"
|
||||
import { Deferred, Effect, Exit, Layer } from "effect"
|
||||
import { Session as SessionNs } from "@/session/session"
|
||||
@@ -14,6 +15,7 @@ import { Storage } from "@/storage/storage"
|
||||
import { RuntimeFlags } from "@/effect/runtime-flags"
|
||||
import { BackgroundJob } from "@/background/job"
|
||||
import { EventV2Bridge } from "@/event-v2-bridge"
|
||||
import { GlobalBus } from "@/bus/global"
|
||||
|
||||
void Log.init({ print: false })
|
||||
|
||||
@@ -101,6 +103,31 @@ describe("session.created event", () => {
|
||||
yield* session.remove(info.id)
|
||||
}),
|
||||
)
|
||||
|
||||
it.instance("emits legacy global sync payload", () =>
|
||||
Effect.gen(function* () {
|
||||
const session = yield* SessionNs.Service
|
||||
const received = yield* Deferred.make<{ syncEvent: EventV2.SerializedEvent }>()
|
||||
const listener = (event: { payload: { type?: string; syncEvent?: EventV2.SerializedEvent } }) => {
|
||||
if (event.payload.type === "sync" && event.payload.syncEvent)
|
||||
Deferred.doneUnsafe(received, Effect.succeed({ syncEvent: event.payload.syncEvent }))
|
||||
}
|
||||
GlobalBus.on("event", listener)
|
||||
yield* Effect.addFinalizer(() => Effect.sync(() => GlobalBus.off("event", listener)))
|
||||
|
||||
const info = yield* session.create({})
|
||||
const event = yield* awaitDeferred(received, "timed out waiting for legacy global sync event")
|
||||
|
||||
expect(event.syncEvent).toMatchObject({
|
||||
type: EventV2.versionedType(SessionNs.Event.Created.type, 1),
|
||||
seq: 0,
|
||||
aggregateID: info.id,
|
||||
data: { sessionID: info.id },
|
||||
})
|
||||
|
||||
yield* session.remove(info.id)
|
||||
}),
|
||||
)
|
||||
})
|
||||
|
||||
describe("step-finish token propagation via event", () => {
|
||||
|
||||
Reference in New Issue
Block a user