Refactor v2 session events as schemas (#24512)
This commit is contained in:
@@ -24,6 +24,7 @@ export function payloads() {
|
||||
.map(([type, def]) => {
|
||||
return z
|
||||
.object({
|
||||
id: z.string(),
|
||||
type: z.literal(type),
|
||||
properties: zodObject(def.properties),
|
||||
})
|
||||
@@ -39,6 +40,7 @@ export function effectPayloads() {
|
||||
.entries()
|
||||
.map(([type, def]) =>
|
||||
Schema.Struct({
|
||||
id: Schema.String,
|
||||
type: Schema.Literal(type),
|
||||
properties: def.properties,
|
||||
}).annotate({ identifier: `Event.${type}` }),
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { EventEmitter } from "events"
|
||||
import { Identifier } from "@/id/id"
|
||||
|
||||
export type GlobalEvent = {
|
||||
directory?: string
|
||||
@@ -7,6 +8,15 @@ export type GlobalEvent = {
|
||||
payload: any
|
||||
}
|
||||
|
||||
export const GlobalBus = new EventEmitter<{
|
||||
class GlobalBusEmitter extends EventEmitter<{
|
||||
event: [GlobalEvent]
|
||||
}>()
|
||||
}> {
|
||||
override emit(eventName: "event", event: GlobalEvent): boolean {
|
||||
if (event.payload && typeof event.payload === "object" && !("id" in event.payload)) {
|
||||
event.payload.id = event.payload.syncEvent?.id ?? Identifier.create("evt", "ascending")
|
||||
}
|
||||
return super.emit(eventName, event)
|
||||
}
|
||||
}
|
||||
|
||||
export const GlobalBus = new GlobalBusEmitter()
|
||||
|
||||
@@ -5,6 +5,7 @@ import { BusEvent } from "./bus-event"
|
||||
import { GlobalBus } from "./global"
|
||||
import { InstanceState } from "@/effect/instance-state"
|
||||
import { makeRuntime } from "@/effect/run-service"
|
||||
import { Identifier } from "@/id/id"
|
||||
|
||||
const log = Log.create({ service: "bus" })
|
||||
|
||||
@@ -18,6 +19,7 @@ export const InstanceDisposed = BusEvent.define(
|
||||
)
|
||||
|
||||
type Payload<D extends BusEvent.Definition = BusEvent.Definition> = {
|
||||
id: string
|
||||
type: D["type"]
|
||||
properties: BusProperties<D>
|
||||
}
|
||||
@@ -28,7 +30,11 @@ type State = {
|
||||
}
|
||||
|
||||
export interface Interface {
|
||||
readonly publish: <D extends BusEvent.Definition>(def: D, properties: BusProperties<D>) => Effect.Effect<void>
|
||||
readonly publish: <D extends BusEvent.Definition>(
|
||||
def: D,
|
||||
properties: BusProperties<D>,
|
||||
options?: { id?: string },
|
||||
) => Effect.Effect<void>
|
||||
readonly subscribe: <D extends BusEvent.Definition>(def: D) => Stream.Stream<Payload<D>>
|
||||
readonly subscribeAll: () => Stream.Stream<Payload>
|
||||
readonly subscribeCallback: <D extends BusEvent.Definition>(
|
||||
@@ -53,6 +59,7 @@ export const layer = Layer.effect(
|
||||
// Publish InstanceDisposed before shutting down so subscribers see it
|
||||
yield* PubSub.publish(wildcard, {
|
||||
type: InstanceDisposed.type,
|
||||
id: createID(),
|
||||
properties: { directory: ctx.directory },
|
||||
})
|
||||
yield* PubSub.shutdown(wildcard)
|
||||
@@ -77,10 +84,10 @@ export const layer = Layer.effect(
|
||||
})
|
||||
}
|
||||
|
||||
function publish<D extends BusEvent.Definition>(def: D, properties: BusProperties<D>) {
|
||||
function publish<D extends BusEvent.Definition>(def: D, properties: BusProperties<D>, options?: { id?: string }) {
|
||||
return Effect.gen(function* () {
|
||||
const s = yield* InstanceState.get(state)
|
||||
const payload: Payload = { type: def.type, properties }
|
||||
const payload: Payload = { id: options?.id ?? createID(), type: def.type, properties }
|
||||
log.info("publishing", { type: def.type })
|
||||
|
||||
const ps = s.typed.get(def.type)
|
||||
@@ -173,8 +180,16 @@ const { runPromise, runSync } = makeRuntime(Service, layer)
|
||||
|
||||
// runSync is safe here because the subscribe chain (InstanceState.get, PubSub.subscribe,
|
||||
// Scope.make, Effect.forkScoped) is entirely synchronous. If any step becomes async, this will throw.
|
||||
export async function publish<D extends BusEvent.Definition>(def: D, properties: BusProperties<D>) {
|
||||
return runPromise((svc) => svc.publish(def, properties))
|
||||
export function createID() {
|
||||
return Identifier.create("evt", "ascending")
|
||||
}
|
||||
|
||||
export async function publish<D extends BusEvent.Definition>(
|
||||
def: D,
|
||||
properties: BusProperties<D>,
|
||||
options?: { id?: string },
|
||||
) {
|
||||
return runPromise((svc) => svc.publish(def, properties, options))
|
||||
}
|
||||
|
||||
export function subscribe<D extends BusEvent.Definition>(def: D, callback: (event: Payload<D>) => unknown) {
|
||||
|
||||
Reference in New Issue
Block a user