What are you using for EventBridge events in TypeS...
# general
d
What are you using for EventBridge events in TypeScript? Trying typebridge but it seem to have a lot of issues.
s
I'm just starting to look more deeply into Event Bridge, so I don't have a suggestion here yet. Would the Event Bridge code bindings be helpful here? I'm not yet certain of their use case
t
I made my own little thing
typebridge looks more full featured than my utility but I didn't want to deal with actual runtime objects being passed around (although it's useful for validation)
I use declaration merging to define my events around my codebase while keeping things typesafe
Copy code
declare module "@acme/core/bus" {
  export interface Events {
    "business.created": {
      id: string
      name: string
    }
    "business.deleted": {
      id: string
    }
  }
}
and then I have a single
Bus.publish("type", properties)
function that is entirely typesafe
I also have a
Bus.createHandler
function to receive events in a typesafe way
d
This seems way better than typebridge to be honest. It requires passing of the bus to event which is beyond my understanding why its api is not split to bus and event with no dependancies.
Do you mind sharing the function signature for Bus.publish? I don't know how second arg depends on first one like that.
t
I can share the whole code one sec
we'll probably publish this as part of our upcoming
@serverless-stack/node
package
this can probably be simplified / cleaned up since it took me a few tries to land on this API but this should work:
Copy code
export interface Event {
  id: string
  source: "acme"
  type: string
  properties: any
  actor: Actor
}

export interface Events {}

export type EventTypes = keyof Events

export type FromType<T extends EventTypes> = payload<T, Events[T]>

export type AnyEvent = FromType<EventTypes>

export type payload<T extends string, P extends Record<string, any>> = {
  id: string
  source: "acme"
  type: T
  properties: P
  actor: Actor
}

export async function publish<T extends EventTypes>(
  type: T,
  properties: Events[T],
  actor?: Actor
) {
  const ctx = context()
  const payload: Event = {
    id: ulid(),
    source: "acme",
    type,
    properties,
    actor: actor ? actor : ctx.actor,
  }
  // Send event
  return payload
}
Ignore the
context()
and
actor
stuff that's a bit specific
can probably ignore FromType and AnyEvent also, I use those in my eventbridge -> queue -> lambda wrapper
Copy code
export function createHandler<T extends EventTypes>(
  cb: (event: FromType<T>, record: SQSRecord) => Promise<void>
) {
  const result = async (event: SQSEvent) => {
    const promises = []
    for (const record of event.Records) {
      const msg = JSON.parse(record.body)
      async function run() {
        try {
          await cb(msg.detail as FromType<T>, record)
          return { type: "success" }
        } catch (e) {
          console.error(e)
          return { type: "error", messageId: record.messageId }
        }
      }
      promises.push(run())
    }
    const results = await Promise.all(promises)
    return {
      batchItemFailures: results
        .filter((i) => i.type === "error")
        .map((i) => ({
          itemIdentifier: i,
        })),
    }
  }
  return AWSLambda.wrapHandler(result) // Sentry
}
r
My weekend project is now to combine this with code gen via EB schemas haha
d
Thanks so much @thdxr, we are now using this 🙏
t
Please pay me $1 per event
d
You definitely have a great meal and a few pints going for you if you come to London 🙂