@orion-js/echoes 4.4.1 → 4.5.1
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/echo/index.d.ts +4 -4
- package/dist/errors.d.ts +26 -0
- package/dist/events/PulseManager.d.ts +2 -2
- package/dist/index.cjs +540 -188
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +6 -3
- package/dist/index.js +515 -175
- package/dist/index.js.map +1 -1
- package/dist/request/getSignature.d.ts +1 -1
- package/dist/requestsHandler/index.d.ts +18 -1
- package/dist/runtime.d.ts +49 -0
- package/dist/schema.d.ts +42 -0
- package/dist/startService/KafkaManager.d.ts +2 -2
- package/dist/types.d.ts +48 -19
- package/package.json +8 -12
package/dist/index.cjs
CHANGED
|
@@ -32,28 +32,40 @@ __export(index_exports, {
|
|
|
32
32
|
EchoEvent: () => EchoEvent,
|
|
33
33
|
EchoRequest: () => EchoRequest,
|
|
34
34
|
Echoes: () => Echoes,
|
|
35
|
+
EchoesUserError: () => EchoesUserError,
|
|
36
|
+
EchoesValidationError: () => EchoesValidationError,
|
|
37
|
+
cleanEchoesSchema: () => cleanEchoesSchema,
|
|
38
|
+
configureEchoesRuntime: () => configureEchoesRuntime,
|
|
35
39
|
createEchoEvent: () => createEchoEvent,
|
|
36
40
|
createEchoRequest: () => createEchoRequest,
|
|
41
|
+
createEchoesUserError: () => createEchoesUserError,
|
|
42
|
+
createEchoesValidationError: () => createEchoesValidationError,
|
|
37
43
|
echo: () => echo,
|
|
44
|
+
getEchoesContext: () => getEchoesContext,
|
|
45
|
+
getEchoesLogger: () => getEchoesLogger,
|
|
46
|
+
getEchoesRuntime: () => getEchoesRuntime,
|
|
38
47
|
getServiceEchoes: () => getServiceEchoes,
|
|
48
|
+
parseEchoesSchema: () => parseEchoesSchema,
|
|
39
49
|
publish: () => publish,
|
|
40
50
|
request: () => request,
|
|
51
|
+
runWithEchoesContext: () => runWithEchoesContext,
|
|
41
52
|
startService: () => startService,
|
|
42
|
-
stopService: () => stopService
|
|
53
|
+
stopService: () => stopService,
|
|
54
|
+
typedEchoesSchema: () => typedEchoesSchema
|
|
43
55
|
});
|
|
44
56
|
module.exports = __toCommonJS(index_exports);
|
|
45
57
|
|
|
46
|
-
// src/startService/index.ts
|
|
47
|
-
var import_http2 = require("@orion-js/http");
|
|
48
|
-
|
|
49
58
|
// src/config.ts
|
|
50
59
|
var config = {};
|
|
51
60
|
var config_default = config;
|
|
52
61
|
|
|
53
|
-
// src/
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
62
|
+
// src/publish/index.ts
|
|
63
|
+
async function publish(options) {
|
|
64
|
+
if (!config_default.eventBus) {
|
|
65
|
+
throw new Error("You must initialize echoes configuration to use publish");
|
|
66
|
+
}
|
|
67
|
+
return await config_default.eventBus.publish(options);
|
|
68
|
+
}
|
|
57
69
|
|
|
58
70
|
// src/echo/deserialize.ts
|
|
59
71
|
function deserialize_default(serializedJavascript) {
|
|
@@ -66,14 +78,426 @@ function deserialize_default(serializedJavascript) {
|
|
|
66
78
|
|
|
67
79
|
// src/publish/serialize.ts
|
|
68
80
|
var import_serialize_javascript = __toESM(require("serialize-javascript"), 1);
|
|
69
|
-
|
|
81
|
+
function clonePropertyDescriptor(descriptor, references) {
|
|
82
|
+
const clonedDescriptor = { ...descriptor, configurable: true };
|
|
83
|
+
if ("value" in clonedDescriptor) {
|
|
84
|
+
clonedDescriptor.value = cloneForSerialization(clonedDescriptor.value, references);
|
|
85
|
+
}
|
|
86
|
+
return clonedDescriptor;
|
|
87
|
+
}
|
|
88
|
+
function copyOwnProperties(source, target, references, shouldCopy = () => true) {
|
|
89
|
+
for (const key of Reflect.ownKeys(source)) {
|
|
90
|
+
if (!shouldCopy(key)) continue;
|
|
91
|
+
const descriptor = Object.getOwnPropertyDescriptor(source, key);
|
|
92
|
+
if (!descriptor) continue;
|
|
93
|
+
Object.defineProperty(target, key, clonePropertyDescriptor(descriptor, references));
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
function preserveCustomToJSON(source, target, references) {
|
|
97
|
+
const toJSON = source.toJSON;
|
|
98
|
+
if (typeof toJSON !== "function") return;
|
|
99
|
+
Object.defineProperty(target, "toJSON", {
|
|
100
|
+
configurable: true,
|
|
101
|
+
enumerable: false,
|
|
102
|
+
writable: true,
|
|
103
|
+
value(key) {
|
|
104
|
+
return cloneForSerialization(toJSON.call(source, key), references);
|
|
105
|
+
}
|
|
106
|
+
});
|
|
107
|
+
}
|
|
108
|
+
function cloneArrayBufferView(value, references) {
|
|
109
|
+
const sourceBuffer = value.buffer;
|
|
110
|
+
let clonedBuffer = references.get(sourceBuffer);
|
|
111
|
+
const shouldCopyBufferProperties = !clonedBuffer;
|
|
112
|
+
if (!clonedBuffer) {
|
|
113
|
+
clonedBuffer = sourceBuffer.slice(0);
|
|
114
|
+
references.set(sourceBuffer, clonedBuffer);
|
|
115
|
+
}
|
|
116
|
+
const clone = value instanceof DataView ? new DataView(clonedBuffer, value.byteOffset, value.byteLength) : new value.constructor(clonedBuffer, value.byteOffset, value.length);
|
|
117
|
+
references.set(value, clone);
|
|
118
|
+
if (shouldCopyBufferProperties) {
|
|
119
|
+
copyOwnProperties(sourceBuffer, clonedBuffer, references);
|
|
120
|
+
}
|
|
121
|
+
copyOwnProperties(value, clone, references, (key) => {
|
|
122
|
+
if (typeof key !== "string") return true;
|
|
123
|
+
const index = Number(key);
|
|
124
|
+
return !(Number.isInteger(index) && index >= 0 && index < value.length && String(index) === key);
|
|
125
|
+
});
|
|
126
|
+
return clone;
|
|
127
|
+
}
|
|
128
|
+
function cloneForSerialization(value, references = /* @__PURE__ */ new WeakMap()) {
|
|
129
|
+
if (value === null || typeof value !== "object" && typeof value !== "function") return value;
|
|
130
|
+
if (typeof value === "function") return value;
|
|
131
|
+
const source = value;
|
|
132
|
+
if (references.has(source)) return references.get(source);
|
|
133
|
+
if (value instanceof Date) {
|
|
134
|
+
const clone2 = new Date(value.getTime());
|
|
135
|
+
Object.setPrototypeOf(clone2, Object.getPrototypeOf(value));
|
|
136
|
+
references.set(source, clone2);
|
|
137
|
+
return clone2;
|
|
138
|
+
}
|
|
139
|
+
if (value instanceof RegExp) {
|
|
140
|
+
const clone2 = new RegExp(value.source, value.flags);
|
|
141
|
+
clone2.lastIndex = value.lastIndex;
|
|
142
|
+
Object.setPrototypeOf(clone2, Object.getPrototypeOf(value));
|
|
143
|
+
references.set(source, clone2);
|
|
144
|
+
return clone2;
|
|
145
|
+
}
|
|
146
|
+
if (value instanceof Map) {
|
|
147
|
+
const clone2 = /* @__PURE__ */ new Map();
|
|
148
|
+
references.set(source, clone2);
|
|
149
|
+
for (const [key, entry] of value) {
|
|
150
|
+
Map.prototype.set.call(
|
|
151
|
+
clone2,
|
|
152
|
+
cloneForSerialization(key, references),
|
|
153
|
+
cloneForSerialization(entry, references)
|
|
154
|
+
);
|
|
155
|
+
}
|
|
156
|
+
Object.setPrototypeOf(clone2, Object.getPrototypeOf(value));
|
|
157
|
+
return clone2;
|
|
158
|
+
}
|
|
159
|
+
if (value instanceof Set) {
|
|
160
|
+
const clone2 = /* @__PURE__ */ new Set();
|
|
161
|
+
references.set(source, clone2);
|
|
162
|
+
for (const entry of value) {
|
|
163
|
+
Set.prototype.add.call(clone2, cloneForSerialization(entry, references));
|
|
164
|
+
}
|
|
165
|
+
Object.setPrototypeOf(clone2, Object.getPrototypeOf(value));
|
|
166
|
+
return clone2;
|
|
167
|
+
}
|
|
168
|
+
if (value instanceof URL) {
|
|
169
|
+
const clone2 = new URL(value.toString());
|
|
170
|
+
Object.setPrototypeOf(clone2, Object.getPrototypeOf(value));
|
|
171
|
+
references.set(source, clone2);
|
|
172
|
+
return clone2;
|
|
173
|
+
}
|
|
174
|
+
if (Buffer.isBuffer(value)) {
|
|
175
|
+
const clone2 = Buffer.from(value);
|
|
176
|
+
references.set(source, clone2);
|
|
177
|
+
return clone2;
|
|
178
|
+
}
|
|
179
|
+
if (ArrayBuffer.isView(value)) {
|
|
180
|
+
return cloneArrayBufferView(value, references);
|
|
181
|
+
}
|
|
182
|
+
if (value instanceof ArrayBuffer || typeof SharedArrayBuffer !== "undefined" && value instanceof SharedArrayBuffer) {
|
|
183
|
+
const clone2 = value.slice(0);
|
|
184
|
+
references.set(source, clone2);
|
|
185
|
+
copyOwnProperties(value, clone2, references);
|
|
186
|
+
return clone2;
|
|
187
|
+
}
|
|
188
|
+
if (Array.isArray(value)) {
|
|
189
|
+
const clone2 = new Array(value.length);
|
|
190
|
+
Object.setPrototypeOf(clone2, Object.getPrototypeOf(value));
|
|
191
|
+
references.set(source, clone2);
|
|
192
|
+
copyOwnProperties(value, clone2, references, (key) => key !== "length");
|
|
193
|
+
return clone2;
|
|
194
|
+
}
|
|
195
|
+
const clone = Object.create(Object.getPrototypeOf(value));
|
|
196
|
+
references.set(source, clone);
|
|
197
|
+
copyOwnProperties(value, clone, references);
|
|
198
|
+
preserveCustomToJSON(source, clone, references);
|
|
199
|
+
return clone;
|
|
200
|
+
}
|
|
70
201
|
function serialize_default(data) {
|
|
71
|
-
const
|
|
72
|
-
const serialized = (0, import_serialize_javascript.default)(cloned, { ignoreFunction: true });
|
|
202
|
+
const serialized = (0, import_serialize_javascript.default)(cloneForSerialization(data), { ignoreFunction: true });
|
|
73
203
|
return serialized;
|
|
74
204
|
}
|
|
75
205
|
|
|
206
|
+
// src/runtime.ts
|
|
207
|
+
var import_node_async_hooks = require("async_hooks");
|
|
208
|
+
var import_node_crypto = require("crypto");
|
|
209
|
+
|
|
210
|
+
// src/errors.ts
|
|
211
|
+
var EchoesUserError = class extends Error {
|
|
212
|
+
isEchoesError = true;
|
|
213
|
+
isOrionError = true;
|
|
214
|
+
isUserError = true;
|
|
215
|
+
code;
|
|
216
|
+
extra;
|
|
217
|
+
constructor(code, message, extra) {
|
|
218
|
+
if (!message) {
|
|
219
|
+
message = code;
|
|
220
|
+
code = "error";
|
|
221
|
+
}
|
|
222
|
+
super(message);
|
|
223
|
+
this.name = "EchoesUserError";
|
|
224
|
+
this.code = code;
|
|
225
|
+
this.extra = extra;
|
|
226
|
+
}
|
|
227
|
+
getInfo() {
|
|
228
|
+
return { error: this.code, message: this.message, extra: this.extra };
|
|
229
|
+
}
|
|
230
|
+
};
|
|
231
|
+
var EchoesValidationError = class extends Error {
|
|
232
|
+
isEchoesError = true;
|
|
233
|
+
isOrionError = true;
|
|
234
|
+
isValidationError = true;
|
|
235
|
+
code = "validationError";
|
|
236
|
+
validationErrors;
|
|
237
|
+
labels;
|
|
238
|
+
constructor(validationErrors, labels = {}) {
|
|
239
|
+
const printableErrors = Object.entries(validationErrors).map(([key, value]) => `${key}: ${value}`).join(", ");
|
|
240
|
+
super(`Validation Error: {${printableErrors}}`);
|
|
241
|
+
this.name = "EchoesValidationError";
|
|
242
|
+
this.validationErrors = validationErrors;
|
|
243
|
+
this.labels = Object.fromEntries(
|
|
244
|
+
Object.keys(validationErrors).filter((key) => labels[key]).map((key) => [key, labels[key]])
|
|
245
|
+
);
|
|
246
|
+
}
|
|
247
|
+
getInfo() {
|
|
248
|
+
return {
|
|
249
|
+
error: this.code,
|
|
250
|
+
message: "Validation Error",
|
|
251
|
+
validationErrors: this.validationErrors,
|
|
252
|
+
labels: this.labels
|
|
253
|
+
};
|
|
254
|
+
}
|
|
255
|
+
};
|
|
256
|
+
|
|
257
|
+
// src/runtime.ts
|
|
258
|
+
var defaultLogger = {
|
|
259
|
+
debug: (message, metadata) => metadata === void 0 ? console.debug(message) : console.debug(message, metadata),
|
|
260
|
+
info: (message, metadata) => metadata === void 0 ? console.info(message) : console.info(message, metadata),
|
|
261
|
+
warn: (message, metadata) => metadata === void 0 ? console.warn(message) : console.warn(message, metadata),
|
|
262
|
+
error: (message, metadata) => metadata === void 0 ? console.error(message) : console.error(message, metadata)
|
|
263
|
+
};
|
|
264
|
+
var runtime = {};
|
|
265
|
+
var contextStorage = new import_node_async_hooks.AsyncLocalStorage();
|
|
266
|
+
function configureEchoesRuntime(adapter) {
|
|
267
|
+
const previous = runtime;
|
|
268
|
+
runtime = { ...runtime, ...adapter };
|
|
269
|
+
return () => {
|
|
270
|
+
runtime = previous;
|
|
271
|
+
};
|
|
272
|
+
}
|
|
273
|
+
function getEchoesRuntime() {
|
|
274
|
+
return runtime;
|
|
275
|
+
}
|
|
276
|
+
function getEchoesLogger() {
|
|
277
|
+
return runtime.logger || defaultLogger;
|
|
278
|
+
}
|
|
279
|
+
function getEchoesContext() {
|
|
280
|
+
return contextStorage.getStore();
|
|
281
|
+
}
|
|
282
|
+
async function runWithEchoesContext(context, callback) {
|
|
283
|
+
const contextWithId = { contextId: context.contextId || (0, import_node_crypto.randomUUID)(), ...context };
|
|
284
|
+
return await contextStorage.run(contextWithId, async () => {
|
|
285
|
+
if (runtime.runWithContext) {
|
|
286
|
+
return await runtime.runWithContext(contextWithId, callback);
|
|
287
|
+
}
|
|
288
|
+
return await callback();
|
|
289
|
+
});
|
|
290
|
+
}
|
|
291
|
+
function isSimpleSchemaLike(schema) {
|
|
292
|
+
return !!schema && typeof schema === "object" && typeof schema.clean === "function" && typeof schema.validate === "function";
|
|
293
|
+
}
|
|
294
|
+
function cloneValue(value) {
|
|
295
|
+
if (value === null || typeof value !== "object") return value;
|
|
296
|
+
if (value instanceof Date) return new Date(value.getTime());
|
|
297
|
+
if (Buffer.isBuffer(value)) return Buffer.from(value);
|
|
298
|
+
if (Array.isArray(value)) return value.map(cloneValue);
|
|
299
|
+
const prototype = Object.getPrototypeOf(value);
|
|
300
|
+
if (prototype !== Object.prototype && prototype !== null) return value;
|
|
301
|
+
const result = {};
|
|
302
|
+
for (const [key, child] of Object.entries(value)) {
|
|
303
|
+
result[key] = cloneValue(child);
|
|
304
|
+
}
|
|
305
|
+
return result;
|
|
306
|
+
}
|
|
307
|
+
async function cleanSimpleSchema(schema, value) {
|
|
308
|
+
const cloned = cloneValue(value);
|
|
309
|
+
return await schema.clean(cloned, { mutate: false });
|
|
310
|
+
}
|
|
311
|
+
async function cleanEchoesSchema(schema, value) {
|
|
312
|
+
if (isSimpleSchemaLike(schema)) {
|
|
313
|
+
return await cleanSimpleSchema(schema, value);
|
|
314
|
+
}
|
|
315
|
+
if (runtime.schema) {
|
|
316
|
+
return await runtime.schema.clean(schema, value);
|
|
317
|
+
}
|
|
318
|
+
throw new Error(
|
|
319
|
+
"Echoes received a schema it cannot execute. Use a SimpleSchema-compatible object or configure an Echoes schema adapter."
|
|
320
|
+
);
|
|
321
|
+
}
|
|
322
|
+
async function parseEchoesSchema(schema, value) {
|
|
323
|
+
if (isSimpleSchemaLike(schema)) {
|
|
324
|
+
const cleaned = await cleanSimpleSchema(schema, value);
|
|
325
|
+
await schema.validate(cleaned);
|
|
326
|
+
return cleaned;
|
|
327
|
+
}
|
|
328
|
+
if (runtime.schema) {
|
|
329
|
+
return await runtime.schema.parse(schema, value);
|
|
330
|
+
}
|
|
331
|
+
throw new Error(
|
|
332
|
+
"Echoes received a schema it cannot execute. Use a SimpleSchema-compatible object or configure an Echoes schema adapter."
|
|
333
|
+
);
|
|
334
|
+
}
|
|
335
|
+
function createEchoesValidationError(info) {
|
|
336
|
+
return runtime.createValidationError ? runtime.createValidationError(info) : new EchoesValidationError(info.validationErrors || {}, info.labels);
|
|
337
|
+
}
|
|
338
|
+
function createEchoesUserError(info) {
|
|
339
|
+
return runtime.createUserError ? runtime.createUserError(info) : new EchoesUserError(info.error, info.message, info.extra);
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
// src/request/getSignature.ts
|
|
343
|
+
var import_node_crypto2 = require("crypto");
|
|
344
|
+
|
|
345
|
+
// src/request/getPassword.ts
|
|
346
|
+
function getEchoesPassword() {
|
|
347
|
+
var _a, _b;
|
|
348
|
+
const secret = ((_b = (_a = config_default) == null ? void 0 : _a.requests) == null ? void 0 : _b.key) || process.env.echoes_password || process.env.ECHOES_PASSWORD;
|
|
349
|
+
if (!secret) {
|
|
350
|
+
getEchoesLogger().warn(
|
|
351
|
+
'Warning: no secret key found for echoes requests. Init echoes or set the env var "echoes_password" or process.env.ECHOES_PASSWORD'
|
|
352
|
+
);
|
|
353
|
+
}
|
|
354
|
+
return secret;
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
// src/request/getSignature.ts
|
|
358
|
+
function getSignature_default(_body) {
|
|
359
|
+
const password = getEchoesPassword();
|
|
360
|
+
return (0, import_node_crypto2.createHmac)("sha1", password || "").update("").digest("hex");
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
// src/request/getURL.ts
|
|
364
|
+
function getURL_default(serviceName) {
|
|
365
|
+
var _a, _b, _c;
|
|
366
|
+
if (serviceName.startsWith("http")) return serviceName;
|
|
367
|
+
const url = (_c = (_b = (_a = config_default) == null ? void 0 : _a.requests) == null ? void 0 : _b.services) == null ? void 0 : _c[serviceName];
|
|
368
|
+
if (!url) {
|
|
369
|
+
throw new Error(`No URL found in echoes config for service ${serviceName}`);
|
|
370
|
+
}
|
|
371
|
+
return url;
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
// src/request/makeRequest.ts
|
|
375
|
+
var import_node_http = __toESM(require("http"), 1);
|
|
376
|
+
var import_node_https = __toESM(require("https"), 1);
|
|
377
|
+
async function executeWithRetries(callback, retries = 0, delayMs = 200) {
|
|
378
|
+
try {
|
|
379
|
+
return await callback();
|
|
380
|
+
} catch (error) {
|
|
381
|
+
if (retries <= 0) throw error;
|
|
382
|
+
await new Promise((resolve) => setTimeout(resolve, delayMs));
|
|
383
|
+
return await executeWithRetries(callback, retries - 1, delayMs);
|
|
384
|
+
}
|
|
385
|
+
}
|
|
386
|
+
async function postJSON(urlValue, data, timeout, redirectsRemaining = 5) {
|
|
387
|
+
const url = new URL(urlValue);
|
|
388
|
+
const body = JSON.stringify(data);
|
|
389
|
+
const transport = url.protocol === "https:" ? import_node_https.default : import_node_http.default;
|
|
390
|
+
return await new Promise((resolve, reject) => {
|
|
391
|
+
const request2 = transport.request(
|
|
392
|
+
url,
|
|
393
|
+
{
|
|
394
|
+
method: "POST",
|
|
395
|
+
headers: {
|
|
396
|
+
"User-Agent": "Orionjs-Echoes/1.1",
|
|
397
|
+
"Content-Type": "application/json",
|
|
398
|
+
"Content-Length": Buffer.byteLength(body)
|
|
399
|
+
}
|
|
400
|
+
},
|
|
401
|
+
(response) => {
|
|
402
|
+
const chunks = [];
|
|
403
|
+
const statusCode = response.statusCode || 0;
|
|
404
|
+
if (statusCode >= 300 && statusCode < 400 && response.headers.location) {
|
|
405
|
+
response.resume();
|
|
406
|
+
if (redirectsRemaining <= 0) {
|
|
407
|
+
reject(new Error("Echoes request exceeded the redirect limit"));
|
|
408
|
+
return;
|
|
409
|
+
}
|
|
410
|
+
resolve(
|
|
411
|
+
postJSON(
|
|
412
|
+
new URL(response.headers.location, url).toString(),
|
|
413
|
+
data,
|
|
414
|
+
timeout,
|
|
415
|
+
redirectsRemaining - 1
|
|
416
|
+
)
|
|
417
|
+
);
|
|
418
|
+
return;
|
|
419
|
+
}
|
|
420
|
+
response.on("data", (chunk) => chunks.push(Buffer.from(chunk)));
|
|
421
|
+
response.on("end", () => {
|
|
422
|
+
try {
|
|
423
|
+
const responseBody = Buffer.concat(chunks).toString("utf8");
|
|
424
|
+
if (statusCode < 200 || statusCode >= 300) {
|
|
425
|
+
reject(new Error(`Request failed with status code ${statusCode}`));
|
|
426
|
+
return;
|
|
427
|
+
}
|
|
428
|
+
resolve({
|
|
429
|
+
statusCode,
|
|
430
|
+
data: responseBody ? JSON.parse(responseBody) : {}
|
|
431
|
+
});
|
|
432
|
+
} catch (error) {
|
|
433
|
+
reject(error);
|
|
434
|
+
}
|
|
435
|
+
});
|
|
436
|
+
}
|
|
437
|
+
);
|
|
438
|
+
request2.on("error", reject);
|
|
439
|
+
if (timeout) {
|
|
440
|
+
request2.setTimeout(timeout, () => {
|
|
441
|
+
request2.destroy(new Error(`Echoes request timed out after ${timeout}ms`));
|
|
442
|
+
});
|
|
443
|
+
}
|
|
444
|
+
request2.end(body);
|
|
445
|
+
});
|
|
446
|
+
}
|
|
447
|
+
var makeRequest = async (options) => {
|
|
448
|
+
return await executeWithRetries(
|
|
449
|
+
() => postJSON(options.url, options.data, options.timeout),
|
|
450
|
+
options.retries || 0
|
|
451
|
+
);
|
|
452
|
+
};
|
|
453
|
+
|
|
454
|
+
// src/request/index.ts
|
|
455
|
+
async function request(options) {
|
|
456
|
+
var _a, _b;
|
|
457
|
+
const { method, service, params } = options;
|
|
458
|
+
const serializedParams = serialize_default(params);
|
|
459
|
+
const date = /* @__PURE__ */ new Date();
|
|
460
|
+
const body = { method, service, serializedParams, date };
|
|
461
|
+
const signature = getSignature_default(body);
|
|
462
|
+
try {
|
|
463
|
+
const requestMaker = ((_b = (_a = config_default) == null ? void 0 : _a.requests) == null ? void 0 : _b.makeRequest) || makeRequest;
|
|
464
|
+
const requestOptions = {
|
|
465
|
+
url: getURL_default(service),
|
|
466
|
+
retries: options.retries,
|
|
467
|
+
timeout: options.timeout,
|
|
468
|
+
data: {
|
|
469
|
+
body,
|
|
470
|
+
signature
|
|
471
|
+
}
|
|
472
|
+
};
|
|
473
|
+
const result = await requestMaker(requestOptions);
|
|
474
|
+
if (result.statusCode !== 200) {
|
|
475
|
+
throw new Error(`Wrong status code ${result.statusCode}`);
|
|
476
|
+
}
|
|
477
|
+
const data = result.data;
|
|
478
|
+
if (data.error) {
|
|
479
|
+
const info = data.errorInfo;
|
|
480
|
+
if (info) {
|
|
481
|
+
if (data.isValidationError) {
|
|
482
|
+
throw createEchoesValidationError(info);
|
|
483
|
+
}
|
|
484
|
+
if (data.isUserError) {
|
|
485
|
+
throw createEchoesUserError(info);
|
|
486
|
+
}
|
|
487
|
+
}
|
|
488
|
+
throw new Error(`${data.error}`);
|
|
489
|
+
}
|
|
490
|
+
const response = deserialize_default(data.result);
|
|
491
|
+
return response;
|
|
492
|
+
} catch (error) {
|
|
493
|
+
const caught = error;
|
|
494
|
+
if (caught.isOrionError || caught.isEchoesError) throw caught;
|
|
495
|
+
throw new Error(`Echoes request network error calling ${service}/${method}: ${caught.message}`);
|
|
496
|
+
}
|
|
497
|
+
}
|
|
498
|
+
|
|
76
499
|
// src/startService/KafkaManager.ts
|
|
500
|
+
var import_node_crypto3 = require("crypto");
|
|
77
501
|
var HEARTBEAT_INTERVAL_SECONDS = 5;
|
|
78
502
|
var CHECK_JOIN_CONSUMER_INTERVAL_SECONDS = 30;
|
|
79
503
|
var DEFAULT_PARTITIONS_CONSUMED_CONCURRENTLY = 4;
|
|
@@ -91,11 +515,21 @@ var KafkaManager = class {
|
|
|
91
515
|
producerConnected = false;
|
|
92
516
|
interval;
|
|
93
517
|
constructor(options) {
|
|
94
|
-
this.kafka = new import_kafkajs.Kafka(options.client);
|
|
95
518
|
this.options = options;
|
|
96
519
|
}
|
|
97
520
|
async start(options) {
|
|
98
521
|
var _a;
|
|
522
|
+
let kafkaModule;
|
|
523
|
+
try {
|
|
524
|
+
kafkaModule = await import("kafkajs");
|
|
525
|
+
} catch (error) {
|
|
526
|
+
const wrapped = new Error(
|
|
527
|
+
"Echoes Kafka transport requires kafkajs to be installed in the application"
|
|
528
|
+
);
|
|
529
|
+
wrapped.cause = error;
|
|
530
|
+
throw wrapped;
|
|
531
|
+
}
|
|
532
|
+
this.kafka = new kafkaModule.Kafka(this.options.client);
|
|
99
533
|
this.onEvent = options.onEvent;
|
|
100
534
|
this.subscriptions = new Map(
|
|
101
535
|
options.subscriptions.map((subscription) => [subscription.topic, subscription])
|
|
@@ -113,7 +547,7 @@ var KafkaManager = class {
|
|
|
113
547
|
this.consumer = this.kafka.consumer(this.options.consumer);
|
|
114
548
|
this.consumerStarted = await this.conditionalStart();
|
|
115
549
|
if (this.consumerStarted) return;
|
|
116
|
-
|
|
550
|
+
getEchoesLogger().info("Echoes: Delaying consumer group join, waiting for conditions to be met");
|
|
117
551
|
this.interval = setInterval(async () => {
|
|
118
552
|
this.consumerStarted = await this.conditionalStart();
|
|
119
553
|
if (this.consumerStarted) clearInterval(this.interval);
|
|
@@ -131,7 +565,7 @@ var KafkaManager = class {
|
|
|
131
565
|
{
|
|
132
566
|
value: serialize_default({ params: options.params }),
|
|
133
567
|
headers: {
|
|
134
|
-
"echoes-event-id": (0,
|
|
568
|
+
"echoes-event-id": (0, import_node_crypto3.randomUUID)()
|
|
135
569
|
}
|
|
136
570
|
}
|
|
137
571
|
]
|
|
@@ -139,7 +573,8 @@ var KafkaManager = class {
|
|
|
139
573
|
}
|
|
140
574
|
async close() {
|
|
141
575
|
var _a, _b;
|
|
142
|
-
|
|
576
|
+
const logger = getEchoesLogger();
|
|
577
|
+
logger.warn("Echoes: Stopping Kafka transport");
|
|
143
578
|
if (this.interval) clearInterval(this.interval);
|
|
144
579
|
await Promise.all([
|
|
145
580
|
(_a = this.consumer) == null ? void 0 : _a.disconnect(),
|
|
@@ -149,6 +584,7 @@ var KafkaManager = class {
|
|
|
149
584
|
this.producerConnected = false;
|
|
150
585
|
}
|
|
151
586
|
async checkJoinConsumerGroupConditions() {
|
|
587
|
+
const logger = getEchoesLogger();
|
|
152
588
|
const admin = this.kafka.admin();
|
|
153
589
|
try {
|
|
154
590
|
await admin.connect();
|
|
@@ -156,7 +592,7 @@ var KafkaManager = class {
|
|
|
156
592
|
const groupDescriptions = await admin.describeGroups([groupId]);
|
|
157
593
|
const group = groupDescriptions.groups[0];
|
|
158
594
|
if (group.state === "Empty") {
|
|
159
|
-
|
|
595
|
+
logger.info(`Echoes: Consumer group ${groupId} is empty, joining`);
|
|
160
596
|
return true;
|
|
161
597
|
}
|
|
162
598
|
const topicsMetadata = await admin.fetchTopicMetadata({ topics: this.topics });
|
|
@@ -164,24 +600,24 @@ var KafkaManager = class {
|
|
|
164
600
|
(acc, topic) => acc + topic.partitions.length,
|
|
165
601
|
0
|
|
166
602
|
);
|
|
167
|
-
|
|
603
|
+
logger.info(
|
|
168
604
|
`Echoes: Consumer group ${groupId} has ${group.members.length} members and ${totalPartitions} partitions`
|
|
169
605
|
);
|
|
170
606
|
const partitionsRatio = this.options.membersToPartitionsRatio || DEFAULT_MEMBERS_TO_PARTITIONS_RATIO;
|
|
171
607
|
const partitionsThreshold = Math.ceil(totalPartitions * partitionsRatio);
|
|
172
608
|
if (partitionsThreshold > group.members.length) {
|
|
173
|
-
|
|
609
|
+
logger.info(
|
|
174
610
|
`Echoes: Consumer group ${groupId} has room for more members ${group.members.length}/${partitionsThreshold}, joining`
|
|
175
611
|
);
|
|
176
612
|
return true;
|
|
177
613
|
}
|
|
178
614
|
return false;
|
|
179
615
|
} catch (error) {
|
|
180
|
-
|
|
616
|
+
logger.error("Echoes: Error checking consumer group conditions, join", { error });
|
|
181
617
|
return true;
|
|
182
618
|
} finally {
|
|
183
619
|
await admin.disconnect().catch((error) => {
|
|
184
|
-
|
|
620
|
+
logger.error("Echoes: Error disconnecting admin client", { error });
|
|
185
621
|
});
|
|
186
622
|
}
|
|
187
623
|
}
|
|
@@ -201,19 +637,20 @@ var KafkaManager = class {
|
|
|
201
637
|
return false;
|
|
202
638
|
}
|
|
203
639
|
async handleMessage(params) {
|
|
640
|
+
const logger = getEchoesLogger();
|
|
204
641
|
const subscription = this.subscriptions.get(params.topic);
|
|
205
642
|
if (!subscription) {
|
|
206
|
-
|
|
643
|
+
logger.warn(`Echoes: Received a message for an unknown topic: ${params.topic}, ignoring it`);
|
|
207
644
|
return;
|
|
208
645
|
}
|
|
209
646
|
let intervalsCount = 0;
|
|
210
647
|
const heartbeatInterval = setInterval(async () => {
|
|
211
648
|
await params.heartbeat().catch((error) => {
|
|
212
|
-
|
|
649
|
+
logger.warn(`Echoes: Error sending heartbeat: ${error.message}`);
|
|
213
650
|
});
|
|
214
651
|
intervalsCount++;
|
|
215
652
|
if (intervalsCount * HEARTBEAT_INTERVAL_SECONDS % 30 === 0) {
|
|
216
|
-
|
|
653
|
+
logger.warn(
|
|
217
654
|
`Echoes: Event is taking too long to process: ${params.topic} ${intervalsCount * HEARTBEAT_INTERVAL_SECONDS}s`
|
|
218
655
|
);
|
|
219
656
|
}
|
|
@@ -225,7 +662,7 @@ var KafkaManager = class {
|
|
|
225
662
|
try {
|
|
226
663
|
await this.handleRetries(subscription, params, error);
|
|
227
664
|
} catch (retryError) {
|
|
228
|
-
|
|
665
|
+
logger.error("Echoes: error processing a message", {
|
|
229
666
|
error: retryError,
|
|
230
667
|
topic: params.topic
|
|
231
668
|
});
|
|
@@ -238,6 +675,9 @@ var KafkaManager = class {
|
|
|
238
675
|
createReceivedEvent(params) {
|
|
239
676
|
var _a, _b, _c, _d;
|
|
240
677
|
const { message, topic, partition } = params;
|
|
678
|
+
if (!message.value) {
|
|
679
|
+
throw new Error(`Echoes received an empty Kafka message for ${topic}`);
|
|
680
|
+
}
|
|
241
681
|
const data = deserialize_default(message.value.toString());
|
|
242
682
|
const retries = Number.parseInt(((_b = (_a = message.headers) == null ? void 0 : _a.retries) == null ? void 0 : _b.toString()) || "0", 10);
|
|
243
683
|
const timestamp = Number.parseInt(message.timestamp || "", 10);
|
|
@@ -254,6 +694,7 @@ var KafkaManager = class {
|
|
|
254
694
|
}
|
|
255
695
|
async handleRetries(subscription, params, error) {
|
|
256
696
|
var _a, _b;
|
|
697
|
+
const logger = getEchoesLogger();
|
|
257
698
|
const { message, topic } = params;
|
|
258
699
|
const retries = Number.parseInt(((_b = (_a = message == null ? void 0 : message.headers) == null ? void 0 : _a.retries) == null ? void 0 : _b.toString()) || "0", 10);
|
|
259
700
|
if (subscription.attemptsBeforeDeadLetter === void 0 || subscription.attemptsBeforeDeadLetter === null) {
|
|
@@ -262,6 +703,7 @@ var KafkaManager = class {
|
|
|
262
703
|
const maxRetries = subscription.attemptsBeforeDeadLetter || 0;
|
|
263
704
|
const exceededMaxRetries = retries >= maxRetries;
|
|
264
705
|
const nextTopic = exceededMaxRetries ? `DLQ-${topic}` : topic;
|
|
706
|
+
if (!message.value) throw error;
|
|
265
707
|
await this.producer.send({
|
|
266
708
|
topic: nextTopic,
|
|
267
709
|
messages: [
|
|
@@ -276,19 +718,18 @@ var KafkaManager = class {
|
|
|
276
718
|
]
|
|
277
719
|
});
|
|
278
720
|
if (exceededMaxRetries) {
|
|
279
|
-
|
|
721
|
+
logger.error(
|
|
280
722
|
"Echoes: a message has reached the maximum number of retries, sending it to DLQ",
|
|
281
723
|
{ topic: nextTopic }
|
|
282
724
|
);
|
|
283
725
|
} else {
|
|
284
|
-
|
|
726
|
+
logger.warn("Echoes: a retryable message failed", { error, topic: nextTopic });
|
|
285
727
|
}
|
|
286
728
|
}
|
|
287
729
|
};
|
|
288
730
|
var KafkaManager_default = KafkaManager;
|
|
289
731
|
|
|
290
732
|
// src/events/EventBus.ts
|
|
291
|
-
var import_logger2 = require("@orion-js/logger");
|
|
292
733
|
var EventBus = class {
|
|
293
734
|
echoes;
|
|
294
735
|
transports;
|
|
@@ -348,9 +789,10 @@ var EventBus = class {
|
|
|
348
789
|
await Promise.all(this.startedTransports.map((transport) => transport.close()));
|
|
349
790
|
}
|
|
350
791
|
async handleEvent(event) {
|
|
792
|
+
const logger = getEchoesLogger();
|
|
351
793
|
const echo2 = this.echoes[event.topic];
|
|
352
794
|
if (!echo2 || echo2.type !== "event") {
|
|
353
|
-
|
|
795
|
+
logger.warn(`Echoes: Received a message for an unknown topic: ${event.topic}, ignoring it`);
|
|
354
796
|
return;
|
|
355
797
|
}
|
|
356
798
|
if (event.transport === "kafka" && event.context) {
|
|
@@ -478,6 +920,14 @@ function createEventBus(options) {
|
|
|
478
920
|
});
|
|
479
921
|
}
|
|
480
922
|
|
|
923
|
+
// src/requestsHandler/checkSignature.ts
|
|
924
|
+
function checkSignature_default(body, signature) {
|
|
925
|
+
const generatedSignature = getSignature_default(body);
|
|
926
|
+
if (generatedSignature !== signature) {
|
|
927
|
+
throw new Error("Echoes invalid signature");
|
|
928
|
+
}
|
|
929
|
+
}
|
|
930
|
+
|
|
481
931
|
// src/requestsHandler/getEcho.ts
|
|
482
932
|
function getEcho_default(method) {
|
|
483
933
|
const echo2 = config_default.echoes[method];
|
|
@@ -490,72 +940,29 @@ function getEcho_default(method) {
|
|
|
490
940
|
return echo2;
|
|
491
941
|
}
|
|
492
942
|
|
|
493
|
-
// src/request/getSignature.ts
|
|
494
|
-
var import_jssha = __toESM(require("jssha"), 1);
|
|
495
|
-
|
|
496
|
-
// src/request/getPassword.ts
|
|
497
|
-
var import_logger3 = require("@orion-js/logger");
|
|
498
|
-
var import_env = require("@orion-js/env");
|
|
499
|
-
function getEchoesPassword() {
|
|
500
|
-
var _a, _b;
|
|
501
|
-
const secret = ((_b = (_a = config_default) == null ? void 0 : _a.requests) == null ? void 0 : _b.key) || (0, import_env.internalGetEnv)("echoes_password", "ECHOES_PASSWORD");
|
|
502
|
-
if (!secret) {
|
|
503
|
-
import_logger3.logger.warn(
|
|
504
|
-
'Warning: no secret key found for echoes requests. Init echoes or set the env var "echoes_password" or process.env.ECHOES_PASSWORD'
|
|
505
|
-
);
|
|
506
|
-
}
|
|
507
|
-
return secret;
|
|
508
|
-
}
|
|
509
|
-
|
|
510
|
-
// src/request/getSignature.ts
|
|
511
|
-
function getSignature_default(body) {
|
|
512
|
-
const password = getEchoesPassword();
|
|
513
|
-
const shaObj = new import_jssha.default("SHA-1", "TEXT");
|
|
514
|
-
shaObj.setHMACKey(password, "TEXT");
|
|
515
|
-
shaObj.update(body);
|
|
516
|
-
return shaObj.getHMAC("HEX");
|
|
517
|
-
}
|
|
518
|
-
|
|
519
|
-
// src/requestsHandler/checkSignature.ts
|
|
520
|
-
function checkSignature_default(body, signature) {
|
|
521
|
-
const generatedSignature = getSignature_default(body);
|
|
522
|
-
if (generatedSignature !== signature) {
|
|
523
|
-
throw new Error("Echoes invalid signature");
|
|
524
|
-
}
|
|
525
|
-
}
|
|
526
|
-
|
|
527
943
|
// src/requestsHandler/index.ts
|
|
528
|
-
var
|
|
529
|
-
var requestsHandler_default = (options) => (0, import_http.route)({
|
|
944
|
+
var requestsHandler_default = (options) => ({
|
|
530
945
|
method: "post",
|
|
531
946
|
path: options.requests.handlerPath || "/echoes-services",
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
limit: "10mb"
|
|
535
|
-
},
|
|
536
|
-
async resolve(req) {
|
|
947
|
+
bodyLimit: "10mb",
|
|
948
|
+
async handle(requestBody) {
|
|
537
949
|
try {
|
|
538
|
-
const { body, signature } =
|
|
950
|
+
const { body, signature } = requestBody;
|
|
539
951
|
checkSignature_default(body, signature);
|
|
540
952
|
const { method, serializedParams } = body;
|
|
541
953
|
const echo2 = getEcho_default(method);
|
|
542
954
|
const result = await echo2.onRequest(serializedParams);
|
|
543
|
-
return {
|
|
544
|
-
body: {
|
|
545
|
-
result: serialize_default(result)
|
|
546
|
-
}
|
|
547
|
-
};
|
|
955
|
+
return { result: serialize_default(result) };
|
|
548
956
|
} catch (error) {
|
|
549
|
-
|
|
550
|
-
|
|
957
|
+
const caught = error;
|
|
958
|
+
if (!caught.getInfo) {
|
|
959
|
+
getEchoesLogger().error("Error at echo requests handler:", { error: caught });
|
|
551
960
|
}
|
|
552
961
|
return {
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
isUserError: !!error.isUserError
|
|
558
|
-
}
|
|
962
|
+
error: caught.message,
|
|
963
|
+
errorInfo: caught.getInfo ? caught.getInfo() : null,
|
|
964
|
+
isValidationError: !!caught.isValidationError,
|
|
965
|
+
isUserError: !!caught.isUserError
|
|
559
966
|
};
|
|
560
967
|
}
|
|
561
968
|
}
|
|
@@ -567,7 +974,13 @@ async function startService(options) {
|
|
|
567
974
|
config_default.echoes = options.echoes;
|
|
568
975
|
if (options.requests) {
|
|
569
976
|
config_default.requests = options.requests;
|
|
570
|
-
|
|
977
|
+
const registerHandler = options.requests.registerHandler || getEchoesRuntime().registerRequestHandler;
|
|
978
|
+
if (!registerHandler) {
|
|
979
|
+
throw new Error(
|
|
980
|
+
"Echoes requests require requests.registerHandler in standalone servers. Orion applications can import @orion-js/echoes-orion once during startup."
|
|
981
|
+
);
|
|
982
|
+
}
|
|
983
|
+
await registerHandler(requestsHandler_default(options));
|
|
571
984
|
}
|
|
572
985
|
const nextEventBus = createEventBus(options);
|
|
573
986
|
if (nextEventBus) {
|
|
@@ -578,115 +991,22 @@ async function startService(options) {
|
|
|
578
991
|
}
|
|
579
992
|
async function stopService() {
|
|
580
993
|
if (eventBus) {
|
|
581
|
-
|
|
994
|
+
const logger = getEchoesLogger();
|
|
995
|
+
logger.info("Stopping Echoes...");
|
|
582
996
|
await eventBus.close();
|
|
583
997
|
eventBus = null;
|
|
584
998
|
config_default.eventBus = void 0;
|
|
585
|
-
|
|
586
|
-
}
|
|
587
|
-
}
|
|
588
|
-
|
|
589
|
-
// src/publish/index.ts
|
|
590
|
-
async function publish(options) {
|
|
591
|
-
if (!config_default.eventBus) {
|
|
592
|
-
throw new Error("You must initialize echoes configuration to use publish");
|
|
593
|
-
}
|
|
594
|
-
return await config_default.eventBus.publish(options);
|
|
595
|
-
}
|
|
596
|
-
|
|
597
|
-
// src/request/getURL.ts
|
|
598
|
-
function getURL_default(serviceName) {
|
|
599
|
-
var _a, _b;
|
|
600
|
-
if (serviceName.startsWith("http")) return serviceName;
|
|
601
|
-
const url = (_b = (_a = config_default) == null ? void 0 : _a.requests) == null ? void 0 : _b.services[serviceName];
|
|
602
|
-
if (!url) {
|
|
603
|
-
throw new Error(`No URL found in echoes config for service ${serviceName}`);
|
|
604
|
-
}
|
|
605
|
-
return url;
|
|
606
|
-
}
|
|
607
|
-
|
|
608
|
-
// src/request/makeRequest.ts
|
|
609
|
-
var import_axios = __toESM(require("axios"), 1);
|
|
610
|
-
var import_helpers2 = require("@orion-js/helpers");
|
|
611
|
-
var makeRequest = async (options) => {
|
|
612
|
-
const result = await (0, import_helpers2.executeWithRetries)(
|
|
613
|
-
async () => {
|
|
614
|
-
return await (0, import_axios.default)({
|
|
615
|
-
method: "post",
|
|
616
|
-
url: options.url,
|
|
617
|
-
timeout: options.timeout,
|
|
618
|
-
headers: {
|
|
619
|
-
"User-Agent": "Orionjs-Echoes/1.1"
|
|
620
|
-
},
|
|
621
|
-
data: options.data
|
|
622
|
-
});
|
|
623
|
-
},
|
|
624
|
-
options.retries,
|
|
625
|
-
200
|
|
626
|
-
);
|
|
627
|
-
return {
|
|
628
|
-
data: result.data,
|
|
629
|
-
statusCode: result.status
|
|
630
|
-
};
|
|
631
|
-
};
|
|
632
|
-
|
|
633
|
-
// src/request/index.ts
|
|
634
|
-
var import_schema = require("@orion-js/schema");
|
|
635
|
-
var import_helpers3 = require("@orion-js/helpers");
|
|
636
|
-
async function request(options) {
|
|
637
|
-
var _a, _b;
|
|
638
|
-
const { method, service, params } = options;
|
|
639
|
-
const serializedParams = serialize_default(params);
|
|
640
|
-
const date = /* @__PURE__ */ new Date();
|
|
641
|
-
const body = { method, service, serializedParams, date };
|
|
642
|
-
const signature = getSignature_default(body);
|
|
643
|
-
try {
|
|
644
|
-
const requestMaker = ((_b = (_a = config_default) == null ? void 0 : _a.requests) == null ? void 0 : _b.makeRequest) || makeRequest;
|
|
645
|
-
const requestOptions = {
|
|
646
|
-
url: getURL_default(service),
|
|
647
|
-
retries: options.retries,
|
|
648
|
-
timeout: options.timeout,
|
|
649
|
-
data: {
|
|
650
|
-
body,
|
|
651
|
-
signature
|
|
652
|
-
}
|
|
653
|
-
};
|
|
654
|
-
const result = await requestMaker(requestOptions);
|
|
655
|
-
if (result.statusCode !== 200) {
|
|
656
|
-
throw new Error(`Wrong status code ${result.statusCode}`);
|
|
657
|
-
}
|
|
658
|
-
const data = result.data;
|
|
659
|
-
if (data.error) {
|
|
660
|
-
const info = data.errorInfo;
|
|
661
|
-
if (info) {
|
|
662
|
-
if (data.isValidationError) {
|
|
663
|
-
throw new import_schema.ValidationError(info.validationErrors);
|
|
664
|
-
}
|
|
665
|
-
if (data.isUserError) {
|
|
666
|
-
throw new import_helpers3.UserError(info.error, info.message, info.extra);
|
|
667
|
-
}
|
|
668
|
-
}
|
|
669
|
-
throw new Error(`${data.error}`);
|
|
670
|
-
}
|
|
671
|
-
const response = deserialize_default(data.result);
|
|
672
|
-
return response;
|
|
673
|
-
} catch (error) {
|
|
674
|
-
if (error.isOrionError) throw error;
|
|
675
|
-
throw new Error(`Echoes request network error calling ${service}/${method}: ${error.message}`);
|
|
999
|
+
logger.info("Echoes stopped");
|
|
676
1000
|
}
|
|
677
1001
|
}
|
|
678
1002
|
|
|
679
|
-
// src/service/index.ts
|
|
680
|
-
var import_logger4 = require("@orion-js/logger");
|
|
681
|
-
|
|
682
1003
|
// src/echo/index.ts
|
|
683
|
-
var import_schema2 = require("@orion-js/schema");
|
|
684
1004
|
var echo = function createNewEcho(options) {
|
|
685
1005
|
const resolve = async (params, context) => {
|
|
686
|
-
const cleaned = options.params ? await (
|
|
1006
|
+
const cleaned = options.params ? await parseEchoesSchema(options.params, params) : params ?? {};
|
|
687
1007
|
const result = await options.resolve(cleaned, context);
|
|
688
1008
|
if (options.returns) {
|
|
689
|
-
return await (
|
|
1009
|
+
return await cleanEchoesSchema(options.returns, result);
|
|
690
1010
|
}
|
|
691
1011
|
return result;
|
|
692
1012
|
};
|
|
@@ -713,6 +1033,9 @@ var echo = function createNewEcho(options) {
|
|
|
713
1033
|
onMessage: async (messageData) => {
|
|
714
1034
|
var _a, _b, _c, _d;
|
|
715
1035
|
const { message } = messageData;
|
|
1036
|
+
if (!message.value) {
|
|
1037
|
+
throw new Error(`Echoes received an empty Kafka message for ${messageData.topic}`);
|
|
1038
|
+
}
|
|
716
1039
|
const data = deserialize_default(message.value.toString());
|
|
717
1040
|
const retries = Number.parseInt(((_b = (_a = message.headers) == null ? void 0 : _a.retries) == null ? void 0 : _b.toString()) || "0", 10);
|
|
718
1041
|
const timestamp = Number(message.timestamp);
|
|
@@ -743,15 +1066,21 @@ function createEchoEvent(options) {
|
|
|
743
1066
|
return echo({ ...options, type: "event" });
|
|
744
1067
|
}
|
|
745
1068
|
|
|
1069
|
+
// src/schema.ts
|
|
1070
|
+
function typedEchoesSchema(schema) {
|
|
1071
|
+
return schema;
|
|
1072
|
+
}
|
|
1073
|
+
|
|
746
1074
|
// src/service/index.ts
|
|
747
|
-
var import_services = require("@orion-js/services");
|
|
748
1075
|
var serviceMetadata = /* @__PURE__ */ new WeakMap();
|
|
749
1076
|
var echoesMetadata = /* @__PURE__ */ new WeakMap();
|
|
750
1077
|
var echoEntriesByClass = /* @__PURE__ */ new Map();
|
|
1078
|
+
var standaloneInstances = /* @__PURE__ */ new WeakMap();
|
|
751
1079
|
var pendingEchoEntries = {};
|
|
752
1080
|
function Echoes() {
|
|
753
1081
|
return (target, context) => {
|
|
754
|
-
|
|
1082
|
+
var _a, _b;
|
|
1083
|
+
(_b = (_a = getEchoesRuntime()).decorateService) == null ? void 0 : _b.call(_a, target, context);
|
|
755
1084
|
serviceMetadata.set(target, { _serviceType: "echoes" });
|
|
756
1085
|
if (Object.keys(pendingEchoEntries).length > 0) {
|
|
757
1086
|
echoEntriesByClass.set(target, pendingEchoEntries);
|
|
@@ -768,7 +1097,7 @@ function EchoEvent(options = {}) {
|
|
|
768
1097
|
return createEchoEvent({
|
|
769
1098
|
...options,
|
|
770
1099
|
resolve: async (params, contextData) => {
|
|
771
|
-
return await (
|
|
1100
|
+
return await runWithEchoesContext(
|
|
772
1101
|
{
|
|
773
1102
|
controllerType: "echo",
|
|
774
1103
|
echoName: propertyKey,
|
|
@@ -797,7 +1126,7 @@ function EchoRequest(options = {}) {
|
|
|
797
1126
|
return createEchoRequest({
|
|
798
1127
|
...options,
|
|
799
1128
|
resolve: async (params, contextData) => {
|
|
800
|
-
return await (
|
|
1129
|
+
return await runWithEchoesContext(
|
|
801
1130
|
{
|
|
802
1131
|
controllerType: "echo",
|
|
803
1132
|
echoName: propertyKey,
|
|
@@ -827,7 +1156,18 @@ function initializeEchoesIfNeeded(instance) {
|
|
|
827
1156
|
echoesMetadata.set(instance, echoes);
|
|
828
1157
|
}
|
|
829
1158
|
function getServiceEchoes(target) {
|
|
830
|
-
|
|
1159
|
+
let instance;
|
|
1160
|
+
if (typeof target !== "function") {
|
|
1161
|
+
instance = target;
|
|
1162
|
+
} else if (getEchoesRuntime().getInstance) {
|
|
1163
|
+
instance = getEchoesRuntime().getInstance(target);
|
|
1164
|
+
} else {
|
|
1165
|
+
instance = standaloneInstances.get(target);
|
|
1166
|
+
if (!instance) {
|
|
1167
|
+
instance = new target();
|
|
1168
|
+
standaloneInstances.set(target, instance);
|
|
1169
|
+
}
|
|
1170
|
+
}
|
|
831
1171
|
if (!serviceMetadata.has(instance.constructor)) {
|
|
832
1172
|
throw new Error("You must pass a class decorated with @Echoes to getServiceEchoes");
|
|
833
1173
|
}
|
|
@@ -844,13 +1184,25 @@ function getServiceEchoes(target) {
|
|
|
844
1184
|
EchoEvent,
|
|
845
1185
|
EchoRequest,
|
|
846
1186
|
Echoes,
|
|
1187
|
+
EchoesUserError,
|
|
1188
|
+
EchoesValidationError,
|
|
1189
|
+
cleanEchoesSchema,
|
|
1190
|
+
configureEchoesRuntime,
|
|
847
1191
|
createEchoEvent,
|
|
848
1192
|
createEchoRequest,
|
|
1193
|
+
createEchoesUserError,
|
|
1194
|
+
createEchoesValidationError,
|
|
849
1195
|
echo,
|
|
1196
|
+
getEchoesContext,
|
|
1197
|
+
getEchoesLogger,
|
|
1198
|
+
getEchoesRuntime,
|
|
850
1199
|
getServiceEchoes,
|
|
1200
|
+
parseEchoesSchema,
|
|
851
1201
|
publish,
|
|
852
1202
|
request,
|
|
1203
|
+
runWithEchoesContext,
|
|
853
1204
|
startService,
|
|
854
|
-
stopService
|
|
1205
|
+
stopService,
|
|
1206
|
+
typedEchoesSchema
|
|
855
1207
|
});
|
|
856
1208
|
//# sourceMappingURL=index.cjs.map
|