11import z from "zod"
2- import type { ZodObject } from "zod"
32import { Database , eq } from "@/storage"
43import { GlobalBus } from "@/bus/global"
54import { Bus as ProjectBus } from "@/bus"
@@ -9,11 +8,16 @@ import { EventSequenceTable, EventTable } from "./event.sql"
98import { WorkspaceContext } from "@/control-plane/workspace-context"
109import { EventID } from "./schema"
1110import { Flag } from "@/flag/flag"
11+ import { Schema as EffectSchema , Types } from "effect"
12+ import { zodObject } from "@/util/effect-zod"
13+ import { isRecord } from "@/util/record"
1214
13- export type Definition = {
15+ export type Definition < Schema extends EffectSchema . Top = EffectSchema . Top , BusSchema extends EffectSchema . Top = Schema > = {
1416 type : string
1517 version : number
1618 aggregate : string
19+ effectSchema : Schema
20+ effectProperties : BusSchema
1721 schema : z . ZodObject
1822
1923 // This is temporary and only exists for compatibility with bus
@@ -25,9 +29,13 @@ export type Event<Def extends Definition = Definition> = {
2529 id : string
2630 seq : number
2731 aggregateID : string
28- data : z . infer < Def [ "schema" ] >
32+ data : Types . DeepMutable < EffectSchema . Schema . Type < Def [ "effectSchema" ] > >
2933}
3034
35+ export type Properties < Def extends Definition = Definition > = Types . DeepMutable <
36+ EffectSchema . Schema . Type < Def [ "effectProperties" ] >
37+ >
38+
3139export type SerializedEvent < Def extends Definition = Definition > = Event < Def > & { type : string }
3240
3341type ProjectorFunc = ( db : Database . TxOrDb , data : unknown ) => void
@@ -36,7 +44,12 @@ export const registry = new Map<string, Definition>()
3644let projectors : Map < Definition , ProjectorFunc > | undefined
3745const versions = new Map < string , number > ( )
3846let frozen = false
39- let convertEvent : ( type : string , event : Event [ "data" ] ) => Promise < Record < string , unknown > > | Record < string , unknown >
47+ let convertEvent : ( type : string , event : Event [ "data" ] ) => Promise < unknown > | unknown
48+
49+ function asRecord ( input : unknown ) {
50+ if ( isRecord ( input ) ) return input
51+ throw new Error ( `SyncEvent.convertEvent must return an object, got: ${ JSON . stringify ( input ) } ` )
52+ }
4053
4154export function reset ( ) {
4255 frozen = false
@@ -54,7 +67,7 @@ export function init(input: { projectors: Array<[Definition, ProjectorFunc]>; co
5467 for ( let [ type , version ] of versions . entries ( ) ) {
5568 let def = registry . get ( versionedType ( type , version ) ) !
5669
57- BusEvent . define ( def . type , def . properties || def . schema )
70+ BusEvent . define ( def . type , def . properties )
5871 }
5972
6073 // Freeze the system so it clearly errors if events are defined
@@ -72,19 +85,26 @@ export function versionedType(type: string, version?: number) {
7285export function define <
7386 Type extends string ,
7487 Agg extends string ,
75- Schema extends ZodObject < Record < Agg , z . ZodType < string > > > ,
76- BusSchema extends ZodObject = Schema ,
77- > ( input : { type : Type ; version : number ; aggregate : Agg ; schema : Schema ; busSchema ?: BusSchema } ) {
88+ Schema extends EffectSchema . Top ,
89+ BusSchema extends EffectSchema . Top = Schema ,
90+ > ( input : { type : Type ; version : number ; aggregate : Agg ; schema : Schema ; busSchema ?: BusSchema } ) : Definition <
91+ Schema ,
92+ BusSchema
93+ > {
7894 if ( frozen ) {
7995 throw new Error ( "Error defining sync event: sync system has been frozen" )
8096 }
8197
98+ const effectProperties = ( input . busSchema ?? input . schema ) as BusSchema
99+
82100 const def = {
83101 type : input . type ,
84102 version : input . version ,
85103 aggregate : input . aggregate ,
86- schema : input . schema ,
87- properties : input . busSchema ? input . busSchema : input . schema ,
104+ effectSchema : input . schema ,
105+ effectProperties,
106+ schema : zodObject ( input . schema ) ,
107+ properties : zodObject ( effectProperties ) ,
88108 }
89109
90110 versions . set ( def . type , Math . max ( def . version , versions . get ( def . type ) || 0 ) )
@@ -143,10 +163,10 @@ function process<Def extends Definition>(def: Def, event: Event<Def>, options: {
143163 const result = convertEvent ( def . type , event . data )
144164 if ( result instanceof Promise ) {
145165 void result . then ( ( data ) => {
146- void ProjectBus . publish ( { type : def . type , properties : def . schema } , data )
166+ void ProjectBus . publish ( { type : def . type , properties : def . properties } , asRecord ( data ) )
147167 } )
148168 } else {
149- void ProjectBus . publish ( { type : def . type , properties : def . schema } , result )
169+ void ProjectBus . publish ( { type : def . type , properties : def . properties } , asRecord ( result ) )
150170 }
151171
152172 GlobalBus . emit ( "event" , {
0 commit comments