@orion-js/echoes 4.5.6 → 4.5.7

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.
@@ -1,9 +1,10 @@
1
1
  import type { EchoesSchema } from '../schema';
2
- import { EchoConfig, EchoEventConfig, EchoRequestConfig, EchoType } from '../types';
2
+ import { EchoBatchEventConfig, EchoConfig, EchoEventConfig, EchoRequestConfig, EchoType } from '../types';
3
3
  /**
4
4
  * @deprecated Use createEchoRequest and createEchoEvent instead
5
5
  */
6
6
  declare const echo: <TParamsSchema extends EchoesSchema, TReturnsSchema extends EchoesSchema, TEchoType extends 'event' | 'request'>(options: EchoConfig<TParamsSchema, TReturnsSchema, TEchoType>) => EchoType<TParamsSchema, TReturnsSchema, TEchoType>;
7
7
  export declare function createEchoRequest<TParamsSchema extends EchoesSchema, TReturnsSchema extends EchoesSchema>(options: EchoRequestConfig<TParamsSchema, TReturnsSchema>): EchoType<TParamsSchema, TReturnsSchema, 'request'>;
8
8
  export declare function createEchoEvent<TParamsSchema extends EchoesSchema, TReturnsSchema extends EchoesSchema>(options: EchoEventConfig<TParamsSchema, TReturnsSchema>): EchoType<TParamsSchema, TReturnsSchema, 'event'>;
9
+ export declare function createEchoBatchEvent<TParamsSchema extends EchoesSchema = any>(options: EchoBatchEventConfig<TParamsSchema>): EchoType<TParamsSchema, any, 'event'>;
9
10
  export { echo };
@@ -19,4 +19,5 @@ export default class EventBus {
19
19
  publish<TParams = any>(options: PublishOptions<TParams>): Promise<any>;
20
20
  close(): Promise<void>;
21
21
  private handleEvent;
22
+ private handleEvents;
22
23
  }
@@ -3,12 +3,16 @@ export interface EventSubscriptionDefinition {
3
3
  topic: string;
4
4
  attemptsBeforeDeadLetter?: number;
5
5
  configVersion?: number;
6
+ maxConcurrency?: number;
7
+ receiverMode: 'single' | 'batch';
8
+ batchSize: number;
6
9
  }
7
10
  export interface EventTransportStartOptions {
8
11
  consume: boolean;
9
12
  publish: boolean;
10
13
  subscriptions: EventSubscriptionDefinition[];
11
14
  onEvent(event: EchoesReceivedEvent): Promise<void>;
15
+ onEvents(events: EchoesReceivedEvent[]): Promise<void>;
12
16
  }
