@orion-js/echoes 4.4.1 → 4.5.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.
package/dist/index.js CHANGED
@@ -1,14 +1,14 @@
1
- // src/startService/index.ts
2
- import { registerRoute } from "@orion-js/http";
3
-
4
1
  // src/config.ts
5
2
  var config = {};
6
3
  var config_default = config;
7
4
 
8
- // src/startService/KafkaManager.ts
9
- import { randomUUID } from "crypto";
10
- import { logger } from "@orion-js/logger";
11
- import { Kafka } from "kafkajs";
5
+ // src/publish/index.ts
6
+ async function publish(options) {
7
+ if (!config_default.eventBus) {
8
+ throw new Error("You must initialize echoes configuration to use publish");
9
+ }
10
+ return await config_default.eventBus.publish(options);
11
+ }
12
12
 
13
13
  // src/echo/deserialize.ts
14
14
  function deserialize_default(serializedJavascript) {
@@ -21,14 +21,306 @@ function deserialize_default(serializedJavascript) {
21
21
 
22
22
  // src/publish/serialize.ts
23
23
  import serialize from "serialize-javascript";
24
- import { clone } from "@orion-js/helpers";
25
24
  function serialize_default(data) {
26
- const cloned = clone(data);
27
- const serialized = serialize(cloned, { ignoreFunction: true });
25
+ const serialized = serialize(data, { ignoreFunction: true });
28
26
  return serialized;
29
27
  }
30
28
 
29
+ // src/runtime.ts
30
+ import { AsyncLocalStorage } from "async_hooks";
31
+ import { randomUUID } from "crypto";
32
+
33
+ // src/errors.ts
34
+ var EchoesUserError = class extends Error {
35
+ isEchoesError = true;
36
+ isOrionError = true;
37
+ isUserError = true;
38
+ code;
39
+ extra;
40
+ constructor(code, message, extra) {
41
+ if (!message) {
42
+ message = code;
43
+ code = "error";
44
+ }
45
+ super(message);
46
+ this.name = "EchoesUserError";
47
+ this.code = code;
48
+ this.extra = extra;
49
+ }
50
+ getInfo() {
51
+ return { error: this.code, message: this.message, extra: this.extra };
52
+ }
53
+ };
54
+ var EchoesValidationError = class extends Error {
55
+ isEchoesError = true;
56
+ isOrionError = true;
57
+ isValidationError = true;
58
+ code = "validationError";
59
+ validationErrors;
60
+ labels;
61
+ constructor(validationErrors, labels = {}) {
62
+ const printableErrors = Object.entries(validationErrors).map(([key, value]) => `${key}: ${value}`).join(", ");
63
+ super(`Validation Error: {${printableErrors}}`);
64
+ this.name = "EchoesValidationError";
65
+ this.validationErrors = validationErrors;
66
+ this.labels = Object.fromEntries(
67
+ Object.keys(validationErrors).filter((key) => labels[key]).map((key) => [key, labels[key]])
68
+ );
69
+ }
70
+ getInfo() {
71
+ return {
72
+ error: this.code,
73
+ message: "Validation Error",
74
+ validationErrors: this.validationErrors,
75
+ labels: this.labels
76
+ };
77
+ }
78
+ };
79
+
80
+ // src/runtime.ts
81
+ var defaultLogger = {
82
+ debug: (message, metadata) => metadata === void 0 ? console.debug(message) : console.debug(message, metadata),
83
+ info: (message, metadata) => metadata === void 0 ? console.info(message) : console.info(message, metadata),
84
+ warn: (message, metadata) => metadata === void 0 ? console.warn(message) : console.warn(message, metadata),
85
+ error: (message, metadata) => metadata === void 0 ? console.error(message) : console.error(message, metadata)
86
+ };
87
+ var runtime = {};
88
+ var contextStorage = new AsyncLocalStorage();
89
+ function configureEchoesRuntime(adapter) {
90
+ const previous = runtime;
91
+ runtime = { ...runtime, ...adapter };
92
+ return () => {
93
+ runtime = previous;
94
+ };
95
+ }
96
+ function getEchoesRuntime() {
97
+ return runtime;
98
+ }
99
+ function getEchoesLogger() {
100
+ return runtime.logger || defaultLogger;
101
+ }
102
+ function getEchoesContext() {
103
+ return contextStorage.getStore();
104
+ }
105
+ async function runWithEchoesContext(context, callback) {
106
+ const contextWithId = { contextId: context.contextId || randomUUID(), ...context };
107
+ return await contextStorage.run(contextWithId, async () => {
108
+ if (runtime.runWithContext) {
109
+ return await runtime.runWithContext(contextWithId, callback);
110
+ }
111
+ return await callback();
112
+ });
113
+ }
114
+ function isSimpleSchemaLike(schema) {
115
+ return !!schema && typeof schema === "object" && typeof schema.clean === "function" && typeof schema.validate === "function";
116
+ }
117
+ function cloneValue(value) {
118
+ if (value === null || typeof value !== "object") return value;
119
+ if (value instanceof Date) return new Date(value.getTime());
120
+ if (Buffer.isBuffer(value)) return Buffer.from(value);
121
+ if (Array.isArray(value)) return value.map(cloneValue);
122
+ const prototype = Object.getPrototypeOf(value);
123
+ if (prototype !== Object.prototype && prototype !== null) return value;
124
+ const result = {};
125
+ for (const [key, child] of Object.entries(value)) {
126
+ result[key] = cloneValue(child);
127
+ }
128
+ return result;
129
+ }
130
+ async function cleanSimpleSchema(schema, value) {
131
+ const cloned = cloneValue(value);
132
+ return await schema.clean(cloned, { mutate: false });
133
+ }
134
+ async function cleanEchoesSchema(schema, value) {
135
+ if (isSimpleSchemaLike(schema)) {
136
+ return await cleanSimpleSchema(schema, value);
137
+ }
138
+ if (runtime.schema) {
139
+ return await runtime.schema.clean(schema, value);
140
+ }
141
+ throw new Error(
142
+ "Echoes received a schema it cannot execute. Use a SimpleSchema-compatible object or configure an Echoes schema adapter."
143
+ );
144
+ }
145
+ async function parseEchoesSchema(schema, value) {
146
+ if (isSimpleSchemaLike(schema)) {
147
+ const cleaned = await cleanSimpleSchema(schema, value);
148
+ await schema.validate(cleaned);
149
+ return cleaned;
150
+ }
151
+ if (runtime.schema) {
152
+ return await runtime.schema.parse(schema, value);
153
+ }
154
+ throw new Error(
155
+ "Echoes received a schema it cannot execute. Use a SimpleSchema-compatible object or configure an Echoes schema adapter."
156
+ );
157
+ }
158
+ function createEchoesValidationError(info) {
159
+ return runtime.createValidationError ? runtime.createValidationError(info) : new EchoesValidationError(info.validationErrors || {}, info.labels);
160
+ }
161
+ function createEchoesUserError(info) {
162
+ return runtime.createUserError ? runtime.createUserError(info) : new EchoesUserError(info.error, info.message, info.extra);
163
+ }
164
+
165
+ // src/request/getSignature.ts
166
+ import { createHmac } from "crypto";
167
+
168
+ // src/request/getPassword.ts
169
+ function getEchoesPassword() {
170
+ var _a, _b;
171
+ const secret = ((_b = (_a = config_default) == null ? void 0 : _a.requests) == null ? void 0 : _b.key) || process.env.echoes_password || process.env.ECHOES_PASSWORD;
172
+ if (!secret) {
173
+ getEchoesLogger().warn(
174
+ 'Warning: no secret key found for echoes requests. Init echoes or set the env var "echoes_password" or process.env.ECHOES_PASSWORD'
175
+ );
176
+ }
177
+ return secret;
178
+ }
179
+
180
+ // src/request/getSignature.ts
181
+ function getSignature_default(_body) {
182
+ const password = getEchoesPassword();
183
+ return createHmac("sha1", password || "").update("").digest("hex");
184
+ }
185
+
186
+ // src/request/getURL.ts
187
+ function getURL_default(serviceName) {
188
+ var _a, _b, _c;
189
+ if (serviceName.startsWith("http")) return serviceName;
190
+ const url = (_c = (_b = (_a = config_default) == null ? void 0 : _a.requests) == null ? void 0 : _b.services) == null ? void 0 : _c[serviceName];
191
+ if (!url) {
192
+ throw new Error(`No URL found in echoes config for service ${serviceName}`);
193
+ }
194
+ return url;
195
+ }
196
+
197
+ // src/request/makeRequest.ts
198
+ import http from "http";
199
+ import https from "https";
200
+ async function executeWithRetries(callback, retries = 0, delayMs = 200) {
201
+ try {
202
+ return await callback();
203
+ } catch (error) {
204
+ if (retries <= 0) throw error;
205
+ await new Promise((resolve) => setTimeout(resolve, delayMs));
206
+ return await executeWithRetries(callback, retries - 1, delayMs);
207
+ }
208
+ }
209
+ async function postJSON(urlValue, data, timeout, redirectsRemaining = 5) {
210
+ const url = new URL(urlValue);
211
+ const body = JSON.stringify(data);
212
+ const transport = url.protocol === "https:" ? https : http;
213
+ return await new Promise((resolve, reject) => {
214
+ const request2 = transport.request(
215
+ url,
216
+ {
217
+ method: "POST",
218
+ headers: {
219
+ "User-Agent": "Orionjs-Echoes/1.1",
220
+ "Content-Type": "application/json",
221
+ "Content-Length": Buffer.byteLength(body)
222
+ }
223
+ },
224
+ (response) => {
225
+ const chunks = [];
226
+ const statusCode = response.statusCode || 0;
227
+ if (statusCode >= 300 && statusCode < 400 && response.headers.location) {
228
+ response.resume();
229
+ if (redirectsRemaining <= 0) {
230
+ reject(new Error("Echoes request exceeded the redirect limit"));
231
+ return;
232
+ }
233
+ resolve(
234
+ postJSON(
235
+ new URL(response.headers.location, url).toString(),
236
+ data,
237
+ timeout,
238
+ redirectsRemaining - 1
239
+ )
240
+ );
241
+ return;
242
+ }
243
+ response.on("data", (chunk) => chunks.push(Buffer.from(chunk)));
244
+ response.on("end", () => {
245
+ try {
246
+ const responseBody = Buffer.concat(chunks).toString("utf8");
247
+ if (statusCode < 200 || statusCode >= 300) {
248
+ reject(new Error(`Request failed with status code ${statusCode}`));
249
+ return;
250
+ }
251
+ resolve({
252
+ statusCode,
253
+ data: responseBody ? JSON.parse(responseBody) : {}
254
+ });
255
+ } catch (error) {
256
+ reject(error);
257
+ }
258
+ });
259
+ }
260
+ );
261
+ request2.on("error", reject);
262
+ if (timeout) {
263
+ request2.setTimeout(timeout, () => {
264
+ request2.destroy(new Error(`Echoes request timed out after ${timeout}ms`));
265
+ });
266
+ }
267
+ request2.end(body);
268
+ });
269
+ }
270
+ var makeRequest = async (options) => {
271
+ return await executeWithRetries(
272
+ () => postJSON(options.url, options.data, options.timeout),
273
+ options.retries || 0
274
+ );
275
+ };
276
+
277
+ // src/request/index.ts
278
+ async function request(options) {
279
+ var _a, _b;
280
+ const { method, service, params } = options;
281
+ const serializedParams = serialize_default(params);
282
+ const date = /* @__PURE__ */ new Date();
283
+ const body = { method, service, serializedParams, date };
284
+ const signature = getSignature_default(body);
285
+ try {
286
+ const requestMaker = ((_b = (_a = config_default) == null ? void 0 : _a.requests) == null ? void 0 : _b.makeRequest) || makeRequest;
287
+ const requestOptions = {
288
+ url: getURL_default(service),
289
+ retries: options.retries,
290
+ timeout: options.timeout,
291
+ data: {
292
+ body,
293
+ signature
294
+ }
295
+ };
296
+ const result = await requestMaker(requestOptions);
297
+ if (result.statusCode !== 200) {
298
+ throw new Error(`Wrong status code ${result.statusCode}`);
299
+ }
300
+ const data = result.data;
301
+ if (data.error) {
302
+ const info = data.errorInfo;
303
+ if (info) {
304
+ if (data.isValidationError) {
305
+ throw createEchoesValidationError(info);
306
+ }
307
+ if (data.isUserError) {
308
+ throw createEchoesUserError(info);
309
+ }
310
+ }
311
+ throw new Error(`${data.error}`);
312
+ }
313
+ const response = deserialize_default(data.result);
314
+ return response;
315
+ } catch (error) {
316
+ const caught = error;
317
+ if (caught.isOrionError || caught.isEchoesError) throw caught;
318
+ throw new Error(`Echoes request network error calling ${service}/${method}: ${caught.message}`);
319
+ }
320
+ }
321
+
31
322
  // src/startService/KafkaManager.ts
323
+ import { randomUUID as randomUUID2 } from "crypto";
32
324
  var HEARTBEAT_INTERVAL_SECONDS = 5;
33
325
  var CHECK_JOIN_CONSUMER_INTERVAL_SECONDS = 30;
34
326
  var DEFAULT_PARTITIONS_CONSUMED_CONCURRENTLY = 4;
@@ -46,11 +338,21 @@ var KafkaManager = class {
46
338
  producerConnected = false;
47
339
  interval;
48
340
  constructor(options) {
49
- this.kafka = new Kafka(options.client);
50
341
  this.options = options;
51
342
  }
52
343
  async start(options) {
53
344
  var _a;
345
+ let kafkaModule;
346
+ try {
347
+ kafkaModule = await import("kafkajs");
348
+ } catch (error) {
349
+ const wrapped = new Error(
350
+ "Echoes Kafka transport requires kafkajs to be installed in the application"
351
+ );
352
+ wrapped.cause = error;
353
+ throw wrapped;
354
+ }
355
+ this.kafka = new kafkaModule.Kafka(this.options.client);
54
356
  this.onEvent = options.onEvent;
55
357
  this.subscriptions = new Map(
56
358
  options.subscriptions.map((subscription) => [subscription.topic, subscription])
@@ -68,7 +370,7 @@ var KafkaManager = class {
68
370
  this.consumer = this.kafka.consumer(this.options.consumer);
69
371
  this.consumerStarted = await this.conditionalStart();
70
372
  if (this.consumerStarted) return;
71
- logger.info("Echoes: Delaying consumer group join, waiting for conditions to be met");
373
+ getEchoesLogger().info("Echoes: Delaying consumer group join, waiting for conditions to be met");
72
374
  this.interval = setInterval(async () => {
73
375
  this.consumerStarted = await this.conditionalStart();
74
376
  if (this.consumerStarted) clearInterval(this.interval);
@@ -86,7 +388,7 @@ var KafkaManager = class {
86
388
  {
87
389
  value: serialize_default({ params: options.params }),
88
390
  headers: {
89
- "echoes-event-id": randomUUID()
391
+ "echoes-event-id": randomUUID2()
90
392
  }
91
393
  }
92
394
  ]
@@ -94,6 +396,7 @@ var KafkaManager = class {
94
396
  }
95
397
  async close() {
96
398
  var _a, _b;
399
+ const logger = getEchoesLogger();
97
400
  logger.warn("Echoes: Stopping Kafka transport");
98
401
  if (this.interval) clearInterval(this.interval);
99
402
  await Promise.all([
@@ -104,6 +407,7 @@ var KafkaManager = class {
104
407
  this.producerConnected = false;
105
408
  }
106
409
  async checkJoinConsumerGroupConditions() {
410
+ const logger = getEchoesLogger();
107
411
  const admin = this.kafka.admin();
108
412
  try {
109
413
  await admin.connect();
@@ -156,6 +460,7 @@ var KafkaManager = class {
156
460
  return false;
157
461
  }
158
462
  async handleMessage(params) {
463
+ const logger = getEchoesLogger();
159
464
  const subscription = this.subscriptions.get(params.topic);
160
465
  if (!subscription) {
161
466
  logger.warn(`Echoes: Received a message for an unknown topic: ${params.topic}, ignoring it`);
@@ -193,6 +498,9 @@ var KafkaManager = class {
193
498
  createReceivedEvent(params) {
194
499
  var _a, _b, _c, _d;
195
500
  const { message, topic, partition } = params;
501
+ if (!message.value) {
502
+ throw new Error(`Echoes received an empty Kafka message for ${topic}`);
503
+ }
196
504
  const data = deserialize_default(message.value.toString());
197
505
  const retries = Number.parseInt(((_b = (_a = message.headers) == null ? void 0 : _a.retries) == null ? void 0 : _b.toString()) || "0", 10);
198
506
  const timestamp = Number.parseInt(message.timestamp || "", 10);
@@ -209,6 +517,7 @@ var KafkaManager = class {
209
517
  }
210
518
  async handleRetries(subscription, params, error) {
211
519
  var _a, _b;
520
+ const logger = getEchoesLogger();
212
521
  const { message, topic } = params;
213
522
  const retries = Number.parseInt(((_b = (_a = message == null ? void 0 : message.headers) == null ? void 0 : _a.retries) == null ? void 0 : _b.toString()) || "0", 10);
214
523
  if (subscription.attemptsBeforeDeadLetter === void 0 || subscription.attemptsBeforeDeadLetter === null) {
@@ -217,6 +526,7 @@ var KafkaManager = class {
217
526
  const maxRetries = subscription.attemptsBeforeDeadLetter || 0;
218
527
  const exceededMaxRetries = retries >= maxRetries;
219
528
  const nextTopic = exceededMaxRetries ? `DLQ-${topic}` : topic;
529
+ if (!message.value) throw error;
220
530
  await this.producer.send({
221
531
  topic: nextTopic,
222
532
  messages: [
@@ -243,7 +553,6 @@ var KafkaManager = class {
243
553
  var KafkaManager_default = KafkaManager;
244
554
 
245
555
  // src/events/EventBus.ts
246
- import { logger as logger2 } from "@orion-js/logger";
247
556
  var EventBus = class {
248
557
  echoes;
249
558
  transports;
@@ -303,9 +612,10 @@ var EventBus = class {
303
612
  await Promise.all(this.startedTransports.map((transport) => transport.close()));
304
613
  }
305
614
  async handleEvent(event) {
615
+ const logger = getEchoesLogger();
306
616
  const echo2 = this.echoes[event.topic];
307
617
  if (!echo2 || echo2.type !== "event") {
308
- logger2.warn(`Echoes: Received a message for an unknown topic: ${event.topic}, ignoring it`);
618
+ logger.warn(`Echoes: Received a message for an unknown topic: ${event.topic}, ignoring it`);
309
619
  return;
310
620
  }
311
621
  if (event.transport === "kafka" && event.context) {
@@ -433,6 +743,14 @@ function createEventBus(options) {
433
743
  });
434
744
  }
435
745
 
746
+ // src/requestsHandler/checkSignature.ts
747
+ function checkSignature_default(body, signature) {
748
+ const generatedSignature = getSignature_default(body);
749
+ if (generatedSignature !== signature) {
750
+ throw new Error("Echoes invalid signature");
751
+ }
752
+ }
753
+
436
754
  // src/requestsHandler/getEcho.ts
437
755
  function getEcho_default(method) {
438
756
  const echo2 = config_default.echoes[method];
@@ -445,72 +763,29 @@ function getEcho_default(method) {
445
763
  return echo2;
446
764
  }
447
765
 
448
- // src/request/getSignature.ts
449
- import JSSHA from "jssha";
450
-
451
- // src/request/getPassword.ts
452
- import { logger as logger3 } from "@orion-js/logger";
453
- import { internalGetEnv } from "@orion-js/env";
454
- function getEchoesPassword() {
455
- var _a, _b;
456
- const secret = ((_b = (_a = config_default) == null ? void 0 : _a.requests) == null ? void 0 : _b.key) || internalGetEnv("echoes_password", "ECHOES_PASSWORD");
457
- if (!secret) {
458
- logger3.warn(
459
- 'Warning: no secret key found for echoes requests. Init echoes or set the env var "echoes_password" or process.env.ECHOES_PASSWORD'
460
- );
461
- }
462
- return secret;
463
- }
464
-
465
- // src/request/getSignature.ts
466
- function getSignature_default(body) {
467
- const password = getEchoesPassword();
468
- const shaObj = new JSSHA("SHA-1", "TEXT");
469
- shaObj.setHMACKey(password, "TEXT");
470
- shaObj.update(body);
471
- return shaObj.getHMAC("HEX");
472
- }
473
-
474
- // src/requestsHandler/checkSignature.ts
475
- function checkSignature_default(body, signature) {
476
- const generatedSignature = getSignature_default(body);
477
- if (generatedSignature !== signature) {
478
- throw new Error("Echoes invalid signature");
479
- }
480
- }
481
-
482
766
  // src/requestsHandler/index.ts
483
- import { route } from "@orion-js/http";
484
- var requestsHandler_default = (options) => route({
767
+ var requestsHandler_default = (options) => ({
485
768
  method: "post",
486
769
  path: options.requests.handlerPath || "/echoes-services",
487
- bodyParser: "json",
488
- bodyParserOptions: {
489
- limit: "10mb"
490
- },
491
- async resolve(req) {
770
+ bodyLimit: "10mb",
771
+ async handle(requestBody) {
492
772
  try {
493
- const { body, signature } = req.body;
773
+ const { body, signature } = requestBody;
494
774
  checkSignature_default(body, signature);
495
775
  const { method, serializedParams } = body;
496
776
  const echo2 = getEcho_default(method);
497
777
  const result = await echo2.onRequest(serializedParams);
498
- return {
499
- body: {
500
- result: serialize_default(result)
501
- }
502
- };
778
+ return { result: serialize_default(result) };
503
779
  } catch (error) {
504
- if (!error.getInfo) {
505
- console.error("Error at echo requests handler:", error);
780
+ const caught = error;
781
+ if (!caught.getInfo) {
782
+ getEchoesLogger().error("Error at echo requests handler:", { error: caught });
506
783
  }
507
784
  return {
508
- body: {
509
- error: error.message,
510
- errorInfo: error.getInfo ? error.getInfo() : null,
511
- isValidationError: !!error.isValidationError,
512
- isUserError: !!error.isUserError
513
- }
785
+ error: caught.message,
786
+ errorInfo: caught.getInfo ? caught.getInfo() : null,
787
+ isValidationError: !!caught.isValidationError,
788
+ isUserError: !!caught.isUserError
514
789
  };
515
790
  }
516
791
  }
@@ -522,7 +797,13 @@ async function startService(options) {
522
797
  config_default.echoes = options.echoes;
523
798
  if (options.requests) {
524
799
  config_default.requests = options.requests;
525
- registerRoute(requestsHandler_default(options));
800
+ const registerHandler = options.requests.registerHandler || getEchoesRuntime().registerRequestHandler;
801
+ if (!registerHandler) {
802
+ throw new Error(
803
+ "Echoes requests require requests.registerHandler in standalone servers. Orion applications can import @orion-js/echoes-orion once during startup."
804
+ );
805
+ }
806
+ await registerHandler(requestsHandler_default(options));
526
807
  }
527
808
  const nextEventBus = createEventBus(options);
528
809
  if (nextEventBus) {
@@ -533,115 +814,22 @@ async function startService(options) {
533
814
  }
534
815
  async function stopService() {
535
816
  if (eventBus) {
536
- console.info("Stoping echoes...");
817
+ const logger = getEchoesLogger();
818
+ logger.info("Stopping Echoes...");
537
819
  await eventBus.close();
538
820
  eventBus = null;
539
821
  config_default.eventBus = void 0;
540
- console.info("Echoes stopped");
541
- }
542
- }
543
-
544
- // src/publish/index.ts
545
- async function publish(options) {
546
- if (!config_default.eventBus) {
547
- throw new Error("You must initialize echoes configuration to use publish");
548
- }
549
- return await config_default.eventBus.publish(options);
550
- }
551
-
552
- // src/request/getURL.ts
553
- function getURL_default(serviceName) {
554
- var _a, _b;
555
- if (serviceName.startsWith("http")) return serviceName;
556
- const url = (_b = (_a = config_default) == null ? void 0 : _a.requests) == null ? void 0 : _b.services[serviceName];
557
- if (!url) {
558
- throw new Error(`No URL found in echoes config for service ${serviceName}`);
559
- }
560
- return url;
561
- }
562
-
563
- // src/request/makeRequest.ts
564
- import axios from "axios";
565
- import { executeWithRetries } from "@orion-js/helpers";
566
- var makeRequest = async (options) => {
567
- const result = await executeWithRetries(
568
- async () => {
569
- return await axios({
570
- method: "post",
571
- url: options.url,
572
- timeout: options.timeout,
573
- headers: {
574
- "User-Agent": "Orionjs-Echoes/1.1"
575
- },
576
- data: options.data
577
- });
578
- },
579
- options.retries,
580
- 200
581
- );
582
- return {
583
- data: result.data,
584
- statusCode: result.status
585
- };
586
- };
587
-
588
- // src/request/index.ts
589
- import { ValidationError } from "@orion-js/schema";
590
- import { UserError } from "@orion-js/helpers";
591
- async function request(options) {
592
- var _a, _b;
593
- const { method, service, params } = options;
594
- const serializedParams = serialize_default(params);
595
- const date = /* @__PURE__ */ new Date();
596
- const body = { method, service, serializedParams, date };
597
- const signature = getSignature_default(body);
598
- try {
599
- const requestMaker = ((_b = (_a = config_default) == null ? void 0 : _a.requests) == null ? void 0 : _b.makeRequest) || makeRequest;
600
- const requestOptions = {
601
- url: getURL_default(service),
602
- retries: options.retries,
603
- timeout: options.timeout,
604
- data: {
605
- body,
606
- signature
607
- }
608
- };
609
- const result = await requestMaker(requestOptions);
610
- if (result.statusCode !== 200) {
611
- throw new Error(`Wrong status code ${result.statusCode}`);
612
- }
613
- const data = result.data;
614
- if (data.error) {
615
- const info = data.errorInfo;
616
- if (info) {
617
- if (data.isValidationError) {
618
- throw new ValidationError(info.validationErrors);
619
- }
620
- if (data.isUserError) {
621
- throw new UserError(info.error, info.message, info.extra);
622
- }
623
- }
624
- throw new Error(`${data.error}`);
625
- }
626
- const response = deserialize_default(data.result);
627
- return response;
628
- } catch (error) {
629
- if (error.isOrionError) throw error;
630
- throw new Error(`Echoes request network error calling ${service}/${method}: ${error.message}`);
822
+ logger.info("Echoes stopped");
631
823
  }
632
824
  }
633
825
 
634
- // src/service/index.ts
635
- import { runWithOrionAsyncContext } from "@orion-js/logger";
636
-
637
826
  // src/echo/index.ts
638
- import { clean, cleanAndValidate } from "@orion-js/schema";
639
827
  var echo = function createNewEcho(options) {
640
828
  const resolve = async (params, context) => {
641
- const cleaned = options.params ? await cleanAndValidate(options.params, params) : params ?? {};
829
+ const cleaned = options.params ? await parseEchoesSchema(options.params, params) : params ?? {};
642
830
  const result = await options.resolve(cleaned, context);
643
831
  if (options.returns) {
644
- return await clean(options.returns, result);
832
+ return await cleanEchoesSchema(options.returns, result);
645
833
  }
646
834
  return result;
647
835
  };
@@ -668,6 +856,9 @@ var echo = function createNewEcho(options) {
668
856
  onMessage: async (messageData) => {
669
857
  var _a, _b, _c, _d;
670
858
  const { message } = messageData;
859
+ if (!message.value) {
860
+ throw new Error(`Echoes received an empty Kafka message for ${messageData.topic}`);
861
+ }
671
862
  const data = deserialize_default(message.value.toString());
672
863
  const retries = Number.parseInt(((_b = (_a = message.headers) == null ? void 0 : _a.retries) == null ? void 0 : _b.toString()) || "0", 10);
673
864
  const timestamp = Number(message.timestamp);
@@ -698,15 +889,21 @@ function createEchoEvent(options) {
698
889
  return echo({ ...options, type: "event" });
699
890
  }
700
891
 
892
+ // src/schema.ts
893
+ function typedEchoesSchema(schema) {
894
+ return schema;
895
+ }
896
+
701
897
  // src/service/index.ts
702
- import { getInstance, Service } from "@orion-js/services";
703
898
  var serviceMetadata = /* @__PURE__ */ new WeakMap();
704
899
  var echoesMetadata = /* @__PURE__ */ new WeakMap();
705
900
  var echoEntriesByClass = /* @__PURE__ */ new Map();
901
+ var standaloneInstances = /* @__PURE__ */ new WeakMap();
706
902
  var pendingEchoEntries = {};
707
903
  function Echoes() {
708
904
  return (target, context) => {
709
- Service()(target, context);
905
+ var _a, _b;
906
+ (_b = (_a = getEchoesRuntime()).decorateService) == null ? void 0 : _b.call(_a, target, context);
710
907
  serviceMetadata.set(target, { _serviceType: "echoes" });
711
908
  if (Object.keys(pendingEchoEntries).length > 0) {
712
909
  echoEntriesByClass.set(target, pendingEchoEntries);
@@ -723,7 +920,7 @@ function EchoEvent(options = {}) {
723
920
  return createEchoEvent({
724
921
  ...options,
725
922
  resolve: async (params, contextData) => {
726
- return await runWithOrionAsyncContext(
923
+ return await runWithEchoesContext(
727
924
  {
728
925
  controllerType: "echo",
729
926
  echoName: propertyKey,
@@ -752,7 +949,7 @@ function EchoRequest(options = {}) {
752
949
  return createEchoRequest({
753
950
  ...options,
754
951
  resolve: async (params, contextData) => {
755
- return await runWithOrionAsyncContext(
952
+ return await runWithEchoesContext(
756
953
  {
757
954
  controllerType: "echo",
758
955
  echoName: propertyKey,
@@ -782,7 +979,18 @@ function initializeEchoesIfNeeded(instance) {
782
979
  echoesMetadata.set(instance, echoes);
783
980
  }
784
981
  function getServiceEchoes(target) {
785
- const instance = getInstance(target);
982
+ let instance;
983
+ if (typeof target !== "function") {
984
+ instance = target;
985
+ } else if (getEchoesRuntime().getInstance) {
986
+ instance = getEchoesRuntime().getInstance(target);
987
+ } else {
988
+ instance = standaloneInstances.get(target);
989
+ if (!instance) {
990
+ instance = new target();
991
+ standaloneInstances.set(target, instance);
992
+ }
993
+ }
786
994
  if (!serviceMetadata.has(instance.constructor)) {
787
995
  throw new Error("You must pass a class decorated with @Echoes to getServiceEchoes");
788
996
  }
@@ -798,13 +1006,25 @@ export {
798
1006
  EchoEvent,
799
1007
  EchoRequest,
800
1008
  Echoes,
1009
+ EchoesUserError,
1010
+ EchoesValidationError,
1011
+ cleanEchoesSchema,
1012
+ configureEchoesRuntime,
801
1013
  createEchoEvent,
802
1014
  createEchoRequest,
1015
+ createEchoesUserError,
1016
+ createEchoesValidationError,
803
1017
  echo,
1018
+ getEchoesContext,
1019
+ getEchoesLogger,
1020
+ getEchoesRuntime,
804
1021
  getServiceEchoes,
1022
+ parseEchoesSchema,
805
1023
  publish,
806
1024
  request,
1025
+ runWithEchoesContext,
807
1026
  startService,
808
- stopService
1027
+ stopService,
1028
+ typedEchoesSchema
809
1029
  };
810
1030
  //# sourceMappingURL=index.js.map