From 95f264e04eca61b4a81ef92ee29476556d299a68 Mon Sep 17 00:00:00 2001 From: Kit Langton Date: Thu, 25 Jun 2026 11:35:11 -0400 Subject: [PATCH] refactor(schema): distinguish published event durability --- CONTEXT.md | 1 + packages/core/src/event.ts | 108 ++-- packages/core/test/event.test.ts | 4 +- .../server/httpapi-public-openapi.test.ts | 10 + .../test/v2/session-message-updater.test.ts | 17 + packages/protocol/src/groups/event.ts | 18 +- packages/schema/src/event.ts | 98 ++-- packages/schema/test/event.test.ts | 95 ++++ packages/sdk/js/src/v2/gen/types.gen.ts | 475 ++++-------------- 9 files changed, 373 insertions(+), 453 deletions(-) diff --git a/CONTEXT.md b/CONTEXT.md index 97919b63f6..d379facbba 100644 --- a/CONTEXT.md +++ b/CONTEXT.md @@ -141,6 +141,7 @@ _Avoid_: Response envelope - Promise streaming methods return a lazy `AsyncIterable` directly rather than a Promise-wrapped stream object. Iteration opens the connection, `AbortSignal` cancels it, and ending iteration closes the underlying request; the Effect emitter analogously returns `Stream` directly. - Promise SSE connection establishment, declared HTTP failures, and infrastructure failures occur during `AsyncIterable` iteration, beginning with its first `next()` call, rather than during synchronous method construction. - Neither generated streaming runtime automatically reconnects after disconnection. Promise `AsyncIterable` and Effect `Stream` fail explicitly; live consumers refresh and resubscribe, while durable sequence-based resume remains explicit composition above the generated client. +- Event definition durability is authoritative for published payloads. Durable definitions publish and decode only with commit metadata (`aggregateID`, `seq`, and `version`); live definitions forbid that metadata. Core's pre-commit payload without an assigned sequence is a separate internal type and never reaches subscribers or projectors. - Promise client construction is synchronous and network-free. It requires `baseUrl`, defaults to `globalThis.fetch`, accepts client-level headers, and merges them with per-call header overrides. - Effect client construction accepts an explicit `baseUrl` and obtains `HttpClient.HttpClient` from the Effect environment. It does not install fetch or duplicate per-call transport policy; callers transform/provide the client for headers, tracing, retries, recording, and tests, while fiber interruption owns cancellation. - Promise and Effect emitters each own their generated public type modules. The **SDK Contract IR**, not a physically shared generated type package, is the common source; this permits zero-Effect wire types and rich decoded Effect types to evolve independently. diff --git a/packages/core/src/event.ts b/packages/core/src/event.ts index 132a88b111..d8ec020627 100644 --- a/packages/core/src/event.ts +++ b/packages/core/src/event.ts @@ -2,7 +2,14 @@ export * as EventV2 from "./event" import { Cause, Context, Effect, Layer, Option, PubSub, Schema, Stream } from "effect" import { Event } from "@opencode-ai/schema/event" -import type { Data, Definition, Payload } from "@opencode-ai/schema/event" +import type { + Data, + Definition, + DurableDefinition, + Payload, + PublishedPayload, + UncommittedPayload, +} from "@opencode-ai/schema/event" import { and, asc, eq, gt } from "drizzle-orm" import { Database } from "./database/database" import { EventSequenceTable, EventTable } from "./event/sql" @@ -13,7 +20,14 @@ import { Durable } from "@opencode-ai/schema/durable-event-manifest" export const ID = Event.ID export type ID = import("@opencode-ai/schema/event").ID -export type { Data, Definition, Payload } from "@opencode-ai/schema/event" +export type { + Data, + Definition, + DurableDefinition, + Payload, + PublishedPayload, + UncommittedPayload, +} from "@opencode-ai/schema/event" export type Subscriber = (event: Payload) => Effect.Effect export type Unsubscribe = Effect.Effect @@ -66,10 +80,13 @@ export interface Interface { ) => Effect.Effect> readonly subscribe: (definition: D) => Stream.Stream> readonly all: () => Stream.Stream - readonly durable: (input: { readonly aggregateID: string; readonly after?: number }) => Stream.Stream + readonly durable: (input: { + readonly aggregateID: string + readonly after?: number + }) => Stream.Stream> /** @deprecated Use `all()` and consume the returned stream. */ readonly listen: (listener: Subscriber) => Effect.Effect - readonly project: (definition: D, projector: Subscriber) => Effect.Effect + readonly project: (definition: D, projector: Subscriber) => Effect.Effect readonly replay: ( event: SerializedEvent, options?: { readonly publish?: boolean; readonly ownerID?: string; readonly strictOwner?: boolean }, @@ -124,8 +141,8 @@ export const layerWith = (options?: LayerOptions) => ) function commitDurableEvent( - definition: Definition, - event: Payload, + definition: DurableDefinition, + event: UncommittedPayload, input?: { readonly seq: number readonly aggregateID: string @@ -135,7 +152,7 @@ export const layerWith = (options?: LayerOptions) => commit?: (seq: number) => Effect.Effect, ) { return Effect.gen(function* () { - const durable = definition?.durable + const durable = definition.durable if (durable) { const aggregateID = (event.data as Record)[durable.aggregate] if (typeof aggregateID !== "string") { @@ -200,7 +217,7 @@ export const layerWith = (options?: LayerOptions) => .run() .pipe(Effect.orDie) } - return + return undefined } yield* Effect.die( new InvalidDurableEventError({ @@ -210,7 +227,7 @@ export const layerWith = (options?: LayerOptions) => ) } if (input && row?.ownerID && row.ownerID !== input.ownerID) { - return + return undefined } const seq = input?.seq ?? latest + 1 if (input && seq !== latest + 1) { @@ -234,10 +251,10 @@ export const layerWith = (options?: LayerOptions) => message: `Event ${event.id} already exists at aggregate ${stored.aggregateID} sequence ${stored.seq}`, }), ) - const committed = { + const committed: Payload = { ...event, durable: { aggregateID, seq, version: durable.version }, - } as Payload + } for (const projector of list) { yield* projector(committed) } @@ -267,14 +284,14 @@ export const layerWith = (options?: LayerOptions) => ]) .run() .pipe(Effect.orDie) - return { aggregateID, seq } + return committed }), { behavior: "immediate" }, ) .pipe(Effect.orDie) if (committed) { yield* Effect.forEach( - pubsub.durable.get(committed.aggregateID) ?? [], + pubsub.durable.get(committed.durable.aggregateID) ?? [], (wake) => PubSub.publish(wake, undefined), { discard: true }, ) @@ -287,7 +304,11 @@ export const layerWith = (options?: LayerOptions) => }) } - function publishEvent(definition: D, event: Payload, commit?: PublishOptions["commit"]) { + function publishEvent( + definition: D, + event: UncommittedPayload, + commit?: PublishOptions["commit"], + ): Effect.Effect> { return Effect.gen(function* () { if (!definition?.durable && commit) return yield* Effect.die( @@ -297,22 +318,22 @@ export const layerWith = (options?: LayerOptions) => }), ) if (definition?.durable) { - const committed = yield* commitDurableEvent(definition, event as Payload, undefined, commit) - if (committed) { - event = { - ...event, - durable: { - aggregateID: committed.aggregateID, - seq: committed.seq, - version: definition.durable.version, - }, - } - yield* notify(event as Payload, true) - return event - } + const committed = yield* commitDurableEvent( + definition, + event as UncommittedPayload, + undefined, + commit, + ) + if (!committed) + return yield* Effect.die( + new InvalidDurableEventError({ type: event.type, message: "New durable event was not committed" }), + ) + yield* notify(committed, true) + return committed as PublishedPayload } - yield* notify(event as Payload, false) - return event + const published = event as PublishedPayload + yield* notify(published, false) + return published }) } @@ -353,7 +374,7 @@ export const layerWith = (options?: LayerOptions) => type: definition.type, ...(location ? { location } : {}), data, - } as Payload, + } as UncommittedPayload, options?.commit, ) }) @@ -370,11 +391,11 @@ export const layerWith = (options?: LayerOptions) => new InvalidDurableEventError({ type: event.type, message: `Unknown durable event type ${event.type}` }), ) } else { - const payload = { + const payload: UncommittedPayload = { id: event.id, type: definition.type, data: Schema.decodeUnknownSync(definition.data)(event.data), - } as Payload + } const committed = yield* commitDurableEvent(definition, payload, { seq: event.seq, aggregateID: event.aggregateID, @@ -382,17 +403,7 @@ export const layerWith = (options?: LayerOptions) => strictOwner: options?.strictOwner, }) if (committed && options?.publish) { - yield* notify( - { - ...payload, - durable: { - aggregateID: committed.aggregateID, - seq: committed.seq, - version: definition.durable.version, - }, - }, - true, - ) + yield* notify(committed, true) } } }) @@ -459,7 +470,7 @@ export const layerWith = (options?: LayerOptions) => const streamAll = (): Stream.Stream => Stream.fromPubSub(pubsub.all) - const decodeSerializedEvent = (event: SerializedEvent) => { + const decodeSerializedEvent = (event: SerializedEvent): Payload => { const definition = Durable.get(event.type) if (!definition?.durable) { throw new InvalidDurableEventError({ type: event.type, message: `Unknown durable event type ${event.type}` }) @@ -516,7 +527,10 @@ export const layerWith = (options?: LayerOptions) => return subscription }) - const durable = (input: { readonly aggregateID: string; readonly after?: number }): Stream.Stream => + const durable = (input: { + readonly aggregateID: string + readonly after?: number + }): Stream.Stream> => Stream.unwrap( Effect.gen(function* () { const wakes = yield* subscribeDurable(input.aggregateID) @@ -524,7 +538,7 @@ export const layerWith = (options?: LayerOptions) => const read = Effect.suspend(() => readAfter(input.aggregateID, sequence)).pipe( Effect.tap((events) => Effect.sync(() => { - sequence = events.at(-1)?.durable?.seq ?? sequence + sequence = events.at(-1)?.durable.seq ?? sequence }), ), ) @@ -546,7 +560,7 @@ export const layerWith = (options?: LayerOptions) => }) }) - const project = (definition: D, projector: Subscriber): Effect.Effect => + const project = (definition: D, projector: Subscriber): Effect.Effect => Effect.sync(() => { const list = projectors.get(definition.type) ?? [] list.push((event) => projector(event as Payload)) diff --git a/packages/core/test/event.test.ts b/packages/core/test/event.test.ts index e2b2a5df04..2284bba7e4 100644 --- a/packages/core/test/event.test.ts +++ b/packages/core/test/event.test.ts @@ -116,7 +116,7 @@ describe("EventV2", () => { const event = yield* events.publish(VersionedMessage, { id: "one", text: "hello" }) expect(event.type).toBe("test.versioned") - expect(event.durable?.version).toBe(2) + expect(event.durable.version).toBe(2) }), ) @@ -764,7 +764,7 @@ describe("EventV2", () => { const replayed = { id: published.id, type: EventV2.versionedType(DurableMessage.type, 1), - seq: published.durable!.seq, + seq: published.durable.seq, aggregateID, data: published.data, } diff --git a/packages/opencode/test/server/httpapi-public-openapi.test.ts b/packages/opencode/test/server/httpapi-public-openapi.test.ts index a8f6f8d1c8..d9eb3643a9 100644 --- a/packages/opencode/test/server/httpapi-public-openapi.test.ts +++ b/packages/opencode/test/server/httpapi-public-openapi.test.ts @@ -99,6 +99,16 @@ describe("PublicApi OpenAPI v2 errors", () => { }) }) + test("documents durable metadata only on durable events", () => { + const spec = OpenApi.fromApi(PublicApi) as OpenApiSpec + const durable = spec.components.schemas.V2EventSessionCreated + const live = spec.components.schemas.V2EventSessionNextTextDelta + + expect(durable?.required).toContain("durable") + expect(durable?.properties?.durable).toBeDefined() + expect(live?.properties?.durable).toBeUndefined() + }) + test("preserves /api auth responses", () => { const spec = OpenApi.fromApi(PublicApi) as OpenApiSpec diff --git a/packages/opencode/test/v2/session-message-updater.test.ts b/packages/opencode/test/v2/session-message-updater.test.ts index 668a353f67..56478a4d1d 100644 --- a/packages/opencode/test/v2/session-message-updater.test.ts +++ b/packages/opencode/test/v2/session-message-updater.test.ts @@ -9,6 +9,12 @@ import { SessionEvent } from "@opencode-ai/core/session/event" import { SessionMessageUpdater } from "@opencode-ai/core/session/message-updater" import { SessionMessage } from "@opencode-ai/core/session/message" +function durable(sessionID: SessionID, seq?: number): { aggregateID: SessionID; seq: number; version: 1 } +function durable(sessionID: SessionID, seq: number, version: 2): { aggregateID: SessionID; seq: number; version: 2 } +function durable(sessionID: SessionID, seq = 0, version: 1 | 2 = 1) { + return { aggregateID: sessionID, seq, version } +} + test.skip("step snapshots carry over to assistant messages", () => { const state: SessionMessageUpdater.MemoryState = { messages: [] } const sessionID = SessionID.make("session") @@ -17,6 +23,7 @@ test.skip("step snapshots carry over to assistant messages", () => { Effect.runSync( SessionMessageUpdater.update(SessionMessageUpdater.memory(state), { id: EventV2.ID.create(), + durable: durable(sessionID), type: "session.next.step.started", data: { sessionID, @@ -38,6 +45,7 @@ test.skip("step snapshots carry over to assistant messages", () => { Effect.runSync( SessionMessageUpdater.update(SessionMessageUpdater.memory(state), { id: EventV2.ID.create(), + durable: durable(sessionID, 1, 2), type: "session.next.step.ended", data: { sessionID, @@ -70,6 +78,7 @@ test.skip("text ended populates assistant text content", () => { Effect.runSync( SessionMessageUpdater.update(SessionMessageUpdater.memory(state), { id: EventV2.ID.create(), + durable: durable(sessionID), type: "session.next.step.started", data: { sessionID, @@ -88,6 +97,7 @@ test.skip("text ended populates assistant text content", () => { Effect.runSync( SessionMessageUpdater.update(SessionMessageUpdater.memory(state), { id: EventV2.ID.create(), + durable: durable(sessionID, 1), type: "session.next.text.started", data: { sessionID, @@ -101,6 +111,7 @@ test.skip("text ended populates assistant text content", () => { Effect.runSync( SessionMessageUpdater.update(SessionMessageUpdater.memory(state), { id: EventV2.ID.create(), + durable: durable(sessionID, 2), type: "session.next.text.ended", data: { sessionID, @@ -126,6 +137,7 @@ test.skip("tool completion stores completed timestamp", () => { Effect.runSync( SessionMessageUpdater.update(SessionMessageUpdater.memory(state), { id: EventV2.ID.create(), + durable: durable(sessionID), type: "session.next.step.started", data: { sessionID, @@ -144,6 +156,7 @@ test.skip("tool completion stores completed timestamp", () => { Effect.runSync( SessionMessageUpdater.update(SessionMessageUpdater.memory(state), { id: EventV2.ID.create(), + durable: durable(sessionID, 1), type: "session.next.tool.input.started", data: { sessionID, @@ -158,6 +171,7 @@ test.skip("tool completion stores completed timestamp", () => { Effect.runSync( SessionMessageUpdater.update(SessionMessageUpdater.memory(state), { id: EventV2.ID.create(), + durable: durable(sessionID, 2), type: "session.next.tool.called", data: { sessionID, @@ -174,6 +188,7 @@ test.skip("tool completion stores completed timestamp", () => { Effect.runSync( SessionMessageUpdater.update(SessionMessageUpdater.memory(state), { id: EventV2.ID.create(), + durable: durable(sessionID, 3), type: "session.next.tool.success", data: { sessionID, @@ -204,6 +219,7 @@ test("compaction events reduce to compaction message only when completed", () => Effect.runSync( SessionMessageUpdater.update(SessionMessageUpdater.memory(state), { id, + durable: durable(sessionID), type: "session.next.compaction.started", data: { sessionID, @@ -245,6 +261,7 @@ test("compaction events reduce to compaction message only when completed", () => Effect.runSync( SessionMessageUpdater.update(SessionMessageUpdater.memory(state), { id: EventV2.ID.create(), + durable: durable(sessionID, 3), type: "session.next.compaction.ended", data: { sessionID, diff --git a/packages/protocol/src/groups/event.ts b/packages/protocol/src/groups/event.ts index 862337e54b..703db3a3d6 100644 --- a/packages/protocol/src/groups/event.ts +++ b/packages/protocol/src/groups/event.ts @@ -8,18 +8,24 @@ import { HttpApiEndpoint, HttpApiGroup, OpenApi } from "effect/unstable/httpapi" const fields = { id: Event.ID, metadata: Schema.optional(Schema.Record(Schema.String, Schema.Unknown)), - durable: Schema.optional(Schema.Struct({ aggregateID: Schema.String, seq: Schema.Int, version: Schema.Int })), location: Schema.optional(Location.Ref), } const schema = (definitions: ReadonlyArray) => Schema.Union([ ...definitions.map((definition) => - Schema.Struct({ - ...fields, - type: Schema.Literal(definition.type), - data: definition.data, - }).annotate({ identifier: `V2Event.${definition.type}` }), + definition.durable + ? Schema.Struct({ + ...fields, + durable: Event.durableEnvelope(definition.durable.version), + type: Schema.Literal(definition.type), + data: definition.data, + }).annotate({ identifier: `V2Event.${definition.type}` }) + : Schema.Struct({ + ...fields, + type: Schema.Literal(definition.type), + data: definition.data, + }).annotate({ identifier: `V2Event.${definition.type}` }), ), ...(definitions.some((definition) => definition.type === "server.connected") ? [] diff --git a/packages/schema/src/event.ts b/packages/schema/src/event.ts index 849ffb8902..ba116b05e5 100644 --- a/packages/schema/src/event.ts +++ b/packages/schema/src/event.ts @@ -3,7 +3,7 @@ export * as Event from "./event" import { Schema } from "effect" import { ascending } from "./identifier" import { Location } from "./location" -import { statics } from "./schema" +import { NonNegativeInt, statics } from "./schema" export const ID = Schema.String.check(Schema.isStartsWith("evt_")).pipe( Schema.brand("Event.ID"), @@ -11,53 +11,95 @@ export const ID = Schema.String.check(Schema.isStartsWith("evt_")).pipe( ) export type ID = typeof ID.Type -export type Definition< +export type DurableOptions = { + readonly version: number + readonly aggregate: string +} + +export type DurableEnvelope = { + readonly aggregateID: string + readonly seq: number + readonly version: Version +} + +export const durableEnvelope = (version: Version) => + Schema.Struct({ aggregateID: Schema.String, seq: NonNegativeInt, version: Schema.Literal(version) }) + +const NoDurableEnvelope = Schema.optional(Schema.Never) + +export type LiveDefinition< Type extends string = string, DataSchema extends Schema.Codec = Schema.Codec, > = Schema.Top & { readonly type: Type - readonly durable?: { - readonly version: number - readonly aggregate: string - } readonly data: DataSchema + readonly durable?: never } +export type DurableDefinition< + Type extends string = string, + DataSchema extends Schema.Codec = Schema.Codec, + Durability extends DurableOptions = DurableOptions, +> = Schema.Top & { + readonly type: Type + readonly data: DataSchema + readonly durable: Durability +} + +export type Definition = LiveDefinition | DurableDefinition + +type Defined< + Type extends string, + DataSchema extends Schema.Codec, + Durability extends DurableOptions | undefined, +> = Durability extends DurableOptions + ? DurableDefinition + : LiveDefinition + export type Data = Schema.Schema.Type -export type Payload = { - readonly id: ID - readonly type: D["type"] - readonly data: Data - readonly durable?: { - readonly aggregateID: string - readonly seq: number - readonly version: number - } - readonly location?: Location.Ref - readonly metadata?: Record -} +export type UncommittedPayload = D extends Definition + ? { + readonly id: ID + readonly type: D["type"] + readonly data: Data + readonly location?: Location.Ref + readonly metadata?: Record + } + : never + +export type PublishedPayload = D extends Definition + ? UncommittedPayload & + (D extends { readonly durable: infer Durability extends DurableOptions } + ? { readonly durable: DurableEnvelope } + : { readonly durable?: never }) + : never + +export type Payload = PublishedPayload + +type EventSchema< + Type extends string, + Fields extends Readonly>>, + Durability extends DurableOptions | undefined, +> = Schema.Schema, Durability>>> & + Defined, Durability> export function define< const Type extends string, Fields extends Readonly>>, + const Durability extends DurableOptions | undefined = undefined, >(input: { readonly type: Type - readonly durable?: { - readonly version: number - readonly aggregate: string - } + readonly durable?: Durability readonly schema: Fields -}): Schema.Schema>>> & Definition> { +}): EventSchema { const data = Schema.Struct(input.schema) return Object.assign( Schema.Struct({ id: ID, metadata: Schema.optional(Schema.Record(Schema.String, Schema.Unknown)), type: Schema.Literal(input.type), - durable: Schema.optional( - Schema.Struct({ aggregateID: Schema.String, seq: Schema.Number, version: Schema.Number }), - ), + durable: input.durable === undefined ? NoDurableEnvelope : durableEnvelope(input.durable.version), location: Schema.optional(Location.Ref), data, }).annotate({ identifier: input.type }), @@ -66,7 +108,7 @@ export function define< ...(input.durable === undefined ? {} : { durable: input.durable }), data, }, - ) as Schema.Schema>>> & Definition> + ) as unknown as EventSchema } export function inventory>(...definitions: Definitions) { @@ -103,7 +145,7 @@ export function durable(definitions: ReadonlyArray) { if (result.has(key)) throw new Error(`Duplicate durable event definition for ${key}`) result.set(key, definition) return result - }, new Map()), + }, new Map()), ) } diff --git a/packages/schema/test/event.test.ts b/packages/schema/test/event.test.ts index 380faa5a4a..3b119368cc 100644 --- a/packages/schema/test/event.test.ts +++ b/packages/schema/test/event.test.ts @@ -34,4 +34,99 @@ describe("public event schemas", () => { expect(Event.durable([definition]).get("test.durable.1")).toBe(definition) }) + + test("durable definitions require published commit metadata", () => { + const definition = Event.define({ + type: "test.durable", + durable: { aggregate: "id", version: 1 }, + schema: { id: Schema.String }, + }) + const payload: typeof definition.Type = { + id: Event.ID.create(), + type: definition.type, + durable: { aggregateID: "aggregate", seq: 0, version: 1 }, + data: { id: "aggregate" }, + } + + expect(Schema.is(definition)(payload)).toBe(true) + expect( + Schema.is(definition)({ + id: Event.ID.create(), + type: definition.type, + data: { id: "aggregate" }, + }), + ).toBe(false) + expect(Schema.is(definition)({ ...payload, durable: { ...payload.durable, seq: -1 } })).toBe(false) + expect(Schema.is(definition)({ ...payload, durable: { ...payload.durable, version: 2 } })).toBe(false) + + // @ts-expect-error Published durable payloads require commit metadata. + const missing: typeof definition.Type = { id: Event.ID.create(), type: definition.type, data: { id: "aggregate" } } + void missing + }) + + test("live definitions reject durable commit metadata", () => { + const definition = Event.define({ + type: "test.live", + schema: { value: Schema.String }, + }) + const payload: typeof definition.Type = { + id: Event.ID.create(), + type: definition.type, + data: { value: "value" }, + } + + expect(Schema.is(definition)(payload)).toBe(true) + expect( + Schema.is(definition)({ + ...payload, + durable: { aggregateID: "aggregate", seq: 0, version: 1 }, + }), + ).toBe(false) + + const invalid: typeof definition.Type = { + ...payload, + // @ts-expect-error Live payloads cannot carry durable commit metadata. + durable: { aggregateID: "aggregate", seq: 0, version: 1 }, + } + void invalid + }) + + test("mixed definition payloads preserve durability correlation", () => { + const durable = Event.define({ + type: "test.mixed.durable", + durable: { aggregate: "id", version: 2 }, + schema: { id: Schema.String }, + }) + const live = Event.define({ + type: "test.mixed.live", + schema: { value: Schema.String }, + }) + type Mixed = Event.Payload + + const committed: Mixed = { + id: Event.ID.create(), + type: durable.type, + durable: { aggregateID: "aggregate", seq: 0, version: 2 }, + data: { id: "aggregate" }, + } + const ephemeral: Mixed = { + id: Event.ID.create(), + type: live.type, + data: { value: "value" }, + } + void committed + void ephemeral + + // @ts-expect-error Durable union members require commit metadata. + const uncommitted: Mixed = { id: Event.ID.create(), type: durable.type, data: { id: "aggregate" } } + const falselyCommitted: Mixed = { + id: Event.ID.create(), + type: live.type, + // @ts-expect-error Live union members cannot carry durable commit metadata. + durable: { aggregateID: "aggregate", seq: 0, version: 2 }, + data: { value: "value" }, + } + void uncommitted + void falselyCommitted + }) }) diff --git a/packages/sdk/js/src/v2/gen/types.gen.ts b/packages/sdk/js/src/v2/gen/types.gen.ts index 2f22dc9e7f..b653c75e1b 100644 --- a/packages/sdk/js/src/v2/gen/types.gen.ts +++ b/packages/sdk/js/src/v2/gen/types.gen.ts @@ -4328,11 +4328,6 @@ export type V2EventModelsDevRefreshed = { metadata?: { [key: string]: unknown } - durable?: { - aggregateID: string - seq: number - version: number - } location?: LocationRef type: "models-dev.refreshed" data: { @@ -4345,11 +4340,6 @@ export type V2EventIntegrationUpdated = { metadata?: { [key: string]: unknown } - durable?: { - aggregateID: string - seq: number - version: number - } location?: LocationRef type: "integration.updated" data: { @@ -4362,11 +4352,6 @@ export type V2EventIntegrationConnectionUpdated = { metadata?: { [key: string]: unknown } - durable?: { - aggregateID: string - seq: number - version: number - } location?: LocationRef type: "integration.connection.updated" data: { @@ -4379,11 +4364,6 @@ export type V2EventCatalogUpdated = { metadata?: { [key: string]: unknown } - durable?: { - aggregateID: string - seq: number - version: number - } location?: LocationRef type: "catalog.updated" data: { @@ -4396,12 +4376,12 @@ export type V2EventSessionCreated = { metadata?: { [key: string]: unknown } - durable?: { + location?: LocationRef + durable: { aggregateID: string seq: number - version: number + version: 1 } - location?: LocationRef type: "session.created" data: { sessionID: string @@ -4414,12 +4394,12 @@ export type V2EventSessionUpdated = { metadata?: { [key: string]: unknown } - durable?: { + location?: LocationRef + durable: { aggregateID: string seq: number - version: number + version: 1 } - location?: LocationRef type: "session.updated" data: { sessionID: string @@ -4432,12 +4412,12 @@ export type V2EventSessionDeleted = { metadata?: { [key: string]: unknown } - durable?: { + location?: LocationRef + durable: { aggregateID: string seq: number - version: number + version: 1 } - location?: LocationRef type: "session.deleted" data: { sessionID: string @@ -4450,12 +4430,12 @@ export type V2EventMessageUpdated = { metadata?: { [key: string]: unknown } - durable?: { + location?: LocationRef + durable: { aggregateID: string seq: number - version: number + version: 1 } - location?: LocationRef type: "message.updated" data: { sessionID: string @@ -4468,12 +4448,12 @@ export type V2EventMessageRemoved = { metadata?: { [key: string]: unknown } - durable?: { + location?: LocationRef + durable: { aggregateID: string seq: number - version: number + version: 1 } - location?: LocationRef type: "message.removed" data: { sessionID: string @@ -4486,12 +4466,12 @@ export type V2EventMessagePartUpdated = { metadata?: { [key: string]: unknown } - durable?: { + location?: LocationRef + durable: { aggregateID: string seq: number - version: number + version: 1 } - location?: LocationRef type: "message.part.updated" data: { sessionID: string @@ -4505,12 +4485,12 @@ export type V2EventMessagePartRemoved = { metadata?: { [key: string]: unknown } - durable?: { + location?: LocationRef + durable: { aggregateID: string seq: number - version: number + version: 1 } - location?: LocationRef type: "message.part.removed" data: { sessionID: string @@ -4524,12 +4504,12 @@ export type V2EventSessionNextAgentSwitched = { metadata?: { [key: string]: unknown } - durable?: { + location?: LocationRef + durable: { aggregateID: string seq: number - version: number + version: 1 } - location?: LocationRef type: "session.next.agent.switched" data: { timestamp: number @@ -4544,12 +4524,12 @@ export type V2EventSessionNextModelSwitched = { metadata?: { [key: string]: unknown } - durable?: { + location?: LocationRef + durable: { aggregateID: string seq: number - version: number + version: 1 } - location?: LocationRef type: "session.next.model.switched" data: { timestamp: number @@ -4568,12 +4548,12 @@ export type V2EventSessionNextMoved = { metadata?: { [key: string]: unknown } - durable?: { + location?: LocationRef + durable: { aggregateID: string seq: number - version: number + version: 1 } - location?: LocationRef type: "session.next.moved" data: { timestamp: number @@ -4588,12 +4568,12 @@ export type V2EventSessionNextPrompted = { metadata?: { [key: string]: unknown } - durable?: { + location?: LocationRef + durable: { aggregateID: string seq: number - version: number + version: 1 } - location?: LocationRef type: "session.next.prompted" data: { timestamp: number @@ -4609,12 +4589,12 @@ export type V2EventSessionNextPromptAdmitted = { metadata?: { [key: string]: unknown } - durable?: { + location?: LocationRef + durable: { aggregateID: string seq: number - version: number + version: 1 } - location?: LocationRef type: "session.next.prompt.admitted" data: { timestamp: number @@ -4630,12 +4610,12 @@ export type V2EventSessionNextContextUpdated = { metadata?: { [key: string]: unknown } - durable?: { + location?: LocationRef + durable: { aggregateID: string seq: number - version: number + version: 1 } - location?: LocationRef type: "session.next.context.updated" data: { timestamp: number @@ -4650,12 +4630,12 @@ export type V2EventSessionNextSynthetic = { metadata?: { [key: string]: unknown } - durable?: { + location?: LocationRef + durable: { aggregateID: string seq: number - version: number + version: 1 } - location?: LocationRef type: "session.next.synthetic" data: { timestamp: number @@ -4670,12 +4650,12 @@ export type V2EventSessionNextShellStarted = { metadata?: { [key: string]: unknown } - durable?: { + location?: LocationRef + durable: { aggregateID: string seq: number - version: number + version: 1 } - location?: LocationRef type: "session.next.shell.started" data: { timestamp: number @@ -4691,12 +4671,12 @@ export type V2EventSessionNextShellEnded = { metadata?: { [key: string]: unknown } - durable?: { + location?: LocationRef + durable: { aggregateID: string seq: number - version: number + version: 1 } - location?: LocationRef type: "session.next.shell.ended" data: { timestamp: number @@ -4711,12 +4691,12 @@ export type V2EventSessionNextStepStarted = { metadata?: { [key: string]: unknown } - durable?: { + location?: LocationRef + durable: { aggregateID: string seq: number - version: number + version: 1 } - location?: LocationRef type: "session.next.step.started" data: { timestamp: number @@ -4737,12 +4717,12 @@ export type V2EventSessionNextStepEnded = { metadata?: { [key: string]: unknown } - durable?: { + location?: LocationRef + durable: { aggregateID: string seq: number - version: number + version: 2 } - location?: LocationRef type: "session.next.step.ended" data: { timestamp: number @@ -4769,12 +4749,12 @@ export type V2EventSessionNextStepFailed = { metadata?: { [key: string]: unknown } - durable?: { + location?: LocationRef + durable: { aggregateID: string seq: number - version: number + version: 2 } - location?: LocationRef type: "session.next.step.failed" data: { timestamp: number @@ -4789,12 +4769,12 @@ export type V2EventSessionNextTextStarted = { metadata?: { [key: string]: unknown } - durable?: { + location?: LocationRef + durable: { aggregateID: string seq: number - version: number + version: 1 } - location?: LocationRef type: "session.next.text.started" data: { timestamp: number @@ -4809,11 +4789,6 @@ export type V2EventSessionNextTextDelta = { metadata?: { [key: string]: unknown } - durable?: { - aggregateID: string - seq: number - version: number - } location?: LocationRef type: "session.next.text.delta" data: { @@ -4830,12 +4805,12 @@ export type V2EventSessionNextTextEnded = { metadata?: { [key: string]: unknown } - durable?: { + location?: LocationRef + durable: { aggregateID: string seq: number - version: number + version: 1 } - location?: LocationRef type: "session.next.text.ended" data: { timestamp: number @@ -4851,12 +4826,12 @@ export type V2EventSessionNextReasoningStarted = { metadata?: { [key: string]: unknown } - durable?: { + location?: LocationRef + durable: { aggregateID: string seq: number - version: number + version: 1 } - location?: LocationRef type: "session.next.reasoning.started" data: { timestamp: number @@ -4876,11 +4851,6 @@ export type V2EventSessionNextReasoningDelta = { metadata?: { [key: string]: unknown } - durable?: { - aggregateID: string - seq: number - version: number - } location?: LocationRef type: "session.next.reasoning.delta" data: { @@ -4897,12 +4867,12 @@ export type V2EventSessionNextReasoningEnded = { metadata?: { [key: string]: unknown } - durable?: { + location?: LocationRef + durable: { aggregateID: string seq: number - version: number + version: 1 } - location?: LocationRef type: "session.next.reasoning.ended" data: { timestamp: number @@ -4923,12 +4893,12 @@ export type V2EventSessionNextToolInputStarted = { metadata?: { [key: string]: unknown } - durable?: { + location?: LocationRef + durable: { aggregateID: string seq: number - version: number + version: 1 } - location?: LocationRef type: "session.next.tool.input.started" data: { timestamp: number @@ -4944,11 +4914,6 @@ export type V2EventSessionNextToolInputDelta = { metadata?: { [key: string]: unknown } - durable?: { - aggregateID: string - seq: number - version: number - } location?: LocationRef type: "session.next.tool.input.delta" data: { @@ -4965,12 +4930,12 @@ export type V2EventSessionNextToolInputEnded = { metadata?: { [key: string]: unknown } - durable?: { + location?: LocationRef + durable: { aggregateID: string seq: number - version: number + version: 1 } - location?: LocationRef type: "session.next.tool.input.ended" data: { timestamp: number @@ -4986,12 +4951,12 @@ export type V2EventSessionNextToolCalled = { metadata?: { [key: string]: unknown } - durable?: { + location?: LocationRef + durable: { aggregateID: string seq: number - version: number + version: 1 } - location?: LocationRef type: "session.next.tool.called" data: { timestamp: number @@ -5018,12 +4983,12 @@ export type V2EventSessionNextToolProgress = { metadata?: { [key: string]: unknown } - durable?: { + location?: LocationRef + durable: { aggregateID: string seq: number - version: number + version: 1 } - location?: LocationRef type: "session.next.tool.progress" data: { timestamp: number @@ -5042,12 +5007,12 @@ export type V2EventSessionNextToolSuccess = { metadata?: { [key: string]: unknown } - durable?: { + location?: LocationRef + durable: { aggregateID: string seq: number - version: number + version: 1 } - location?: LocationRef type: "session.next.tool.success" data: { timestamp: number @@ -5076,12 +5041,12 @@ export type V2EventSessionNextToolFailed = { metadata?: { [key: string]: unknown } - durable?: { + location?: LocationRef + durable: { aggregateID: string seq: number - version: number + version: 1 } - location?: LocationRef type: "session.next.tool.failed" data: { timestamp: number @@ -5106,12 +5071,12 @@ export type V2EventSessionNextRetried = { metadata?: { [key: string]: unknown } - durable?: { + location?: LocationRef + durable: { aggregateID: string seq: number - version: number + version: 1 } - location?: LocationRef type: "session.next.retried" data: { timestamp: number @@ -5126,12 +5091,12 @@ export type V2EventSessionNextCompactionStarted = { metadata?: { [key: string]: unknown } - durable?: { + location?: LocationRef + durable: { aggregateID: string seq: number - version: number + version: 1 } - location?: LocationRef type: "session.next.compaction.started" data: { timestamp: number @@ -5146,11 +5111,6 @@ export type V2EventSessionNextCompactionDelta = { metadata?: { [key: string]: unknown } - durable?: { - aggregateID: string - seq: number - version: number - } location?: LocationRef type: "session.next.compaction.delta" data: { @@ -5166,12 +5126,12 @@ export type V2EventSessionNextCompactionEnded = { metadata?: { [key: string]: unknown } - durable?: { + location?: LocationRef + durable: { aggregateID: string seq: number - version: number + version: 1 } - location?: LocationRef type: "session.next.compaction.ended" data: { timestamp: number @@ -5188,12 +5148,12 @@ export type V2EventSessionNextRevertStaged = { metadata?: { [key: string]: unknown } - durable?: { + location?: LocationRef + durable: { aggregateID: string seq: number - version: number + version: 1 } - location?: LocationRef type: "session.next.revert.staged" data: { timestamp: number @@ -5213,12 +5173,12 @@ export type V2EventSessionNextRevertCleared = { metadata?: { [key: string]: unknown } - durable?: { + location?: LocationRef + durable: { aggregateID: string seq: number - version: number + version: 1 } - location?: LocationRef type: "session.next.revert.cleared" data: { timestamp: number @@ -5231,12 +5191,12 @@ export type V2EventSessionNextRevertCommitted = { metadata?: { [key: string]: unknown } - durable?: { + location?: LocationRef + durable: { aggregateID: string seq: number - version: number + version: 1 } - location?: LocationRef type: "session.next.revert.committed" data: { timestamp: number @@ -5250,11 +5210,6 @@ export type V2EventMessagePartDelta = { metadata?: { [key: string]: unknown } - durable?: { - aggregateID: string - seq: number - version: number - } location?: LocationRef type: "message.part.delta" data: { @@ -5271,11 +5226,6 @@ export type V2EventSessionDiff = { metadata?: { [key: string]: unknown } - durable?: { - aggregateID: string - seq: number - version: number - } location?: LocationRef type: "session.diff" data: { @@ -5289,11 +5239,6 @@ export type V2EventSessionError = { metadata?: { [key: string]: unknown } - durable?: { - aggregateID: string - seq: number - version: number - } location?: LocationRef type: "session.error" data: { @@ -5315,11 +5260,6 @@ export type V2EventInstallationUpdated = { metadata?: { [key: string]: unknown } - durable?: { - aggregateID: string - seq: number - version: number - } location?: LocationRef type: "installation.updated" data: { @@ -5332,11 +5272,6 @@ export type V2EventInstallationUpdateAvailable = { metadata?: { [key: string]: unknown } - durable?: { - aggregateID: string - seq: number - version: number - } location?: LocationRef type: "installation.update-available" data: { @@ -5349,11 +5284,6 @@ export type V2EventFileEdited = { metadata?: { [key: string]: unknown } - durable?: { - aggregateID: string - seq: number - version: number - } location?: LocationRef type: "file.edited" data: { @@ -5366,11 +5296,6 @@ export type V2EventReferenceUpdated = { metadata?: { [key: string]: unknown } - durable?: { - aggregateID: string - seq: number - version: number - } location?: LocationRef type: "reference.updated" data: { @@ -5383,11 +5308,6 @@ export type V2EventPermissionV2Asked = { metadata?: { [key: string]: unknown } - durable?: { - aggregateID: string - seq: number - version: number - } location?: LocationRef type: "permission.v2.asked" data: { @@ -5408,11 +5328,6 @@ export type V2EventPermissionV2Replied = { metadata?: { [key: string]: unknown } - durable?: { - aggregateID: string - seq: number - version: number - } location?: LocationRef type: "permission.v2.replied" data: { @@ -5427,11 +5342,6 @@ export type V2EventPluginAdded = { metadata?: { [key: string]: unknown } - durable?: { - aggregateID: string - seq: number - version: number - } location?: LocationRef type: "plugin.added" data: { @@ -5444,11 +5354,6 @@ export type V2EventProjectDirectoriesUpdated = { metadata?: { [key: string]: unknown } - durable?: { - aggregateID: string - seq: number - version: number - } location?: LocationRef type: "project.directories.updated" data: { @@ -5461,11 +5366,6 @@ export type V2EventFileWatcherUpdated = { metadata?: { [key: string]: unknown } - durable?: { - aggregateID: string - seq: number - version: number - } location?: LocationRef type: "file.watcher.updated" data: { @@ -5479,11 +5379,6 @@ export type V2EventPtyCreated = { metadata?: { [key: string]: unknown } - durable?: { - aggregateID: string - seq: number - version: number - } location?: LocationRef type: "pty.created" data: { @@ -5496,11 +5391,6 @@ export type V2EventPtyUpdated = { metadata?: { [key: string]: unknown } - durable?: { - aggregateID: string - seq: number - version: number - } location?: LocationRef type: "pty.updated" data: { @@ -5513,11 +5403,6 @@ export type V2EventPtyExited = { metadata?: { [key: string]: unknown } - durable?: { - aggregateID: string - seq: number - version: number - } location?: LocationRef type: "pty.exited" data: { @@ -5531,11 +5416,6 @@ export type V2EventPtyDeleted = { metadata?: { [key: string]: unknown } - durable?: { - aggregateID: string - seq: number - version: number - } location?: LocationRef type: "pty.deleted" data: { @@ -5548,11 +5428,6 @@ export type V2EventQuestionV2Asked = { metadata?: { [key: string]: unknown } - durable?: { - aggregateID: string - seq: number - version: number - } location?: LocationRef type: "question.v2.asked" data: { @@ -5571,11 +5446,6 @@ export type V2EventQuestionV2Replied = { metadata?: { [key: string]: unknown } - durable?: { - aggregateID: string - seq: number - version: number - } location?: LocationRef type: "question.v2.replied" data: { @@ -5590,11 +5460,6 @@ export type V2EventQuestionV2Rejected = { metadata?: { [key: string]: unknown } - durable?: { - aggregateID: string - seq: number - version: number - } location?: LocationRef type: "question.v2.rejected" data: { @@ -5608,11 +5473,6 @@ export type V2EventTodoUpdated = { metadata?: { [key: string]: unknown } - durable?: { - aggregateID: string - seq: number - version: number - } location?: LocationRef type: "todo.updated" data: { @@ -5626,11 +5486,6 @@ export type V2EventLspUpdated = { metadata?: { [key: string]: unknown } - durable?: { - aggregateID: string - seq: number - version: number - } location?: LocationRef type: "lsp.updated" data: { @@ -5643,11 +5498,6 @@ export type V2EventPermissionAsked = { metadata?: { [key: string]: unknown } - durable?: { - aggregateID: string - seq: number - version: number - } location?: LocationRef type: "permission.asked" data: { @@ -5671,11 +5521,6 @@ export type V2EventPermissionReplied = { metadata?: { [key: string]: unknown } - durable?: { - aggregateID: string - seq: number - version: number - } location?: LocationRef type: "permission.replied" data: { @@ -5690,11 +5535,6 @@ export type V2EventTuiPromptAppend = { metadata?: { [key: string]: unknown } - durable?: { - aggregateID: string - seq: number - version: number - } location?: LocationRef type: "tui.prompt.append" data: { @@ -5707,11 +5547,6 @@ export type V2EventTuiCommandExecute = { metadata?: { [key: string]: unknown } - durable?: { - aggregateID: string - seq: number - version: number - } location?: LocationRef type: "tui.command.execute" data: { @@ -5741,11 +5576,6 @@ export type V2EventTuiToastShow = { metadata?: { [key: string]: unknown } - durable?: { - aggregateID: string - seq: number - version: number - } location?: LocationRef type: "tui.toast.show" data: { @@ -5761,11 +5591,6 @@ export type V2EventTuiSessionSelect = { metadata?: { [key: string]: unknown } - durable?: { - aggregateID: string - seq: number - version: number - } location?: LocationRef type: "tui.session.select" data: { @@ -5781,11 +5606,6 @@ export type V2EventMcpToolsChanged = { metadata?: { [key: string]: unknown } - durable?: { - aggregateID: string - seq: number - version: number - } location?: LocationRef type: "mcp.tools.changed" data: { @@ -5798,11 +5618,6 @@ export type V2EventMcpBrowserOpenFailed = { metadata?: { [key: string]: unknown } - durable?: { - aggregateID: string - seq: number - version: number - } location?: LocationRef type: "mcp.browser.open.failed" data: { @@ -5816,11 +5631,6 @@ export type V2EventCommandExecuted = { metadata?: { [key: string]: unknown } - durable?: { - aggregateID: string - seq: number - version: number - } location?: LocationRef type: "command.executed" data: { @@ -5836,11 +5646,6 @@ export type V2EventProjectUpdated = { metadata?: { [key: string]: unknown } - durable?: { - aggregateID: string - seq: number - version: number - } location?: LocationRef type: "project.updated" data: { @@ -5873,11 +5678,6 @@ export type V2EventSessionStatus = { metadata?: { [key: string]: unknown } - durable?: { - aggregateID: string - seq: number - version: number - } location?: LocationRef type: "session.status" data: { @@ -5891,11 +5691,6 @@ export type V2EventSessionIdle = { metadata?: { [key: string]: unknown } - durable?: { - aggregateID: string - seq: number - version: number - } location?: LocationRef type: "session.idle" data: { @@ -5908,11 +5703,6 @@ export type V2EventQuestionAsked = { metadata?: { [key: string]: unknown } - durable?: { - aggregateID: string - seq: number - version: number - } location?: LocationRef type: "question.asked" data: { @@ -5931,11 +5721,6 @@ export type V2EventQuestionReplied = { metadata?: { [key: string]: unknown } - durable?: { - aggregateID: string - seq: number - version: number - } location?: LocationRef type: "question.replied" data: { @@ -5950,11 +5735,6 @@ export type V2EventQuestionRejected = { metadata?: { [key: string]: unknown } - durable?: { - aggregateID: string - seq: number - version: number - } location?: LocationRef type: "question.rejected" data: { @@ -5968,11 +5748,6 @@ export type V2EventSessionCompacted = { metadata?: { [key: string]: unknown } - durable?: { - aggregateID: string - seq: number - version: number - } location?: LocationRef type: "session.compacted" data: { @@ -5985,11 +5760,6 @@ export type V2EventVcsBranchUpdated = { metadata?: { [key: string]: unknown } - durable?: { - aggregateID: string - seq: number - version: number - } location?: LocationRef type: "vcs.branch.updated" data: { @@ -6002,11 +5772,6 @@ export type V2EventWorkspaceReady = { metadata?: { [key: string]: unknown } - durable?: { - aggregateID: string - seq: number - version: number - } location?: LocationRef type: "workspace.ready" data: { @@ -6019,11 +5784,6 @@ export type V2EventWorkspaceFailed = { metadata?: { [key: string]: unknown } - durable?: { - aggregateID: string - seq: number - version: number - } location?: LocationRef type: "workspace.failed" data: { @@ -6036,11 +5796,6 @@ export type V2EventWorkspaceStatus = { metadata?: { [key: string]: unknown } - durable?: { - aggregateID: string - seq: number - version: number - } location?: LocationRef type: "workspace.status" data: { @@ -6054,11 +5809,6 @@ export type V2EventWorktreeReady = { metadata?: { [key: string]: unknown } - durable?: { - aggregateID: string - seq: number - version: number - } location?: LocationRef type: "worktree.ready" data: { @@ -6072,11 +5822,6 @@ export type V2EventWorktreeFailed = { metadata?: { [key: string]: unknown } - durable?: { - aggregateID: string - seq: number - version: number - } location?: LocationRef type: "worktree.failed" data: { @@ -6089,11 +5834,6 @@ export type V2EventServerConnected = { metadata?: { [key: string]: unknown } - durable?: { - aggregateID: string - seq: number - version: number - } location?: LocationRef type: "server.connected" data: { @@ -6106,11 +5846,6 @@ export type V2EventGlobalDisposed = { metadata?: { [key: string]: unknown } - durable?: { - aggregateID: string - seq: number - version: number - } location?: LocationRef type: "global.disposed" data: {