13
17
  export interface EventTransport {
14
18
  readonly name: EchoesEventTransportName;
package/dist/index.cjs CHANGED
@@ -29,6 +29,7 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
29
29
  // src/index.ts
30
30
  var index_exports = {};
31
31
  __export(index_exports, {
32
+ EchoBatchEvent: () => EchoBatchEvent,
32
33
  EchoEvent: () => EchoEvent,
33
34
  EchoRequest: () => EchoRequest,
34
35
  Echoes: () => Echoes,
@@ -36,6 +37,7 @@ __export(index_exports, {
36
37
  EchoesValidationError: () => EchoesValidationError,
37
38
  cleanEchoesSchema: () => cleanEchoesSchema,
38
39
  configureEchoesRuntime: () => configureEchoesRuntime,
40
+ createEchoBatchEvent: () => createEchoBatchEvent,
39
41
  createEchoEvent: () => createEchoEvent,
40
42
  createEchoRequest: () => createEchoRequest,
41
43
  createEchoesUserError: () => createEchoesUserError,
@@ -756,8 +758,14 @@ var EventBus = class {
756
758
  const subscriptions = Object.entries(this.echoes).filter(([, echo2]) => echo2.type === "event").map(([topic, echo2]) => ({
757
759
  topic,
758
760
  attemptsBeforeDeadLetter: echo2.attemptsBeforeDeadLetter,
759
- configVersion: echo2.configVersion
761
+ configVersion: echo2.configVersion,
762
+ maxConcurrency: echo2.maxConcurrency,
763
+ receiverMode: echo2.receiverMode ?? "single",
764
+ batchSize: echo2.batchSize ?? 1
760
765
  }));
766
+ if (this.consumeFrom.includes("kafka") && subscriptions.some((subscription) => subscription.receiverMode === "batch")) {
767
+ throw new Error("Echoes batch event receivers are supported only by the Pulse transport.");
768
+ }
761
769
  try {
762
770
  for (const name of selected) {
763
771
  const transport = this.transports[name];
@@ -766,7 +774,8 @@ var EventBus = class {
766
774
  consume: this.consumeFrom.includes(name),
767
775
  publish: this.publishTo === name,
768
776
  subscriptions,
769
- onEvent: (event) => this.handleEvent(event)
777
+ onEvent: (event) => this.handleEvent(event),
778
+ onEvents: (events) => this.handleEvents(events)
770
779
  });
771
780
  }
772
781
  this.started = true;
@@ -815,6 +824,15 @@ var EventBus = class {
815
824
  data: event.data
816
825
  });
817
826
  }
827
+ async handleEvents(events) {
828
+ if (events.length === 0) return;
829
+ const echo2 = this.echoes[events[0].topic];
830
+ if ((echo2 == null ? void 0 : echo2.type) === "event" && echo2.onEvents) {
831
+ await echo2.onEvents(events);
832
+ return;
833
+ }
834
+ for (const event of events) await this.handleEvent(event);
835
+ }
818
836
  };
819
837
 
820
838
  // src/events/PulseManager.ts
@@ -844,6 +862,18 @@ var PulseManager = class {
844
862
  this.subscriptions = await Promise.all(
845
863
  options.subscriptions.map(async (definition) => {
846
864
  const subscribeOptions = this.getSubscribeOptions(subscription, definition);
865
+ if (definition.receiverMode === "batch") {
866
+ if (typeof this.pulse.subscribeBatch !== "function") {
867
+ throw new Error(
868
+ "Echoes batch event receivers require a version of @orion-js/pulse with subscribeBatch support."
869
+ );
870
+ }
871
+ return await this.pulse.subscribeBatch(
872
+ definition.topic,
873
+ (events) => options.onEvents(events.map((event) => this.createReceivedEvent(event))),
874
+ { ...subscribeOptions, batchSize: definition.batchSize }
875
+ );
876
+ }
847
877
  return await this.pulse.subscribe(
848
878
  definition.topic,
849
879
  (event) => options.onEvent(this.createReceivedEvent(event)),
@@ -870,7 +900,8 @@ var PulseManager = class {
870
900
  return {
871
901
  ...defaults,
872
902
  ...definition.configVersion === void 0 ? {} : { configVersion: definition.configVersion },
873
- ...definition.attemptsBeforeDeadLetter === void 0 ? {} : { maxRetries: definition.attemptsBeforeDeadLetter }
903
+ ...definition.attemptsBeforeDeadLetter === void 0 ? {} : { maxRetries: definition.attemptsBeforeDeadLetter },
904
+ ...definition.maxConcurrency === void 0 ? {} : { maxConcurrency: definition.maxConcurrency }
874
905
  };
875
906
  }
876
907
  createReceivedEvent(event) {
@@ -1004,6 +1035,18 @@ async function stopService() {
1004
1035
  }
1005
1036
 
1006
1037
  // src/echo/index.ts
1038
+ function receivedEventContext(event) {
1039
+ return {
1040
+ ...event.context || {},
1041
+ transport: event.transport,
1042
+ eventId: event.id,
1043
+ topic: event.topic,
1044
+ headers: event.headers,
1045
+ createdAt: event.createdAt,
1046
+ attempt: event.attempt,
1047
+ data: event.data
1048
+ };
1049
+ }
1007
1050
  var echo = function createNewEcho(options) {
1008
1051
  const resolve = async (params, context) => {
1009
1052
  const cleaned = options.params ? await parseEchoesSchema(options.params, params) : params ?? {};
@@ -1014,17 +1057,7 @@ var echo = function createNewEcho(options) {
1014
1057
  return result;
1015
1058
  };
1016
1059
  const onEvent = async (event) => {
1017
- const context = {
1018
- ...event.context || {},
1019
- transport: event.transport,
1020
- eventId: event.id,
1021
- topic: event.topic,
1022
- headers: event.headers,
1023
- createdAt: event.createdAt,
1024
- attempt: event.attempt,
1025
- data: event.data
1026
- };
1027
- await resolve(event.data.params, context);
1060
+ await resolve(event.data.params, receivedEventContext(event));
1028
1061
  };
1029
1062
  return {
1030
1063
  type: options.type,
@@ -1032,6 +1065,9 @@ var echo = function createNewEcho(options) {
1032
1065
  returns: options.returns,
1033
1066
  attemptsBeforeDeadLetter: options.type === "event" ? options.attemptsBeforeDeadLetter : void 0,
1034
1067
  configVersion: options.type === "event" ? options.configVersion : void 0,
1068
+ maxConcurrency: options.type === "event" ? options.maxConcurrency : void 0,
1069
+ receiverMode: options.type === "event" ? "single" : void 0,
1070
+ batchSize: options.type === "event" ? 1 : void 0,
1035
1071
  resolve,
1036
1072
  onEvent,
1037
1073
  onMessage: async (messageData) => {
@@ -1069,6 +1105,50 @@ function createEchoRequest(options) {
1069
1105
  function createEchoEvent(options) {
1070
1106
  return echo({ ...options, type: "event" });
1071
1107
  }
1108
+ function createEchoBatchEvent(options) {
1109
+ if (!Number.isInteger(options.batchSize) || options.batchSize <= 0) {
1110
+ throw new Error("batchSize must be a positive integer.");
1111
+ }
1112
+ const resolveBatch = async (events) => {
1113
+ const cleaned = await Promise.all(
1114
+ events.map(async (event) => ({
1115
+ params: options.params ? await parseEchoesSchema(options.params, event.params) : event.params ?? {},
1116
+ context: event.context
1117
+ }))
1118
+ );
1119
+ await options.resolveBatch(cleaned);
1120
+ };
1121
+ const onEvents = async (events) => {
1122
+ await resolveBatch(
1123
+ events.map((event) => ({
1124
+ params: event.data.params,
1125
+ context: receivedEventContext(event)
1126
+ }))
1127
+ );
1128
+ };
1129
+ return {
1130
+ type: "event",
1131
+ params: options.params,
1132
+ attemptsBeforeDeadLetter: options.attemptsBeforeDeadLetter,
1133
+ configVersion: options.configVersion,
1134
+ maxConcurrency: options.maxConcurrency,
1135
+ receiverMode: "batch",
1136
+ batchSize: options.batchSize,
1137
+ resolve: async (params, context) => {
1138
+ await resolveBatch([{ params, context: context ?? {} }]);
1139
+ return void 0;
1140
+ },
1141
+ resolveBatch,
1142
+ onEvent: async (event) => await onEvents([event]),
1143
+ onEvents,
1144
+ onMessage: async () => {
1145
+ throw new Error("Echoes batch event receivers are supported only by the Pulse transport.");
1146
+ },
1147
+ onRequest: async () => {
1148
+ throw new Error("Echoes batch events cannot be invoked as requests.");
1149
+ }
1150
+ };
1151
+ }
1072
1152
 
1073
1153
  // src/schema.ts
1074
1154
  function typedEchoesSchema(schema) {
@@ -1121,6 +1201,28 @@ function EchoEvent(options = {}) {
1121
1201
  return method;
1122
1202
  };
1123
1203
  }
1204
+ function EchoBatchEvent(options) {
1205
+ return (method, context) => {
1206
+ const propertyKey = String(context.name);
1207
+ pendingEchoEntries[propertyKey] = (instance) => {
1208
+ const originalResolveBatch = instance[propertyKey].bind(instance);
1209
+ return createEchoBatchEvent({
1210
+ ...options,
1211
+ resolveBatch: async (events) => {
1212
+ return await runWithEchoesContext(
1213
+ {
1214
+ controllerType: "echo",
1215
+ echoName: propertyKey,
1216
+ params: events.map((event) => event.params)
1217
+ },
1218
+ async () => await originalResolveBatch(events)
1219
+ );
1220
+ }
1221
+ });
1222
+ };
1223
+ return method;
1224
+ };
1225
+ }
1124
1226
  function EchoRequest(options = {}) {
1125
1227
  return (method, context) => {
1126
1228
  const propertyKey = String(context.name);
@@ -1185,6 +1287,7 @@ function getServiceEchoes(target) {
1185
1287
  }
1186
1288
  // Annotate the CommonJS export names for ESM import in node:
1187
1289
  0 && (module.exports = {
1290
+ EchoBatchEvent,
1188
1291
  EchoEvent,
1189
1292
  EchoRequest,
1190
1293
  Echoes,
@@ -1192,6 +1295,7 @@ function getServiceEchoes(target) {
1192
1295
  EchoesValidationError,
1193
1296
  cleanEchoesSchema,
1194
1297
  configureEchoesRuntime,
1298
+ createEchoBatchEvent,
1195
1299
  createEchoEvent,
1196
1300
  createEchoRequest,
1197
1301
  createEchoesUserError,