@secondlayer/sdk 6.38.0 → 6.40.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -230,6 +230,12 @@ type StreamsEventBase = {
230
230
  * Optional for back-compat; the API always sets it on Streams responses.
231
231
  */
232
232
  finalized?: boolean
233
+ /**
234
+ * Labels whose filter group this event satisfied, present only when the
235
+ * request used a labelled `filters` map. The SDK dispatches on it for you
236
+ * (`on.<label>`), so handlers rarely read it directly.
237
+ */
238
+ matched?: string[]
233
239
  };
234
240
  type StreamsEventOf<
235
241
  T extends StreamsEventType,
@@ -299,6 +305,34 @@ type StreamsReorgsListEnvelope = {
299
305
  };
300
306
  /** A filter that matches a single value or any value in a list. */
301
307
  type StreamsFilterValue = string | readonly string[];
308
+ /**
309
+ * One labelled filter group. Fields inside a group AND together; groups in a
310
+ * map OR together server-side.
311
+ */
312
+ type StreamsLabelledFilter = {
313
+ types?: readonly StreamsEventType[]
314
+ contractId?: StreamsFilterValue
315
+ sender?: StreamsFilterValue
316
+ recipient?: StreamsFilterValue
317
+ assetIdentifier?: string
318
+ };
319
+ /** A map of label → filter group. Labels are yours; the server echoes them. */
320
+ type StreamsFilterMap = Record<string, StreamsLabelledFilter>;
321
+ /**
322
+ * The events one label can yield. A group that declares `types` narrows to
323
+ * exactly those variants, so a per-label handler needs no `event_type` guard;
324
+ * a group without `types` keeps the full union.
325
+ */
326
+ type StreamsEventForFilter<
327
+ F,
328
+ D extends boolean = false
329
+ > = F extends {
330
+ types: readonly (infer T extends StreamsEventType)[]
331
+ } ? D extends true ? Extract<IndexEvent, {
332
+ event_type: T
333
+ }> : Extract<StreamsEvent, {
334
+ event_type: T
335
+ }> : D extends true ? IndexEvent : StreamsEvent;
302
336
  type StreamsEventsListParams = {
303
337
  cursor?: string | null
304
338
  fromHeight?: number
@@ -310,6 +344,12 @@ type StreamsEventsListParams = {
310
344
  sender?: StreamsFilterValue
311
345
  recipient?: StreamsFilterValue
312
346
  assetIdentifier?: string
347
+ /**
348
+ * Labelled filter groups. The groups OR together in one scan and each
349
+ * returned event carries the labels it matched (`event.matched`) — two
350
+ * unrelated concerns share one page, one cursor, one checkpoint.
351
+ */
352
+ filters?: StreamsFilterMap
313
353
  limit?: number
314
354
  };
315
355
  type StreamsEventsStreamParams = {
@@ -320,6 +360,8 @@ type StreamsEventsStreamParams = {
320
360
  sender?: StreamsFilterValue
321
361
  recipient?: StreamsFilterValue
322
362
  assetIdentifier?: string
363
+ /** Labelled filter groups; see {@link StreamsEventsListParams.filters}. */
364
+ filters?: StreamsFilterMap
323
365
  batchSize?: number
324
366
  emptyBackoffMs?: number
325
367
  maxPages?: number
@@ -335,6 +377,8 @@ type StreamsEventsSubscribeParams = {
335
377
  sender?: StreamsFilterValue
336
378
  recipient?: StreamsFilterValue
337
379
  assetIdentifier?: string
380
+ /** Labelled filter groups; see {@link StreamsEventsListParams.filters}. */
381
+ filters?: StreamsFilterMap
338
382
  /** Abort to unsubscribe (the returned function does the same). */
339
383
  signal?: AbortSignal
340
384
  /** Called for each pushed event, in order. */
@@ -386,7 +430,8 @@ type StreamsReorgContext = {
386
430
  };
387
431
  type StreamsEventsConsumeParams<
388
432
  TTx = never,
389
- D extends boolean = false
433
+ D extends boolean = false,
434
+ F extends StreamsFilterMap = Record<never, never>
390
435
  > = {
391
436
  fromCursor?: string | null
392
437
  /**
@@ -420,13 +465,33 @@ type StreamsEventsConsumeParams<
420
465
  sender?: StreamsFilterValue
421
466
  recipient?: StreamsFilterValue
422
467
  assetIdentifier?: string
468
+ /**
469
+ * Labelled filter groups. The groups OR together in ONE server-side scan,
470
+ * so two unrelated concerns share one page, one cursor, and one checkpoint
471
+ * instead of two consume loops. Pair with `on` to handle each label.
472
+ */
473
+ filters?: F
474
+ /**
475
+ * One handler per label in `filters`. Every label must be handled, so
476
+ * adding a label is a compile error until its handler exists.
477
+ *
478
+ * A label's declared `types` narrows its handler's events, so `payload` is
479
+ * typed without an `event_type` guard. Labels are dispatched in declaration
480
+ * order: a label's own events stay in cursor order, but events of different
481
+ * labels do not interleave within a page — add `onBatch` when you need
482
+ * strict global order across labels.
483
+ */
484
+ on?: { [K in keyof F] : (events: StreamsEventForFilter<F[K], D>[], ctx: StreamsBatchContext & WithSinkTx<TTx>) => void | Promise<void> }
423
485
  batchSize?: number
424
486
  /**
425
487
  * Apply a page of canonical events. Persist `ctx.cursor` in the same
426
488
  * transaction as your writes. Returning a cursor overrides `ctx.cursor` as
427
489
  * the resume point (advanced manual control); returning nothing uses it.
490
+ *
491
+ * Optional only when `on` handles the page instead; a consume call with
492
+ * neither throws.
428
493
  */
429
- onBatch: (events: D extends true ? IndexEvent[] : StreamsEvent[], envelope: StreamsEventsEnvelope, ctx: StreamsBatchContext & WithSinkTx<TTx>) => void | string | null | undefined | Promise<void> | Promise<string | null | undefined>
494
+ onBatch?: (events: D extends true ? IndexEvent[] : StreamsEvent[], envelope: StreamsEventsEnvelope, ctx: StreamsBatchContext & WithSinkTx<TTx>) => void | string | null | undefined | Promise<void> | Promise<string | null | undefined>
430
495
  /**
431
496
  * Roll your projection back to `reorg.fork_point_height`, persisting
432
497
  * `ctx.cursor` in the same transaction. Called once per *new* reorg
@@ -585,9 +650,10 @@ type StreamsClient = {
585
650
  * stops it.
586
651
  */
587
652
  consume<
653
+ const F extends StreamsFilterMap = Record<never, never>,
588
654
  TTx = never,
589
655
  D extends boolean = false
590
- >(params: StreamsEventsConsumeParams<TTx, D> & {
656
+ >(params: StreamsEventsConsumeParams<TTx, D, F> & {
591
657
  sink?: ConsumerSink<TTx>
592
658
  }): Promise<StreamsEventsConsumeResult>
593
659
  /**
@@ -413,7 +413,8 @@ async function consumeStreamsEvents(opts) {
413
413
  contractId: opts.contractId,
414
414
  sender: opts.sender,
415
415
  recipient: opts.recipient,
416
- assetIdentifier: opts.assetIdentifier
416
+ assetIdentifier: opts.assetIdentifier,
417
+ filters: opts.filters
417
418
  }), {
418
419
  retryCount: opts.retryCount,
419
420
  retryDelay: opts.retryDelay,
@@ -490,7 +491,8 @@ async function* iterateStreamsBatches(opts) {
490
491
  contractId: opts.contractId,
491
492
  sender: opts.sender,
492
493
  recipient: opts.recipient,
493
- assetIdentifier: opts.assetIdentifier
494
+ assetIdentifier: opts.assetIdentifier,
495
+ filters: opts.filters
494
496
  });
495
497
  const checkpoint = envelope.next_cursor ?? cursor;
496
498
  if (envelope.events.length > 0 || envelope.reorgs.length > 0) {
@@ -527,7 +529,8 @@ async function* streamStreamsEvents(opts) {
527
529
  contractId: opts.contractId,
528
530
  sender: opts.sender,
529
531
  recipient: opts.recipient,
530
- assetIdentifier: opts.assetIdentifier
532
+ assetIdentifier: opts.assetIdentifier,
533
+ filters: opts.filters
531
534
  });
532
535
  pages++;
533
536
  for (const event of envelope.events) {
@@ -802,7 +805,8 @@ function subscribeStreamsEvents(opts) {
802
805
  contract_id: params.contractId,
803
806
  sender: params.sender,
804
807
  recipient: params.recipient,
805
- asset_identifier: params.assetIdentifier
808
+ asset_identifier: params.assetIdentifier,
809
+ filters: params.filters ? JSON.stringify(params.filters) : undefined
806
810
  })}`;
807
811
  const res = await opts.fetchImpl(url, {
808
812
  headers: {
@@ -1046,7 +1050,8 @@ function createStreamsClient(options) {
1046
1050
  contractId,
1047
1051
  sender,
1048
1052
  recipient,
1049
- assetIdentifier
1053
+ assetIdentifier,
1054
+ filters
1050
1055
  }) => {
1051
1056
  return listEvents({
1052
1057
  cursor,
@@ -1056,9 +1061,13 @@ function createStreamsClient(options) {
1056
1061
  contractId,
1057
1062
  sender,
1058
1063
  recipient,
1059
- assetIdentifier
1064
+ assetIdentifier,
1065
+ filters
1060
1066
  });
1061
1067
  };
1068
+ function encodeFilters(filters) {
1069
+ return filters ? JSON.stringify(filters) : undefined;
1070
+ }
1062
1071
  async function listEvents(params = {}) {
1063
1072
  return request(`/v1/streams/events${buildQuery({
1064
1073
  cursor: params.cursor,
@@ -1070,9 +1079,56 @@ function createStreamsClient(options) {
1070
1079
  recipient: params.recipient,
1071
1080
  asset_identifier: params.assetIdentifier,
1072
1081
  types: params.types,
1073
- not_types: params.notTypes
1082
+ not_types: params.notTypes,
1083
+ filters: encodeFilters(params.filters)
1074
1084
  })}`);
1075
1085
  }
1086
+ function consumeEvents(params) {
1087
+ const labels = params.filters ? Object.keys(params.filters) : [];
1088
+ if (labels.length === 0 && !params.onBatch) {
1089
+ throw new ValidationError("consume requires onBatch, or filters + on handlers.", 400);
1090
+ }
1091
+ if (labels.length > 0 && !params.on && !params.onBatch) {
1092
+ throw new ValidationError("consume with filters requires on handlers (or onBatch).", 400);
1093
+ }
1094
+ const dispatch = params.on;
1095
+ const project = (events) => params.decoded ? events.map(decode) : events;
1096
+ const onBatch = async (events, envelope, ctx) => {
1097
+ for (const label of labels) {
1098
+ const forLabel = events.filter((event) => event.matched?.includes(label));
1099
+ if (forLabel.length === 0)
1100
+ continue;
1101
+ await dispatch?.[label]?.(project(forLabel), ctx);
1102
+ }
1103
+ const userOnBatch = params.onBatch;
1104
+ return await userOnBatch?.(project(events), envelope, ctx);
1105
+ };
1106
+ return consumeStreamsEvents({
1107
+ fromCursor: params.fromCursor,
1108
+ sink: params.sink,
1109
+ onProgress: params.onProgress,
1110
+ mode: params.mode,
1111
+ finalizedOnly: params.finalizedOnly,
1112
+ types: params.types,
1113
+ notTypes: params.notTypes,
1114
+ contractId: params.contractId,
1115
+ sender: params.sender,
1116
+ recipient: params.recipient,
1117
+ assetIdentifier: params.assetIdentifier,
1118
+ filters: params.filters,
1119
+ batchSize: params.batchSize ?? 100,
1120
+ fetchEvents,
1121
+ onBatch,
1122
+ onReorg: params.onReorg,
1123
+ emptyBackoffMs: params.emptyBackoffMs,
1124
+ maxPages: params.maxPages,
1125
+ maxEmptyPolls: params.maxEmptyPolls,
1126
+ signal: params.signal,
1127
+ retryCount: params.retryCount,
1128
+ retryDelay: params.retryDelay,
1129
+ onError: params.onError
1130
+ });
1131
+ }
1076
1132
  return {
1077
1133
  consume(params = {}) {
1078
1134
  return iterateStreamsBatches({
@@ -1094,33 +1150,7 @@ function createStreamsClient(options) {
1094
1150
  byTxId(txId) {
1095
1151
  return request(`/v1/streams/events/${encodeURIComponent(txId)}`);
1096
1152
  },
1097
- consume(params) {
1098
- const onBatch = params.decoded ? (events, envelope, ctx) => params.onBatch(events.map(decode), envelope, ctx) : params.onBatch;
1099
- return consumeStreamsEvents({
1100
- fromCursor: params.fromCursor,
1101
- sink: params.sink,
1102
- onProgress: params.onProgress,
1103
- mode: params.mode,
1104
- finalizedOnly: params.finalizedOnly,
1105
- types: params.types,
1106
- notTypes: params.notTypes,
1107
- contractId: params.contractId,
1108
- sender: params.sender,
1109
- recipient: params.recipient,
1110
- assetIdentifier: params.assetIdentifier,
1111
- batchSize: params.batchSize ?? 100,
1112
- fetchEvents,
1113
- onBatch,
1114
- onReorg: params.onReorg,
1115
- emptyBackoffMs: params.emptyBackoffMs,
1116
- maxPages: params.maxPages,
1117
- maxEmptyPolls: params.maxEmptyPolls,
1118
- signal: params.signal,
1119
- retryCount: params.retryCount,
1120
- retryDelay: params.retryDelay,
1121
- onError: params.onError
1122
- });
1123
- },
1153
+ consume: consumeEvents,
1124
1154
  stream(params = {}) {
1125
1155
  return streamStreamsEvents({
1126
1156
  fromCursor: params.fromCursor,
@@ -1453,5 +1483,5 @@ export {
1453
1483
  AuthError
1454
1484
  };
1455
1485
 
1456
- //# debugId=5CDDE8F307DF3D9164756E2164756E21
1486
+ //# debugId=C3835A12D654E64864756E2164756E21
1457
1487
  //# sourceMappingURL=index.js.map