@omen.foundation/node-microservice-runtime 0.1.76 → 0.1.77

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.
@@ -0,0 +1,545 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.createLogger = createLogger;
37
+ const pino_1 = __importStar(require("pino"));
38
+ const node_stream_1 = require("node:stream");
39
+ const node_module_1 = require("node:module");
40
+ const env_js_1 = require("./env.js");
41
+ const api_logs_1 = require("@opentelemetry/api-logs");
42
+ const sdk_logs_1 = require("@opentelemetry/sdk-logs");
43
+ const exporter_logs_otlp_http_1 = require("@opentelemetry/exporter-logs-otlp-http");
44
+ const resources_1 = require("@opentelemetry/resources");
45
+ const collector_manager_js_1 = require("./collector-manager.js");
46
+ function getRequire() {
47
+ if (typeof require !== 'undefined' && typeof require.main !== 'undefined') {
48
+ return require;
49
+ }
50
+ return (0, node_module_1.createRequire)(import.meta.url);
51
+ }
52
+ function shouldUsePrettyLogs() {
53
+ return process.env.IS_LOCAL === '1' || process.env.IS_LOCAL === 'true';
54
+ }
55
+ function mapPinoLevelToBeamableLevel(level) {
56
+ switch (level) {
57
+ case 10:
58
+ return 'Debug';
59
+ case 20:
60
+ return 'Debug';
61
+ case 30:
62
+ return 'Info';
63
+ case 40:
64
+ return 'Warning';
65
+ case 50:
66
+ return 'Error';
67
+ case 60:
68
+ return 'Fatal';
69
+ default:
70
+ return 'Info';
71
+ }
72
+ }
73
+ async function initializeBetterStackLogging(serviceName, qualifiedServiceName, env) {
74
+ const betterStackEnabled = process.env.BEAM_BETTERSTACK_ENABLED === 'true' ||
75
+ process.env.BEAM_BETTERSTACK_ENABLED === '1';
76
+ if (!betterStackEnabled) {
77
+ return Promise.resolve(null);
78
+ }
79
+ const betterStackToken = process.env.BEAM_BETTERSTACK_TOKEN || process.env.BETTERSTACK_TOKEN;
80
+ const betterStackEndpoint = process.env.BEAM_BETTERSTACK_ENDPOINT ||
81
+ process.env.BETTERSTACK_ENDPOINT ||
82
+ 'https://in.logs.betterstack.com';
83
+ if (!betterStackToken) {
84
+ console.warn('[BetterStack] BetterStack logging is enabled but BEAM_BETTERSTACK_TOKEN is not set. Skipping BetterStack logging.');
85
+ return Promise.resolve(null);
86
+ }
87
+ try {
88
+ const resourceAttributes = {};
89
+ if (serviceName) {
90
+ resourceAttributes['service.namespace'] = serviceName;
91
+ resourceAttributes['service.name'] = serviceName;
92
+ }
93
+ if (qualifiedServiceName) {
94
+ resourceAttributes['service.instance.id'] = qualifiedServiceName;
95
+ }
96
+ if (env === null || env === void 0 ? void 0 : env.cid) {
97
+ resourceAttributes['beam.cid'] = String(env.cid);
98
+ }
99
+ if (env === null || env === void 0 ? void 0 : env.pid) {
100
+ resourceAttributes['beam.pid'] = String(env.pid);
101
+ }
102
+ if (env === null || env === void 0 ? void 0 : env.routingKey) {
103
+ resourceAttributes['beam.routing_key'] = String(env.routingKey);
104
+ }
105
+ const endpointUrl = betterStackEndpoint.includes('/v1/logs')
106
+ ? betterStackEndpoint
107
+ : `${betterStackEndpoint.replace(/\/$/, '')}/v1/logs`;
108
+ const exporterOptions = {
109
+ url: endpointUrl,
110
+ headers: {
111
+ 'Authorization': `Bearer ${betterStackToken}`,
112
+ },
113
+ contentType: 'application/json',
114
+ };
115
+ const exporter = new exporter_logs_otlp_http_1.OTLPLogExporter(exporterOptions);
116
+ console.error(`[BetterStack] BetterStack logging initialized. Endpoint: ${endpointUrl}, Service: ${serviceName || 'unknown'}`);
117
+ return Promise.resolve(exporter);
118
+ }
119
+ catch (error) {
120
+ console.error('[BetterStack] Failed to initialize BetterStack logging:', error instanceof Error ? error.message : String(error));
121
+ if (error instanceof Error && error.stack) {
122
+ console.error('[BetterStack] Stack trace:', error.stack);
123
+ }
124
+ return Promise.resolve(null);
125
+ }
126
+ }
127
+ async function initializeOtlpLogging(serviceName, qualifiedServiceName, env, logger) {
128
+ const otlpEndpoint = process.env.BEAM_OTEL_EXPORTER_OTLP_ENDPOINT
129
+ || process.env.OTEL_EXPORTER_OTLP_ENDPOINT
130
+ || (process.env.OTEL_EXPORTER_OTLP_ENDPOINT_LOGS ? process.env.OTEL_EXPORTER_OTLP_ENDPOINT_LOGS : null);
131
+ const otlpProtocol = process.env.BEAM_OTEL_EXPORTER_OTLP_PROTOCOL
132
+ || process.env.OTEL_EXPORTER_OTLP_PROTOCOL
133
+ || process.env.OTEL_EXPORTER_OTLP_PROTOCOL_LOGS;
134
+ const isInDocker = process.env.IS_LOCAL !== '1' && process.env.IS_LOCAL !== 'true';
135
+ const useLocalOtel = !!process.env.BEAM_LOCAL_OTEL;
136
+ const standardOtelEnabled = (isInDocker || useLocalOtel) && !process.env.BEAM_DISABLE_STANDARD_OTEL;
137
+ if (!otlpEndpoint && !standardOtelEnabled) {
138
+ return Promise.resolve(null);
139
+ }
140
+ try {
141
+ const resourceAttributes = {};
142
+ if (serviceName) {
143
+ resourceAttributes['service.namespace'] = serviceName;
144
+ resourceAttributes['service.name'] = serviceName;
145
+ }
146
+ if (qualifiedServiceName) {
147
+ resourceAttributes['service.instance.id'] = qualifiedServiceName;
148
+ }
149
+ if (env === null || env === void 0 ? void 0 : env.cid) {
150
+ resourceAttributes['beam.cid'] = String(env.cid);
151
+ }
152
+ if (env === null || env === void 0 ? void 0 : env.pid) {
153
+ resourceAttributes['beam.pid'] = String(env.pid);
154
+ }
155
+ if (env === null || env === void 0 ? void 0 : env.routingKey) {
156
+ resourceAttributes['beam.routing_key'] = String(env.routingKey);
157
+ }
158
+ let endpointUrl = otlpEndpoint;
159
+ if (!endpointUrl && standardOtelEnabled && logger) {
160
+ try {
161
+ const discoveredEndpoint = await (0, collector_manager_js_1.discoverOrStartCollector)(logger, standardOtelEnabled, env);
162
+ if (discoveredEndpoint) {
163
+ endpointUrl = discoveredEndpoint;
164
+ }
165
+ else {
166
+ console.error('[OTLP] Standard OTLP is enabled but could not discover or start collector.');
167
+ return Promise.resolve(null);
168
+ }
169
+ }
170
+ catch (error) {
171
+ console.error('[OTLP] Failed to discover/start collector:', error instanceof Error ? error.message : String(error));
172
+ return Promise.resolve(null);
173
+ }
174
+ }
175
+ if (!endpointUrl) {
176
+ if (standardOtelEnabled) {
177
+ console.error('[OTLP] Standard OTLP is enabled but no endpoint available. Set BEAM_OTEL_EXPORTER_OTLP_ENDPOINT to enable OTLP logging.');
178
+ }
179
+ return Promise.resolve(null);
180
+ }
181
+ let finalEndpointUrl = endpointUrl;
182
+ if (otlpProtocol && otlpProtocol.toLowerCase() === 'grpc') {
183
+ console.warn('[OTLP] Grpc protocol specified but not yet supported, using HTTP endpoint format');
184
+ finalEndpointUrl = endpointUrl.includes('/v1/logs')
185
+ ? endpointUrl
186
+ : `${endpointUrl.replace(/\/$/, '')}/v1/logs`;
187
+ }
188
+ else {
189
+ finalEndpointUrl = endpointUrl.includes('/v1/logs')
190
+ ? endpointUrl
191
+ : `${endpointUrl.replace(/\/$/, '')}/v1/logs`;
192
+ }
193
+ const exporterOptions = {
194
+ url: finalEndpointUrl,
195
+ };
196
+ if (otlpProtocol) {
197
+ const protocol = otlpProtocol.toLowerCase();
198
+ if (protocol === 'httpprotobuf' || protocol === 'protobuf') {
199
+ exporterOptions.contentType = 'application/x-protobuf';
200
+ }
201
+ else if (protocol === 'httpjson' || protocol === 'json') {
202
+ exporterOptions.contentType = 'application/json';
203
+ }
204
+ else if (protocol === 'grpc') {
205
+ console.warn('[OTLP] Grpc protocol is not yet supported in Node.js runtime, falling back to HttpProtobuf');
206
+ exporterOptions.contentType = 'application/x-protobuf';
207
+ }
208
+ else {
209
+ console.warn(`[OTLP] Unknown protocol "${otlpProtocol}", defaulting to HttpProtobuf`);
210
+ exporterOptions.contentType = 'application/x-protobuf';
211
+ }
212
+ }
213
+ else {
214
+ exporterOptions.contentType = 'application/x-protobuf';
215
+ }
216
+ if (process.env.BEAM_OTEL_EXPORTER_OTLP_HEADERS) {
217
+ exporterOptions.headers = JSON.parse(process.env.BEAM_OTEL_EXPORTER_OTLP_HEADERS);
218
+ }
219
+ const exporter = new exporter_logs_otlp_http_1.OTLPLogExporter(exporterOptions);
220
+ const baseResource = (0, resources_1.defaultResource)();
221
+ const customResource = (0, resources_1.resourceFromAttributes)(resourceAttributes);
222
+ const resource = baseResource.merge(customResource);
223
+ const processors = [new sdk_logs_1.BatchLogRecordProcessor(exporter)];
224
+ try {
225
+ const betterStackExporter = await initializeBetterStackLogging(serviceName, qualifiedServiceName, env);
226
+ if (betterStackExporter) {
227
+ processors.push(new sdk_logs_1.BatchLogRecordProcessor(betterStackExporter));
228
+ console.error('[BetterStack] BetterStack exporter added as second processor - logs will be sent to both ClickHouse and BetterStack');
229
+ }
230
+ }
231
+ catch (error) {
232
+ console.warn('[BetterStack] Failed to initialize BetterStack exporter (continuing without it):', error instanceof Error ? error.message : String(error));
233
+ }
234
+ const loggerProvider = new sdk_logs_1.LoggerProvider({
235
+ resource: resource,
236
+ processors: processors,
237
+ });
238
+ api_logs_1.logs.setGlobalLoggerProvider(loggerProvider);
239
+ console.error(`[OTLP] OpenTelemetry logging initialized. Endpoint: ${finalEndpointUrl}, Service: ${serviceName || 'unknown'}`);
240
+ if (standardOtelEnabled && logger) {
241
+ try {
242
+ const { isCollectorRunning } = await Promise.resolve().then(() => __importStar(require('./collector-manager.js')));
243
+ for (let i = 0; i < 50; i++) {
244
+ const status = await isCollectorRunning();
245
+ if (status.isRunning && status.isReady) {
246
+ if (logger) {
247
+ logger.info(`[OTLP] Collector confirmed ready at ${status.otlpEndpoint || finalEndpointUrl}`);
248
+ }
249
+ break;
250
+ }
251
+ await new Promise(resolve => setTimeout(resolve, 100));
252
+ }
253
+ }
254
+ catch (error) {
255
+ if (logger) {
256
+ logger.warn(`[OTLP] Could not verify collector readiness: ${error instanceof Error ? error.message : String(error)}`);
257
+ }
258
+ }
259
+ }
260
+ return Promise.resolve(loggerProvider);
261
+ }
262
+ catch (error) {
263
+ console.error('[OTLP] Failed to initialize OTLP logging:', error instanceof Error ? error.message : String(error));
264
+ if (error instanceof Error && error.stack) {
265
+ console.error('[OTLP] Stack trace:', error.stack);
266
+ }
267
+ return Promise.resolve(null);
268
+ }
269
+ }
270
+ function createBeamableLogFormatter(serviceName, qualifiedServiceName, otlpProviderRef) {
271
+ return new node_stream_1.Transform({
272
+ objectMode: false,
273
+ transform(chunk, _encoding, callback) {
274
+ const buffer = Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk);
275
+ try {
276
+ const line = buffer.toString('utf8');
277
+ if (!line.trim()) {
278
+ callback();
279
+ return;
280
+ }
281
+ const pinoLog = JSON.parse(line);
282
+ let timestamp;
283
+ if (typeof pinoLog.time === 'string') {
284
+ timestamp = pinoLog.time;
285
+ }
286
+ else if (typeof pinoLog.time === 'number') {
287
+ timestamp = new Date(pinoLog.time).toISOString();
288
+ }
289
+ else {
290
+ timestamp = new Date().toISOString();
291
+ }
292
+ const level = mapPinoLevelToBeamableLevel(pinoLog.level);
293
+ const messageParts = [];
294
+ if (pinoLog.msg) {
295
+ messageParts.push(pinoLog.msg);
296
+ }
297
+ if (pinoLog.err) {
298
+ const err = pinoLog.err;
299
+ const errMsg = err.message || err.msg || 'Error';
300
+ const errStack = err.stack ? `\n${err.stack}` : '';
301
+ messageParts.push(`${errMsg}${errStack}`);
302
+ }
303
+ const beamableLog = {
304
+ __t: timestamp,
305
+ __l: level,
306
+ __m: messageParts.length > 0 ? messageParts.join(' ') : 'No message',
307
+ };
308
+ const contextFields = {};
309
+ if (pinoLog.cid)
310
+ contextFields.cid = pinoLog.cid;
311
+ if (pinoLog.pid)
312
+ contextFields.pid = pinoLog.pid;
313
+ if (pinoLog.routingKey)
314
+ contextFields.routingKey = pinoLog.routingKey;
315
+ if (pinoLog.service)
316
+ contextFields.service = pinoLog.service;
317
+ if (pinoLog.component)
318
+ contextFields.component = pinoLog.component;
319
+ if (serviceName) {
320
+ contextFields.serviceName = serviceName;
321
+ }
322
+ if (qualifiedServiceName) {
323
+ contextFields.qualifiedServiceName = qualifiedServiceName;
324
+ }
325
+ const standardPinoFields = ['level', 'time', 'pid', 'hostname', 'name', 'msg', 'err', 'v', 'cid', 'pid', 'routingKey', 'sdkVersionExecution', 'service', 'component'];
326
+ for (const [key, value] of Object.entries(pinoLog)) {
327
+ if (!standardPinoFields.includes(key) && value !== undefined && value !== null) {
328
+ contextFields[key] = value;
329
+ }
330
+ }
331
+ if (Object.keys(contextFields).length > 0) {
332
+ beamableLog.__c = contextFields;
333
+ }
334
+ const otelFields = {};
335
+ const resourceAttributes = {};
336
+ if (serviceName) {
337
+ resourceAttributes['service.namespace'] = serviceName;
338
+ resourceAttributes['service.name'] = serviceName;
339
+ }
340
+ if (qualifiedServiceName) {
341
+ resourceAttributes['service.qualifiedName'] = qualifiedServiceName;
342
+ }
343
+ if (pinoLog.cid) {
344
+ resourceAttributes['beam.cid'] = String(pinoLog.cid);
345
+ }
346
+ if (pinoLog.pid) {
347
+ resourceAttributes['beam.pid'] = String(pinoLog.pid);
348
+ }
349
+ if (pinoLog.routingKey) {
350
+ resourceAttributes['beam.routing_key'] = String(pinoLog.routingKey);
351
+ }
352
+ const logAttributes = {};
353
+ if (pinoLog.component) {
354
+ logAttributes['component'] = String(pinoLog.component);
355
+ }
356
+ if (pinoLog.err) {
357
+ const err = pinoLog.err;
358
+ if (err.message)
359
+ logAttributes['exception.message'] = String(err.message);
360
+ if (err.stack)
361
+ logAttributes['exception.stacktrace'] = String(err.stack);
362
+ if (err.type)
363
+ logAttributes['exception.type'] = String(err.type);
364
+ }
365
+ const severityTextMap = {
366
+ 'Debug': 'Debug',
367
+ 'Info': 'Information',
368
+ 'Warning': 'Warning',
369
+ 'Error': 'Error',
370
+ 'Fatal': 'Critical',
371
+ };
372
+ const severityText = severityTextMap[level] || 'Information';
373
+ if (serviceName && !resourceAttributes['service.namespace']) {
374
+ resourceAttributes['service.namespace'] = serviceName;
375
+ resourceAttributes['service.name'] = serviceName;
376
+ }
377
+ otelFields['Timestamp'] = timestamp;
378
+ otelFields['SeverityText'] = severityText;
379
+ otelFields['Body'] = messageParts.length > 0 ? messageParts.join(' ') : 'No message';
380
+ otelFields['ResourceAttributes'] = resourceAttributes;
381
+ otelFields['LogAttributes'] = logAttributes;
382
+ Object.assign(beamableLog, otelFields);
383
+ if (otlpProviderRef === null || otlpProviderRef === void 0 ? void 0 : otlpProviderRef.provider) {
384
+ try {
385
+ const otlpLogger = otlpProviderRef.provider.getLogger(serviceName || 'beamable-node-runtime', undefined, {
386
+ schemaUrl: undefined,
387
+ });
388
+ const severityNumberMap = {
389
+ 'Debug': 5,
390
+ 'Info': 9,
391
+ 'Warning': 13,
392
+ 'Error': 17,
393
+ 'Fatal': 21,
394
+ };
395
+ otlpLogger.emit({
396
+ severityNumber: severityNumberMap[level] || 9,
397
+ severityText: severityText,
398
+ body: messageParts.length > 0 ? messageParts.join(' ') : 'No message',
399
+ attributes: {
400
+ ...logAttributes,
401
+ ...(pinoLog.component ? { component: String(pinoLog.component) } : {}),
402
+ },
403
+ timestamp: new Date(timestamp).getTime() * 1000000,
404
+ observedTimestamp: Date.now() * 1000000,
405
+ });
406
+ }
407
+ catch (otlpError) {
408
+ console.error(`[OTLP] Failed to emit log record via OTLP: ${otlpError instanceof Error ? otlpError.message : String(otlpError)}`);
409
+ }
410
+ }
411
+ const output = JSON.stringify(beamableLog) + '\n';
412
+ callback(null, Buffer.from(output, 'utf8'));
413
+ }
414
+ catch (error) {
415
+ const fallbackLog = {
416
+ __t: new Date().toISOString(),
417
+ __l: 'Error',
418
+ __m: `Failed to parse log entry: ${chunk.toString().substring(0, 200)}`,
419
+ };
420
+ callback(null, Buffer.from(JSON.stringify(fallbackLog) + '\n', 'utf8'));
421
+ }
422
+ },
423
+ });
424
+ }
425
+ function createLogger(env, options = {}) {
426
+ var _a, _b, _c;
427
+ const configuredDestination = (_a = options.destinationPath) !== null && _a !== void 0 ? _a : process.env.LOG_PATH;
428
+ const usePrettyLogs = shouldUsePrettyLogs();
429
+ const isInDocker = process.env.IS_LOCAL !== '1' && process.env.IS_LOCAL !== 'true';
430
+ const useLocalOtel = !!process.env.BEAM_LOCAL_OTEL;
431
+ const standardOtelEnabled = (isInDocker || useLocalOtel) && !process.env.BEAM_DISABLE_STANDARD_OTEL;
432
+ const otlpProviderRef = { provider: null };
433
+ if (options.otlpEndpoint) {
434
+ const originalEndpoint = process.env.BEAM_OTEL_EXPORTER_OTLP_ENDPOINT;
435
+ process.env.BEAM_OTEL_EXPORTER_OTLP_ENDPOINT = options.otlpEndpoint;
436
+ const initLogger = (0, pino_1.default)({
437
+ name: 'beamable-otlp-init',
438
+ level: 'info',
439
+ }, process.stdout);
440
+ initializeOtlpLogging(options.serviceName, options.qualifiedServiceName, env, initLogger).then((provider) => {
441
+ if (provider) {
442
+ otlpProviderRef.provider = provider;
443
+ initLogger.info(`[OTLP] OTLP provider created using existing collector at ${options.otlpEndpoint}`);
444
+ initLogger.info(`[OTLP] OpenTelemetry logging initialized. Endpoint: ${options.otlpEndpoint}/v1/logs, Service: ${options.serviceName || 'unknown'}`);
445
+ }
446
+ else {
447
+ initLogger.warn('[OTLP] OTLP provider creation returned null, structured logs will not be sent via OTLP');
448
+ otlpProviderRef.provider = null;
449
+ }
450
+ }).catch((error) => {
451
+ const errorMsg = error instanceof Error ? error.message : String(error);
452
+ initLogger.error(`[OTLP] Failed to create OTLP provider: ${errorMsg}`);
453
+ otlpProviderRef.provider = null;
454
+ });
455
+ if (originalEndpoint !== undefined) {
456
+ process.env.BEAM_OTEL_EXPORTER_OTLP_ENDPOINT = originalEndpoint;
457
+ }
458
+ else {
459
+ delete process.env.BEAM_OTEL_EXPORTER_OTLP_ENDPOINT;
460
+ }
461
+ }
462
+ else {
463
+ otlpProviderRef.provider = null;
464
+ if (standardOtelEnabled) {
465
+ (async () => {
466
+ const bgLogger = (0, pino_1.default)({ name: 'beamable-otlp-bg', level: 'info' }, process.stdout);
467
+ const maxAttempts = 30;
468
+ const checkInterval = 1000;
469
+ for (let attempt = 0; attempt < maxAttempts; attempt++) {
470
+ try {
471
+ const { isCollectorRunning } = await Promise.resolve().then(() => __importStar(require('./collector-manager.js')));
472
+ const collectorStatus = await isCollectorRunning();
473
+ if (collectorStatus.isRunning && collectorStatus.isReady && collectorStatus.otlpEndpoint) {
474
+ const endpoint = collectorStatus.otlpEndpoint.startsWith('http')
475
+ ? collectorStatus.otlpEndpoint
476
+ : `http://${collectorStatus.otlpEndpoint}`;
477
+ const newProvider = await initializeOtlpLogging(options.serviceName, options.qualifiedServiceName, env, bgLogger);
478
+ if (newProvider) {
479
+ otlpProviderRef.provider = newProvider;
480
+ console.error(`[OTLP] Connected to collector at ${endpoint} (background connection)`);
481
+ break;
482
+ }
483
+ }
484
+ }
485
+ catch (error) {
486
+ }
487
+ if (attempt < maxAttempts - 1) {
488
+ await new Promise(resolve => setTimeout(resolve, checkInterval));
489
+ }
490
+ }
491
+ })();
492
+ }
493
+ }
494
+ const pinoOptions = {
495
+ name: (_b = options.name) !== null && _b !== void 0 ? _b : 'beamable-node-runtime',
496
+ level: env.logLevel,
497
+ base: {
498
+ cid: env.cid,
499
+ pid: env.pid,
500
+ routingKey: (_c = env.routingKey) !== null && _c !== void 0 ? _c : null,
501
+ sdkVersionExecution: env.sdkVersionExecution,
502
+ serviceName: options.serviceName,
503
+ qualifiedServiceName: options.qualifiedServiceName,
504
+ },
505
+ redact: {
506
+ paths: ['secret', 'refreshToken'],
507
+ censor: '***',
508
+ },
509
+ timestamp: pino_1.default.stdTimeFunctions.isoTime,
510
+ };
511
+ if (!configuredDestination || configuredDestination === '-' || configuredDestination === 'stdout' || configuredDestination === 'console') {
512
+ if (!usePrettyLogs) {
513
+ const beamableFormatter = createBeamableLogFormatter(options.serviceName, options.qualifiedServiceName, otlpProviderRef);
514
+ beamableFormatter.pipe(process.stdout);
515
+ return (0, pino_1.default)(pinoOptions, beamableFormatter);
516
+ }
517
+ else {
518
+ try {
519
+ const requireFn = getRequire();
520
+ const pinoPretty = requireFn('pino-pretty');
521
+ const prettyStream = pinoPretty({
522
+ colorize: true,
523
+ translateTime: 'HH:MM:ss.l',
524
+ ignore: 'pid,hostname',
525
+ singleLine: false,
526
+ });
527
+ return (0, pino_1.default)(pinoOptions, prettyStream);
528
+ }
529
+ catch {
530
+ return (0, pino_1.default)(pinoOptions, process.stdout);
531
+ }
532
+ }
533
+ }
534
+ const resolvedDestination = configuredDestination === 'temp' ? (0, env_js_1.ensureWritableTempDirectory)() : configuredDestination;
535
+ if (!usePrettyLogs) {
536
+ const beamableFormatter = createBeamableLogFormatter(options.serviceName, options.qualifiedServiceName, otlpProviderRef);
537
+ const fileStream = (0, pino_1.destination)({ dest: resolvedDestination, mkdir: true, append: true, sync: false });
538
+ beamableFormatter.pipe(fileStream);
539
+ return (0, pino_1.default)(pinoOptions, beamableFormatter);
540
+ }
541
+ else {
542
+ const fileStream = (0, pino_1.destination)({ dest: resolvedDestination, mkdir: true, append: true, sync: false });
543
+ return (0, pino_1.default)(pinoOptions, fileStream);
544
+ }
545
+ }
@@ -0,0 +1,19 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.allocateRequestId = allocateRequestId;
4
+ exports.serializeGatewayRequest = serializeGatewayRequest;
5
+ exports.deserializeGatewayResponse = deserializeGatewayResponse;
6
+ let nextRequestId = -1;
7
+ function allocateRequestId() {
8
+ nextRequestId -= 1;
9
+ if (nextRequestId < -9000000000) {
10
+ nextRequestId = -1;
11
+ }
12
+ return nextRequestId;
13
+ }
14
+ function serializeGatewayRequest(request) {
15
+ return JSON.stringify(request);
16
+ }
17
+ function deserializeGatewayResponse(raw) {
18
+ return JSON.parse(raw);
19
+ }
@@ -0,0 +1,100 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.GatewayRequester = void 0;
4
+ const node_events_1 = require("node:events");
5
+ const errors_js_1 = require("./errors.js");
6
+ const message_js_1 = require("./message.js");
7
+ class GatewayRequester {
8
+ constructor(socket, logger) {
9
+ this.pending = new Map();
10
+ this.emitter = new node_events_1.EventEmitter();
11
+ this.requestTimeoutMs = 15000;
12
+ this.socket = socket;
13
+ this.logger = logger.child({ component: 'GatewayRequester' });
14
+ this.socket.on('message', (...args) => { var _a; return this.onRawMessage(String((_a = args[0]) !== null && _a !== void 0 ? _a : '')); });
15
+ }
16
+ on(event, listener) {
17
+ this.emitter.on(event, listener);
18
+ }
19
+ off(event, listener) {
20
+ this.emitter.off(event, listener);
21
+ }
22
+ setRequestTimeout(timeoutMs) {
23
+ this.requestTimeoutMs = timeoutMs;
24
+ }
25
+ async request(method, path, body) {
26
+ const id = (0, message_js_1.allocateRequestId)();
27
+ const effectiveBody = body !== null && body !== void 0 ? body : {};
28
+ const request = {
29
+ id,
30
+ method: method.toLowerCase(),
31
+ path,
32
+ body: effectiveBody,
33
+ };
34
+ this.logger.debug({ id, method, path, body: effectiveBody }, 'Sending gateway request.');
35
+ const payload = (0, message_js_1.serializeGatewayRequest)(request);
36
+ return new Promise((resolve, reject) => {
37
+ const timeoutHandle = setTimeout(() => {
38
+ this.pending.delete(id);
39
+ reject(new errors_js_1.TimeoutError(`Request ${method} ${path} timed out after ${this.requestTimeoutMs}ms`));
40
+ }, this.requestTimeoutMs).unref();
41
+ this.pending.set(id, {
42
+ resolve: resolve,
43
+ reject,
44
+ timeoutHandle,
45
+ path,
46
+ method,
47
+ });
48
+ this.socket
49
+ .send(payload)
50
+ .catch((error) => {
51
+ clearTimeout(timeoutHandle);
52
+ this.pending.delete(id);
53
+ reject(error instanceof Error ? error : new Error(String(error)));
54
+ });
55
+ });
56
+ }
57
+ async sendResponse(response) {
58
+ const payload = JSON.stringify(response);
59
+ await this.socket.send(payload);
60
+ }
61
+ async acknowledge(id, status = 200) {
62
+ await this.sendResponse({ id, status, body: null });
63
+ }
64
+ onRawMessage(raw) {
65
+ this.logger.debug({ raw }, 'Received websocket frame.');
66
+ let envelope;
67
+ try {
68
+ envelope = (0, message_js_1.deserializeGatewayResponse)(raw);
69
+ }
70
+ catch (error) {
71
+ this.logger.error({ err: error, raw }, 'Failed to parse gateway message.');
72
+ return;
73
+ }
74
+ if (typeof envelope.id !== 'number') {
75
+ this.logger.warn({ envelope }, 'Invalid gateway message without id.');
76
+ return;
77
+ }
78
+ const pending = this.pending.get(envelope.id);
79
+ if (pending) {
80
+ clearTimeout(pending.timeoutHandle);
81
+ this.pending.delete(envelope.id);
82
+ if ('status' in envelope && envelope.status === 403) {
83
+ pending.reject(new errors_js_1.AuthenticationError('Gateway rejected the request with 403.'));
84
+ return;
85
+ }
86
+ pending.resolve(envelope.body);
87
+ return;
88
+ }
89
+ this.emitter.emit('event', envelope);
90
+ }
91
+ dispose() {
92
+ for (const [id, pending] of this.pending.entries()) {
93
+ clearTimeout(pending.timeoutHandle);
94
+ pending.reject(new Error(`Request ${pending.method} ${pending.path} cancelled during shutdown.`));
95
+ this.pending.delete(id);
96
+ }
97
+ this.emitter.removeAllListeners();
98
+ }
99
+ }
100
+ exports.GatewayRequester = GatewayRequester;