@@ -130,7 +130,7 @@ const client = new pg.Client({
130130await client .connect ();
131131
132132const processor = new EventProcessor ({
133- client: createProcessorClient ({ querier: client }),
133+ client: createProcessorClient ({ querier: client , eventSchemas }),
134134 handlerMap: {
135135 UserCreated: {
136136 // Handlers are processed concurrently and independently with retries
@@ -354,18 +354,20 @@ const incrementCounter: TxOBEventHandler = async (event) => {
354354
355355#### Typed payloads with Standard Schema (Zod/ArkType/Valibot/etc.)
356356
357- txob supports schema-driven event payload typing through the Standard Schema interface.
357+ txob uses schema-driven event payload typing through the Standard Schema interface.
358+ ` eventSchemas ` is required by both ` createProcessorClient(...) ` and ` createEventProcessor(...) ` .
359+ Use any validator that implements Standard Schema (for example Zod, ArkType, or Valibot).
358360
359361``` typescript
360362import { z } from " zod" ;
361363import {
362- defineTxOBEventHandlerMap ,
363- defineTxOBEventSchemas ,
364- EventProcessor ,
365- type TxOBEventDataMapFromSchemas ,
364+ createEventHandlerMap ,
365+ createEventProcessor ,
366+ type TxOBEventSchemaMap ,
366367} from " txob" ;
368+ import { createProcessorClient } from " txob/pg" ;
367369
368- const eventSchemas = defineTxOBEventSchemas ( {
370+ const eventSchemas = {
369371 UserCreated: z .object ({
370372 userId: z .string ().uuid (),
371373 email: z .string ().email (),
@@ -374,31 +376,32 @@ const eventSchemas = defineTxOBEventSchemas({
374376 orderId: z .string ().uuid (),
375377 amount: z .number ().positive (),
376378 }),
377- }) ;
379+ } satisfies TxOBEventSchemaMap < " UserCreated " | " OrderPlaced " > ;
378380
379- type EventType = keyof typeof eventSchemas ;
380- type EventDataMap = TxOBEventDataMapFromSchemas < typeof eventSchemas >;
381-
382- const handlers = defineTxOBEventHandlerMap ( eventSchemas , {
383- UserCreated: {
384- sendWelcomeEmail : async (event ) => {
385- await emailService . send ( event . data . email ); // typed as string
381+ const handlerMap = createEventHandlerMap ({
382+ eventSchemas ,
383+ handlerMap: {
384+ UserCreated: {
385+ sendWelcomeEmail : async ( event ) => {
386+ await emailService . send (event . data . email ); // typed as string
387+ },
386388 },
387- },
388- OrderPlaced: {
389- sendReceipt : async (event ) => {
390- await receipts . send ( event . data . orderId , event . data . amount ); // strongly typed
389+ OrderPlaced: {
390+ sendReceipt : async ( event ) => {
391+ await receipts . send (event . data . orderId , event . data . amount ); // strongly typed
392+ },
391393 },
392394 },
393395});
394396
395- const processor = new EventProcessor <EventType , EventDataMap >({
396- client: createProcessorClient <EventType , EventDataMap >({ querier: client }),
397- handlerMap: handlers ,
397+ const processor = createEventProcessor ({
398+ eventSchemas ,
399+ client: createProcessorClient ({ querier: client , eventSchemas }),
400+ handlerMap ,
398401});
399402```
400403
401- ` defineTxOBEventSchemas(...) ` is optional. It is a convenience helper for cleaner type inference. You can also define schema maps without it using explicit types .
404+ Schema-first inference via ` eventSchemas ` is the standard and required approach .
402405
403406### Handler Results
404407
@@ -843,7 +846,7 @@ await client.connect();
843846
844847// 3. Create and start the processor
845848const processor = new EventProcessor <EventType >({
846- client: createProcessorClient < EventType > ({ querier: client }),
849+ client: createProcessorClient ({ querier: client , eventSchemas }),
847850 handlerMap: {
848851 UserCreated: {
849852 sendEmail : async (event , { signal }) => {
@@ -963,7 +966,7 @@ gracefulShutdown(server, {
963966
964967``` typescript
965968const processor = new EventProcessor ({
966- client: createProcessorClient ({ querier: client }),
969+ client: createProcessorClient ({ querier: client , eventSchemas }),
967970 handlerMap: {
968971 UserCreated: {
969972 sendWelcomeEmail : async (event ) => {
@@ -1061,7 +1064,7 @@ const producer = kafka.producer();
10611064await producer .connect ();
10621065
10631066const processor = new EventProcessor ({
1064- client: createProcessorClient ({ querier: client }),
1067+ client: createProcessorClient ({ querier: client , eventSchemas }),
10651068 handlerMap: {
10661069 UserCreated: {
10671070 // Publish to Kafka with guaranteed consistency
@@ -1118,7 +1121,7 @@ const client = new pg.Client({
11181121await client .connect ();
11191122
11201123const processor = new EventProcessor ({
1121- client: createProcessorClient ({ querier: client }),
1124+ client: createProcessorClient ({ querier: client , eventSchemas }),
11221125 handlerMap: {
11231126 // All your handlers...
11241127 },
@@ -1191,11 +1194,12 @@ Creates a PostgreSQL processor client.
11911194``` typescript
11921195import { createProcessorClient } from " txob/pg" ;
11931196
1194- createProcessorClient < EventType > (opts : {
1197+ createProcessorClient (opts : {
11951198 querier: pg .Client ;
1199+ eventSchemas : Record < string , StandardSchemaV1<unknown , unknown>>;
11961200 table?: string ; // Default: "events"
11971201 limit ?: number ; // Default: 100
1198- }): TxOBProcessorClient < EventType >
1202+ }): TxOBProcessorClient < ... inferred from eventSchemas ... >
11991203```
12001204
12011205### ` createProcessorClient ` (MongoDB)
@@ -1205,12 +1209,13 @@ Creates a MongoDB processor client.
12051209``` typescript
12061210import { createProcessorClient } from " txob/mongodb" ;
12071211
1208- createProcessorClient < EventType > (opts : {
1212+ createProcessorClient (opts : {
12091213 mongo: mongodb .MongoClient ;
12101214 db : string ; // Database name
1215+ eventSchemas : Record < string , StandardSchemaV1<unknown , unknown>>;
12111216 collection?: string ; // Default: "events"
12121217 limit ?: number ; // Default: 100
1213- }): TxOBProcessorClient < EventType >
1218+ }): TxOBProcessorClient < ... inferred from eventSchemas ... >
12141219```
12151220
12161221### ` TxOBError `
@@ -1317,10 +1322,12 @@ type TxOBEventHandlerMap<
13171322 [TType in EventType ]: Record <string , TxOBEventHandler <TType , EventDataMap [TType ]>>;
13181323};
13191324
1320- // Standard Schema helpers
1321- type TxOBEventDataMapFromSchemas <TSchemas > = {
1322- [TType in keyof TSchemas & string ]: /* schema output for TType */ ;
1323- };
1325+ // Schema-first convenience API
1326+ createEventProcessor ({
1327+ eventSchemas ,
1328+ client: createProcessorClient ({ querier , eventSchemas }),
1329+ handlerMap ,
1330+ });
13241331
13251332// Handler result tracking
13261333type TxOBEventHandlerResult = {
@@ -1460,7 +1467,7 @@ If using `FOR UPDATE SKIP LOCKED` properly (which txob does), stuck events are n
14601467- Lower ` maxEventConcurrency `
14611468- Profile handlers for memory leaks
14621469- Archive old events
1463- - Reduce ` limit ` in ` createProcessorClient({ querier: client, table, limit }) `
1470+ - Reduce ` limit ` in ` createProcessorClient({ querier: client, eventSchemas, table, limit }) `
14641471
14651472### Duplicate handler executions
14661473
@@ -1765,7 +1772,7 @@ txob can emit spans and metrics without depending on a specific telemetry SDK. I
17651772import { metrics , trace } from " @opentelemetry/api" ;
17661773
17671774const processor = new EventProcessor ({
1768- client: createProcessorClient ({ querier: client }),
1775+ client: createProcessorClient ({ querier: client , eventSchemas }),
17691776 handlerMap: handlers ,
17701777 telemetry: {
17711778 tracer: trace .getTracer (" txob" ),
@@ -1837,35 +1844,37 @@ Yes! txob is written in TypeScript and provides full type safety, including type
18371844``` typescript
18381845import { z } from " zod" ;
18391846import {
1840- defineTxOBEventHandlerMap ,
1841- defineTxOBEventSchemas ,
1842- type TxOBEventDataMapFromSchemas ,
1847+ createEventHandlerMap ,
1848+ createEventProcessor ,
1849+ type TxOBEventSchemaMap ,
18431850} from " txob" ;
1851+ import { createProcessorClient } from " txob/pg" ;
18441852
1845- const eventSchemas = defineTxOBEventSchemas ( {
1853+ const eventSchemas = {
18461854 UserCreated: z .object ({ userId: z .string ().uuid (), email: z .string ().email () }),
18471855 OrderPlaced: z .object ({ orderId: z .string ().uuid (), amount: z .number () }),
1848- });
1849-
1850- type EventType = keyof typeof eventSchemas ;
1851- type EventDataMap = TxOBEventDataMapFromSchemas <typeof eventSchemas >;
1856+ } satisfies TxOBEventSchemaMap <" UserCreated" | " OrderPlaced" >;
18521857
1853- const handlers = defineTxOBEventHandlerMap (eventSchemas , {
1854- UserCreated: {
1855- sendWelcomeEmail : async (event ) => {
1856- event .data .email ; // string
1858+ const handlers = createEventHandlerMap ({
1859+ eventSchemas ,
1860+ handlerMap: {
1861+ UserCreated: {
1862+ sendWelcomeEmail : async (event ) => {
1863+ event .data .email ; // string
1864+ },
18571865 },
1858- },
1859- OrderPlaced: {
1860- sendReceipt : async ( event ) => {
1861- event . data . amount ; // number
1866+ OrderPlaced: {
1867+ sendReceipt : async ( event ) => {
1868+ event . data . amount ; // number
1869+ },
18621870 },
1871+ // Missing an event type? TypeScript error
18631872 },
1864- // Missing an event type? TypeScript error
18651873});
18661874
1867- const processor = new EventProcessor <EventType , EventDataMap >({
1868- client: createProcessorClient <EventType , EventDataMap >({ querier: client }),
1875+ const processor = createEventProcessor ({
1876+ eventSchemas ,
1877+ client: createProcessorClient ({ querier: client , eventSchemas }),
18691878 handlerMap: handlers ,
18701879});
18711880```
0 commit comments