@omen.foundation/node-microservice-runtime 0.1.59 → 0.1.61

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.
@@ -146,6 +146,11 @@ async function fetchClickHouseCredentials(env) {
146
146
  return credentials;
147
147
  }
148
148
  function getCollectorStoragePath() {
149
+ const productionPath = '/opt/beam/collectors';
150
+ const productionVersionPath = (0, path_1.join)(productionPath, COLLECTOR_VERSION);
151
+ if ((0, fs_1.existsSync)(productionPath)) {
152
+ return productionVersionPath;
153
+ }
149
154
  const tempDir = process.env.TMPDIR || process.env.TMP || '/tmp';
150
155
  return (0, path_1.join)(tempDir, 'beam', 'collectors', COLLECTOR_VERSION);
151
156
  }
@@ -310,12 +315,42 @@ async function resolveCollector(allowDownload = true, logger) {
310
315
  configPath: (0, fs_1.existsSync)(configPath) ? configPath : null,
311
316
  };
312
317
  }
313
- function discoverCollectorViaUDP(timeoutMs = 5000) {
318
+ function discoverCollectorViaUDP(timeoutMs = 1000) {
314
319
  return new Promise((resolve) => {
315
320
  const socket = dgram_1.default.createSocket('udp4');
316
321
  const discovered = [];
317
322
  let timeout;
323
+ let resolved = false;
318
324
  const startTime = Date.now();
325
+ const safetyTimeout = setTimeout(() => {
326
+ if (!resolved) {
327
+ console.log(`[UDP Discovery] Safety timeout triggered - forcing resolution`);
328
+ resolved = true;
329
+ try {
330
+ socket.removeAllListeners();
331
+ socket.close();
332
+ }
333
+ catch (e) {
334
+ }
335
+ clearTimeout(timeout);
336
+ resolve(discovered.length > 0 ? discovered[0] : null);
337
+ }
338
+ }, timeoutMs + 100);
339
+ const doResolve = (result) => {
340
+ if (!resolved) {
341
+ resolved = true;
342
+ clearTimeout(timeout);
343
+ clearTimeout(safetyTimeout);
344
+ try {
345
+ socket.removeAllListeners();
346
+ socket.close();
347
+ }
348
+ catch (e) {
349
+ }
350
+ console.log(`[UDP Discovery] Resolving promise with result: ${result ? 'found' : 'null'}`);
351
+ resolve(result);
352
+ }
353
+ };
319
354
  socket.on('message', (msg) => {
320
355
  try {
321
356
  const message = JSON.parse(msg.toString());
@@ -323,23 +358,21 @@ function discoverCollectorViaUDP(timeoutMs = 5000) {
323
358
  discovered.push(message);
324
359
  const elapsed = Date.now() - startTime;
325
360
  console.log(`[UDP Discovery] Found collector after ${elapsed}ms: ${message.otlpEndpoint}`);
361
+ doResolve(discovered[0]);
326
362
  }
327
363
  }
328
364
  catch (error) {
329
365
  }
330
366
  });
331
367
  socket.on('error', (err) => {
332
- clearTimeout(timeout);
333
- socket.close();
334
368
  const elapsed = Date.now() - startTime;
335
369
  console.log(`[UDP Discovery] Socket error after ${elapsed}ms: ${err.message}`);
336
- resolve(null);
370
+ doResolve(null);
337
371
  });
338
372
  socket.bind(() => {
339
373
  socket.setBroadcast(true);
340
374
  console.log(`[UDP Discovery] Listening for collector broadcasts (timeout: ${timeoutMs}ms)...`);
341
375
  timeout = setTimeout(() => {
342
- socket.close();
343
376
  const elapsed = Date.now() - startTime;
344
377
  if (discovered.length > 0) {
345
378
  console.log(`[UDP Discovery] Timeout after ${elapsed}ms, found ${discovered.length} collector(s)`);
@@ -347,7 +380,7 @@ function discoverCollectorViaUDP(timeoutMs = 5000) {
347
380
  else {
348
381
  console.log(`[UDP Discovery] Timeout after ${elapsed}ms, no collector found`);
349
382
  }
350
- resolve(discovered.length > 0 ? discovered[0] : null);
383
+ doResolve(discovered.length > 0 ? discovered[0] : null);
351
384
  }, timeoutMs);
352
385
  });
353
386
  });
@@ -411,8 +444,11 @@ async function isCollectorRunning() {
411
444
  }
412
445
  try {
413
446
  const udpStartTime = Date.now();
414
- const discovered = await discoverCollectorViaUDP(2000);
447
+ console.log('[UDP Discovery] Starting UDP discovery in isCollectorRunning()...');
448
+ console.log('[UDP Discovery] Calling discoverCollectorViaUDP(1000)...');
449
+ const discovered = await discoverCollectorViaUDP(1000);
415
450
  const udpElapsed = Date.now() - udpStartTime;
451
+ console.log(`[UDP Discovery] UDP discovery promise resolved after ${udpElapsed}ms, result: ${discovered ? 'found' : 'null'}`);
416
452
  if (discovered) {
417
453
  console.log(`[UDP Discovery] Found collector in ${udpElapsed}ms: ${discovered.otlpEndpoint}`);
418
454
  return {
@@ -424,12 +460,17 @@ async function isCollectorRunning() {
424
460
  };
425
461
  }
426
462
  else {
427
- console.log(`[UDP Discovery] No collector found after ${udpElapsed}ms`);
463
+ console.log(`[UDP Discovery] No collector found after ${udpElapsed}ms, returning not running status`);
428
464
  }
429
465
  }
430
466
  catch (error) {
431
- console.log(`[UDP Discovery] Error: ${error instanceof Error ? error.message : String(error)}`);
467
+ const errorMsg = error instanceof Error ? error.message : String(error);
468
+ console.log(`[UDP Discovery] Error in isCollectorRunning(): ${errorMsg}`);
469
+ if (error instanceof Error && error.stack) {
470
+ console.log(`[UDP Discovery] Error stack: ${error.stack}`);
471
+ }
432
472
  }
473
+ console.log('[UDP Discovery] Returning default not-running status from isCollectorRunning()');
433
474
  return {
434
475
  isRunning: false,
435
476
  isReady: false,
@@ -777,13 +818,14 @@ async function discoverOrStartCollector(logger, standardOtelEnabled, env) {
777
818
  }
778
819
  }
779
820
  if (!globalCollectorProcess) {
780
- logger.info('[Collector] Checking for existing collector via UDP discovery (timeout: 2s)...');
821
+ logger.info('[Collector] Quick check for existing collector via UDP discovery (timeout: 1s, matching C#)...');
781
822
  const udpStartTime = Date.now();
823
+ logger.info('[Collector] Calling isCollectorRunning()...');
782
824
  const status = await isCollectorRunning();
783
825
  const udpElapsed = Date.now() - udpStartTime;
784
- logger.info(`[Collector] UDP discovery completed in ${udpElapsed}ms: isRunning=${status.isRunning}, isReady=${status.isReady}, endpoint=${status.otlpEndpoint || 'none'}`);
826
+ logger.info(`[Collector] isCollectorRunning() returned after ${udpElapsed}ms: isRunning=${status.isRunning}, isReady=${status.isReady}, endpoint=${status.otlpEndpoint || 'none'}`);
785
827
  if (status.isRunning && status.isReady && status.otlpEndpoint) {
786
- logger.info(`[Collector] Found running collector at ${status.otlpEndpoint}`);
828
+ logger.info(`[Collector] Found running collector at ${status.otlpEndpoint}, will reuse it`);
787
829
  return `http://${status.otlpEndpoint}`;
788
830
  }
789
831
  logger.info('[Collector] No existing collector found, will start new one...');
@@ -1 +1 @@
1
- {"version":3,"file":"collector-manager.d.ts","sourceRoot":"","sources":["../src/collector-manager.ts"],"names":[],"mappings":"AAAA,OAAO,EAAS,YAAY,EAAE,MAAM,eAAe,CAAC;AAOpD,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,MAAM,CAAC;AAInC,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAYpD,MAAM,WAAW,eAAe;IAC9B,SAAS,EAAE,OAAO,CAAC;IACnB,OAAO,EAAE,OAAO,CAAC;IACjB,GAAG,EAAE,MAAM,CAAC;IACZ,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAuCD;;GAEG;AACH,UAAU,qBAAqB;IAC7B,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;CAClB;AAqCD;;;;GAIG;AACH,wBAAsB,0BAA0B,CAC9C,GAAG,EAAE,iBAAiB,GACrB,OAAO,CAAC,qBAAqB,CAAC,CAsDhC;AA6PD;;GAEG;AACH,wBAAgB,8BAA8B,IAAI;IAChD,WAAW,EAAE,OAAO,CAAC;IACrB,WAAW,EAAE,OAAO,CAAC;IACrB,WAAW,EAAE,OAAO,CAAC;IACrB,MAAM,EAAE,aAAa,GAAG,KAAK,GAAG,SAAS,CAAC;CAC3C,CAoBA;AAED;;GAEG;AACH,wBAAsB,kBAAkB,IAAI,OAAO,CAAC,eAAe,CAAC,CA+EnE;AA0BD;;GAEG;AACH,wBAAgB,sBAAsB,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,IAAI,CAYjG;AAED;;;;GAIG;AACH,wBAAsB,6BAA6B,CACjD,GAAG,EAAE,iBAAiB,EACtB,UAAU,CAAC,EAAE,MAAM,GAClB,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAwCxB;AAED;;;;;GAKG;AACH,wBAAgB,mBAAmB,CAAC,GAAG,EAAE,iBAAiB,GAAG,IAAI,CAsChE;AAED;;;;;GAKG;AACH,wBAAgB,2BAA2B,CACzC,GAAG,EAAE,iBAAiB,EACtB,SAAS,GAAE,MAAc,GACxB,MAAM,GAAG,IAAI,CA8Ef;AAED;;GAEG;AACH,wBAAsB,cAAc,CAClC,MAAM,EAAE,MAAM,EACd,YAAY,CAAC,EAAE,MAAM,EACrB,GAAG,CAAC,EAAE,iBAAiB,GACtB,OAAO,CAAC;IAAE,OAAO,EAAE,YAAY,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,CAAC,CAuNtD;AAED;;GAEG;AACH,wBAAgB,yBAAyB,IAAI;IAC3C,UAAU,EAAE,OAAO,CAAC;IACpB,GAAG,EAAE,MAAM,GAAG,IAAI,CAAC;IACnB,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,MAAM,EAAE,MAAM,EAAE,CAAC;CAClB,CASA;AAED;;GAEG;AACH,wBAAsB,wBAAwB,CAC5C,MAAM,EAAE,MAAM,EACd,mBAAmB,EAAE,OAAO,EAC5B,GAAG,CAAC,EAAE,iBAAiB,GACtB,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAuKxB"}
1
+ {"version":3,"file":"collector-manager.d.ts","sourceRoot":"","sources":["../src/collector-manager.ts"],"names":[],"mappings":"AAAA,OAAO,EAAS,YAAY,EAAE,MAAM,eAAe,CAAC;AAOpD,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,MAAM,CAAC;AAInC,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAYpD,MAAM,WAAW,eAAe;IAC9B,SAAS,EAAE,OAAO,CAAC;IACnB,OAAO,EAAE,OAAO,CAAC;IACjB,GAAG,EAAE,MAAM,CAAC;IACZ,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAuCD;;GAEG;AACH,UAAU,qBAAqB;IAC7B,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;CAClB;AAqCD;;;;GAIG;AACH,wBAAsB,0BAA0B,CAC9C,GAAG,EAAE,iBAAiB,GACrB,OAAO,CAAC,qBAAqB,CAAC,CAsDhC;AAuSD;;GAEG;AACH,wBAAgB,8BAA8B,IAAI;IAChD,WAAW,EAAE,OAAO,CAAC;IACrB,WAAW,EAAE,OAAO,CAAC;IACrB,WAAW,EAAE,OAAO,CAAC;IACrB,MAAM,EAAE,aAAa,GAAG,KAAK,GAAG,SAAS,CAAC;CAC3C,CAoBA;AAED;;GAEG;AACH,wBAAsB,kBAAkB,IAAI,OAAO,CAAC,eAAe,CAAC,CAuFnE;AA0BD;;GAEG;AACH,wBAAgB,sBAAsB,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,IAAI,CAYjG;AAED;;;;GAIG;AACH,wBAAsB,6BAA6B,CACjD,GAAG,EAAE,iBAAiB,EACtB,UAAU,CAAC,EAAE,MAAM,GAClB,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAwCxB;AAED;;;;;GAKG;AACH,wBAAgB,mBAAmB,CAAC,GAAG,EAAE,iBAAiB,GAAG,IAAI,CAsChE;AAED;;;;;GAKG;AACH,wBAAgB,2BAA2B,CACzC,GAAG,EAAE,iBAAiB,EACtB,SAAS,GAAE,MAAc,GACxB,MAAM,GAAG,IAAI,CA8Ef;AAED;;GAEG;AACH,wBAAsB,cAAc,CAClC,MAAM,EAAE,MAAM,EACd,YAAY,CAAC,EAAE,MAAM,EACrB,GAAG,CAAC,EAAE,iBAAiB,GACtB,OAAO,CAAC;IAAE,OAAO,EAAE,YAAY,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,CAAC,CAuNtD;AAED;;GAEG;AACH,wBAAgB,yBAAyB,IAAI;IAC3C,UAAU,EAAE,OAAO,CAAC;IACpB,GAAG,EAAE,MAAM,GAAG,IAAI,CAAC;IACnB,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,MAAM,EAAE,MAAM,EAAE,CAAC;CAClB,CASA;AAED;;GAEG;AACH,wBAAsB,wBAAwB,CAC5C,MAAM,EAAE,MAAM,EACd,mBAAmB,EAAE,OAAO,EAC5B,GAAG,CAAC,EAAE,iBAAiB,GACtB,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAyKxB"}
@@ -124,9 +124,18 @@ export async function fetchClickHouseCredentials(env) {
124
124
  }
125
125
  /**
126
126
  * Gets the collector storage directory (similar to C# LocalApplicationData/beam/collectors/version)
127
+ * Checks production location first (pre-installed in Docker), then falls back to temp directory
127
128
  */
128
129
  function getCollectorStoragePath() {
129
- // Use temp directory for now - in containers this should be writable
130
+ // Check production location first (pre-installed in Docker image at /opt/beam/collectors)
131
+ // This avoids runtime download delays (~12 seconds)
132
+ const productionPath = '/opt/beam/collectors';
133
+ const productionVersionPath = join(productionPath, COLLECTOR_VERSION);
134
+ // Use production path if it exists (Docker image pre-installed collector)
135
+ if (existsSync(productionPath)) {
136
+ return productionVersionPath;
137
+ }
138
+ // Fallback to temp directory (local development without Docker)
130
139
  const tempDir = process.env.TMPDIR || process.env.TMP || '/tmp';
131
140
  return join(tempDir, 'beam', 'collectors', COLLECTOR_VERSION);
132
141
  }
@@ -314,12 +323,45 @@ async function resolveCollector(allowDownload = true, logger) {
314
323
  /**
315
324
  * Discovers collector via UDP broadcast
316
325
  */
317
- function discoverCollectorViaUDP(timeoutMs = 5000) {
326
+ function discoverCollectorViaUDP(timeoutMs = 1000) {
318
327
  return new Promise((resolve) => {
319
328
  const socket = dgram.createSocket('udp4');
320
329
  const discovered = [];
321
330
  let timeout;
331
+ let resolved = false; // Guard to prevent double resolution
322
332
  const startTime = Date.now();
333
+ // Safety timeout - force resolve after timeout + 100ms buffer
334
+ const safetyTimeout = setTimeout(() => {
335
+ if (!resolved) {
336
+ console.log(`[UDP Discovery] Safety timeout triggered - forcing resolution`);
337
+ resolved = true;
338
+ try {
339
+ socket.removeAllListeners();
340
+ socket.close();
341
+ }
342
+ catch (e) {
343
+ // Ignore
344
+ }
345
+ clearTimeout(timeout);
346
+ resolve(discovered.length > 0 ? discovered[0] : null);
347
+ }
348
+ }, timeoutMs + 100);
349
+ const doResolve = (result) => {
350
+ if (!resolved) {
351
+ resolved = true;
352
+ clearTimeout(timeout);
353
+ clearTimeout(safetyTimeout);
354
+ try {
355
+ socket.removeAllListeners();
356
+ socket.close();
357
+ }
358
+ catch (e) {
359
+ // Ignore
360
+ }
361
+ console.log(`[UDP Discovery] Resolving promise with result: ${result ? 'found' : 'null'}`);
362
+ resolve(result);
363
+ }
364
+ };
323
365
  socket.on('message', (msg) => {
324
366
  try {
325
367
  const message = JSON.parse(msg.toString());
@@ -328,6 +370,8 @@ function discoverCollectorViaUDP(timeoutMs = 5000) {
328
370
  discovered.push(message);
329
371
  const elapsed = Date.now() - startTime;
330
372
  console.log(`[UDP Discovery] Found collector after ${elapsed}ms: ${message.otlpEndpoint}`);
373
+ // Resolve immediately when collector found
374
+ doResolve(discovered[0]);
331
375
  }
332
376
  }
333
377
  catch (error) {
@@ -335,17 +379,14 @@ function discoverCollectorViaUDP(timeoutMs = 5000) {
335
379
  }
336
380
  });
337
381
  socket.on('error', (err) => {
338
- clearTimeout(timeout);
339
- socket.close();
340
382
  const elapsed = Date.now() - startTime;
341
383
  console.log(`[UDP Discovery] Socket error after ${elapsed}ms: ${err.message}`);
342
- resolve(null);
384
+ doResolve(null);
343
385
  });
344
386
  socket.bind(() => {
345
387
  socket.setBroadcast(true);
346
388
  console.log(`[UDP Discovery] Listening for collector broadcasts (timeout: ${timeoutMs}ms)...`);
347
389
  timeout = setTimeout(() => {
348
- socket.close();
349
390
  const elapsed = Date.now() - startTime;
350
391
  if (discovered.length > 0) {
351
392
  console.log(`[UDP Discovery] Timeout after ${elapsed}ms, found ${discovered.length} collector(s)`);
@@ -353,8 +394,7 @@ function discoverCollectorViaUDP(timeoutMs = 5000) {
353
394
  else {
354
395
  console.log(`[UDP Discovery] Timeout after ${elapsed}ms, no collector found`);
355
396
  }
356
- // Return the first discovered collector
357
- resolve(discovered.length > 0 ? discovered[0] : null);
397
+ doResolve(discovered.length > 0 ? discovered[0] : null);
358
398
  }, timeoutMs);
359
399
  });
360
400
  });
@@ -437,8 +477,11 @@ export async function isCollectorRunning() {
437
477
  // Try UDP discovery as fallback
438
478
  try {
439
479
  const udpStartTime = Date.now();
440
- const discovered = await discoverCollectorViaUDP(2000);
480
+ console.log('[UDP Discovery] Starting UDP discovery in isCollectorRunning()...');
481
+ console.log('[UDP Discovery] Calling discoverCollectorViaUDP(1000)...');
482
+ const discovered = await discoverCollectorViaUDP(1000); // Match C#: 1 second max (10 attempts × 100ms)
441
483
  const udpElapsed = Date.now() - udpStartTime;
484
+ console.log(`[UDP Discovery] UDP discovery promise resolved after ${udpElapsed}ms, result: ${discovered ? 'found' : 'null'}`);
442
485
  if (discovered) {
443
486
  console.log(`[UDP Discovery] Found collector in ${udpElapsed}ms: ${discovered.otlpEndpoint}`);
444
487
  return {
@@ -450,13 +493,18 @@ export async function isCollectorRunning() {
450
493
  };
451
494
  }
452
495
  else {
453
- console.log(`[UDP Discovery] No collector found after ${udpElapsed}ms`);
496
+ console.log(`[UDP Discovery] No collector found after ${udpElapsed}ms, returning not running status`);
454
497
  }
455
498
  }
456
499
  catch (error) {
457
500
  // Discovery failed, collector probably not running
458
- console.log(`[UDP Discovery] Error: ${error instanceof Error ? error.message : String(error)}`);
501
+ const errorMsg = error instanceof Error ? error.message : String(error);
502
+ console.log(`[UDP Discovery] Error in isCollectorRunning(): ${errorMsg}`);
503
+ if (error instanceof Error && error.stack) {
504
+ console.log(`[UDP Discovery] Error stack: ${error.stack}`);
505
+ }
459
506
  }
507
+ console.log('[UDP Discovery] Returning default not-running status from isCollectorRunning()');
460
508
  return {
461
509
  isRunning: false,
462
510
  isReady: false,
@@ -918,16 +966,18 @@ export async function discoverOrStartCollector(logger, standardOtelEnabled, env)
918
966
  globalCollectorStderr = [];
919
967
  }
920
968
  }
921
- // First, check if collector is already running (via UDP discovery)
969
+ // First, quick check if collector is already running (via UDP discovery)
970
+ // Match C#: 10 attempts × 100ms = 1 second max (much faster than before)
922
971
  // Skip UDP discovery if we already have a process reference (faster)
923
972
  if (!globalCollectorProcess) {
924
- logger.info('[Collector] Checking for existing collector via UDP discovery (timeout: 2s)...');
973
+ logger.info('[Collector] Quick check for existing collector via UDP discovery (timeout: 1s, matching C#)...');
925
974
  const udpStartTime = Date.now();
975
+ logger.info('[Collector] Calling isCollectorRunning()...');
926
976
  const status = await isCollectorRunning();
927
977
  const udpElapsed = Date.now() - udpStartTime;
928
- logger.info(`[Collector] UDP discovery completed in ${udpElapsed}ms: isRunning=${status.isRunning}, isReady=${status.isReady}, endpoint=${status.otlpEndpoint || 'none'}`);
978
+ logger.info(`[Collector] isCollectorRunning() returned after ${udpElapsed}ms: isRunning=${status.isRunning}, isReady=${status.isReady}, endpoint=${status.otlpEndpoint || 'none'}`);
929
979
  if (status.isRunning && status.isReady && status.otlpEndpoint) {
930
- logger.info(`[Collector] Found running collector at ${status.otlpEndpoint}`);
980
+ logger.info(`[Collector] Found running collector at ${status.otlpEndpoint}, will reuse it`);
931
981
  return `http://${status.otlpEndpoint}`;
932
982
  }
933
983
  logger.info('[Collector] No existing collector found, will start new one...');
@@ -1 +1 @@
1
- {"version":3,"file":"collector-manager.js","sourceRoot":"","sources":["../src/collector-manager.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAgB,MAAM,eAAe,CAAC;AACpD,OAAO,EAAE,iBAAiB,EAAE,UAAU,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,IAAI,CAAC;AACzE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,MAAM,CAAC;AACrC,OAAO,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AAC3C,OAAO,EAAE,YAAY,EAAE,MAAM,MAAM,CAAC;AACpC,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,YAAY,EAAE,MAAM,KAAK,CAAC;AAEnC,OAAO,IAAI,MAAM,MAAM,CAAC;AACxB,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,OAAO,MAAM,SAAS,CAAC;AAE9B,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAmBhD,MAAM,iBAAiB,GAAG,OAAO,CAAC,CAAC,2DAA2D;AAC9F,MAAM,uBAAuB,GAAG,2CAA2C,iBAAiB,EAAE,CAAC;AAC/F,MAAM,cAAc,GAAG,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,6BAA6B,IAAI,MAAM,EAAE,EAAE,CAAC,CAAC;AAEzF;;GAEG;AACH,SAAS,YAAY;IACnB,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;QACrC,MAAM,MAAM,GAAG,YAAY,EAAE,CAAC;QAC9B,MAAM,CAAC,MAAM,CAAC,CAAC,EAAE,GAAG,EAAE;YACpB,MAAM,OAAO,GAAG,MAAM,CAAC,OAAO,EAAE,CAAC;YACjC,MAAM,IAAI,GAAG,OAAO,OAAO,KAAK,QAAQ,IAAI,OAAO,KAAK,IAAI,CAAC,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC;YAChF,MAAM,CAAC,KAAK,CAAC,GAAG,EAAE;gBAChB,IAAI,IAAI,GAAG,CAAC,EAAE,CAAC;oBACb,OAAO,CAAC,IAAI,CAAC,CAAC;gBAChB,CAAC;qBAAM,CAAC;oBACN,qDAAqD;oBACrD,OAAO,CAAC,IAAI,CAAC,CAAC;gBAChB,CAAC;YACH,CAAC,CAAC,CAAC;QACL,CAAC,CAAC,CAAC;QACH,MAAM,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,GAAG,EAAE,EAAE;YACzB,MAAM,CAAC,GAAG,CAAC,CAAC;QACd,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;AACL,CAAC;AAED,mFAAmF;AACnF,IAAI,sBAAsB,GAAwB,IAAI,CAAC;AACvD,IAAI,yBAAyB,GAAkB,IAAI,CAAC;AACpD,IAAI,uBAAuB,GAAkB,IAAI,CAAC;AAClD,IAAI,qBAAqB,GAAa,EAAE,CAAC;AACzC,wEAAwE;AACxE,IAAI,6BAA6B,GAAkC,IAAI,CAAC;AACxE,IAAI,wBAAwB,GAAkB,IAAI,CAAC,CAAC,8CAA8C;AAYlG;;;;GAIG;AACH,SAAS,kBAAkB,CACzB,GAAW,EACX,MAAc,EACd,eAAuB,EACvB,OAAsB,IAAI,EAC1B,UAAkB,GAAG;IAErB,IAAI,UAAU,GAAG,GAAG,MAAM,GAAG,GAAG,GAAG,OAAO,GAAG,eAAe,EAAE,CAAC;IAC/D,IAAI,IAAI,EAAE,CAAC;QACT,UAAU,IAAI,IAAI,CAAC;IACrB,CAAC;IAED,kDAAkD;IAClD,MAAM,IAAI,GAAG,UAAU,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,UAAU,EAAE,MAAM,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;IAC3E,OAAO,IAAI,CAAC;AACd,CAAC;AAED;;GAEG;AACH,SAAS,eAAe,CAAC,GAAW;IAClC,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,IAAI,GAAG,CAAC,GAAG,CAAC,CAAC;QAC5B,OAAO,MAAM,CAAC,QAAQ,GAAG,MAAM,CAAC,MAAM,CAAC;IACzC,CAAC;IAAC,MAAM,CAAC;QACP,qCAAqC;QACrC,OAAO,GAAG,CAAC;IACb,CAAC;AACH,CAAC;AAED;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,0BAA0B,CAC9C,GAAsB;IAEtB,MAAM,MAAM,GAAG,aAAa,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;IACvC,MAAM,OAAO,GAAG,oCAAoC,CAAC;IACrD,MAAM,SAAS,GAAG,IAAI,GAAG,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC,QAAQ,EAAE,CAAC;IAEtD,6CAA6C;IAC7C,MAAM,aAAa,GAAG,IAAI,CAAC,EAAE,IAAI,EAAE,mBAAmB,EAAE,KAAK,EAAE,MAAM,EAAE,EAAE,OAAO,CAAC,MAAM,CAAC,CAAC;IACzF,aAAa,CAAC,IAAI,CAAC,gDAAgD,SAAS,KAAK,CAAC,CAAC;IAEnF,6DAA6D;IAC7D,MAAM,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC;IAClC,IAAI,CAAC,MAAM,EAAE,CAAC;QACZ,aAAa,CAAC,KAAK,CAAC,sDAAsD,CAAC,CAAC;QAC5E,MAAM,IAAI,KAAK,CAAC,yEAAyE,CAAC,CAAC;IAC7F,CAAC;IACD,aAAa,CAAC,IAAI,CAAC,sDAAsD,CAAC,CAAC;IAE3E,2EAA2E;IAC3E,MAAM,YAAY,GAAG,eAAe,CAAC,OAAO,CAAC,CAAC;IAC9C,MAAM,SAAS,GAAG,kBAAkB,CAAC,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,YAAY,EAAE,IAAI,EAAE,GAAG,CAAC,CAAC;IAC/E,aAAa,CAAC,IAAI,CAAC,2DAA2D,CAAC,CAAC;IAEhF,6EAA6E;IAC7E,MAAM,OAAO,GAA2B;QACtC,cAAc,EAAE,kBAAkB;QAClC,MAAM,EAAE,kBAAkB;QAC1B,cAAc,EAAE,GAAG,GAAG,CAAC,GAAG,IAAI,GAAG,CAAC,GAAG,EAAE;QACvC,kBAAkB,EAAE,SAAS;KAC9B,CAAC;IAEF,MAAM,cAAc,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;IAClC,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,SAAS,EAAE;QACtC,MAAM,EAAE,KAAK;QACb,OAAO;KACR,CAAC,CAAC;IACH,MAAM,YAAY,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,cAAc,CAAC;IACjD,aAAa,CAAC,IAAI,CAAC,0CAA0C,YAAY,eAAe,QAAQ,CAAC,MAAM,EAAE,CAAC,CAAC;IAE3G,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;QACjB,MAAM,SAAS,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,eAAe,CAAC,CAAC;QACrE,aAAa,CAAC,KAAK,CAAC,qCAAqC,QAAQ,CAAC,MAAM,IAAI,QAAQ,CAAC,UAAU,EAAE,CAAC,CAAC;QACnG,MAAM,IAAI,KAAK,CAAC,+CAA+C,SAAS,KAAK,QAAQ,CAAC,MAAM,IAAI,QAAQ,CAAC,UAAU,MAAM,SAAS,CAAC,SAAS,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,CAAC,CAAC;IAC1J,CAAC;IAED,aAAa,CAAC,IAAI,CAAC,wCAAwC,CAAC,CAAC;IAC7D,MAAM,WAAW,GAAG,MAAM,QAAQ,CAAC,IAAI,EAA2B,CAAC;IAEnE,IAAI,CAAC,WAAW,CAAC,QAAQ,IAAI,CAAC,WAAW,CAAC,QAAQ,IAAI,CAAC,WAAW,CAAC,QAAQ,EAAE,CAAC;QAC5E,aAAa,CAAC,KAAK,CAAC,yDAAyD,CAAC,CAAC;QAC/E,MAAM,IAAI,KAAK,CAAC,kEAAkE,CAAC,CAAC;IACtF,CAAC;IAED,aAAa,CAAC,IAAI,CAAC,6DAA6D,WAAW,CAAC,QAAQ,eAAe,WAAW,CAAC,QAAQ,GAAG,CAAC,CAAC;IAC5I,OAAO,WAAW,CAAC;AACrB,CAAC;AAED;;GAEG;AACH,SAAS,uBAAuB;IAC9B,qEAAqE;IACrE,MAAM,OAAO,GAAG,OAAO,CAAC,GAAG,CAAC,MAAM,IAAI,OAAO,CAAC,GAAG,CAAC,GAAG,IAAI,MAAM,CAAC;IAChE,OAAO,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,YAAY,EAAE,iBAAiB,CAAC,CAAC;AAChE,CAAC;AAED;;GAEG;AACH,SAAS,sBAAsB;IAC7B,MAAM,QAAQ,GAAG,OAAO,CAAC,QAAQ,CAAC;IAClC,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC;IAE1B,4CAA4C;IAC5C,2EAA2E;IAC3E,IAAI,QAAQ,KAAK,OAAO,IAAI,IAAI,KAAK,KAAK,EAAE,CAAC;QAC3C,OAAO,uBAAuB,CAAC;IACjC,CAAC;SAAM,IAAI,QAAQ,KAAK,OAAO,IAAI,IAAI,KAAK,OAAO,EAAE,CAAC;QACpD,OAAO,uBAAuB,CAAC;IACjC,CAAC;SAAM,IAAI,QAAQ,KAAK,QAAQ,IAAI,IAAI,KAAK,KAAK,EAAE,CAAC;QACnD,OAAO,wBAAwB,CAAC;IAClC,CAAC;SAAM,IAAI,QAAQ,KAAK,QAAQ,IAAI,IAAI,KAAK,OAAO,EAAE,CAAC;QACrD,OAAO,wBAAwB,CAAC;IAClC,CAAC;SAAM,IAAI,QAAQ,KAAK,OAAO,IAAI,IAAI,KAAK,KAAK,EAAE,CAAC;QAClD,OAAO,6BAA6B,CAAC;IACvC,CAAC;IAED,MAAM,IAAI,KAAK,CAAC,yBAAyB,QAAQ,IAAI,IAAI,EAAE,CAAC,CAAC;AAC/D,CAAC;AAED;;GAEG;AACH,KAAK,UAAU,yBAAyB,CAAC,GAAW,EAAE,UAAkB,EAAE,iBAA0B,KAAK;IACvG,IAAI,QAAkB,CAAC;IACvB,IAAI,CAAC;QACH,wCAAwC;QACxC,MAAM,UAAU,GAAG,IAAI,eAAe,EAAE,CAAC;QACzC,MAAM,SAAS,GAAG,UAAU,CAAC,GAAG,EAAE,CAAC,UAAU,CAAC,KAAK,EAAE,EAAE,KAAK,CAAC,CAAC,CAAC,oBAAoB;QAEnF,IAAI,CAAC;YACH,QAAQ,GAAG,MAAM,KAAK,CAAC,GAAG,EAAE;gBAC1B,MAAM,EAAE,UAAU,CAAC,MAAM;gBACzB,OAAO,EAAE;oBACP,YAAY,EAAE,wCAAwC;iBACvD;aACF,CAAC,CAAC;YACH,YAAY,CAAC,SAAS,CAAC,CAAC;QAC1B,CAAC;QAAC,OAAO,UAAU,EAAE,CAAC;YACpB,YAAY,CAAC,SAAS,CAAC,CAAC;YACxB,IAAI,UAAU,YAAY,KAAK,EAAE,CAAC;gBAChC,8CAA8C;gBAC9C,IAAI,eAAe,GAAG,EAAE,CAAC;gBACzB,IAAK,UAAkB,CAAC,KAAK,EAAE,CAAC;oBAC9B,MAAM,KAAK,GAAI,UAAkB,CAAC,KAAK,CAAC;oBACxC,IAAI,KAAK,YAAY,KAAK,EAAE,CAAC;wBAC3B,MAAM,SAAS,GAAI,KAAa,CAAC,IAAI,CAAC;wBACtC,eAAe,GAAG,YAAY,KAAK,CAAC,IAAI,MAAM,KAAK,CAAC,OAAO,GAAG,SAAS,CAAC,CAAC,CAAC,WAAW,SAAS,GAAG,CAAC,CAAC,CAAC,EAAE,GAAG,CAAC;oBAC5G,CAAC;yBAAM,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,CAAC,IAAI,EAAE,CAAC;wBACnD,eAAe,GAAG,iBAAiB,KAAK,CAAC,IAAI,GAAG,CAAC;oBACnD,CAAC;gBACH,CAAC;gBAED,uCAAuC;gBACvC,IAAI,UAAU,CAAC,IAAI,KAAK,YAAY,EAAE,CAAC;oBACrC,MAAM,IAAI,KAAK,CAAC,uBAAuB,GAAG,wBAAwB,eAAe,EAAE,CAAC,CAAC;gBACvF,CAAC;gBAED,wDAAwD;gBACxD,MAAM,SAAS,GAAI,UAAkB,CAAC,IAAI,IAAI,CAAE,UAAkB,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC;gBAChF,IAAI,SAAS,EAAE,CAAC;oBACd,IAAI,SAAS,KAAK,WAAW,IAAI,SAAS,KAAK,WAAW,EAAE,CAAC;wBAC3D,MAAM,IAAI,KAAK,CAAC,6BAA6B,GAAG,WAAW,SAAS,iDAAiD,CAAC,CAAC;oBACzH,CAAC;oBACD,IAAI,SAAS,KAAK,cAAc,EAAE,CAAC;wBACjC,MAAM,IAAI,KAAK,CAAC,yBAAyB,GAAG,WAAW,SAAS,6CAA6C,CAAC,CAAC;oBACjH,CAAC;oBACD,IAAI,SAAS,KAAK,WAAW,IAAI,SAAS,KAAK,YAAY,EAAE,CAAC;wBAC5D,MAAM,IAAI,KAAK,CAAC,+BAA+B,GAAG,WAAW,SAAS,wCAAwC,CAAC,CAAC;oBAClH,CAAC;oBACD,IAAI,SAAS,KAAK,kBAAkB,IAAI,SAAS,KAAK,iCAAiC,EAAE,CAAC;wBACxF,MAAM,IAAI,KAAK,CAAC,2CAA2C,GAAG,WAAW,SAAS,MAAM,UAAU,CAAC,OAAO,EAAE,CAAC,CAAC;oBAChH,CAAC;gBACH,CAAC;gBAED,6CAA6C;gBAC7C,MAAM,QAAQ,GAAG,UAAU,CAAC,OAAO,CAAC,WAAW,EAAE,CAAC;gBAClD,IAAI,QAAQ,CAAC,QAAQ,CAAC,WAAW,CAAC,IAAI,QAAQ,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC;oBAC/D,MAAM,IAAI,KAAK,CAAC,6BAA6B,GAAG,iDAAiD,eAAe,EAAE,CAAC,CAAC;gBACtH,CAAC;gBACD,IAAI,QAAQ,CAAC,QAAQ,CAAC,cAAc,CAAC,IAAI,QAAQ,CAAC,QAAQ,CAAC,oBAAoB,CAAC,EAAE,CAAC;oBACjF,MAAM,IAAI,KAAK,CAAC,yBAAyB,GAAG,6CAA6C,eAAe,EAAE,CAAC,CAAC;gBAC9G,CAAC;gBACD,IAAI,QAAQ,CAAC,QAAQ,CAAC,WAAW,CAAC,IAAI,QAAQ,CAAC,QAAQ,CAAC,SAAS,CAAC,EAAE,CAAC;oBACnE,MAAM,IAAI,KAAK,CAAC,yBAAyB,GAAG,wCAAwC,eAAe,EAAE,CAAC,CAAC;gBACzG,CAAC;gBACD,IAAI,QAAQ,CAAC,QAAQ,CAAC,aAAa,CAAC,IAAI,QAAQ,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,QAAQ,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC;oBAC7F,MAAM,IAAI,KAAK,CAAC,+BAA+B,GAAG,KAAK,UAAU,CAAC,OAAO,GAAG,eAAe,EAAE,CAAC,CAAC;gBACjG,CAAC;gBACD,MAAM,IAAI,KAAK,CAAC,6BAA6B,GAAG,KAAK,UAAU,CAAC,IAAI,MAAM,UAAU,CAAC,OAAO,GAAG,eAAe,EAAE,CAAC,CAAC;YACpH,CAAC;YACD,MAAM,IAAI,KAAK,CAAC,6BAA6B,GAAG,KAAK,MAAM,CAAC,UAAU,CAAC,EAAE,CAAC,CAAC;QAC7E,CAAC;IACH,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,6BAA6B;QAC7B,IAAI,KAAK,YAAY,KAAK,EAAE,CAAC;YAC3B,IAAI,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAC,IAAI,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAC,EAAE,CAAC;gBAC/G,MAAM,KAAK,CAAC,CAAC,2BAA2B;YAC1C,CAAC;YACD,MAAM,IAAI,KAAK,CAAC,6BAA6B,GAAG,KAAK,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC;QACxE,CAAC;QACD,MAAM,IAAI,KAAK,CAAC,6BAA6B,GAAG,KAAK,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;IACxE,CAAC;IAED,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;QACjB,MAAM,SAAS,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,EAAE,CAAC,CAAC;QACxD,MAAM,IAAI,KAAK,CAAC,QAAQ,QAAQ,CAAC,MAAM,gBAAgB,GAAG,KAAK,QAAQ,CAAC,UAAU,GAAG,SAAS,CAAC,CAAC,CAAC,MAAM,SAAS,CAAC,SAAS,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;IAC/I,CAAC;IAED,MAAM,GAAG,GAAG,OAAO,CAAC,UAAU,CAAC,CAAC;IAChC,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;QACrB,SAAS,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IACtC,CAAC;IAED,MAAM,MAAM,GAAG,YAAY,EAAE,CAAC;IAC9B,MAAM,WAAW,GAAG,iBAAiB,CAAC,UAAU,CAAC,CAAC;IAElD,MAAM,QAAQ,CAAC,QAAQ,CAAC,IAAW,EAAE,MAAM,EAAE,WAAW,CAAC,CAAC;IAE1D,IAAI,cAAc,IAAI,OAAO,CAAC,QAAQ,KAAK,OAAO,EAAE,CAAC;QACnD,IAAI,CAAC;YACH,SAAS,CAAC,UAAU,EAAE,KAAK,CAAC,CAAC;QAC/B,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,OAAO,CAAC,KAAK,CAAC,kBAAkB,UAAU,cAAc,EAAE,KAAK,CAAC,CAAC;QACnE,CAAC;IACH,CAAC;AACH,CAAC;AAED;;GAEG;AACH,KAAK,UAAU,gBAAgB,CAAC,gBAAyB,IAAI,EAAE,MAAe;IAC5E,MAAM,QAAQ,GAAG,uBAAuB,EAAE,CAAC;IAC3C,MAAM,UAAU,GAAG,sBAAsB,EAAE,CAAC;IAC5C,MAAM,UAAU,GAAG,wBAAwB,CAAC;IAE5C,MAAM,UAAU,GAAG,IAAI,CAAC,QAAQ,EAAE,UAAU,CAAC,CAAC;IAC9C,MAAM,UAAU,GAAG,IAAI,CAAC,QAAQ,EAAE,UAAU,CAAC,CAAC;IAE9C,MAAM,eAAe,GAA8D,EAAE,CAAC;IAEtF,IAAI,CAAC,UAAU,CAAC,UAAU,CAAC,IAAI,aAAa,EAAE,CAAC;QAC7C,MAAM,SAAS,GAAG,GAAG,uBAAuB,IAAI,UAAU,KAAK,CAAC;QAChE,eAAe,CAAC,IAAI,CAAC,EAAE,GAAG,EAAE,SAAS,EAAE,IAAI,EAAE,UAAU,EAAE,UAAU,EAAE,IAAI,EAAE,CAAC,CAAC;QAC7E,MAAM,EAAE,IAAI,CAAC,0CAA0C,SAAS,EAAE,CAAC,CAAC;IACtE,CAAC;SAAM,IAAI,UAAU,CAAC,UAAU,CAAC,EAAE,CAAC;QAClC,MAAM,EAAE,IAAI,CAAC,gCAAgC,UAAU,EAAE,CAAC,CAAC;IAC7D,CAAC;IAED,IAAI,CAAC,UAAU,CAAC,UAAU,CAAC,IAAI,aAAa,EAAE,CAAC;QAC7C,MAAM,SAAS,GAAG,GAAG,uBAAuB,IAAI,UAAU,KAAK,CAAC;QAChE,eAAe,CAAC,IAAI,CAAC,EAAE,GAAG,EAAE,SAAS,EAAE,IAAI,EAAE,UAAU,EAAE,UAAU,EAAE,KAAK,EAAE,CAAC,CAAC;QAC9E,MAAM,EAAE,IAAI,CAAC,0CAA0C,SAAS,EAAE,CAAC,CAAC;IACtE,CAAC;SAAM,IAAI,UAAU,CAAC,UAAU,CAAC,EAAE,CAAC;QAClC,MAAM,EAAE,IAAI,CAAC,gCAAgC,UAAU,EAAE,CAAC,CAAC;IAC7D,CAAC;IAED,mFAAmF;IACnF,IAAI,eAAe,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC/B,MAAM,EAAE,IAAI,CAAC,2BAA2B,eAAe,CAAC,MAAM,yBAAyB,CAAC,CAAC;QACzF,MAAM,gBAAgB,GAAG,eAAe,CAAC,GAAG,CAAC,KAAK,EAAE,IAAI,EAAE,EAAE;YAC1D,IAAI,CAAC;gBACH,MAAM,EAAE,IAAI,CAAC,2BAA2B,IAAI,CAAC,GAAG,KAAK,CAAC,CAAC;gBACvD,MAAM,yBAAyB,CAAC,IAAI,CAAC,GAAG,EAAE,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,UAAU,CAAC,CAAC;gBACtE,MAAM,EAAE,IAAI,CAAC,6BAA6B,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC;YACzD,CAAC;YAAC,OAAO,KAAK,EAAE,CAAC;gBACf,wEAAwE;gBACxE,MAAM,QAAQ,GAAG,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;gBACxE,MAAM,EAAE,KAAK,CAAC,kCAAkC,IAAI,CAAC,GAAG,KAAK,QAAQ,EAAE,CAAC,CAAC;gBACzE,yDAAyD;gBACzD,IAAI,KAAK,YAAY,KAAK,IAAI,QAAQ,CAAC,QAAQ,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC;oBAC1D,MAAM,KAAK,CAAC,CAAC,oCAAoC;gBACnD,CAAC;gBACD,MAAM,IAAI,KAAK,CAAC,gCAAgC,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,QAAQ,SAAS,IAAI,CAAC,GAAG,KAAK,QAAQ,EAAE,CAAC,CAAC;YACzH,CAAC;QACH,CAAC,CAAC,CAAC;QAEH,+CAA+C;QAC/C,MAAM,OAAO,CAAC,GAAG,CAAC,gBAAgB,CAAC,CAAC;IACtC,CAAC;IAED,OAAO;QACL,UAAU,EAAE,UAAU,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,IAAI;QACtD,UAAU,EAAE,UAAU,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,IAAI;KACvD,CAAC;AACJ,CAAC;AAED;;GAEG;AACH,SAAS,uBAAuB,CAAC,YAAoB,IAAI;IACvD,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE;QAC7B,MAAM,MAAM,GAAG,KAAK,CAAC,YAAY,CAAC,MAAM,CAAC,CAAC;QAC1C,MAAM,UAAU,GAA8B,EAAE,CAAC;QACjD,IAAI,OAAuB,CAAC;QAC5B,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QAE7B,MAAM,CAAC,EAAE,CAAC,SAAS,EAAE,CAAC,GAAG,EAAE,EAAE;YAC3B,IAAI,CAAC;gBACH,MAAM,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,QAAQ,EAAE,CAA4B,CAAC;gBACtE,2BAA2B;gBAC3B,IAAI,OAAO,CAAC,OAAO,KAAK,iBAAiB,IAAI,OAAO,CAAC,MAAM,KAAK,OAAO,EAAE,CAAC;oBACxE,UAAU,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;oBACzB,MAAM,OAAO,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,SAAS,CAAC;oBACvC,OAAO,CAAC,GAAG,CAAC,yCAAyC,OAAO,OAAO,OAAO,CAAC,YAAY,EAAE,CAAC,CAAC;gBAC7F,CAAC;YACH,CAAC;YAAC,OAAO,KAAK,EAAE,CAAC;gBACf,sBAAsB;YACxB,CAAC;QACH,CAAC,CAAC,CAAC;QAEH,MAAM,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,GAAG,EAAE,EAAE;YACzB,YAAY,CAAC,OAAO,CAAC,CAAC;YACtB,MAAM,CAAC,KAAK,EAAE,CAAC;YACf,MAAM,OAAO,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,SAAS,CAAC;YACvC,OAAO,CAAC,GAAG,CAAC,sCAAsC,OAAO,OAAO,GAAG,CAAC,OAAO,EAAE,CAAC,CAAC;YAC/E,OAAO,CAAC,IAAI,CAAC,CAAC;QAChB,CAAC,CAAC,CAAC;QAEH,MAAM,CAAC,IAAI,CAAC,GAAG,EAAE;YACf,MAAM,CAAC,YAAY,CAAC,IAAI,CAAC,CAAC;YAC1B,OAAO,CAAC,GAAG,CAAC,gEAAgE,SAAS,QAAQ,CAAC,CAAC;YAE/F,OAAO,GAAG,UAAU,CAAC,GAAG,EAAE;gBACxB,MAAM,CAAC,KAAK,EAAE,CAAC;gBACf,MAAM,OAAO,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,SAAS,CAAC;gBACvC,IAAI,UAAU,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;oBAC1B,OAAO,CAAC,GAAG,CAAC,iCAAiC,OAAO,aAAa,UAAU,CAAC,MAAM,eAAe,CAAC,CAAC;gBACrG,CAAC;qBAAM,CAAC;oBACN,OAAO,CAAC,GAAG,CAAC,iCAAiC,OAAO,wBAAwB,CAAC,CAAC;gBAChF,CAAC;gBACD,wCAAwC;gBACxC,OAAO,CAAC,UAAU,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;YACxD,CAAC,EAAE,SAAS,CAAC,CAAC;QAChB,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;AACL,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,8BAA8B;IAM5C,MAAM,WAAW,GAAG,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,wBAAwB,CAAC;IAC3D,MAAM,WAAW,GAAG,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,wBAAwB,CAAC;IAC3D,MAAM,WAAW,GAAG,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,wBAAwB,CAAC;IAE3D,IAAI,WAAW,IAAI,WAAW,IAAI,WAAW,EAAE,CAAC;QAC9C,OAAO;YACL,WAAW,EAAE,IAAI;YACjB,WAAW,EAAE,IAAI;YACjB,WAAW,EAAE,IAAI;YACjB,MAAM,EAAE,aAAa;SACtB,CAAC;IACJ,CAAC;IAED,OAAO;QACL,WAAW;QACX,WAAW;QACX,WAAW;QACX,MAAM,EAAE,SAAS;KAClB,CAAC;AACJ,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,kBAAkB;IACtC,+DAA+D;IAC/D,uFAAuF;IACvF,IAAI,sBAAsB,EAAE,CAAC;QAC3B,kCAAkC;QAClC,IAAI,CAAC;YACH,4DAA4D;YAC5D,MAAM,YAAY,GAAG,sBAAsB,CAAC,QAAQ,KAAK,IAAI;gBACxC,sBAAsB,CAAC,MAAM,KAAK,KAAK,CAAC;YAE7D,IAAI,YAAY,EAAE,CAAC;gBACjB,kEAAkE;gBAClE,2DAA2D;gBAC3D,MAAM,UAAU,GAAG,qBAAqB,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;gBACpD,MAAM,OAAO,GAAG,UAAU,CAAC,QAAQ,CAAC,qBAAqB,CAAC;oBAC3C,UAAU,CAAC,QAAQ,CAAC,mCAAmC,CAAC,CAAC;gBAExE,IAAI,OAAO,EAAE,CAAC;oBACZ,sFAAsF;oBACtF,IAAI,CAAC;wBACH,MAAM,UAAU,GAAG,MAAM,uBAAuB,CAAC,IAAI,CAAC,CAAC,CAAC,6CAA6C;wBACrG,IAAI,UAAU,IAAI,UAAU,CAAC,MAAM,KAAK,OAAO,EAAE,CAAC;4BAChD,OAAO;gCACL,SAAS,EAAE,IAAI;gCACf,OAAO,EAAE,IAAI;gCACb,GAAG,EAAE,UAAU,CAAC,GAAG,IAAI,sBAAsB,CAAC,GAAG,IAAI,CAAC;gCACtD,YAAY,EAAE,UAAU,CAAC,YAAY;gCACrC,OAAO,EAAE,UAAU,CAAC,OAAO;6BAC5B,CAAC;wBACJ,CAAC;oBACH,CAAC;oBAAC,MAAM,CAAC;wBACP,mFAAmF;wBACnF,0CAA0C;oBAC5C,CAAC;oBAED,yEAAyE;oBACzE,mDAAmD;oBACnD,MAAM,kBAAkB,GAAG,OAAO,CAAC,GAAG,CAAC,uBAAuB,IAAI,cAAc,CAAC;oBACjF,OAAO;wBACL,SAAS,EAAE,IAAI;wBACf,OAAO,EAAE,IAAI;wBACb,GAAG,EAAE,sBAAsB,CAAC,GAAG,IAAI,CAAC;wBACpC,YAAY,EAAE,kBAAkB;wBAChC,OAAO,EAAE,iBAAiB;qBAC3B,CAAC;gBACJ,CAAC;YACH,CAAC;QACH,CAAC;QAAC,MAAM,CAAC;YACP,0CAA0C;QAC5C,CAAC;IACH,CAAC;IAED,gCAAgC;IAChC,IAAI,CAAC;QACH,MAAM,YAAY,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QAChC,MAAM,UAAU,GAAG,MAAM,uBAAuB,CAAC,IAAI,CAAC,CAAC;QACvD,MAAM,UAAU,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,YAAY,CAAC;QAC7C,IAAI,UAAU,EAAE,CAAC;YACf,OAAO,CAAC,GAAG,CAAC,sCAAsC,UAAU,OAAO,UAAU,CAAC,YAAY,EAAE,CAAC,CAAC;YAC9F,OAAO;gBACL,SAAS,EAAE,IAAI;gBACf,OAAO,EAAE,UAAU,CAAC,MAAM,KAAK,OAAO;gBACtC,GAAG,EAAE,UAAU,CAAC,GAAG;gBACnB,YAAY,EAAE,UAAU,CAAC,YAAY;gBACrC,OAAO,EAAE,UAAU,CAAC,OAAO;aAC5B,CAAC;QACJ,CAAC;aAAM,CAAC;YACN,OAAO,CAAC,GAAG,CAAC,4CAA4C,UAAU,IAAI,CAAC,CAAC;QAC1E,CAAC;IACH,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,mDAAmD;QACnD,OAAO,CAAC,GAAG,CAAC,0BAA0B,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;IAClG,CAAC;IAED,OAAO;QACL,SAAS,EAAE,KAAK;QAChB,OAAO,EAAE,KAAK;QACd,GAAG,EAAE,CAAC;KACP,CAAC;AACJ,CAAC;AAED;;;GAGG;AACH,SAAS,sCAAsC;IAC7C,MAAM,QAAQ,GAA2B;QACvC,iCAAiC,EAAE,IAAI;QACvC,oCAAoC,EAAE,MAAM;QAC5C,gCAAgC,EAAE,IAAI;QACtC,mCAAmC,EAAE,MAAM;QAC3C,sCAAsC,EAAE,MAAM;QAC9C,+CAA+C,EAAE,IAAI;QACrD,2CAA2C,EAAE,KAAK;QAClD,+CAA+C,EAAE,MAAM;KACxD,CAAC;IAEF,qDAAqD;IACrD,KAAK,MAAM,CAAC,GAAG,EAAE,YAAY,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAE,CAAC;QAC3D,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC;YACtB,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,YAAY,CAAC;QAClC,CAAC;IACH,CAAC;AACH,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,sBAAsB,CAAC,QAAgB,EAAE,QAAgB,EAAE,QAAgB;IACzF,wEAAwE;IACxE,6FAA6F;IAC7F,kHAAkH;IAClH,OAAO,CAAC,GAAG,CAAC,wBAAwB,GAAG,QAAQ,CAAC;IAChD,OAAO,CAAC,GAAG,CAAC,wBAAwB,GAAG,QAAQ,CAAC;IAChD,OAAO,CAAC,GAAG,CAAC,wBAAwB,GAAG,QAAQ,CAAC;IAEhD,gDAAgD;IAChD,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,wBAAwB,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,wBAAwB,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,wBAAwB,EAAE,CAAC;QAC5H,MAAM,IAAI,KAAK,CAAC,2FAA2F,CAAC,CAAC;IAC/G,CAAC;AACH,CAAC;AAED;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,6BAA6B,CACjD,GAAsB,EACtB,UAAmB,CAAC,wCAAwC;;IAE5D,mFAAmF;IACnF,MAAM,UAAU,GAAG,OAAO,CAAC,GAAG,CAAC,QAAQ,KAAK,GAAG,IAAI,OAAO,CAAC,GAAG,CAAC,QAAQ,KAAK,MAAM,CAAC;IACnF,MAAM,YAAY,GAAG,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,eAAe,CAAC;IACnD,MAAM,mBAAmB,GAAG,CAAC,UAAU,IAAI,YAAY,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,0BAA0B,CAAC;IACpG,MAAM,mBAAmB,GAAG,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,gCAAgC,CAAC;IAE3E,4CAA4C;IAC5C,IAAI,CAAC,mBAAmB,IAAI,CAAC,mBAAmB,EAAE,CAAC;QACjD,OAAO,IAAI,CAAC;IACd,CAAC;IAED,4EAA4E;IAC5E,MAAM,UAAU,GAAG,IAAI,CAAC;QACtB,IAAI,EAAE,oBAAoB;QAC1B,KAAK,EAAE,MAAM;KACd,EAAE,OAAO,CAAC,MAAM,CAAC,CAAC;IAEnB,UAAU,CAAC,IAAI,CAAC,oFAAoF,CAAC,CAAC;IACtG,MAAM,cAAc,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;IAElC,sEAAsE;IACtE,IAAI,CAAC;QACH,UAAU,CAAC,IAAI,CAAC,qDAAqD,CAAC,CAAC;QACvE,MAAM,QAAQ,GAAG,MAAM,wBAAwB,CAAC,UAAU,EAAE,mBAAmB,EAAE,GAAG,CAAC,CAAC;QACtF,MAAM,OAAO,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,cAAc,CAAC;QAE5C,IAAI,QAAQ,EAAE,CAAC;YACb,UAAU,CAAC,IAAI,CAAC,6BAA6B,QAAQ,oCAAoC,OAAO,KAAK,CAAC,CAAC;YACvG,OAAO,QAAQ,CAAC;QAClB,CAAC;aAAM,CAAC;YACN,UAAU,CAAC,IAAI,CAAC,wEAAwE,OAAO,KAAK,CAAC,CAAC;YACtG,OAAO,IAAI,CAAC;QACd,CAAC;IACH,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,MAAM,OAAO,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,cAAc,CAAC;QAC5C,MAAM,QAAQ,GAAG,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;QACxE,UAAU,CAAC,KAAK,CAAC,uCAAuC,OAAO,OAAO,QAAQ,EAAE,CAAC,CAAC;QAClF,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,mBAAmB,CAAC,GAAsB;IACxD,mFAAmF;IACnF,MAAM,UAAU,GAAG,OAAO,CAAC,GAAG,CAAC,QAAQ,KAAK,GAAG,IAAI,OAAO,CAAC,GAAG,CAAC,QAAQ,KAAK,MAAM,CAAC;IACnF,MAAM,YAAY,GAAG,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,eAAe,CAAC;IACnD,MAAM,mBAAmB,GAAG,CAAC,UAAU,IAAI,YAAY,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,0BAA0B,CAAC;IACpG,MAAM,mBAAmB,GAAG,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,gCAAgC,CAAC;IAE3E,4CAA4C;IAC5C,IAAI,CAAC,mBAAmB,IAAI,CAAC,mBAAmB,EAAE,CAAC;QACjD,OAAO;IACT,CAAC;IAED,4EAA4E;IAC5E,MAAM,UAAU,GAAG,IAAI,CAAC;QACtB,IAAI,EAAE,oBAAoB;QAC1B,KAAK,EAAE,MAAM;KACd,EAAE,OAAO,CAAC,MAAM,CAAC,CAAC;IAEnB,UAAU,CAAC,IAAI,CAAC,iEAAiE,CAAC,CAAC;IAEnF,2DAA2D;IAC3D,uEAAuE;IACvE,wBAAwB,CAAC,UAAU,EAAE,mBAAmB,EAAE,GAAG,CAAC;SAC3D,IAAI,CAAC,CAAC,MAAM,EAAE,EAAE;QACf,IAAI,MAAM,EAAE,CAAC;YACX,UAAU,CAAC,IAAI,CAAC,4DAA4D,MAAM,EAAE,CAAC,CAAC;YACtF,gEAAgE;YAChE,0EAA0E;QAC5E,CAAC;aAAM,CAAC;YACN,UAAU,CAAC,IAAI,CAAC,qEAAqE,CAAC,CAAC;QACzF,CAAC;IACH,CAAC,CAAC;SACD,KAAK,CAAC,CAAC,KAAK,EAAE,EAAE;QACf,MAAM,QAAQ,GAAG,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;QACxE,UAAU,CAAC,KAAK,CAAC,mDAAmD,QAAQ,EAAE,CAAC,CAAC;IAClF,CAAC,CAAC,CAAC;IAEL,0DAA0D;AAC5D,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,2BAA2B,CACzC,GAAsB,EACtB,YAAoB,KAAK;IAEzB,mFAAmF;IACnF,MAAM,UAAU,GAAG,OAAO,CAAC,GAAG,CAAC,QAAQ,KAAK,GAAG,IAAI,OAAO,CAAC,GAAG,CAAC,QAAQ,KAAK,MAAM,CAAC;IACnF,MAAM,YAAY,GAAG,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,eAAe,CAAC;IACnD,MAAM,mBAAmB,GAAG,CAAC,UAAU,IAAI,YAAY,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,0BAA0B,CAAC;IACpG,MAAM,mBAAmB,GAAG,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,gCAAgC,CAAC;IAE3E,4CAA4C;IAC5C,IAAI,CAAC,mBAAmB,IAAI,CAAC,mBAAmB,EAAE,CAAC;QACjD,OAAO,IAAI,CAAC;IACd,CAAC;IAED,4EAA4E;IAC5E,MAAM,UAAU,GAAG,IAAI,CAAC;QACtB,IAAI,EAAE,oBAAoB;QAC1B,KAAK,EAAE,MAAM;KACd,EAAE,OAAO,CAAC,MAAM,CAAC,CAAC;IAEnB,UAAU,CAAC,IAAI,CAAC,8DAA8D,CAAC,CAAC;IAEhF,wDAAwD;IACxD,IAAI,QAAQ,GAAkB,IAAI,CAAC;IACnC,IAAI,SAAS,GAAG,KAAK,CAAC;IACtB,IAAI,UAAU,GAAkB,IAAI,CAAC;IAErC,gCAAgC;IAChC,wBAAwB,CAAC,UAAU,EAAE,mBAAmB,EAAE,GAAG,CAAC;SAC3D,IAAI,CAAC,CAAC,MAAM,EAAE,EAAE;QACf,QAAQ,GAAG,MAAM,CAAC;QAClB,SAAS,GAAG,IAAI,CAAC;QACjB,IAAI,MAAM,EAAE,CAAC;YACX,UAAU,CAAC,IAAI,CAAC,8CAA8C,MAAM,EAAE,CAAC,CAAC;QAC1E,CAAC;aAAM,CAAC;YACN,UAAU,CAAC,IAAI,CAAC,qEAAqE,CAAC,CAAC;QACzF,CAAC;QACD,OAAO,MAAM,CAAC;IAChB,CAAC,CAAC;SACD,KAAK,CAAC,CAAC,KAAK,EAAE,EAAE;QACf,UAAU,GAAG,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;QACpE,SAAS,GAAG,IAAI,CAAC;QACjB,UAAU,CAAC,KAAK,CAAC,qCAAqC,UAAU,EAAE,CAAC,CAAC;QACpE,QAAQ,GAAG,IAAI,CAAC;IAClB,CAAC,CAAC,CAAC;IAEL,qDAAqD;IACrD,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;IAC7B,MAAM,SAAS,GAAG,UAAU,CAAC,GAAG,EAAE;QAChC,IAAI,CAAC,SAAS,EAAE,CAAC;YACf,UAAU,CAAC,IAAI,CAAC,wCAAwC,SAAS,6BAA6B,CAAC,CAAC;YAChG,SAAS,GAAG,IAAI,CAAC;QACnB,CAAC;IACH,CAAC,EAAE,SAAS,CAAC,CAAC;IAEd,IAAI,CAAC;QACH,qFAAqF;QACrF,OAAO,CAAC,SAAS,CAAC,GAAG,EAAE;YACrB,MAAM,OAAO,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,SAAS,CAAC;YACvC,IAAI,OAAO,IAAI,SAAS,EAAE,CAAC;gBACzB,OAAO,KAAK,CAAC,CAAC,eAAe;YAC/B,CAAC;YACD,OAAO,CAAC,SAAS,CAAC,CAAC,oCAAoC;QACzD,CAAC,CAAC,CAAC;IACL,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,UAAU,CAAC,KAAK,CAAC,6CAA6C,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;IAC1H,CAAC;IAED,YAAY,CAAC,SAAS,CAAC,CAAC;IAExB,IAAI,SAAS,IAAI,QAAQ,EAAE,CAAC;QAC1B,UAAU,CAAC,IAAI,CAAC,4DAA4D,CAAC,CAAC;QAC9E,OAAO,QAAQ,CAAC;IAClB,CAAC;SAAM,IAAI,UAAU,EAAE,CAAC;QACtB,UAAU,CAAC,KAAK,CAAC,kCAAkC,UAAU,2BAA2B,CAAC,CAAC;QAC1F,OAAO,IAAI,CAAC;IACd,CAAC;SAAM,CAAC;QACN,UAAU,CAAC,IAAI,CAAC,0EAA0E,CAAC,CAAC;QAC5F,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,cAAc,CAClC,MAAc,EACd,YAAqB,EACrB,GAAuB;IAEvB,MAAM,CAAC,IAAI,CAAC,8CAA8C,CAAC,CAAC;IAC5D,4BAA4B;IAC5B,yBAAyB,GAAG,IAAI,CAAC;IACjC,wBAAwB,GAAG,IAAI,CAAC;IAEhC,8EAA8E;IAC9E,+EAA+E;IAC/E,+EAA+E;IAC/E,iHAAiH;IACjH,IAAI,kBAAkB,GAAG,OAAO,CAAC,GAAG,CAAC,wBAAwB,CAAC;IAC9D,IAAI,kBAAkB,GAAG,OAAO,CAAC,GAAG,CAAC,wBAAwB,CAAC;IAC9D,IAAI,kBAAkB,GAAG,OAAO,CAAC,GAAG,CAAC,wBAAwB,CAAC;IAE9D,IAAI,CAAC,CAAC,kBAAkB,IAAI,CAAC,kBAAkB,IAAI,CAAC,kBAAkB,CAAC,IAAI,GAAG,EAAE,CAAC;QAC/E,IAAI,CAAC;YACH,MAAM,CAAC,IAAI,CAAC,kEAAkE,CAAC,CAAC;YAChF,MAAM,aAAa,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;YACjC,MAAM,WAAW,GAAG,MAAM,0BAA0B,CAAC,GAAG,CAAC,CAAC;YAC1D,MAAM,WAAW,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,aAAa,CAAC;YAC/C,MAAM,CAAC,IAAI,CAAC,yDAAyD,WAAW,IAAI,CAAC,CAAC;YACtF,kBAAkB,GAAG,WAAW,CAAC,QAAQ,CAAC;YAC1C,kBAAkB,GAAG,WAAW,CAAC,QAAQ,CAAC;YAC1C,kBAAkB,GAAG,WAAW,CAAC,QAAQ,CAAC;YAE1C,qHAAqH;YACrH,kHAAkH;YAClH,0GAA0G;YAC1G,sBAAsB,CAAC,kBAAkB,EAAE,kBAAkB,EAAE,kBAAkB,CAAC,CAAC;YAEnF,wEAAwE;YACxE,MAAM,cAAc,GAAG,OAAO,CAAC,GAAG,CAAC,wBAAwB,CAAC;YAC5D,MAAM,cAAc,GAAG,OAAO,CAAC,GAAG,CAAC,wBAAwB,CAAC;YAC5D,MAAM,cAAc,GAAG,OAAO,CAAC,GAAG,CAAC,wBAAwB,CAAC;YAE5D,IAAI,CAAC,cAAc,IAAI,CAAC,cAAc,IAAI,CAAC,cAAc,EAAE,CAAC;gBAC1D,MAAM,CAAC,KAAK,CAAC,wGAAwG,CAAC,CAAC;gBACvH,MAAM,IAAI,KAAK,CAAC,yDAAyD,CAAC,CAAC;YAC7E,CAAC;YAED,MAAM,CAAC,IAAI,CAAC,iFAAiF,CAAC,CAAC;QACjG,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,MAAM,QAAQ,GAAG,gEAAgE,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC;YAC1I,MAAM,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC;YACvB,MAAM,IAAI,KAAK,CAAC,QAAQ,CAAC,CAAC;QAC5B,CAAC;IACH,CAAC;IAED,iEAAiE;IACjE,0EAA0E;IAC1E,IAAI,CAAC,kBAAkB,IAAI,CAAC,kBAAkB,IAAI,CAAC,kBAAkB,EAAE,CAAC;QACtE,MAAM,QAAQ,GAAG,0LAA0L,CAAC;QAC5M,MAAM,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC;QACvB,MAAM,IAAI,KAAK,CAAC,QAAQ,CAAC,CAAC;IAC5B,CAAC;IAED,kFAAkF;IAClF,MAAM,CAAC,IAAI,CAAC,8DAA8D,CAAC,CAAC;IAC5E,MAAM,gBAAgB,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;IACpC,MAAM,aAAa,GAAG,MAAM,gBAAgB,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;IAC3D,MAAM,cAAc,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,gBAAgB,CAAC;IACrD,MAAM,CAAC,IAAI,CAAC,+DAA+D,cAAc,IAAI,CAAC,CAAC;IAE/F,IAAI,CAAC,aAAa,CAAC,UAAU,EAAE,CAAC;QAC9B,MAAM,CAAC,KAAK,CAAC,kDAAkD,CAAC,CAAC;QACjE,MAAM,IAAI,KAAK,CAAC,gDAAgD,CAAC,CAAC;IACpE,CAAC;IAED,IAAI,CAAC,aAAa,CAAC,UAAU,EAAE,CAAC;QAC9B,MAAM,CAAC,KAAK,CAAC,kDAAkD,CAAC,CAAC;QACjE,MAAM,IAAI,KAAK,CAAC,gDAAgD,CAAC,CAAC;IACpE,CAAC;IAED,MAAM,CAAC,IAAI,CAAC,6BAA6B,aAAa,CAAC,UAAU,EAAE,CAAC,CAAC;IACrE,MAAM,CAAC,IAAI,CAAC,6BAA6B,aAAa,CAAC,UAAU,EAAE,CAAC,CAAC;IAErE,uBAAuB;IACvB,IAAI,CAAC,aAAa,CAAC,UAAU,IAAI,CAAC,UAAU,CAAC,aAAa,CAAC,UAAU,CAAC,EAAE,CAAC;QACvE,MAAM,IAAI,KAAK,CAAC,iCAAiC,aAAa,CAAC,UAAU,EAAE,CAAC,CAAC;IAC/E,CAAC;IAED,sFAAsF;IACtF,IAAI,OAAO,CAAC,QAAQ,KAAK,OAAO,EAAE,CAAC;QACjC,IAAI,CAAC;YACH,MAAM,UAAU,GAAG,MAAM,MAAM,CAAC,aAAa,CAAC,CAAC;YAC/C,MAAM,KAAK,GAAG,MAAM,UAAU,CAAC,IAAI,CAAC,aAAa,CAAC,UAAU,CAAC,CAAC;YAC9D,MAAM,IAAI,GAAG,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;YAChC,MAAM,YAAY,GAAG,CAAC,CAAC,CAAC,IAAI,GAAG,QAAQ,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,oBAAoB;YACxE,IAAI,CAAC,YAAY,EAAE,CAAC;gBAClB,MAAM,CAAC,IAAI,CAAC,mDAAmD,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;gBACnF,kCAAkC;gBAClC,IAAI,CAAC;oBACH,SAAS,CAAC,aAAa,CAAC,UAAU,EAAE,KAAK,CAAC,CAAC;oBAC3C,MAAM,CAAC,IAAI,CAAC,oCAAoC,CAAC,CAAC;gBACpD,CAAC;gBAAC,OAAO,UAAU,EAAE,CAAC;oBACpB,MAAM,CAAC,KAAK,CAAC,iDAAiD,UAAU,YAAY,KAAK,CAAC,CAAC,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,UAAU,CAAC,EAAE,CAAC,CAAC;gBACzI,CAAC;YACH,CAAC;QACH,CAAC;QAAC,OAAO,SAAS,EAAE,CAAC;YACnB,MAAM,CAAC,IAAI,CAAC,mDAAmD,SAAS,YAAY,KAAK,CAAC,CAAC,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,SAAS,CAAC,EAAE,CAAC,CAAC;QACvI,CAAC;IACH,CAAC;IAED,2EAA2E;IAC3E,6FAA6F;IAC7F,uEAAuE;IACvE,sCAAsC,EAAE,CAAC;IAEzC,sHAAsH;IACtH,iDAAiD;IACjD,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,6BAA6B,EAAE,CAAC;QAC/C,OAAO,CAAC,GAAG,CAAC,6BAA6B,GAAG,MAAM,CAAC,cAAc,CAAC,CAAC;QACnE,MAAM,CAAC,IAAI,CAAC,iDAAiD,cAAc,YAAY,CAAC,CAAC;IAC3F,CAAC;IAED,0BAA0B;IAC1B,+EAA+E;IAC/E,IAAI,aAAa,GAAG,YAAY,CAAC;IACjC,IAAI,CAAC,aAAa,EAAE,CAAC;QACnB,sCAAsC;QACtC,6DAA6D;QAC7D,aAAa,GAAG,cAAc,CAAC;IACjC,CAAC;IACD,aAAa,GAAG,aAAa,CAAC,OAAO,CAAC,YAAY,EAAE,EAAE,CAAC,CAAC,OAAO,CAAC,aAAa,EAAE,EAAE,CAAC,CAAC;IAEnF,uEAAuE;IACvE,2EAA2E;IAC3E,iFAAiF;IACjF,mEAAmE;IACnE,gDAAgD;IAChD,MAAM,cAAc,GAAG,MAAM,YAAY,EAAE,CAAC;IAE5C,0CAA0C;IAC1C,6EAA6E;IAC7E,sEAAsE;IACtE,8FAA8F;IAC9F,6FAA6F;IAC7F,MAAM,YAAY,GAAsB;QACtC,GAAG,OAAO,CAAC,GAAG,EAAE,yEAAyE;QACzF,uBAAuB,EAAE,aAAa;QACtC,6BAA6B,EAAE,MAAM,CAAC,cAAc,CAAC;QACrD,8BAA8B,EAAE,MAAM,CAAC,cAAc,CAAC;KACvD,CAAC;IAEF,0BAA0B;IAC1B,MAAM,gBAAgB,GAAG,KAAK,CAAC,aAAa,CAAC,UAAU,EAAE,CAAC,UAAU,EAAE,aAAa,CAAC,UAAU,CAAC,EAAE;QAC/F,GAAG,EAAE,YAAY;QACjB,KAAK,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,CAAC;QACjC,QAAQ,EAAE,KAAK;KAChB,CAAC,CAAC;IAEH,gDAAgD;IAChD,sBAAsB,GAAG,gBAAgB,CAAC;IAC1C,yBAAyB,GAAG,IAAI,CAAC;IACjC,uBAAuB,GAAG,IAAI,CAAC;IAC/B,qBAAqB,GAAG,EAAE,CAAC;IAE3B,+EAA+E;IAC/E,gBAAgB,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,EAAE;QAC3C,MAAM,UAAU,GAAG,IAAI,CAAC,QAAQ,EAAE,CAAC,IAAI,EAAE,CAAC;QAC1C,mDAAmD;QACnD,MAAM,CAAC,IAAI,CAAC,mBAAmB,UAAU,EAAE,CAAC,CAAC;IAC/C,CAAC,CAAC,CAAC;IAEH,gBAAgB,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,EAAE;QAC3C,MAAM,SAAS,GAAG,IAAI,CAAC,QAAQ,EAAE,CAAC,IAAI,EAAE,CAAC;QACzC,qBAAqB,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;QACtC,mDAAmD;QACnD,IAAI,qBAAqB,CAAC,MAAM,GAAG,EAAE,EAAE,CAAC;YACtC,qBAAqB,CAAC,KAAK,EAAE,CAAC;QAChC,CAAC;QACD,+DAA+D;QAC/D,MAAM,CAAC,IAAI,CAAC,mBAAmB,SAAS,EAAE,CAAC,CAAC;IAC9C,CAAC,CAAC,CAAC;IAEH,gBAAgB,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,GAAG,EAAE,EAAE;QACnC,yBAAyB,GAAG,GAAG,CAAC,OAAO,CAAC;QACxC,MAAM,CAAC,KAAK,CAAC,gCAAgC,GAAG,CAAC,OAAO,EAAE,CAAC,CAAC;IAC9D,CAAC,CAAC,CAAC;IAEH,gBAAgB,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE;QAC3C,uBAAuB,GAAG,IAAI,CAAC;QAC/B,MAAM,CAAC,IAAI,CAAC,wCAAwC,IAAI,GAAG,MAAM,CAAC,CAAC,CAAC,YAAY,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;QAEjG,+DAA+D;QAC/D,IAAI,IAAI,KAAK,CAAC,IAAI,qBAAqB,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YACnD,MAAM,CAAC,KAAK,CAAC,iCAAiC,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,qBAAqB,CAAC,MAAM,CAAC,gBAAgB,CAAC,CAAC;YAC1G,qBAAqB,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,OAAO,CAAC,CAAC,IAAI,EAAE,EAAE;gBAChD,MAAM,CAAC,KAAK,CAAC,mBAAmB,IAAI,EAAE,CAAC,CAAC;YAC1C,CAAC,CAAC,CAAC;QACL,CAAC;QAED,gEAAgE;QAChE,mFAAmF;IACrF,CAAC,CAAC,CAAC;IAEH,MAAM,CAAC,IAAI,CAAC,gCAAgC,gBAAgB,CAAC,GAAG,eAAe,aAAa,EAAE,CAAC,CAAC;IAEhG,qEAAqE;IACrE,8CAA8C;IAC9C,yDAAyD;IACzD,MAAM,IAAI,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC,UAAU,CAAC,OAAO,EAAE,GAAG,CAAC,CAAC,CAAC;IAEvD,oDAAoD;IACpD,IAAI,uBAAuB,KAAK,IAAI,IAAI,uBAAuB,KAAK,CAAC,EAAE,CAAC;QACtE,MAAM,SAAS,GAAG,qBAAqB,CAAC,MAAM,GAAG,CAAC;YAChD,CAAC,CAAC,YAAY,qBAAqB,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE;YAChD,CAAC,CAAC,6BAA6B,CAAC;QAClC,MAAM,IAAI,KAAK,CAAC,gEAAgE,uBAAuB,IAAI,SAAS,EAAE,CAAC,CAAC;IAC1H,CAAC;IAED,OAAO;QACL,OAAO,EAAE,gBAAgB;QACzB,QAAQ,EAAE,UAAU,aAAa,EAAE;KACpC,CAAC;AACJ,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,yBAAyB;IAQvC,OAAO;QACL,UAAU,EAAE,sBAAsB,KAAK,IAAI;QAC3C,GAAG,EAAE,sBAAsB,EAAE,GAAG,IAAI,IAAI;QACxC,QAAQ,EAAE,uBAAuB;QACjC,UAAU,EAAE,yBAAyB;QACrC,SAAS,EAAE,wBAAwB;QACnC,MAAM,EAAE,CAAC,GAAG,qBAAqB,CAAC,EAAE,gBAAgB;KACrD,CAAC;AACJ,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,wBAAwB,CAC5C,MAAc,EACd,mBAA4B,EAC5B,GAAuB;IAEvB,IAAI,CAAC,mBAAmB,EAAE,CAAC;QACzB,OAAO,IAAI,CAAC;IACd,CAAC;IAED,8DAA8D;IAC9D,qFAAqF;IACrF,oFAAoF;IACpF,IAAI,6BAA6B,EAAE,CAAC;QAClC,MAAM,CAAC,IAAI,CAAC,gGAAgG,CAAC,CAAC;QAC9G,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,MAAM,6BAA6B,CAAC;YACnD,4DAA4D;YAC5D,6BAA6B,GAAG,IAAI,CAAC;YACrC,OAAO,MAAM,CAAC;QAChB,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,MAAM,CAAC,KAAK,CAAC,gDAAgD,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;YACvH,oCAAoC;YACpC,6BAA6B,GAAG,IAAI,CAAC;YACrC,kCAAkC;QACpC,CAAC;IACH,CAAC;IAED,0EAA0E;IAC1E,qFAAqF;IACrF,IAAI,gBAAoC,CAAC;IACzC,IAAI,sBAAsB,EAAE,CAAC;QAC3B,kCAAkC;QAClC,MAAM,YAAY,GAAG,sBAAsB,CAAC,QAAQ,KAAK,IAAI;YACxC,sBAAsB,CAAC,MAAM,KAAK,KAAK,CAAC;QAE7D,IAAI,YAAY,EAAE,CAAC;YACjB,MAAM,CAAC,IAAI,CAAC,qDAAqD,sBAAsB,CAAC,GAAG,kCAAkC,CAAC,CAAC;YAC/H,uEAAuE;YACvE,gBAAgB,GAAG,OAAO,CAAC,GAAG,CAAC,uBAAuB,CAAC,CAAC;gBACtD,UAAU,OAAO,CAAC,GAAG,CAAC,uBAAuB,EAAE,CAAC,CAAC;gBACjD,qBAAqB,CAAC;YACxB,qEAAqE;QACvE,CAAC;aAAM,CAAC;YACN,4CAA4C;YAC5C,MAAM,CAAC,IAAI,CAAC,+CAA+C,sBAAsB,CAAC,GAAG,gCAAgC,CAAC,CAAC;YACvH,sBAAsB,GAAG,IAAI,CAAC;YAC9B,uBAAuB,GAAG,IAAI,CAAC;YAC/B,qBAAqB,GAAG,EAAE,CAAC;QAC7B,CAAC;IACH,CAAC;IAED,mEAAmE;IACnE,qEAAqE;IACrE,IAAI,CAAC,sBAAsB,EAAE,CAAC;QAC5B,MAAM,CAAC,IAAI,CAAC,gFAAgF,CAAC,CAAC;QAC9F,MAAM,YAAY,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QAChC,MAAM,MAAM,GAAG,MAAM,kBAAkB,EAAE,CAAC;QAC1C,MAAM,UAAU,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,YAAY,CAAC;QAC7C,MAAM,CAAC,IAAI,CAAC,0CAA0C,UAAU,iBAAiB,MAAM,CAAC,SAAS,aAAa,MAAM,CAAC,OAAO,cAAc,MAAM,CAAC,YAAY,IAAI,MAAM,EAAE,CAAC,CAAC;QAC3K,IAAI,MAAM,CAAC,SAAS,IAAI,MAAM,CAAC,OAAO,IAAI,MAAM,CAAC,YAAY,EAAE,CAAC;YAC9D,MAAM,CAAC,IAAI,CAAC,0CAA0C,MAAM,CAAC,YAAY,EAAE,CAAC,CAAC;YAC7E,OAAO,UAAU,MAAM,CAAC,YAAY,EAAE,CAAC;QACzC,CAAC;QACD,MAAM,CAAC,IAAI,CAAC,gEAAgE,CAAC,CAAC;IAChF,CAAC;SAAM,CAAC;QACN,MAAM,CAAC,IAAI,CAAC,yEAAyE,CAAC,CAAC;IACzF,CAAC;IAED,0EAA0E;IAC1E,oEAAoE;IACpE,2EAA2E;IAC3E,MAAM,CAAC,IAAI,CAAC,yCAAyC,CAAC,CAAC;IACvD,MAAM,cAAc,GAAG,CAAC,KAAK,IAA4B,EAAE;QACzD,MAAM,CAAC,IAAI,CAAC,0CAA0C,CAAC,CAAC;QACxD,IAAI,CAAC;YACH,gCAAgC;YAChC,wBAAwB,GAAG,IAAI,CAAC;YAChC,MAAM,CAAC,IAAI,CAAC,0CAA0C,gBAAgB,IAAI,MAAM,EAAE,CAAC,CAAC;YAEpF,IAAI,QAAgB,CAAC;YACrB,IAAI,gBAAgB,EAAE,CAAC;gBACrB,2DAA2D;gBAC3D,QAAQ,GAAG,gBAAgB,CAAC;gBAC5B,MAAM,CAAC,IAAI,CAAC,iEAAiE,QAAQ,KAAK,CAAC,CAAC;YAChG,CAAC;iBAAM,CAAC;gBACN,wBAAwB;gBACxB,MAAM,CAAC,IAAI,CAAC,qDAAqD,CAAC,CAAC;gBACnE,MAAM,kBAAkB,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;gBACtC,MAAM,WAAW,GAAG,MAAM,cAAc,CAAC,MAAM,EAAE,SAAS,EAAE,GAAG,CAAC,CAAC;gBACjE,MAAM,qBAAqB,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,kBAAkB,CAAC;gBAC9D,MAAM,CAAC,IAAI,CAAC,4CAA4C,qBAAqB,iBAAiB,WAAW,CAAC,QAAQ,EAAE,CAAC,CAAC;gBACtH,QAAQ,GAAG,WAAW,CAAC,QAAQ,CAAC;gBAEhC,0DAA0D;gBAC1D,MAAM,CAAC,IAAI,CAAC,+DAA+D,CAAC,CAAC;gBAC7E,MAAM,IAAI,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC,UAAU,CAAC,OAAO,EAAE,GAAG,CAAC,CAAC,CAAC;gBAEvD,IAAI,uBAAuB,KAAK,IAAI,IAAI,uBAAuB,KAAK,CAAC,EAAE,CAAC;oBACtE,MAAM,QAAQ,GAAG,kDAAkD,uBAAuB,KAAK,qBAAqB,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,WAAW,qBAAqB,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,mBAAmB,EAAE,CAAC;oBACxM,wBAAwB,GAAG,QAAQ,CAAC;oBACpC,MAAM,CAAC,KAAK,CAAC,eAAe,QAAQ,EAAE,CAAC,CAAC;oBACxC,OAAO,IAAI,CAAC;gBACd,CAAC;gBACD,MAAM,CAAC,IAAI,CAAC,kFAAkF,CAAC,CAAC;YAClG,CAAC;YAED,kEAAkE;YAClE,oDAAoD;YACpD,kFAAkF;YAClF,MAAM,WAAW,GAAG,KAAK,CAAC,CAAC,aAAa;YACxC,MAAM,aAAa,GAAG,GAAG,CAAC,CAAC,oBAAoB;YAC/C,MAAM,SAAS,GAAG,IAAI,CAAC,KAAK,CAAC,WAAW,GAAG,aAAa,CAAC,CAAC;YAE1D,MAAM,CAAC,IAAI,CAAC,qEAAqE,aAAa,WAAW,WAAW,GAAG,IAAI,OAAO,CAAC,CAAC;YACpI,MAAM,kBAAkB,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;YAEtC,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,SAAS,EAAE,CAAC,EAAE,EAAE,CAAC;gBACnC,MAAM,IAAI,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC,UAAU,CAAC,OAAO,EAAE,aAAa,CAAC,CAAC,CAAC;gBACjE,MAAM,OAAO,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,kBAAkB,CAAC;gBAEhD,sCAAsC;gBACtC,IAAI,uBAAuB,KAAK,IAAI,IAAI,uBAAuB,KAAK,CAAC,EAAE,CAAC;oBACtE,MAAM,QAAQ,GAAG,qDAAqD,uBAAuB,KAAK,qBAAqB,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,WAAW,qBAAqB,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,mBAAmB,EAAE,CAAC;oBAC3M,wBAAwB,GAAG,QAAQ,CAAC;oBACpC,MAAM,CAAC,KAAK,CAAC,eAAe,QAAQ,WAAW,OAAO,KAAK,CAAC,CAAC;oBAC7D,OAAO,IAAI,CAAC;gBACd,CAAC;gBAED,MAAM,CAAC,IAAI,CAAC,gDAAgD,CAAC,OAAO,GAAG,IAAI,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,sBAAsB,CAAC,GAAG,CAAC,IAAI,SAAS,GAAG,CAAC,CAAC;gBACpI,MAAM,SAAS,GAAG,MAAM,kBAAkB,EAAE,CAAC;gBAC7C,MAAM,CAAC,IAAI,CAAC,2CAA2C,SAAS,CAAC,SAAS,aAAa,SAAS,CAAC,OAAO,SAAS,SAAS,CAAC,GAAG,cAAc,SAAS,CAAC,YAAY,IAAI,MAAM,EAAE,CAAC,CAAC;gBAEhL,IAAI,SAAS,CAAC,SAAS,IAAI,SAAS,CAAC,OAAO,EAAE,CAAC;oBAC7C,MAAM,CAAC,IAAI,CAAC,qCAAqC,SAAS,CAAC,YAAY,IAAI,QAAQ,iBAAiB,OAAO,KAAK,CAAC,CAAC;oBAClH,OAAO,SAAS,CAAC,YAAY,CAAC,CAAC,CAAC,UAAU,SAAS,CAAC,YAAY,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC;gBAChF,CAAC;gBAED,6CAA6C;gBAC7C,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC;oBACzB,MAAM,CAAC,IAAI,CAAC,+DAA+D,CAAC,OAAO,GAAG,IAAI,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC;gBACtH,CAAC;YACH,CAAC;YAED,wCAAwC;YACxC,IAAI,uBAAuB,KAAK,IAAI,IAAI,uBAAuB,KAAK,CAAC,EAAE,CAAC;gBACtE,MAAM,QAAQ,GAAG,sCAAsC,uBAAuB,KAAK,qBAAqB,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,WAAW,qBAAqB,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,mBAAmB,EAAE,CAAC;gBAC5L,wBAAwB,GAAG,QAAQ,CAAC;gBACpC,MAAM,CAAC,KAAK,CAAC,eAAe,QAAQ,EAAE,CAAC,CAAC;gBACxC,OAAO,IAAI,CAAC;YACd,CAAC;YAEC,gDAAgD;YAChD,MAAM,CAAC,KAAK,CAAC,qDAAqD,WAAW,GAAG,IAAI,UAAU,CAAC,CAAC;YAChG,OAAO,IAAI,CAAC;QACd,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,MAAM,QAAQ,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;YAClE,wBAAwB,GAAG,QAAQ,CAAC;YACpC,MAAM,CAAC,KAAK,CAAC,0CAA0C,QAAQ,EAAE,CAAC,CAAC;YACnE,OAAO,IAAI,CAAC;QACd,CAAC;IACH,CAAC,CAAC,EAAE,CAAC;IAEL,6EAA6E;IAC7E,6BAA6B,GAAG,cAAc,CAAC;IAE/C,iFAAiF;IACjF,cAAc,CAAC,OAAO,CAAC,GAAG,EAAE;QAC1B,6BAA6B,GAAG,IAAI,CAAC;IACvC,CAAC,CAAC,CAAC;IAEH,OAAO,MAAM,cAAc,CAAC;AAC9B,CAAC","sourcesContent":["import { spawn, ChildProcess } from 'child_process';\r\nimport { createWriteStream, existsSync, chmodSync, mkdirSync } from 'fs';\r\nimport { join, dirname } from 'path';\r\nimport { pipeline } from 'stream/promises';\r\nimport { createGunzip } from 'zlib';\r\nimport { createHash } from 'node:crypto';\r\nimport { createServer } from 'net';\r\nimport type { Logger } from 'pino';\r\nimport pino from 'pino';\r\nimport dgram from 'dgram';\r\nimport deasync from 'deasync';\r\nimport type { EnvironmentConfig } from './types.js';\r\nimport { hostToHttpUrl } from './utils/urls.js';\r\n\r\n// Protocol is httpprotobuf \r\n\r\ninterface CollectorDiscoveryEntry {\r\n version: string;\r\n status: string;\r\n pid: number;\r\n otlpEndpoint: string;\r\n}\r\n\r\nexport interface CollectorStatus {\r\n isRunning: boolean;\r\n isReady: boolean;\r\n pid: number;\r\n otlpEndpoint?: string;\r\n version?: string;\r\n}\r\n\r\nconst COLLECTOR_VERSION = '1.0.1'; // Match C# collector version (from collector-version.json)\r\nconst COLLECTOR_DOWNLOAD_BASE = `https://collectors.beamable.com/version/${COLLECTOR_VERSION}`;\r\nconst DISCOVERY_PORT = parseInt(process.env.BEAM_COLLECTOR_DISCOVERY_PORT || '8688', 10);\r\n\r\n/**\r\n * Finds a free TCP port (matching C# PortUtil.FreeTcpPort())\r\n */\r\nfunction findFreePort(): Promise<number> {\r\n return new Promise((resolve, reject) => {\r\n const server = createServer();\r\n server.listen(0, () => {\r\n const address = server.address();\r\n const port = typeof address === 'object' && address !== null ? address.port : 0;\r\n server.close(() => {\r\n if (port > 0) {\r\n resolve(port);\r\n } else {\r\n // Fallback to a default port if something went wrong\r\n resolve(9090);\r\n }\r\n });\r\n });\r\n server.on('error', (err) => {\r\n reject(err);\r\n });\r\n });\r\n}\r\n\r\n// Global storage for collector process and errors (to prevent GC and track status)\r\nlet globalCollectorProcess: ChildProcess | null = null;\r\nlet globalCollectorStartError: string | null = null;\r\nlet globalCollectorExitCode: number | null = null;\r\nlet globalCollectorStderr: string[] = [];\r\n// Track if collector startup is in progress to prevent duplicate starts\r\nlet globalCollectorStartupPromise: Promise<string | null> | null = null;\r\nlet globalCollectorInitError: string | null = null; // Tracks errors from discoverOrStartCollector\r\n\r\n/**\r\n * ClickHouse credentials response from Beamable API\r\n */\r\ninterface ClickHouseCredentials {\r\n endpoint: string;\r\n expiresAt?: string;\r\n password: string;\r\n username: string;\r\n}\r\n\r\n/**\r\n * Calculates Beamable signature for signed requests\r\n * Signature format: MD5(secret + pid + version + uriPathAndQuery + body) as Base64\r\n * Matches C# SignedRequesterHelper.CalculateSignature\r\n */\r\nfunction calculateSignature(\r\n pid: string,\r\n secret: string,\r\n uriPathAndQuery: string,\r\n body: string | null = null,\r\n version: string = '1'\r\n): string {\r\n let dataToSign = `${secret}${pid}${version}${uriPathAndQuery}`;\r\n if (body) {\r\n dataToSign += body;\r\n }\r\n \r\n // MD5 hash to Base64 (matching C# implementation)\r\n const hash = createHash('md5').update(dataToSign, 'utf8').digest('base64');\r\n return hash;\r\n}\r\n\r\n/**\r\n * Extracts path and query from a URL\r\n */\r\nfunction getPathAndQuery(url: string): string {\r\n try {\r\n const urlObj = new URL(url);\r\n return urlObj.pathname + urlObj.search;\r\n } catch {\r\n // If URL parsing fails, return as-is\r\n return url;\r\n }\r\n}\r\n\r\n/**\r\n * Fetches ClickHouse credentials from Beamable API\r\n * GET /api/beamo/otel/auth/writer/config\r\n * Requires signed request authentication (X-BEAM-SIGNATURE header)\r\n */\r\nexport async function fetchClickHouseCredentials(\r\n env: EnvironmentConfig\r\n): Promise<ClickHouseCredentials> {\r\n const apiUrl = hostToHttpUrl(env.host);\r\n const uriPath = '/api/beamo/otel/auth/writer/config';\r\n const configUrl = new URL(uriPath, apiUrl).toString();\r\n \r\n // Create a minimal logger for verbose output\r\n const verboseLogger = pino({ name: 'fetch-credentials', level: 'info' }, process.stdout);\r\n verboseLogger.info(`[Credentials] Starting credential fetch from ${configUrl}...`);\r\n \r\n // Get secret from environment (required for signed requests)\r\n const secret = process.env.SECRET;\r\n if (!secret) {\r\n verboseLogger.error('[Credentials] SECRET environment variable is missing');\r\n throw new Error('SECRET environment variable is required to fetch ClickHouse credentials');\r\n }\r\n verboseLogger.info('[Credentials] SECRET found, calculating signature...');\r\n \r\n // Calculate signature for signed request (matching C# HttpSignedRequester)\r\n const pathAndQuery = getPathAndQuery(uriPath);\r\n const signature = calculateSignature(env.pid, secret, pathAndQuery, null, '1');\r\n verboseLogger.info('[Credentials] Signature calculated, making API request...');\r\n \r\n // Build headers with signed authentication (matching C# HttpSignedRequester)\r\n const headers: Record<string, string> = {\r\n 'Content-Type': 'application/json',\r\n Accept: 'application/json',\r\n 'X-BEAM-SCOPE': `${env.cid}.${env.pid}`,\r\n 'X-BEAM-SIGNATURE': signature,\r\n };\r\n \r\n const fetchStartTime = Date.now();\r\n const response = await fetch(configUrl, {\r\n method: 'GET',\r\n headers,\r\n });\r\n const fetchElapsed = Date.now() - fetchStartTime;\r\n verboseLogger.info(`[Credentials] API request completed in ${fetchElapsed}ms, status: ${response.status}`);\r\n \r\n if (!response.ok) {\r\n const errorText = await response.text().catch(() => 'Unknown error');\r\n verboseLogger.error(`[Credentials] API request failed: ${response.status} ${response.statusText}`);\r\n throw new Error(`Failed to fetch ClickHouse credentials from ${configUrl}: ${response.status} ${response.statusText} - ${errorText.substring(0, 200)}`);\r\n }\r\n \r\n verboseLogger.info('[Credentials] Parsing response JSON...');\r\n const credentials = await response.json() as ClickHouseCredentials;\r\n \r\n if (!credentials.endpoint || !credentials.username || !credentials.password) {\r\n verboseLogger.error('[Credentials] Invalid response: missing required fields');\r\n throw new Error('Invalid ClickHouse credentials response: missing required fields');\r\n }\r\n \r\n verboseLogger.info(`[Credentials] Successfully fetched credentials (endpoint: ${credentials.endpoint}, username: ${credentials.username})`);\r\n return credentials;\r\n}\r\n\r\n/**\r\n * Gets the collector storage directory (similar to C# LocalApplicationData/beam/collectors/version)\r\n */\r\nfunction getCollectorStoragePath(): string {\r\n // Use temp directory for now - in containers this should be writable\r\n const tempDir = process.env.TMPDIR || process.env.TMP || '/tmp';\r\n return join(tempDir, 'beam', 'collectors', COLLECTOR_VERSION);\r\n}\r\n\r\n/**\r\n * Gets the collector binary name for the current platform\r\n */\r\nfunction getCollectorBinaryName(): string {\r\n const platform = process.platform;\r\n const arch = process.arch;\r\n \r\n // Match C# naming: collector-{osArchSuffix}\r\n // C# returns \"collector-linux-amd64\", not \"beamable-collector-linux-amd64\"\r\n if (platform === 'linux' && arch === 'x64') {\r\n return 'collector-linux-amd64';\r\n } else if (platform === 'linux' && arch === 'arm64') {\r\n return 'collector-linux-arm64';\r\n } else if (platform === 'darwin' && arch === 'x64') {\r\n return 'collector-darwin-amd64';\r\n } else if (platform === 'darwin' && arch === 'arm64') {\r\n return 'collector-darwin-arm64';\r\n } else if (platform === 'win32' && arch === 'x64') {\r\n return 'collector-windows-amd64.exe';\r\n }\r\n \r\n throw new Error(`Unsupported platform: ${platform} ${arch}`);\r\n}\r\n\r\n/**\r\n * Downloads and decompresses a gzipped file\r\n */\r\nasync function downloadAndDecompressGzip(url: string, outputPath: string, makeExecutable: boolean = false): Promise<void> {\r\n let response: Response;\r\n try {\r\n // Add timeout and better error handling\r\n const controller = new AbortController();\r\n const timeoutId = setTimeout(() => controller.abort(), 30000); // 30 second timeout\r\n \r\n try {\r\n response = await fetch(url, {\r\n signal: controller.signal,\r\n headers: {\r\n 'User-Agent': 'Beamable-Node-Microservice-Runtime/1.0',\r\n },\r\n });\r\n clearTimeout(timeoutId);\r\n } catch (fetchError) {\r\n clearTimeout(timeoutId);\r\n if (fetchError instanceof Error) {\r\n // Extract underlying error details from cause\r\n let underlyingError = '';\r\n if ((fetchError as any).cause) {\r\n const cause = (fetchError as any).cause;\r\n if (cause instanceof Error) {\r\n const causeCode = (cause as any).code;\r\n underlyingError = ` (cause: ${cause.name} - ${cause.message}${causeCode ? ` [code: ${causeCode}]` : ''})`;\r\n } else if (typeof cause === 'object' && cause.code) {\r\n underlyingError = ` (cause code: ${cause.code})`;\r\n }\r\n }\r\n \r\n // Provide more context about the error\r\n if (fetchError.name === 'AbortError') {\r\n throw new Error(`Timeout downloading ${url} (30s limit exceeded)${underlyingError}`);\r\n }\r\n \r\n // Check error code if available (Node.js system errors)\r\n const errorCode = (fetchError as any).code || ((fetchError as any).cause?.code);\r\n if (errorCode) {\r\n if (errorCode === 'ENOTFOUND' || errorCode === 'EAI_AGAIN') {\r\n throw new Error(`DNS resolution failed for ${url} (code: ${errorCode}). Check network connectivity and DNS settings.`);\r\n }\r\n if (errorCode === 'ECONNREFUSED') {\r\n throw new Error(`Connection refused to ${url} (code: ${errorCode}). Server may be down or firewall blocking.`);\r\n }\r\n if (errorCode === 'ETIMEDOUT' || errorCode === 'ECONNRESET') {\r\n throw new Error(`Connection timeout/reset to ${url} (code: ${errorCode}). Network may be slow or unreachable.`);\r\n }\r\n if (errorCode === 'CERT_HAS_EXPIRED' || errorCode === 'UNABLE_TO_VERIFY_LEAF_SIGNATURE') {\r\n throw new Error(`SSL/TLS certificate error connecting to ${url} (code: ${errorCode}): ${fetchError.message}`);\r\n }\r\n }\r\n \r\n // Check for common network errors in message\r\n const errorMsg = fetchError.message.toLowerCase();\r\n if (errorMsg.includes('enotfound') || errorMsg.includes('dns')) {\r\n throw new Error(`DNS resolution failed for ${url}. Check network connectivity and DNS settings.${underlyingError}`);\r\n }\r\n if (errorMsg.includes('econnrefused') || errorMsg.includes('connection refused')) {\r\n throw new Error(`Connection refused to ${url}. Server may be down or firewall blocking.${underlyingError}`);\r\n }\r\n if (errorMsg.includes('etimedout') || errorMsg.includes('timeout')) {\r\n throw new Error(`Connection timeout to ${url}. Network may be slow or unreachable.${underlyingError}`);\r\n }\r\n if (errorMsg.includes('certificate') || errorMsg.includes('ssl') || errorMsg.includes('tls')) {\r\n throw new Error(`SSL/TLS error connecting to ${url}: ${fetchError.message}${underlyingError}`);\r\n }\r\n throw new Error(`Network error downloading ${url}: ${fetchError.name} - ${fetchError.message}${underlyingError}`);\r\n }\r\n throw new Error(`Network error downloading ${url}: ${String(fetchError)}`);\r\n }\r\n } catch (error) {\r\n // Re-throw with more context\r\n if (error instanceof Error) {\r\n if (error.message.includes('Timeout') || error.message.includes('DNS') || error.message.includes('Connection')) {\r\n throw error; // Already has good context\r\n }\r\n throw new Error(`Network error downloading ${url}: ${error.message}`);\r\n }\r\n throw new Error(`Network error downloading ${url}: ${String(error)}`);\r\n }\r\n \r\n if (!response.ok) {\r\n const errorText = await response.text().catch(() => '');\r\n throw new Error(`HTTP ${response.status} downloading ${url}: ${response.statusText}${errorText ? ` - ${errorText.substring(0, 200)}` : ''}`);\r\n }\r\n \r\n const dir = dirname(outputPath);\r\n if (!existsSync(dir)) {\r\n mkdirSync(dir, { recursive: true });\r\n }\r\n \r\n const gunzip = createGunzip();\r\n const writeStream = createWriteStream(outputPath);\r\n \r\n await pipeline(response.body as any, gunzip, writeStream);\r\n \r\n if (makeExecutable && process.platform !== 'win32') {\r\n try {\r\n chmodSync(outputPath, 0o755);\r\n } catch (error) {\r\n console.error(`Failed to make ${outputPath} executable:`, error);\r\n }\r\n }\r\n}\r\n\r\n/**\r\n * Resolves the collector binary and config, downloading if needed\r\n */\r\nasync function resolveCollector(allowDownload: boolean = true, logger?: Logger): Promise<{ binaryPath: string | null; configPath: string | null }> {\r\n const basePath = getCollectorStoragePath();\r\n const binaryName = getCollectorBinaryName();\r\n const configName = 'clickhouse-config.yaml';\r\n \r\n const binaryPath = join(basePath, binaryName);\r\n const configPath = join(basePath, configName);\r\n \r\n const itemsToDownload: Array<{ url: string; path: string; executable: boolean }> = [];\r\n \r\n if (!existsSync(binaryPath) && allowDownload) {\r\n const binaryUrl = `${COLLECTOR_DOWNLOAD_BASE}/${binaryName}.gz`;\r\n itemsToDownload.push({ url: binaryUrl, path: binaryPath, executable: true });\r\n logger?.info(`[Collector] Will download binary from: ${binaryUrl}`);\r\n } else if (existsSync(binaryPath)) {\r\n logger?.info(`[Collector] Binary found at: ${binaryPath}`);\r\n }\r\n \r\n if (!existsSync(configPath) && allowDownload) {\r\n const configUrl = `${COLLECTOR_DOWNLOAD_BASE}/${configName}.gz`;\r\n itemsToDownload.push({ url: configUrl, path: configPath, executable: false });\r\n logger?.info(`[Collector] Will download config from: ${configUrl}`);\r\n } else if (existsSync(configPath)) {\r\n logger?.info(`[Collector] Config found at: ${configPath}`);\r\n }\r\n \r\n // Download items in parallel for faster startup (binary and config simultaneously)\r\n if (itemsToDownload.length > 0) {\r\n logger?.info(`[Collector] Downloading ${itemsToDownload.length} item(s) in parallel...`);\r\n const downloadPromises = itemsToDownload.map(async (item) => {\r\n try {\r\n logger?.info(`[Collector] Downloading ${item.url}...`);\r\n await downloadAndDecompressGzip(item.url, item.path, item.executable);\r\n logger?.info(`[Collector] Downloaded to ${item.path}`);\r\n } catch (error) {\r\n // Don't wrap the error again if it already contains the URL and details\r\n const errorMsg = error instanceof Error ? error.message : String(error);\r\n logger?.error(`[Collector] Failed to download ${item.url}: ${errorMsg}`);\r\n // Only wrap if the error doesn't already contain the URL\r\n if (error instanceof Error && errorMsg.includes(item.url)) {\r\n throw error; // Error already has URL and context\r\n }\r\n throw new Error(`Failed to download collector ${item.executable ? 'binary' : 'config'} from ${item.url}: ${errorMsg}`);\r\n }\r\n });\r\n \r\n // Wait for all downloads to complete (or fail)\r\n await Promise.all(downloadPromises);\r\n }\r\n \r\n return {\r\n binaryPath: existsSync(binaryPath) ? binaryPath : null,\r\n configPath: existsSync(configPath) ? configPath : null,\r\n };\r\n}\r\n\r\n/**\r\n * Discovers collector via UDP broadcast\r\n */\r\nfunction discoverCollectorViaUDP(timeoutMs: number = 5000): Promise<CollectorDiscoveryEntry | null> {\r\n return new Promise((resolve) => {\r\n const socket = dgram.createSocket('udp4');\r\n const discovered: CollectorDiscoveryEntry[] = [];\r\n let timeout: NodeJS.Timeout;\r\n const startTime = Date.now();\r\n \r\n socket.on('message', (msg) => {\r\n try {\r\n const message = JSON.parse(msg.toString()) as CollectorDiscoveryEntry;\r\n // Check if version matches\r\n if (message.version === COLLECTOR_VERSION && message.status === 'READY') {\r\n discovered.push(message);\r\n const elapsed = Date.now() - startTime;\r\n console.log(`[UDP Discovery] Found collector after ${elapsed}ms: ${message.otlpEndpoint}`);\r\n }\r\n } catch (error) {\r\n // Ignore parse errors\r\n }\r\n });\r\n \r\n socket.on('error', (err) => {\r\n clearTimeout(timeout);\r\n socket.close();\r\n const elapsed = Date.now() - startTime;\r\n console.log(`[UDP Discovery] Socket error after ${elapsed}ms: ${err.message}`);\r\n resolve(null);\r\n });\r\n \r\n socket.bind(() => {\r\n socket.setBroadcast(true);\r\n console.log(`[UDP Discovery] Listening for collector broadcasts (timeout: ${timeoutMs}ms)...`);\r\n \r\n timeout = setTimeout(() => {\r\n socket.close();\r\n const elapsed = Date.now() - startTime;\r\n if (discovered.length > 0) {\r\n console.log(`[UDP Discovery] Timeout after ${elapsed}ms, found ${discovered.length} collector(s)`);\r\n } else {\r\n console.log(`[UDP Discovery] Timeout after ${elapsed}ms, no collector found`);\r\n }\r\n // Return the first discovered collector\r\n resolve(discovered.length > 0 ? discovered[0] : null);\r\n }, timeoutMs);\r\n });\r\n });\r\n}\r\n\r\n/**\r\n * Gets the current status of ClickHouse credentials (from env or API)\r\n */\r\nexport function getClickHouseCredentialsStatus(): {\r\n hasEndpoint: boolean;\r\n hasUsername: boolean;\r\n hasPassword: boolean;\r\n source: 'environment' | 'api' | 'missing';\r\n} {\r\n const hasEndpoint = !!process.env.BEAM_CLICKHOUSE_ENDPOINT;\r\n const hasUsername = !!process.env.BEAM_CLICKHOUSE_USERNAME;\r\n const hasPassword = !!process.env.BEAM_CLICKHOUSE_PASSWORD;\r\n \r\n if (hasEndpoint && hasUsername && hasPassword) {\r\n return {\r\n hasEndpoint: true,\r\n hasUsername: true,\r\n hasPassword: true,\r\n source: 'environment',\r\n };\r\n }\r\n \r\n return {\r\n hasEndpoint,\r\n hasUsername,\r\n hasPassword,\r\n source: 'missing',\r\n };\r\n}\r\n\r\n/**\r\n * Checks if collector is already running via UDP discovery\r\n */\r\nexport async function isCollectorRunning(): Promise<CollectorStatus> {\r\n // First, check if we have a global collector process reference\r\n // If the process is running and we've seen \"Everything is ready\" in stderr, it's ready\r\n if (globalCollectorProcess) {\r\n // Check if process is still alive\r\n try {\r\n // Process is alive if we can access it and it hasn't exited\r\n const processAlive = globalCollectorProcess.exitCode === null && \r\n globalCollectorProcess.killed === false;\r\n \r\n if (processAlive) {\r\n // Check if we've seen the \"Everything is ready\" message in stderr\r\n // This is a reliable indicator that the collector is ready\r\n const stderrText = globalCollectorStderr.join('\\n');\r\n const isReady = stderrText.includes('Everything is ready') || \r\n stderrText.includes('Begin running and processing data');\r\n \r\n if (isReady) {\r\n // Try UDP discovery to get the endpoint, but if it fails, use the configured endpoint\r\n try {\r\n const discovered = await discoverCollectorViaUDP(1000); // Shorter timeout since we know it's running\r\n if (discovered && discovered.status === 'READY') {\r\n return {\r\n isRunning: true,\r\n isReady: true,\r\n pid: discovered.pid || globalCollectorProcess.pid || 0,\r\n otlpEndpoint: discovered.otlpEndpoint,\r\n version: discovered.version,\r\n };\r\n }\r\n } catch {\r\n // UDP discovery failed, but process is alive and has \"Everything is ready\" message\r\n // Use the configured endpoint as fallback\r\n }\r\n \r\n // Process is alive and we've seen \"Everything is ready\" - treat as ready\r\n // Extract endpoint from environment or use default\r\n const configuredEndpoint = process.env.BEAM_OTLP_HTTP_ENDPOINT || '0.0.0.0:4318';\r\n return {\r\n isRunning: true,\r\n isReady: true,\r\n pid: globalCollectorProcess.pid || 0,\r\n otlpEndpoint: configuredEndpoint,\r\n version: COLLECTOR_VERSION,\r\n };\r\n }\r\n }\r\n } catch {\r\n // Process might have exited or is invalid\r\n }\r\n }\r\n \r\n // Try UDP discovery as fallback\r\n try {\r\n const udpStartTime = Date.now();\r\n const discovered = await discoverCollectorViaUDP(2000);\r\n const udpElapsed = Date.now() - udpStartTime;\r\n if (discovered) {\r\n console.log(`[UDP Discovery] Found collector in ${udpElapsed}ms: ${discovered.otlpEndpoint}`);\r\n return {\r\n isRunning: true,\r\n isReady: discovered.status === 'READY',\r\n pid: discovered.pid,\r\n otlpEndpoint: discovered.otlpEndpoint,\r\n version: discovered.version,\r\n };\r\n } else {\r\n console.log(`[UDP Discovery] No collector found after ${udpElapsed}ms`);\r\n }\r\n } catch (error) {\r\n // Discovery failed, collector probably not running\r\n console.log(`[UDP Discovery] Error: ${error instanceof Error ? error.message : String(error)}`);\r\n }\r\n \r\n return {\r\n isRunning: false,\r\n isReady: false,\r\n pid: 0,\r\n };\r\n}\r\n\r\n/**\r\n * Sets default collector configuration environment variables in process.env\r\n * Matches C# CollectorManager.AddCollectorConfigurationToEnvironment()\r\n */\r\nfunction addCollectorConfigurationToEnvironment(): void {\r\n const defaults: Record<string, string> = {\r\n BEAM_CLICKHOUSE_PROCESSOR_TIMEOUT: '5s',\r\n BEAM_CLICKHOUSE_PROCESSOR_BATCH_SIZE: '5000',\r\n BEAM_CLICKHOUSE_EXPORTER_TIMEOUT: '5s',\r\n BEAM_CLICKHOUSE_EXPORTER_QUEUE_SIZE: '1000',\r\n BEAM_CLICKHOUSE_EXPORTER_RETRY_ENABLED: 'true',\r\n BEAM_CLICKHOUSE_EXPORTER_RETRY_INITIAL_INTERVAL: '5s',\r\n BEAM_CLICKHOUSE_EXPORTER_RETRY_MAX_INTERVAL: '30s',\r\n BEAM_CLICKHOUSE_EXPORTER_RETRY_MAX_ELAPSED_TIME: '300s',\r\n };\r\n \r\n // Only set if not already set (matching C# behavior)\r\n for (const [key, defaultValue] of Object.entries(defaults)) {\r\n if (!process.env[key]) {\r\n process.env[key] = defaultValue;\r\n }\r\n }\r\n}\r\n\r\n/**\r\n * Sets ClickHouse credentials in process.env (matching C# CollectorManager.AddAuthEnvironmentVars)\r\n */\r\nexport function addAuthEnvironmentVars(endpoint: string, username: string, password: string): void {\r\n // Always set the values when explicitly provided (matching C# behavior)\r\n // This ensures credentials fetched from API override any existing (potentially empty) values\r\n // In Node.js, process.env is a writable object - setting properties here persists for the lifetime of the process\r\n process.env.BEAM_CLICKHOUSE_ENDPOINT = endpoint;\r\n process.env.BEAM_CLICKHOUSE_USERNAME = username;\r\n process.env.BEAM_CLICKHOUSE_PASSWORD = password;\r\n \r\n // Verify they were actually set (for debugging)\r\n if (!process.env.BEAM_CLICKHOUSE_ENDPOINT || !process.env.BEAM_CLICKHOUSE_USERNAME || !process.env.BEAM_CLICKHOUSE_PASSWORD) {\r\n throw new Error(`Failed to set ClickHouse credentials in process.env - this should never happen in Node.js`);\r\n }\r\n}\r\n\r\n/**\r\n * Starts the collector and waits for it to be ready before returning.\r\n * This ensures Portal logs (structured logs via OTLP) only start appearing AFTER collector is ready.\r\n * Returns the OTLP endpoint when ready, or null if it times out or fails.\r\n */\r\nexport async function startCollectorAndWaitForReady(\r\n env: EnvironmentConfig,\r\n _timeoutMs?: number // Not used - kept for API compatibility\r\n): Promise<string | null> {\r\n // Match C# logic: (this.InDocker() || UseLocalOtel) && !BEAM_DISABLE_STANDARD_OTEL\r\n const isInDocker = process.env.IS_LOCAL !== '1' && process.env.IS_LOCAL !== 'true';\r\n const useLocalOtel = !!process.env.BEAM_LOCAL_OTEL;\r\n const standardOtelEnabled = (isInDocker || useLocalOtel) && !process.env.BEAM_DISABLE_STANDARD_OTEL;\r\n const hasExplicitEndpoint = !!process.env.BEAM_OTEL_EXPORTER_OTLP_ENDPOINT;\r\n\r\n // If OTLP is not needed, return immediately\r\n if (!standardOtelEnabled && !hasExplicitEndpoint) {\r\n return null;\r\n }\r\n\r\n // Create a minimal console logger for initialization messages (no OTLP yet)\r\n const initLogger = pino({\r\n name: 'beamable-otlp-init',\r\n level: 'info',\r\n }, process.stdout);\r\n\r\n initLogger.info('[OTLP] Setting up collector (waiting for readiness before enabling Portal logs)...');\r\n const setupStartTime = Date.now();\r\n\r\n // Simple linear async/await - no timeouts, no Promise.race complexity\r\n try {\r\n initLogger.info('[OTLP] Step 1: Discovering or starting collector...');\r\n const endpoint = await discoverOrStartCollector(initLogger, standardOtelEnabled, env);\r\n const elapsed = Date.now() - setupStartTime;\r\n \r\n if (endpoint) {\r\n initLogger.info(`[OTLP] Collector ready at ${endpoint}. Portal logs now enabled. (took ${elapsed}ms)`);\r\n return endpoint;\r\n } else {\r\n initLogger.warn(`[OTLP] Collector setup failed, continuing without Portal logs. (took ${elapsed}ms)`);\r\n return null;\r\n }\r\n } catch (error) {\r\n const elapsed = Date.now() - setupStartTime;\r\n const errorMsg = error instanceof Error ? error.message : String(error);\r\n initLogger.error(`[OTLP] Collector setup failed after ${elapsed}ms: ${errorMsg}`);\r\n return null;\r\n }\r\n}\r\n\r\n/**\r\n * Starts the collector asynchronously in the background (non-blocking).\r\n * This allows the service to start immediately while collector downloads/starts.\r\n * Returns immediately - collector setup happens in background.\r\n * @deprecated Use startCollectorAndWaitForReady() to ensure Portal logs only appear after collector is ready\r\n */\r\nexport function startCollectorAsync(env: EnvironmentConfig): void {\r\n // Match C# logic: (this.InDocker() || UseLocalOtel) && !BEAM_DISABLE_STANDARD_OTEL\r\n const isInDocker = process.env.IS_LOCAL !== '1' && process.env.IS_LOCAL !== 'true';\r\n const useLocalOtel = !!process.env.BEAM_LOCAL_OTEL;\r\n const standardOtelEnabled = (isInDocker || useLocalOtel) && !process.env.BEAM_DISABLE_STANDARD_OTEL;\r\n const hasExplicitEndpoint = !!process.env.BEAM_OTEL_EXPORTER_OTLP_ENDPOINT;\r\n\r\n // If OTLP is not needed, return immediately\r\n if (!standardOtelEnabled && !hasExplicitEndpoint) {\r\n return;\r\n }\r\n\r\n // Create a minimal console logger for initialization messages (no OTLP yet)\r\n const initLogger = pino({\r\n name: 'beamable-otlp-init',\r\n level: 'info',\r\n }, process.stdout);\r\n\r\n initLogger.info('[OTLP] Starting collector setup in background (non-blocking)...');\r\n\r\n // Start collector setup asynchronously - don't wait for it\r\n // The service can start immediately, collector will connect when ready\r\n discoverOrStartCollector(initLogger, standardOtelEnabled, env)\r\n .then((result) => {\r\n if (result) {\r\n initLogger.info(`[OTLP] Collector setup complete in background, endpoint: ${result}`);\r\n // Update the global logger provider if it exists to enable OTLP\r\n // The logger will automatically start using OTLP once the provider is set\r\n } else {\r\n initLogger.warn('[OTLP] Collector setup returned null, OTLP logging will be disabled');\r\n }\r\n })\r\n .catch((error) => {\r\n const errorMsg = error instanceof Error ? error.message : String(error);\r\n initLogger.error(`[OTLP] Failed to setup collector in background: ${errorMsg}`);\r\n });\r\n \r\n // Return immediately - service can start serving requests\r\n}\r\n\r\n/**\r\n * Sets up the collector BEFORE logging is initialized (DEPRECATED - blocking approach).\r\n * This function is kept for backwards compatibility but is no longer recommended.\r\n * Use startCollectorAsync() for non-blocking startup instead.\r\n * @deprecated Use startCollectorAsync() for non-blocking startup\r\n */\r\nexport function setupCollectorBeforeLogging(\r\n env: EnvironmentConfig,\r\n timeoutMs: number = 60000\r\n): string | null {\r\n // Match C# logic: (this.InDocker() || UseLocalOtel) && !BEAM_DISABLE_STANDARD_OTEL\r\n const isInDocker = process.env.IS_LOCAL !== '1' && process.env.IS_LOCAL !== 'true';\r\n const useLocalOtel = !!process.env.BEAM_LOCAL_OTEL;\r\n const standardOtelEnabled = (isInDocker || useLocalOtel) && !process.env.BEAM_DISABLE_STANDARD_OTEL;\r\n const hasExplicitEndpoint = !!process.env.BEAM_OTEL_EXPORTER_OTLP_ENDPOINT;\r\n\r\n // If OTLP is not needed, return immediately\r\n if (!standardOtelEnabled && !hasExplicitEndpoint) {\r\n return null;\r\n }\r\n\r\n // Create a minimal console logger for initialization messages (no OTLP yet)\r\n const initLogger = pino({\r\n name: 'beamable-otlp-init',\r\n level: 'info',\r\n }, process.stdout);\r\n\r\n initLogger.info('[OTLP] Setting up collector before logging initialization...');\r\n\r\n // Use deasync to wait synchronously for collector setup\r\n let endpoint: string | null = null;\r\n let completed = false;\r\n let setupError: string | null = null;\r\n\r\n // Start collector setup promise\r\n discoverOrStartCollector(initLogger, standardOtelEnabled, env)\r\n .then((result) => {\r\n endpoint = result;\r\n completed = true;\r\n if (result) {\r\n initLogger.info(`[OTLP] Collector setup complete, endpoint: ${result}`);\r\n } else {\r\n initLogger.warn('[OTLP] Collector setup returned null, OTLP logging will be disabled');\r\n }\r\n return result;\r\n })\r\n .catch((error) => {\r\n setupError = error instanceof Error ? error.message : String(error);\r\n completed = true;\r\n initLogger.error(`[OTLP] Failed to setup collector: ${setupError}`);\r\n endpoint = null;\r\n });\r\n\r\n // Wait synchronously for collector setup to complete\r\n const startTime = Date.now();\r\n const timeoutId = setTimeout(() => {\r\n if (!completed) {\r\n initLogger.warn(`[OTLP] Collector setup timeout after ${timeoutMs}ms, continuing without OTLP`);\r\n completed = true;\r\n }\r\n }, timeoutMs);\r\n\r\n try {\r\n // Use deasync to wait for completion (allows event loop to process async operations)\r\n deasync.loopWhile(() => {\r\n const elapsed = Date.now() - startTime;\r\n if (elapsed >= timeoutMs) {\r\n return false; // Stop waiting\r\n }\r\n return !completed; // Continue waiting if not completed\r\n });\r\n } catch (error) {\r\n initLogger.error(`[OTLP] Error during collector setup wait: ${error instanceof Error ? error.message : String(error)}`);\r\n }\r\n\r\n clearTimeout(timeoutId);\r\n\r\n if (completed && endpoint) {\r\n initLogger.info('[OTLP] Collector is ready, proceeding with logger creation');\r\n return endpoint;\r\n } else if (setupError) {\r\n initLogger.error(`[OTLP] Collector setup failed: ${setupError}, continuing without OTLP`);\r\n return null;\r\n } else {\r\n initLogger.warn('[OTLP] Collector setup did not complete in time, continuing without OTLP');\r\n return null;\r\n }\r\n}\r\n\r\n/**\r\n * Starts the OpenTelemetry collector process\r\n */\r\nexport async function startCollector(\r\n logger: Logger,\r\n otlpEndpoint?: string,\r\n env?: EnvironmentConfig\r\n): Promise<{ process: ChildProcess; endpoint: string }> {\r\n logger.info('[Collector] === startCollector() ENTERED ===');\r\n // Clear any previous errors\r\n globalCollectorStartError = null;\r\n globalCollectorInitError = null;\r\n \r\n // CRITICAL: Fetch credentials FIRST, before resolving collector binary/config\r\n // This ensures credentials are in process.env even if collector download fails\r\n // The credentials will persist in process.env for the lifetime of the process.\r\n // Per Gabriel: \"these OTEL related ones you need to do it yourself at the beginning of the microservice startup\"\r\n let clickhouseEndpoint = process.env.BEAM_CLICKHOUSE_ENDPOINT;\r\n let clickhouseUsername = process.env.BEAM_CLICKHOUSE_USERNAME;\r\n let clickhousePassword = process.env.BEAM_CLICKHOUSE_PASSWORD;\r\n \r\n if ((!clickhouseEndpoint || !clickhouseUsername || !clickhousePassword) && env) {\r\n try {\r\n logger.info('[Collector] Fetching ClickHouse credentials from Beamable API...');\r\n const credStartTime = Date.now();\r\n const credentials = await fetchClickHouseCredentials(env);\r\n const credElapsed = Date.now() - credStartTime;\r\n logger.info(`[Collector] ClickHouse credentials fetch completed in ${credElapsed}ms`);\r\n clickhouseEndpoint = credentials.endpoint;\r\n clickhouseUsername = credentials.username;\r\n clickhousePassword = credentials.password;\r\n \r\n // CRITICAL: Set them in process.env IMMEDIATELY after fetching (matching C# CollectorManager.AddAuthEnvironmentVars)\r\n // In Node.js, process.env is a writable object - setting properties here persists for the lifetime of the process\r\n // This ensures they're available to both the Node.js process and inherited by the collector child process\r\n addAuthEnvironmentVars(clickhouseEndpoint, clickhouseUsername, clickhousePassword);\r\n \r\n // Verify they were set (defensive check - should never fail in Node.js)\r\n const verifyEndpoint = process.env.BEAM_CLICKHOUSE_ENDPOINT;\r\n const verifyUsername = process.env.BEAM_CLICKHOUSE_USERNAME;\r\n const verifyPassword = process.env.BEAM_CLICKHOUSE_PASSWORD;\r\n \r\n if (!verifyEndpoint || !verifyUsername || !verifyPassword) {\r\n logger.error(`[Collector] CRITICAL: Credentials were set but are missing from process.env! This should never happen.`);\r\n throw new Error('Failed to persist ClickHouse credentials in process.env');\r\n }\r\n \r\n logger.info('[Collector] ClickHouse credentials fetched from API and verified in process.env');\r\n } catch (error) {\r\n const errorMsg = `[Collector] Failed to fetch ClickHouse credentials from API: ${error instanceof Error ? error.message : String(error)}`;\r\n logger.error(errorMsg);\r\n throw new Error(errorMsg);\r\n }\r\n }\r\n \r\n // Validate required environment variables (matching C# behavior)\r\n // These must be set before starting the collector, otherwise it will fail\r\n if (!clickhouseEndpoint || !clickhouseUsername || !clickhousePassword) {\r\n const errorMsg = `[Collector] Required ClickHouse credentials are missing. Set BEAM_CLICKHOUSE_ENDPOINT, BEAM_CLICKHOUSE_USERNAME, and BEAM_CLICKHOUSE_PASSWORD, or ensure the API endpoint is accessible.`;\r\n logger.error(errorMsg);\r\n throw new Error(errorMsg);\r\n }\r\n \r\n // Now resolve collector binary and config (after credentials are fetched and set)\r\n logger.info('[Collector] Step 2: Resolving collector binary and config...');\r\n const resolveStartTime = Date.now();\r\n const collectorInfo = await resolveCollector(true, logger);\r\n const resolveElapsed = Date.now() - resolveStartTime;\r\n logger.info(`[Collector] Collector binary/config resolution completed in ${resolveElapsed}ms`);\r\n \r\n if (!collectorInfo.binaryPath) {\r\n logger.error('[Collector] Binary not found and download failed');\r\n throw new Error('Collector binary not found and download failed');\r\n }\r\n \r\n if (!collectorInfo.configPath) {\r\n logger.error('[Collector] Config not found and download failed');\r\n throw new Error('Collector config not found and download failed');\r\n }\r\n \r\n logger.info(`[Collector] Using binary: ${collectorInfo.binaryPath}`);\r\n logger.info(`[Collector] Using config: ${collectorInfo.configPath}`);\r\n \r\n // Verify binary exists\r\n if (!collectorInfo.binaryPath || !existsSync(collectorInfo.binaryPath)) {\r\n throw new Error(`Collector binary not found at ${collectorInfo.binaryPath}`);\r\n }\r\n \r\n // Check if binary is executable (Unix only - Windows doesn't have execute permission)\r\n if (process.platform !== 'win32') {\r\n try {\r\n const fsPromises = await import('fs/promises');\r\n const stats = await fsPromises.stat(collectorInfo.binaryPath);\r\n const mode = Number(stats.mode);\r\n const isExecutable = !!(mode & parseInt('111', 8)); // Check execute bit\r\n if (!isExecutable) {\r\n logger.warn(`[Collector] Binary may not be executable. Mode: ${mode.toString(8)}`);\r\n // Try to make it executable again\r\n try {\r\n chmodSync(collectorInfo.binaryPath, 0o755);\r\n logger.info(`[Collector] Made binary executable`);\r\n } catch (chmodError) {\r\n logger.error(`[Collector] Failed to make binary executable: ${chmodError instanceof Error ? chmodError.message : String(chmodError)}`);\r\n }\r\n }\r\n } catch (statError) {\r\n logger.warn(`[Collector] Could not check binary permissions: ${statError instanceof Error ? statError.message : String(statError)}`);\r\n }\r\n }\r\n\r\n // Set default collector configuration environment variables in process.env\r\n // This ensures they're available to both the Node.js process and the collector child process\r\n // Matches C# CollectorManager.AddCollectorConfigurationToEnvironment()\r\n addCollectorConfigurationToEnvironment();\r\n \r\n // CRITICAL: Set BEAM_COLLECTOR_DISCOVERY_PORT if not already set (matching C# AddDefaultCollectorHostAndPortFallback)\r\n // This MUST be set before starting the collector\r\n if (!process.env.BEAM_COLLECTOR_DISCOVERY_PORT) {\r\n process.env.BEAM_COLLECTOR_DISCOVERY_PORT = String(DISCOVERY_PORT);\r\n logger.info(`[Collector] Set BEAM_COLLECTOR_DISCOVERY_PORT=${DISCOVERY_PORT} (default)`);\r\n }\r\n \r\n // Determine OTLP endpoint\r\n // Use a free port if not specified (like C# does with PortUtil.FreeEndpoint())\r\n let localEndpoint = otlpEndpoint;\r\n if (!localEndpoint) {\r\n // For now, use default OTLP HTTP port\r\n // In production, this would be discovered or set by Beamable\r\n localEndpoint = '0.0.0.0:4318';\r\n }\r\n localEndpoint = localEndpoint.replace(/^http:\\/\\//, '').replace(/^https:\\/\\//, '');\r\n \r\n // Find a free port for Prometheus (matching C# PortUtil.FreeTcpPort())\r\n // We'll use a simple approach: bind to port 0 and let the OS assign a port\r\n // For now, use a default port (9090 is common for Prometheus) or find a free one\r\n // C# uses PortUtil.FreeTcpPort() which finds an available TCP port\r\n // We'll use a simple helper to find a free port\r\n const prometheusPort = await findFreePort();\r\n \r\n // Set environment variables for collector\r\n // Note: BEAM_CLICKHOUSE_ENDPOINT is for collector → ClickHouse communication\r\n // This is different from the OTLP endpoint (microservice → collector)\r\n // The collector process will inherit all environment variables from process.env automatically\r\n // We only need to set the OTLP endpoint, discovery port, and Prometheus port explicitly here\r\n const collectorEnv: NodeJS.ProcessEnv = {\r\n ...process.env, // Inherit all process.env (including credentials and config we just set)\r\n BEAM_OTLP_HTTP_ENDPOINT: localEndpoint,\r\n BEAM_COLLECTOR_DISCOVERY_PORT: String(DISCOVERY_PORT),\r\n BEAM_COLLECTOR_PROMETHEUS_PORT: String(prometheusPort),\r\n };\r\n \r\n // Start collector process\r\n const collectorProcess = spawn(collectorInfo.binaryPath, ['--config', collectorInfo.configPath], {\r\n env: collectorEnv,\r\n stdio: ['ignore', 'pipe', 'pipe'],\r\n detached: false,\r\n });\r\n \r\n // Store globally to prevent GC and track status\r\n globalCollectorProcess = collectorProcess;\r\n globalCollectorStartError = null;\r\n globalCollectorExitCode = null;\r\n globalCollectorStderr = [];\r\n \r\n // Set up handlers BEFORE we check if process started, so we capture all output\r\n collectorProcess.stdout?.on('data', (data) => {\r\n const outputLine = data.toString().trim();\r\n // Log stdout at info level to see collector output\r\n logger.info(`[Collector OUT] ${outputLine}`);\r\n });\r\n \r\n collectorProcess.stderr?.on('data', (data) => {\r\n const errorLine = data.toString().trim();\r\n globalCollectorStderr.push(errorLine);\r\n // Keep only last 50 lines to prevent memory issues\r\n if (globalCollectorStderr.length > 50) {\r\n globalCollectorStderr.shift();\r\n }\r\n // Log stderr at info level so we can see why collector crashes\r\n logger.info(`[Collector ERR] ${errorLine}`);\r\n });\r\n \r\n collectorProcess.on('error', (err) => {\r\n globalCollectorStartError = err.message;\r\n logger.error(`[Collector] Failed to start: ${err.message}`);\r\n });\r\n \r\n collectorProcess.on('exit', (code, signal) => {\r\n globalCollectorExitCode = code;\r\n logger.warn(`[Collector] Process exited with code ${code}${signal ? `, signal ${signal}` : ''}`);\r\n \r\n // If process exited with an error code, log accumulated stderr\r\n if (code !== 0 && globalCollectorStderr.length > 0) {\r\n logger.error(`[Collector] Exit error - Last ${Math.min(10, globalCollectorStderr.length)} stderr lines:`);\r\n globalCollectorStderr.slice(-10).forEach((line) => {\r\n logger.error(`[Collector ERR] ${line}`);\r\n });\r\n }\r\n \r\n // Don't clear reference immediately - keep it for status checks\r\n // globalCollectorProcess = null; // Keep reference for getCollectorProcessStatus()\r\n });\r\n \r\n logger.info(`[Collector] Started with PID ${collectorProcess.pid}, endpoint: ${localEndpoint}`);\r\n \r\n // Give the process a moment to start and potentially write to stderr\r\n // This helps capture immediate startup errors\r\n // Wait a bit longer to ensure we catch immediate crashes\r\n await new Promise(resolve => setTimeout(resolve, 500));\r\n \r\n // Check if process already exited (immediate crash)\r\n if (globalCollectorExitCode !== null && globalCollectorExitCode !== 0) {\r\n const stderrMsg = globalCollectorStderr.length > 0 \r\n ? ` Stderr: ${globalCollectorStderr.join('; ')}` \r\n : ' No stderr output captured.';\r\n throw new Error(`Collector process exited immediately after startup with code ${globalCollectorExitCode}.${stderrMsg}`);\r\n }\r\n \r\n return {\r\n process: collectorProcess,\r\n endpoint: `http://${localEndpoint}`,\r\n };\r\n}\r\n\r\n/**\r\n * Gets detailed collector status including process info and errors\r\n */\r\nexport function getCollectorProcessStatus(): {\r\n hasProcess: boolean;\r\n pid: number | null;\r\n exitCode: number | null;\r\n startError: string | null;\r\n initError: string | null;\r\n stderr: string[];\r\n} {\r\n return {\r\n hasProcess: globalCollectorProcess !== null,\r\n pid: globalCollectorProcess?.pid ?? null,\r\n exitCode: globalCollectorExitCode,\r\n startError: globalCollectorStartError,\r\n initError: globalCollectorInitError,\r\n stderr: [...globalCollectorStderr], // Return a copy\r\n };\r\n}\r\n\r\n/**\r\n * Discovers or starts the collector and returns the OTLP endpoint\r\n */\r\nexport async function discoverOrStartCollector(\r\n logger: Logger,\r\n standardOtelEnabled: boolean,\r\n env?: EnvironmentConfig\r\n): Promise<string | null> {\r\n if (!standardOtelEnabled) {\r\n return null;\r\n }\r\n \r\n // CRITICAL: Check if collector startup is already in progress\r\n // This prevents duplicate collector starts if this function is called multiple times\r\n // (e.g., if setupCollectorBeforeLogging times out but the promise is still running)\r\n if (globalCollectorStartupPromise) {\r\n logger.info('[Collector] Collector startup already in progress, waiting for existing startup to complete...');\r\n try {\r\n const result = await globalCollectorStartupPromise;\r\n // Clear the promise after it completes (success or failure)\r\n globalCollectorStartupPromise = null;\r\n return result;\r\n } catch (error) {\r\n logger.error(`[Collector] Existing startup promise failed: ${error instanceof Error ? error.message : String(error)}`);\r\n // Clear the promise so we can retry\r\n globalCollectorStartupPromise = null;\r\n // Fall through to start a new one\r\n }\r\n }\r\n \r\n // CRITICAL: Check if we already have a collector process starting/running\r\n // This prevents duplicate collector starts if this function is called multiple times\r\n let existingEndpoint: string | undefined;\r\n if (globalCollectorProcess) {\r\n // Check if process is still alive\r\n const processAlive = globalCollectorProcess.exitCode === null && \r\n globalCollectorProcess.killed === false;\r\n \r\n if (processAlive) {\r\n logger.info(`[Collector] Collector process already exists (PID ${globalCollectorProcess.pid}), waiting for it to be ready...`);\r\n // Use the configured endpoint from environment (we started it earlier)\r\n existingEndpoint = process.env.BEAM_OTLP_HTTP_ENDPOINT ? \r\n `http://${process.env.BEAM_OTLP_HTTP_ENDPOINT}` : \r\n 'http://0.0.0.0:4318';\r\n // Fall through to the wait logic below (don't start a new collector)\r\n } else {\r\n // Process is dead, clear it and start fresh\r\n logger.warn(`[Collector] Previous collector process (PID ${globalCollectorProcess.pid}) is dead, starting new one...`);\r\n globalCollectorProcess = null;\r\n globalCollectorExitCode = null;\r\n globalCollectorStderr = [];\r\n }\r\n }\r\n \r\n // First, check if collector is already running (via UDP discovery)\r\n // Skip UDP discovery if we already have a process reference (faster)\r\n if (!globalCollectorProcess) {\r\n logger.info('[Collector] Checking for existing collector via UDP discovery (timeout: 2s)...');\r\n const udpStartTime = Date.now();\r\n const status = await isCollectorRunning();\r\n const udpElapsed = Date.now() - udpStartTime;\r\n logger.info(`[Collector] UDP discovery completed in ${udpElapsed}ms: isRunning=${status.isRunning}, isReady=${status.isReady}, endpoint=${status.otlpEndpoint || 'none'}`);\r\n if (status.isRunning && status.isReady && status.otlpEndpoint) {\r\n logger.info(`[Collector] Found running collector at ${status.otlpEndpoint}`);\r\n return `http://${status.otlpEndpoint}`;\r\n }\r\n logger.info('[Collector] No existing collector found, will start new one...');\r\n } else {\r\n logger.info('[Collector] Collector process already exists, skipping UDP discovery...');\r\n }\r\n \r\n // Collector not running - start it (or wait for existing one to be ready)\r\n // Wrap the entire startup logic in a promise that we track globally\r\n // This prevents duplicate starts if this function is called multiple times\r\n logger.info('[Collector] Creating startup promise...');\r\n const startupPromise = (async (): Promise<string | null> => {\r\n logger.info('[Collector] Startup promise executing...');\r\n try {\r\n // Clear any previous init error\r\n globalCollectorInitError = null;\r\n logger.info(`[Collector] Checking existingEndpoint: ${existingEndpoint || 'none'}`);\r\n \r\n let endpoint: string;\r\n if (existingEndpoint) {\r\n // Collector already starting, just wait for it to be ready\r\n endpoint = existingEndpoint;\r\n logger.info(`[Collector] Waiting for existing collector to become ready at ${endpoint}...`);\r\n } else {\r\n // Start a new collector\r\n logger.info('[Collector] Starting new OpenTelemetry collector...');\r\n const startCollectorTime = Date.now();\r\n const startResult = await startCollector(logger, undefined, env);\r\n const startCollectorElapsed = Date.now() - startCollectorTime;\r\n logger.info(`[Collector] Collector process started in ${startCollectorElapsed}ms, endpoint: ${startResult.endpoint}`);\r\n endpoint = startResult.endpoint;\r\n \r\n // Check if collector process exited immediately (crashed)\r\n logger.info('[Collector] Checking if collector process is still running...');\r\n await new Promise(resolve => setTimeout(resolve, 200));\r\n \r\n if (globalCollectorExitCode !== null && globalCollectorExitCode !== 0) {\r\n const errorMsg = `Collector process exited immediately with code ${globalCollectorExitCode}. ${globalCollectorStderr.length > 0 ? `Stderr: ${globalCollectorStderr.join('; ')}` : 'No stderr output.'}`;\r\n globalCollectorInitError = errorMsg;\r\n logger.error(`[Collector] ${errorMsg}`);\r\n return null;\r\n }\r\n logger.info('[Collector] Collector process is still running, proceeding to readiness check...');\r\n }\r\n \r\n // CRITICAL: Wait for collector to be fully ready before returning\r\n // We'll wait up to 60 seconds, checking every 500ms\r\n // This ensures the collector is actually ready to receive logs before we continue\r\n const maxWaitTime = 60000; // 60 seconds\r\n const checkInterval = 500; // Check every 500ms\r\n const maxChecks = Math.floor(maxWaitTime / checkInterval);\r\n \r\n logger.info(`[Collector] Waiting for collector to become ready (checking every ${checkInterval}ms, max ${maxWaitTime / 1000}s)...`);\r\n const readinessStartTime = Date.now();\r\n \r\n for (let i = 0; i < maxChecks; i++) {\r\n await new Promise(resolve => setTimeout(resolve, checkInterval));\r\n const elapsed = Date.now() - readinessStartTime;\r\n \r\n // Check if process exited during wait\r\n if (globalCollectorExitCode !== null && globalCollectorExitCode !== 0) {\r\n const errorMsg = `Collector process exited during startup with code ${globalCollectorExitCode}. ${globalCollectorStderr.length > 0 ? `Stderr: ${globalCollectorStderr.join('; ')}` : 'No stderr output.'}`;\r\n globalCollectorInitError = errorMsg;\r\n logger.error(`[Collector] ${errorMsg} (after ${elapsed}ms)`);\r\n return null;\r\n }\r\n \r\n logger.info(`[Collector] Checking collector readiness... (${(elapsed / 1000).toFixed(1)}s elapsed, attempt ${i + 1}/${maxChecks})`);\r\n const newStatus = await isCollectorRunning();\r\n logger.info(`[Collector] Collector status: isRunning=${newStatus.isRunning}, isReady=${newStatus.isReady}, pid=${newStatus.pid}, endpoint=${newStatus.otlpEndpoint || 'none'}`);\r\n \r\n if (newStatus.isRunning && newStatus.isReady) {\r\n logger.info(`[Collector] Collector is ready at ${newStatus.otlpEndpoint || endpoint} (ready after ${elapsed}ms)`);\r\n return newStatus.otlpEndpoint ? `http://${newStatus.otlpEndpoint}` : endpoint;\r\n }\r\n \r\n // Log progress every second (every 2 checks)\r\n if (i > 0 && i % 2 === 0) {\r\n logger.info(`[Collector] Still waiting for collector to become ready... (${(elapsed / 1000).toFixed(1)}s elapsed)`);\r\n }\r\n }\r\n \r\n // Check one more time if process exited\r\n if (globalCollectorExitCode !== null && globalCollectorExitCode !== 0) {\r\n const errorMsg = `Collector process exited with code ${globalCollectorExitCode}. ${globalCollectorStderr.length > 0 ? `Stderr: ${globalCollectorStderr.join('; ')}` : 'No stderr output.'}`;\r\n globalCollectorInitError = errorMsg;\r\n logger.error(`[Collector] ${errorMsg}`);\r\n return null;\r\n }\r\n \r\n // Collector did not become ready within timeout\r\n logger.error(`[Collector] Collector did not become ready within ${maxWaitTime / 1000} seconds`);\r\n return null;\r\n } catch (err) {\r\n const errorMsg = err instanceof Error ? err.message : String(err);\r\n globalCollectorInitError = errorMsg;\r\n logger.error(`[Collector] Failed to start collector: ${errorMsg}`);\r\n return null;\r\n }\r\n })();\r\n \r\n // Store the promise globally so other calls to this function can wait for it\r\n globalCollectorStartupPromise = startupPromise;\r\n \r\n // Clear the promise when it completes (so we don't keep waiting on old promises)\r\n startupPromise.finally(() => {\r\n globalCollectorStartupPromise = null;\r\n });\r\n \r\n return await startupPromise;\r\n}\r\n\r\n"]}
1
+ {"version":3,"file":"collector-manager.js","sourceRoot":"","sources":["../src/collector-manager.ts"],"names":[],"mappings":"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","sourcesContent":["import { spawn, ChildProcess } from 'child_process';\r\nimport { createWriteStream, existsSync, chmodSync, mkdirSync } from 'fs';\r\nimport { join, dirname } from 'path';\r\nimport { pipeline } from 'stream/promises';\r\nimport { createGunzip } from 'zlib';\r\nimport { createHash } from 'node:crypto';\r\nimport { createServer } from 'net';\r\nimport type { Logger } from 'pino';\r\nimport pino from 'pino';\r\nimport dgram from 'dgram';\r\nimport deasync from 'deasync';\r\nimport type { EnvironmentConfig } from './types.js';\r\nimport { hostToHttpUrl } from './utils/urls.js';\r\n\r\n// Protocol is httpprotobuf \r\n\r\ninterface CollectorDiscoveryEntry {\r\n version: string;\r\n status: string;\r\n pid: number;\r\n otlpEndpoint: string;\r\n}\r\n\r\nexport interface CollectorStatus {\r\n isRunning: boolean;\r\n isReady: boolean;\r\n pid: number;\r\n otlpEndpoint?: string;\r\n version?: string;\r\n}\r\n\r\nconst COLLECTOR_VERSION = '1.0.1'; // Match C# collector version (from collector-version.json)\r\nconst COLLECTOR_DOWNLOAD_BASE = `https://collectors.beamable.com/version/${COLLECTOR_VERSION}`;\r\nconst DISCOVERY_PORT = parseInt(process.env.BEAM_COLLECTOR_DISCOVERY_PORT || '8688', 10);\r\n\r\n/**\r\n * Finds a free TCP port (matching C# PortUtil.FreeTcpPort())\r\n */\r\nfunction findFreePort(): Promise<number> {\r\n return new Promise((resolve, reject) => {\r\n const server = createServer();\r\n server.listen(0, () => {\r\n const address = server.address();\r\n const port = typeof address === 'object' && address !== null ? address.port : 0;\r\n server.close(() => {\r\n if (port > 0) {\r\n resolve(port);\r\n } else {\r\n // Fallback to a default port if something went wrong\r\n resolve(9090);\r\n }\r\n });\r\n });\r\n server.on('error', (err) => {\r\n reject(err);\r\n });\r\n });\r\n}\r\n\r\n// Global storage for collector process and errors (to prevent GC and track status)\r\nlet globalCollectorProcess: ChildProcess | null = null;\r\nlet globalCollectorStartError: string | null = null;\r\nlet globalCollectorExitCode: number | null = null;\r\nlet globalCollectorStderr: string[] = [];\r\n// Track if collector startup is in progress to prevent duplicate starts\r\nlet globalCollectorStartupPromise: Promise<string | null> | null = null;\r\nlet globalCollectorInitError: string | null = null; // Tracks errors from discoverOrStartCollector\r\n\r\n/**\r\n * ClickHouse credentials response from Beamable API\r\n */\r\ninterface ClickHouseCredentials {\r\n endpoint: string;\r\n expiresAt?: string;\r\n password: string;\r\n username: string;\r\n}\r\n\r\n/**\r\n * Calculates Beamable signature for signed requests\r\n * Signature format: MD5(secret + pid + version + uriPathAndQuery + body) as Base64\r\n * Matches C# SignedRequesterHelper.CalculateSignature\r\n */\r\nfunction calculateSignature(\r\n pid: string,\r\n secret: string,\r\n uriPathAndQuery: string,\r\n body: string | null = null,\r\n version: string = '1'\r\n): string {\r\n let dataToSign = `${secret}${pid}${version}${uriPathAndQuery}`;\r\n if (body) {\r\n dataToSign += body;\r\n }\r\n \r\n // MD5 hash to Base64 (matching C# implementation)\r\n const hash = createHash('md5').update(dataToSign, 'utf8').digest('base64');\r\n return hash;\r\n}\r\n\r\n/**\r\n * Extracts path and query from a URL\r\n */\r\nfunction getPathAndQuery(url: string): string {\r\n try {\r\n const urlObj = new URL(url);\r\n return urlObj.pathname + urlObj.search;\r\n } catch {\r\n // If URL parsing fails, return as-is\r\n return url;\r\n }\r\n}\r\n\r\n/**\r\n * Fetches ClickHouse credentials from Beamable API\r\n * GET /api/beamo/otel/auth/writer/config\r\n * Requires signed request authentication (X-BEAM-SIGNATURE header)\r\n */\r\nexport async function fetchClickHouseCredentials(\r\n env: EnvironmentConfig\r\n): Promise<ClickHouseCredentials> {\r\n const apiUrl = hostToHttpUrl(env.host);\r\n const uriPath = '/api/beamo/otel/auth/writer/config';\r\n const configUrl = new URL(uriPath, apiUrl).toString();\r\n \r\n // Create a minimal logger for verbose output\r\n const verboseLogger = pino({ name: 'fetch-credentials', level: 'info' }, process.stdout);\r\n verboseLogger.info(`[Credentials] Starting credential fetch from ${configUrl}...`);\r\n \r\n // Get secret from environment (required for signed requests)\r\n const secret = process.env.SECRET;\r\n if (!secret) {\r\n verboseLogger.error('[Credentials] SECRET environment variable is missing');\r\n throw new Error('SECRET environment variable is required to fetch ClickHouse credentials');\r\n }\r\n verboseLogger.info('[Credentials] SECRET found, calculating signature...');\r\n \r\n // Calculate signature for signed request (matching C# HttpSignedRequester)\r\n const pathAndQuery = getPathAndQuery(uriPath);\r\n const signature = calculateSignature(env.pid, secret, pathAndQuery, null, '1');\r\n verboseLogger.info('[Credentials] Signature calculated, making API request...');\r\n \r\n // Build headers with signed authentication (matching C# HttpSignedRequester)\r\n const headers: Record<string, string> = {\r\n 'Content-Type': 'application/json',\r\n Accept: 'application/json',\r\n 'X-BEAM-SCOPE': `${env.cid}.${env.pid}`,\r\n 'X-BEAM-SIGNATURE': signature,\r\n };\r\n \r\n const fetchStartTime = Date.now();\r\n const response = await fetch(configUrl, {\r\n method: 'GET',\r\n headers,\r\n });\r\n const fetchElapsed = Date.now() - fetchStartTime;\r\n verboseLogger.info(`[Credentials] API request completed in ${fetchElapsed}ms, status: ${response.status}`);\r\n \r\n if (!response.ok) {\r\n const errorText = await response.text().catch(() => 'Unknown error');\r\n verboseLogger.error(`[Credentials] API request failed: ${response.status} ${response.statusText}`);\r\n throw new Error(`Failed to fetch ClickHouse credentials from ${configUrl}: ${response.status} ${response.statusText} - ${errorText.substring(0, 200)}`);\r\n }\r\n \r\n verboseLogger.info('[Credentials] Parsing response JSON...');\r\n const credentials = await response.json() as ClickHouseCredentials;\r\n \r\n if (!credentials.endpoint || !credentials.username || !credentials.password) {\r\n verboseLogger.error('[Credentials] Invalid response: missing required fields');\r\n throw new Error('Invalid ClickHouse credentials response: missing required fields');\r\n }\r\n \r\n verboseLogger.info(`[Credentials] Successfully fetched credentials (endpoint: ${credentials.endpoint}, username: ${credentials.username})`);\r\n return credentials;\r\n}\r\n\r\n/**\r\n * Gets the collector storage directory (similar to C# LocalApplicationData/beam/collectors/version)\r\n * Checks production location first (pre-installed in Docker), then falls back to temp directory\r\n */\r\nfunction getCollectorStoragePath(): string {\r\n // Check production location first (pre-installed in Docker image at /opt/beam/collectors)\r\n // This avoids runtime download delays (~12 seconds)\r\n const productionPath = '/opt/beam/collectors';\r\n const productionVersionPath = join(productionPath, COLLECTOR_VERSION);\r\n \r\n // Use production path if it exists (Docker image pre-installed collector)\r\n if (existsSync(productionPath)) {\r\n return productionVersionPath;\r\n }\r\n \r\n // Fallback to temp directory (local development without Docker)\r\n const tempDir = process.env.TMPDIR || process.env.TMP || '/tmp';\r\n return join(tempDir, 'beam', 'collectors', COLLECTOR_VERSION);\r\n}\r\n\r\n/**\r\n * Gets the collector binary name for the current platform\r\n */\r\nfunction getCollectorBinaryName(): string {\r\n const platform = process.platform;\r\n const arch = process.arch;\r\n \r\n // Match C# naming: collector-{osArchSuffix}\r\n // C# returns \"collector-linux-amd64\", not \"beamable-collector-linux-amd64\"\r\n if (platform === 'linux' && arch === 'x64') {\r\n return 'collector-linux-amd64';\r\n } else if (platform === 'linux' && arch === 'arm64') {\r\n return 'collector-linux-arm64';\r\n } else if (platform === 'darwin' && arch === 'x64') {\r\n return 'collector-darwin-amd64';\r\n } else if (platform === 'darwin' && arch === 'arm64') {\r\n return 'collector-darwin-arm64';\r\n } else if (platform === 'win32' && arch === 'x64') {\r\n return 'collector-windows-amd64.exe';\r\n }\r\n \r\n throw new Error(`Unsupported platform: ${platform} ${arch}`);\r\n}\r\n\r\n/**\r\n * Downloads and decompresses a gzipped file\r\n */\r\nasync function downloadAndDecompressGzip(url: string, outputPath: string, makeExecutable: boolean = false): Promise<void> {\r\n let response: Response;\r\n try {\r\n // Add timeout and better error handling\r\n const controller = new AbortController();\r\n const timeoutId = setTimeout(() => controller.abort(), 30000); // 30 second timeout\r\n \r\n try {\r\n response = await fetch(url, {\r\n signal: controller.signal,\r\n headers: {\r\n 'User-Agent': 'Beamable-Node-Microservice-Runtime/1.0',\r\n },\r\n });\r\n clearTimeout(timeoutId);\r\n } catch (fetchError) {\r\n clearTimeout(timeoutId);\r\n if (fetchError instanceof Error) {\r\n // Extract underlying error details from cause\r\n let underlyingError = '';\r\n if ((fetchError as any).cause) {\r\n const cause = (fetchError as any).cause;\r\n if (cause instanceof Error) {\r\n const causeCode = (cause as any).code;\r\n underlyingError = ` (cause: ${cause.name} - ${cause.message}${causeCode ? ` [code: ${causeCode}]` : ''})`;\r\n } else if (typeof cause === 'object' && cause.code) {\r\n underlyingError = ` (cause code: ${cause.code})`;\r\n }\r\n }\r\n \r\n // Provide more context about the error\r\n if (fetchError.name === 'AbortError') {\r\n throw new Error(`Timeout downloading ${url} (30s limit exceeded)${underlyingError}`);\r\n }\r\n \r\n // Check error code if available (Node.js system errors)\r\n const errorCode = (fetchError as any).code || ((fetchError as any).cause?.code);\r\n if (errorCode) {\r\n if (errorCode === 'ENOTFOUND' || errorCode === 'EAI_AGAIN') {\r\n throw new Error(`DNS resolution failed for ${url} (code: ${errorCode}). Check network connectivity and DNS settings.`);\r\n }\r\n if (errorCode === 'ECONNREFUSED') {\r\n throw new Error(`Connection refused to ${url} (code: ${errorCode}). Server may be down or firewall blocking.`);\r\n }\r\n if (errorCode === 'ETIMEDOUT' || errorCode === 'ECONNRESET') {\r\n throw new Error(`Connection timeout/reset to ${url} (code: ${errorCode}). Network may be slow or unreachable.`);\r\n }\r\n if (errorCode === 'CERT_HAS_EXPIRED' || errorCode === 'UNABLE_TO_VERIFY_LEAF_SIGNATURE') {\r\n throw new Error(`SSL/TLS certificate error connecting to ${url} (code: ${errorCode}): ${fetchError.message}`);\r\n }\r\n }\r\n \r\n // Check for common network errors in message\r\n const errorMsg = fetchError.message.toLowerCase();\r\n if (errorMsg.includes('enotfound') || errorMsg.includes('dns')) {\r\n throw new Error(`DNS resolution failed for ${url}. Check network connectivity and DNS settings.${underlyingError}`);\r\n }\r\n if (errorMsg.includes('econnrefused') || errorMsg.includes('connection refused')) {\r\n throw new Error(`Connection refused to ${url}. Server may be down or firewall blocking.${underlyingError}`);\r\n }\r\n if (errorMsg.includes('etimedout') || errorMsg.includes('timeout')) {\r\n throw new Error(`Connection timeout to ${url}. Network may be slow or unreachable.${underlyingError}`);\r\n }\r\n if (errorMsg.includes('certificate') || errorMsg.includes('ssl') || errorMsg.includes('tls')) {\r\n throw new Error(`SSL/TLS error connecting to ${url}: ${fetchError.message}${underlyingError}`);\r\n }\r\n throw new Error(`Network error downloading ${url}: ${fetchError.name} - ${fetchError.message}${underlyingError}`);\r\n }\r\n throw new Error(`Network error downloading ${url}: ${String(fetchError)}`);\r\n }\r\n } catch (error) {\r\n // Re-throw with more context\r\n if (error instanceof Error) {\r\n if (error.message.includes('Timeout') || error.message.includes('DNS') || error.message.includes('Connection')) {\r\n throw error; // Already has good context\r\n }\r\n throw new Error(`Network error downloading ${url}: ${error.message}`);\r\n }\r\n throw new Error(`Network error downloading ${url}: ${String(error)}`);\r\n }\r\n \r\n if (!response.ok) {\r\n const errorText = await response.text().catch(() => '');\r\n throw new Error(`HTTP ${response.status} downloading ${url}: ${response.statusText}${errorText ? ` - ${errorText.substring(0, 200)}` : ''}`);\r\n }\r\n \r\n const dir = dirname(outputPath);\r\n if (!existsSync(dir)) {\r\n mkdirSync(dir, { recursive: true });\r\n }\r\n \r\n const gunzip = createGunzip();\r\n const writeStream = createWriteStream(outputPath);\r\n \r\n await pipeline(response.body as any, gunzip, writeStream);\r\n \r\n if (makeExecutable && process.platform !== 'win32') {\r\n try {\r\n chmodSync(outputPath, 0o755);\r\n } catch (error) {\r\n console.error(`Failed to make ${outputPath} executable:`, error);\r\n }\r\n }\r\n}\r\n\r\n/**\r\n * Resolves the collector binary and config, downloading if needed\r\n */\r\nasync function resolveCollector(allowDownload: boolean = true, logger?: Logger): Promise<{ binaryPath: string | null; configPath: string | null }> {\r\n const basePath = getCollectorStoragePath();\r\n const binaryName = getCollectorBinaryName();\r\n const configName = 'clickhouse-config.yaml';\r\n \r\n const binaryPath = join(basePath, binaryName);\r\n const configPath = join(basePath, configName);\r\n \r\n const itemsToDownload: Array<{ url: string; path: string; executable: boolean }> = [];\r\n \r\n if (!existsSync(binaryPath) && allowDownload) {\r\n const binaryUrl = `${COLLECTOR_DOWNLOAD_BASE}/${binaryName}.gz`;\r\n itemsToDownload.push({ url: binaryUrl, path: binaryPath, executable: true });\r\n logger?.info(`[Collector] Will download binary from: ${binaryUrl}`);\r\n } else if (existsSync(binaryPath)) {\r\n logger?.info(`[Collector] Binary found at: ${binaryPath}`);\r\n }\r\n \r\n if (!existsSync(configPath) && allowDownload) {\r\n const configUrl = `${COLLECTOR_DOWNLOAD_BASE}/${configName}.gz`;\r\n itemsToDownload.push({ url: configUrl, path: configPath, executable: false });\r\n logger?.info(`[Collector] Will download config from: ${configUrl}`);\r\n } else if (existsSync(configPath)) {\r\n logger?.info(`[Collector] Config found at: ${configPath}`);\r\n }\r\n \r\n // Download items in parallel for faster startup (binary and config simultaneously)\r\n if (itemsToDownload.length > 0) {\r\n logger?.info(`[Collector] Downloading ${itemsToDownload.length} item(s) in parallel...`);\r\n const downloadPromises = itemsToDownload.map(async (item) => {\r\n try {\r\n logger?.info(`[Collector] Downloading ${item.url}...`);\r\n await downloadAndDecompressGzip(item.url, item.path, item.executable);\r\n logger?.info(`[Collector] Downloaded to ${item.path}`);\r\n } catch (error) {\r\n // Don't wrap the error again if it already contains the URL and details\r\n const errorMsg = error instanceof Error ? error.message : String(error);\r\n logger?.error(`[Collector] Failed to download ${item.url}: ${errorMsg}`);\r\n // Only wrap if the error doesn't already contain the URL\r\n if (error instanceof Error && errorMsg.includes(item.url)) {\r\n throw error; // Error already has URL and context\r\n }\r\n throw new Error(`Failed to download collector ${item.executable ? 'binary' : 'config'} from ${item.url}: ${errorMsg}`);\r\n }\r\n });\r\n \r\n // Wait for all downloads to complete (or fail)\r\n await Promise.all(downloadPromises);\r\n }\r\n \r\n return {\r\n binaryPath: existsSync(binaryPath) ? binaryPath : null,\r\n configPath: existsSync(configPath) ? configPath : null,\r\n };\r\n}\r\n\r\n/**\r\n * Discovers collector via UDP broadcast\r\n */\r\nfunction discoverCollectorViaUDP(timeoutMs: number = 1000): Promise<CollectorDiscoveryEntry | null> {\r\n return new Promise((resolve) => {\r\n const socket = dgram.createSocket('udp4');\r\n const discovered: CollectorDiscoveryEntry[] = [];\r\n let timeout: NodeJS.Timeout;\r\n let resolved = false; // Guard to prevent double resolution\r\n const startTime = Date.now();\r\n \r\n // Safety timeout - force resolve after timeout + 100ms buffer\r\n const safetyTimeout = setTimeout(() => {\r\n if (!resolved) {\r\n console.log(`[UDP Discovery] Safety timeout triggered - forcing resolution`);\r\n resolved = true;\r\n try {\r\n socket.removeAllListeners();\r\n socket.close();\r\n } catch (e) {\r\n // Ignore\r\n }\r\n clearTimeout(timeout);\r\n resolve(discovered.length > 0 ? discovered[0] : null);\r\n }\r\n }, timeoutMs + 100);\r\n \r\n const doResolve = (result: CollectorDiscoveryEntry | null) => {\r\n if (!resolved) {\r\n resolved = true;\r\n clearTimeout(timeout);\r\n clearTimeout(safetyTimeout);\r\n try {\r\n socket.removeAllListeners();\r\n socket.close();\r\n } catch (e) {\r\n // Ignore\r\n }\r\n console.log(`[UDP Discovery] Resolving promise with result: ${result ? 'found' : 'null'}`);\r\n resolve(result);\r\n }\r\n };\r\n \r\n socket.on('message', (msg) => {\r\n try {\r\n const message = JSON.parse(msg.toString()) as CollectorDiscoveryEntry;\r\n // Check if version matches\r\n if (message.version === COLLECTOR_VERSION && message.status === 'READY') {\r\n discovered.push(message);\r\n const elapsed = Date.now() - startTime;\r\n console.log(`[UDP Discovery] Found collector after ${elapsed}ms: ${message.otlpEndpoint}`);\r\n // Resolve immediately when collector found\r\n doResolve(discovered[0]);\r\n }\r\n } catch (error) {\r\n // Ignore parse errors\r\n }\r\n });\r\n \r\n socket.on('error', (err) => {\r\n const elapsed = Date.now() - startTime;\r\n console.log(`[UDP Discovery] Socket error after ${elapsed}ms: ${err.message}`);\r\n doResolve(null);\r\n });\r\n \r\n socket.bind(() => {\r\n socket.setBroadcast(true);\r\n console.log(`[UDP Discovery] Listening for collector broadcasts (timeout: ${timeoutMs}ms)...`);\r\n \r\n timeout = setTimeout(() => {\r\n const elapsed = Date.now() - startTime;\r\n if (discovered.length > 0) {\r\n console.log(`[UDP Discovery] Timeout after ${elapsed}ms, found ${discovered.length} collector(s)`);\r\n } else {\r\n console.log(`[UDP Discovery] Timeout after ${elapsed}ms, no collector found`);\r\n }\r\n doResolve(discovered.length > 0 ? discovered[0] : null);\r\n }, timeoutMs);\r\n });\r\n });\r\n}\r\n\r\n/**\r\n * Gets the current status of ClickHouse credentials (from env or API)\r\n */\r\nexport function getClickHouseCredentialsStatus(): {\r\n hasEndpoint: boolean;\r\n hasUsername: boolean;\r\n hasPassword: boolean;\r\n source: 'environment' | 'api' | 'missing';\r\n} {\r\n const hasEndpoint = !!process.env.BEAM_CLICKHOUSE_ENDPOINT;\r\n const hasUsername = !!process.env.BEAM_CLICKHOUSE_USERNAME;\r\n const hasPassword = !!process.env.BEAM_CLICKHOUSE_PASSWORD;\r\n \r\n if (hasEndpoint && hasUsername && hasPassword) {\r\n return {\r\n hasEndpoint: true,\r\n hasUsername: true,\r\n hasPassword: true,\r\n source: 'environment',\r\n };\r\n }\r\n \r\n return {\r\n hasEndpoint,\r\n hasUsername,\r\n hasPassword,\r\n source: 'missing',\r\n };\r\n}\r\n\r\n/**\r\n * Checks if collector is already running via UDP discovery\r\n */\r\nexport async function isCollectorRunning(): Promise<CollectorStatus> {\r\n // First, check if we have a global collector process reference\r\n // If the process is running and we've seen \"Everything is ready\" in stderr, it's ready\r\n if (globalCollectorProcess) {\r\n // Check if process is still alive\r\n try {\r\n // Process is alive if we can access it and it hasn't exited\r\n const processAlive = globalCollectorProcess.exitCode === null && \r\n globalCollectorProcess.killed === false;\r\n \r\n if (processAlive) {\r\n // Check if we've seen the \"Everything is ready\" message in stderr\r\n // This is a reliable indicator that the collector is ready\r\n const stderrText = globalCollectorStderr.join('\\n');\r\n const isReady = stderrText.includes('Everything is ready') || \r\n stderrText.includes('Begin running and processing data');\r\n \r\n if (isReady) {\r\n // Try UDP discovery to get the endpoint, but if it fails, use the configured endpoint\r\n try {\r\n const discovered = await discoverCollectorViaUDP(1000); // Shorter timeout since we know it's running\r\n if (discovered && discovered.status === 'READY') {\r\n return {\r\n isRunning: true,\r\n isReady: true,\r\n pid: discovered.pid || globalCollectorProcess.pid || 0,\r\n otlpEndpoint: discovered.otlpEndpoint,\r\n version: discovered.version,\r\n };\r\n }\r\n } catch {\r\n // UDP discovery failed, but process is alive and has \"Everything is ready\" message\r\n // Use the configured endpoint as fallback\r\n }\r\n \r\n // Process is alive and we've seen \"Everything is ready\" - treat as ready\r\n // Extract endpoint from environment or use default\r\n const configuredEndpoint = process.env.BEAM_OTLP_HTTP_ENDPOINT || '0.0.0.0:4318';\r\n return {\r\n isRunning: true,\r\n isReady: true,\r\n pid: globalCollectorProcess.pid || 0,\r\n otlpEndpoint: configuredEndpoint,\r\n version: COLLECTOR_VERSION,\r\n };\r\n }\r\n }\r\n } catch {\r\n // Process might have exited or is invalid\r\n }\r\n }\r\n \r\n // Try UDP discovery as fallback\r\n try {\r\n const udpStartTime = Date.now();\r\n console.log('[UDP Discovery] Starting UDP discovery in isCollectorRunning()...');\r\n console.log('[UDP Discovery] Calling discoverCollectorViaUDP(1000)...');\r\n const discovered = await discoverCollectorViaUDP(1000); // Match C#: 1 second max (10 attempts × 100ms)\r\n const udpElapsed = Date.now() - udpStartTime;\r\n console.log(`[UDP Discovery] UDP discovery promise resolved after ${udpElapsed}ms, result: ${discovered ? 'found' : 'null'}`);\r\n if (discovered) {\r\n console.log(`[UDP Discovery] Found collector in ${udpElapsed}ms: ${discovered.otlpEndpoint}`);\r\n return {\r\n isRunning: true,\r\n isReady: discovered.status === 'READY',\r\n pid: discovered.pid,\r\n otlpEndpoint: discovered.otlpEndpoint,\r\n version: discovered.version,\r\n };\r\n } else {\r\n console.log(`[UDP Discovery] No collector found after ${udpElapsed}ms, returning not running status`);\r\n }\r\n } catch (error) {\r\n // Discovery failed, collector probably not running\r\n const errorMsg = error instanceof Error ? error.message : String(error);\r\n console.log(`[UDP Discovery] Error in isCollectorRunning(): ${errorMsg}`);\r\n if (error instanceof Error && error.stack) {\r\n console.log(`[UDP Discovery] Error stack: ${error.stack}`);\r\n }\r\n }\r\n \r\n console.log('[UDP Discovery] Returning default not-running status from isCollectorRunning()');\r\n return {\r\n isRunning: false,\r\n isReady: false,\r\n pid: 0,\r\n };\r\n}\r\n\r\n/**\r\n * Sets default collector configuration environment variables in process.env\r\n * Matches C# CollectorManager.AddCollectorConfigurationToEnvironment()\r\n */\r\nfunction addCollectorConfigurationToEnvironment(): void {\r\n const defaults: Record<string, string> = {\r\n BEAM_CLICKHOUSE_PROCESSOR_TIMEOUT: '5s',\r\n BEAM_CLICKHOUSE_PROCESSOR_BATCH_SIZE: '5000',\r\n BEAM_CLICKHOUSE_EXPORTER_TIMEOUT: '5s',\r\n BEAM_CLICKHOUSE_EXPORTER_QUEUE_SIZE: '1000',\r\n BEAM_CLICKHOUSE_EXPORTER_RETRY_ENABLED: 'true',\r\n BEAM_CLICKHOUSE_EXPORTER_RETRY_INITIAL_INTERVAL: '5s',\r\n BEAM_CLICKHOUSE_EXPORTER_RETRY_MAX_INTERVAL: '30s',\r\n BEAM_CLICKHOUSE_EXPORTER_RETRY_MAX_ELAPSED_TIME: '300s',\r\n };\r\n \r\n // Only set if not already set (matching C# behavior)\r\n for (const [key, defaultValue] of Object.entries(defaults)) {\r\n if (!process.env[key]) {\r\n process.env[key] = defaultValue;\r\n }\r\n }\r\n}\r\n\r\n/**\r\n * Sets ClickHouse credentials in process.env (matching C# CollectorManager.AddAuthEnvironmentVars)\r\n */\r\nexport function addAuthEnvironmentVars(endpoint: string, username: string, password: string): void {\r\n // Always set the values when explicitly provided (matching C# behavior)\r\n // This ensures credentials fetched from API override any existing (potentially empty) values\r\n // In Node.js, process.env is a writable object - setting properties here persists for the lifetime of the process\r\n process.env.BEAM_CLICKHOUSE_ENDPOINT = endpoint;\r\n process.env.BEAM_CLICKHOUSE_USERNAME = username;\r\n process.env.BEAM_CLICKHOUSE_PASSWORD = password;\r\n \r\n // Verify they were actually set (for debugging)\r\n if (!process.env.BEAM_CLICKHOUSE_ENDPOINT || !process.env.BEAM_CLICKHOUSE_USERNAME || !process.env.BEAM_CLICKHOUSE_PASSWORD) {\r\n throw new Error(`Failed to set ClickHouse credentials in process.env - this should never happen in Node.js`);\r\n }\r\n}\r\n\r\n/**\r\n * Starts the collector and waits for it to be ready before returning.\r\n * This ensures Portal logs (structured logs via OTLP) only start appearing AFTER collector is ready.\r\n * Returns the OTLP endpoint when ready, or null if it times out or fails.\r\n */\r\nexport async function startCollectorAndWaitForReady(\r\n env: EnvironmentConfig,\r\n _timeoutMs?: number // Not used - kept for API compatibility\r\n): Promise<string | null> {\r\n // Match C# logic: (this.InDocker() || UseLocalOtel) && !BEAM_DISABLE_STANDARD_OTEL\r\n const isInDocker = process.env.IS_LOCAL !== '1' && process.env.IS_LOCAL !== 'true';\r\n const useLocalOtel = !!process.env.BEAM_LOCAL_OTEL;\r\n const standardOtelEnabled = (isInDocker || useLocalOtel) && !process.env.BEAM_DISABLE_STANDARD_OTEL;\r\n const hasExplicitEndpoint = !!process.env.BEAM_OTEL_EXPORTER_OTLP_ENDPOINT;\r\n\r\n // If OTLP is not needed, return immediately\r\n if (!standardOtelEnabled && !hasExplicitEndpoint) {\r\n return null;\r\n }\r\n\r\n // Create a minimal console logger for initialization messages (no OTLP yet)\r\n const initLogger = pino({\r\n name: 'beamable-otlp-init',\r\n level: 'info',\r\n }, process.stdout);\r\n\r\n initLogger.info('[OTLP] Setting up collector (waiting for readiness before enabling Portal logs)...');\r\n const setupStartTime = Date.now();\r\n\r\n // Simple linear async/await - no timeouts, no Promise.race complexity\r\n try {\r\n initLogger.info('[OTLP] Step 1: Discovering or starting collector...');\r\n const endpoint = await discoverOrStartCollector(initLogger, standardOtelEnabled, env);\r\n const elapsed = Date.now() - setupStartTime;\r\n \r\n if (endpoint) {\r\n initLogger.info(`[OTLP] Collector ready at ${endpoint}. Portal logs now enabled. (took ${elapsed}ms)`);\r\n return endpoint;\r\n } else {\r\n initLogger.warn(`[OTLP] Collector setup failed, continuing without Portal logs. (took ${elapsed}ms)`);\r\n return null;\r\n }\r\n } catch (error) {\r\n const elapsed = Date.now() - setupStartTime;\r\n const errorMsg = error instanceof Error ? error.message : String(error);\r\n initLogger.error(`[OTLP] Collector setup failed after ${elapsed}ms: ${errorMsg}`);\r\n return null;\r\n }\r\n}\r\n\r\n/**\r\n * Starts the collector asynchronously in the background (non-blocking).\r\n * This allows the service to start immediately while collector downloads/starts.\r\n * Returns immediately - collector setup happens in background.\r\n * @deprecated Use startCollectorAndWaitForReady() to ensure Portal logs only appear after collector is ready\r\n */\r\nexport function startCollectorAsync(env: EnvironmentConfig): void {\r\n // Match C# logic: (this.InDocker() || UseLocalOtel) && !BEAM_DISABLE_STANDARD_OTEL\r\n const isInDocker = process.env.IS_LOCAL !== '1' && process.env.IS_LOCAL !== 'true';\r\n const useLocalOtel = !!process.env.BEAM_LOCAL_OTEL;\r\n const standardOtelEnabled = (isInDocker || useLocalOtel) && !process.env.BEAM_DISABLE_STANDARD_OTEL;\r\n const hasExplicitEndpoint = !!process.env.BEAM_OTEL_EXPORTER_OTLP_ENDPOINT;\r\n\r\n // If OTLP is not needed, return immediately\r\n if (!standardOtelEnabled && !hasExplicitEndpoint) {\r\n return;\r\n }\r\n\r\n // Create a minimal console logger for initialization messages (no OTLP yet)\r\n const initLogger = pino({\r\n name: 'beamable-otlp-init',\r\n level: 'info',\r\n }, process.stdout);\r\n\r\n initLogger.info('[OTLP] Starting collector setup in background (non-blocking)...');\r\n\r\n // Start collector setup asynchronously - don't wait for it\r\n // The service can start immediately, collector will connect when ready\r\n discoverOrStartCollector(initLogger, standardOtelEnabled, env)\r\n .then((result) => {\r\n if (result) {\r\n initLogger.info(`[OTLP] Collector setup complete in background, endpoint: ${result}`);\r\n // Update the global logger provider if it exists to enable OTLP\r\n // The logger will automatically start using OTLP once the provider is set\r\n } else {\r\n initLogger.warn('[OTLP] Collector setup returned null, OTLP logging will be disabled');\r\n }\r\n })\r\n .catch((error) => {\r\n const errorMsg = error instanceof Error ? error.message : String(error);\r\n initLogger.error(`[OTLP] Failed to setup collector in background: ${errorMsg}`);\r\n });\r\n \r\n // Return immediately - service can start serving requests\r\n}\r\n\r\n/**\r\n * Sets up the collector BEFORE logging is initialized (DEPRECATED - blocking approach).\r\n * This function is kept for backwards compatibility but is no longer recommended.\r\n * Use startCollectorAsync() for non-blocking startup instead.\r\n * @deprecated Use startCollectorAsync() for non-blocking startup\r\n */\r\nexport function setupCollectorBeforeLogging(\r\n env: EnvironmentConfig,\r\n timeoutMs: number = 60000\r\n): string | null {\r\n // Match C# logic: (this.InDocker() || UseLocalOtel) && !BEAM_DISABLE_STANDARD_OTEL\r\n const isInDocker = process.env.IS_LOCAL !== '1' && process.env.IS_LOCAL !== 'true';\r\n const useLocalOtel = !!process.env.BEAM_LOCAL_OTEL;\r\n const standardOtelEnabled = (isInDocker || useLocalOtel) && !process.env.BEAM_DISABLE_STANDARD_OTEL;\r\n const hasExplicitEndpoint = !!process.env.BEAM_OTEL_EXPORTER_OTLP_ENDPOINT;\r\n\r\n // If OTLP is not needed, return immediately\r\n if (!standardOtelEnabled && !hasExplicitEndpoint) {\r\n return null;\r\n }\r\n\r\n // Create a minimal console logger for initialization messages (no OTLP yet)\r\n const initLogger = pino({\r\n name: 'beamable-otlp-init',\r\n level: 'info',\r\n }, process.stdout);\r\n\r\n initLogger.info('[OTLP] Setting up collector before logging initialization...');\r\n\r\n // Use deasync to wait synchronously for collector setup\r\n let endpoint: string | null = null;\r\n let completed = false;\r\n let setupError: string | null = null;\r\n\r\n // Start collector setup promise\r\n discoverOrStartCollector(initLogger, standardOtelEnabled, env)\r\n .then((result) => {\r\n endpoint = result;\r\n completed = true;\r\n if (result) {\r\n initLogger.info(`[OTLP] Collector setup complete, endpoint: ${result}`);\r\n } else {\r\n initLogger.warn('[OTLP] Collector setup returned null, OTLP logging will be disabled');\r\n }\r\n return result;\r\n })\r\n .catch((error) => {\r\n setupError = error instanceof Error ? error.message : String(error);\r\n completed = true;\r\n initLogger.error(`[OTLP] Failed to setup collector: ${setupError}`);\r\n endpoint = null;\r\n });\r\n\r\n // Wait synchronously for collector setup to complete\r\n const startTime = Date.now();\r\n const timeoutId = setTimeout(() => {\r\n if (!completed) {\r\n initLogger.warn(`[OTLP] Collector setup timeout after ${timeoutMs}ms, continuing without OTLP`);\r\n completed = true;\r\n }\r\n }, timeoutMs);\r\n\r\n try {\r\n // Use deasync to wait for completion (allows event loop to process async operations)\r\n deasync.loopWhile(() => {\r\n const elapsed = Date.now() - startTime;\r\n if (elapsed >= timeoutMs) {\r\n return false; // Stop waiting\r\n }\r\n return !completed; // Continue waiting if not completed\r\n });\r\n } catch (error) {\r\n initLogger.error(`[OTLP] Error during collector setup wait: ${error instanceof Error ? error.message : String(error)}`);\r\n }\r\n\r\n clearTimeout(timeoutId);\r\n\r\n if (completed && endpoint) {\r\n initLogger.info('[OTLP] Collector is ready, proceeding with logger creation');\r\n return endpoint;\r\n } else if (setupError) {\r\n initLogger.error(`[OTLP] Collector setup failed: ${setupError}, continuing without OTLP`);\r\n return null;\r\n } else {\r\n initLogger.warn('[OTLP] Collector setup did not complete in time, continuing without OTLP');\r\n return null;\r\n }\r\n}\r\n\r\n/**\r\n * Starts the OpenTelemetry collector process\r\n */\r\nexport async function startCollector(\r\n logger: Logger,\r\n otlpEndpoint?: string,\r\n env?: EnvironmentConfig\r\n): Promise<{ process: ChildProcess; endpoint: string }> {\r\n logger.info('[Collector] === startCollector() ENTERED ===');\r\n // Clear any previous errors\r\n globalCollectorStartError = null;\r\n globalCollectorInitError = null;\r\n \r\n // CRITICAL: Fetch credentials FIRST, before resolving collector binary/config\r\n // This ensures credentials are in process.env even if collector download fails\r\n // The credentials will persist in process.env for the lifetime of the process.\r\n // Per Gabriel: \"these OTEL related ones you need to do it yourself at the beginning of the microservice startup\"\r\n let clickhouseEndpoint = process.env.BEAM_CLICKHOUSE_ENDPOINT;\r\n let clickhouseUsername = process.env.BEAM_CLICKHOUSE_USERNAME;\r\n let clickhousePassword = process.env.BEAM_CLICKHOUSE_PASSWORD;\r\n \r\n if ((!clickhouseEndpoint || !clickhouseUsername || !clickhousePassword) && env) {\r\n try {\r\n logger.info('[Collector] Fetching ClickHouse credentials from Beamable API...');\r\n const credStartTime = Date.now();\r\n const credentials = await fetchClickHouseCredentials(env);\r\n const credElapsed = Date.now() - credStartTime;\r\n logger.info(`[Collector] ClickHouse credentials fetch completed in ${credElapsed}ms`);\r\n clickhouseEndpoint = credentials.endpoint;\r\n clickhouseUsername = credentials.username;\r\n clickhousePassword = credentials.password;\r\n \r\n // CRITICAL: Set them in process.env IMMEDIATELY after fetching (matching C# CollectorManager.AddAuthEnvironmentVars)\r\n // In Node.js, process.env is a writable object - setting properties here persists for the lifetime of the process\r\n // This ensures they're available to both the Node.js process and inherited by the collector child process\r\n addAuthEnvironmentVars(clickhouseEndpoint, clickhouseUsername, clickhousePassword);\r\n \r\n // Verify they were set (defensive check - should never fail in Node.js)\r\n const verifyEndpoint = process.env.BEAM_CLICKHOUSE_ENDPOINT;\r\n const verifyUsername = process.env.BEAM_CLICKHOUSE_USERNAME;\r\n const verifyPassword = process.env.BEAM_CLICKHOUSE_PASSWORD;\r\n \r\n if (!verifyEndpoint || !verifyUsername || !verifyPassword) {\r\n logger.error(`[Collector] CRITICAL: Credentials were set but are missing from process.env! This should never happen.`);\r\n throw new Error('Failed to persist ClickHouse credentials in process.env');\r\n }\r\n \r\n logger.info('[Collector] ClickHouse credentials fetched from API and verified in process.env');\r\n } catch (error) {\r\n const errorMsg = `[Collector] Failed to fetch ClickHouse credentials from API: ${error instanceof Error ? error.message : String(error)}`;\r\n logger.error(errorMsg);\r\n throw new Error(errorMsg);\r\n }\r\n }\r\n \r\n // Validate required environment variables (matching C# behavior)\r\n // These must be set before starting the collector, otherwise it will fail\r\n if (!clickhouseEndpoint || !clickhouseUsername || !clickhousePassword) {\r\n const errorMsg = `[Collector] Required ClickHouse credentials are missing. Set BEAM_CLICKHOUSE_ENDPOINT, BEAM_CLICKHOUSE_USERNAME, and BEAM_CLICKHOUSE_PASSWORD, or ensure the API endpoint is accessible.`;\r\n logger.error(errorMsg);\r\n throw new Error(errorMsg);\r\n }\r\n \r\n // Now resolve collector binary and config (after credentials are fetched and set)\r\n logger.info('[Collector] Step 2: Resolving collector binary and config...');\r\n const resolveStartTime = Date.now();\r\n const collectorInfo = await resolveCollector(true, logger);\r\n const resolveElapsed = Date.now() - resolveStartTime;\r\n logger.info(`[Collector] Collector binary/config resolution completed in ${resolveElapsed}ms`);\r\n \r\n if (!collectorInfo.binaryPath) {\r\n logger.error('[Collector] Binary not found and download failed');\r\n throw new Error('Collector binary not found and download failed');\r\n }\r\n \r\n if (!collectorInfo.configPath) {\r\n logger.error('[Collector] Config not found and download failed');\r\n throw new Error('Collector config not found and download failed');\r\n }\r\n \r\n logger.info(`[Collector] Using binary: ${collectorInfo.binaryPath}`);\r\n logger.info(`[Collector] Using config: ${collectorInfo.configPath}`);\r\n \r\n // Verify binary exists\r\n if (!collectorInfo.binaryPath || !existsSync(collectorInfo.binaryPath)) {\r\n throw new Error(`Collector binary not found at ${collectorInfo.binaryPath}`);\r\n }\r\n \r\n // Check if binary is executable (Unix only - Windows doesn't have execute permission)\r\n if (process.platform !== 'win32') {\r\n try {\r\n const fsPromises = await import('fs/promises');\r\n const stats = await fsPromises.stat(collectorInfo.binaryPath);\r\n const mode = Number(stats.mode);\r\n const isExecutable = !!(mode & parseInt('111', 8)); // Check execute bit\r\n if (!isExecutable) {\r\n logger.warn(`[Collector] Binary may not be executable. Mode: ${mode.toString(8)}`);\r\n // Try to make it executable again\r\n try {\r\n chmodSync(collectorInfo.binaryPath, 0o755);\r\n logger.info(`[Collector] Made binary executable`);\r\n } catch (chmodError) {\r\n logger.error(`[Collector] Failed to make binary executable: ${chmodError instanceof Error ? chmodError.message : String(chmodError)}`);\r\n }\r\n }\r\n } catch (statError) {\r\n logger.warn(`[Collector] Could not check binary permissions: ${statError instanceof Error ? statError.message : String(statError)}`);\r\n }\r\n }\r\n\r\n // Set default collector configuration environment variables in process.env\r\n // This ensures they're available to both the Node.js process and the collector child process\r\n // Matches C# CollectorManager.AddCollectorConfigurationToEnvironment()\r\n addCollectorConfigurationToEnvironment();\r\n \r\n // CRITICAL: Set BEAM_COLLECTOR_DISCOVERY_PORT if not already set (matching C# AddDefaultCollectorHostAndPortFallback)\r\n // This MUST be set before starting the collector\r\n if (!process.env.BEAM_COLLECTOR_DISCOVERY_PORT) {\r\n process.env.BEAM_COLLECTOR_DISCOVERY_PORT = String(DISCOVERY_PORT);\r\n logger.info(`[Collector] Set BEAM_COLLECTOR_DISCOVERY_PORT=${DISCOVERY_PORT} (default)`);\r\n }\r\n \r\n // Determine OTLP endpoint\r\n // Use a free port if not specified (like C# does with PortUtil.FreeEndpoint())\r\n let localEndpoint = otlpEndpoint;\r\n if (!localEndpoint) {\r\n // For now, use default OTLP HTTP port\r\n // In production, this would be discovered or set by Beamable\r\n localEndpoint = '0.0.0.0:4318';\r\n }\r\n localEndpoint = localEndpoint.replace(/^http:\\/\\//, '').replace(/^https:\\/\\//, '');\r\n \r\n // Find a free port for Prometheus (matching C# PortUtil.FreeTcpPort())\r\n // We'll use a simple approach: bind to port 0 and let the OS assign a port\r\n // For now, use a default port (9090 is common for Prometheus) or find a free one\r\n // C# uses PortUtil.FreeTcpPort() which finds an available TCP port\r\n // We'll use a simple helper to find a free port\r\n const prometheusPort = await findFreePort();\r\n \r\n // Set environment variables for collector\r\n // Note: BEAM_CLICKHOUSE_ENDPOINT is for collector → ClickHouse communication\r\n // This is different from the OTLP endpoint (microservice → collector)\r\n // The collector process will inherit all environment variables from process.env automatically\r\n // We only need to set the OTLP endpoint, discovery port, and Prometheus port explicitly here\r\n const collectorEnv: NodeJS.ProcessEnv = {\r\n ...process.env, // Inherit all process.env (including credentials and config we just set)\r\n BEAM_OTLP_HTTP_ENDPOINT: localEndpoint,\r\n BEAM_COLLECTOR_DISCOVERY_PORT: String(DISCOVERY_PORT),\r\n BEAM_COLLECTOR_PROMETHEUS_PORT: String(prometheusPort),\r\n };\r\n \r\n // Start collector process\r\n const collectorProcess = spawn(collectorInfo.binaryPath, ['--config', collectorInfo.configPath], {\r\n env: collectorEnv,\r\n stdio: ['ignore', 'pipe', 'pipe'],\r\n detached: false,\r\n });\r\n \r\n // Store globally to prevent GC and track status\r\n globalCollectorProcess = collectorProcess;\r\n globalCollectorStartError = null;\r\n globalCollectorExitCode = null;\r\n globalCollectorStderr = [];\r\n \r\n // Set up handlers BEFORE we check if process started, so we capture all output\r\n collectorProcess.stdout?.on('data', (data) => {\r\n const outputLine = data.toString().trim();\r\n // Log stdout at info level to see collector output\r\n logger.info(`[Collector OUT] ${outputLine}`);\r\n });\r\n \r\n collectorProcess.stderr?.on('data', (data) => {\r\n const errorLine = data.toString().trim();\r\n globalCollectorStderr.push(errorLine);\r\n // Keep only last 50 lines to prevent memory issues\r\n if (globalCollectorStderr.length > 50) {\r\n globalCollectorStderr.shift();\r\n }\r\n // Log stderr at info level so we can see why collector crashes\r\n logger.info(`[Collector ERR] ${errorLine}`);\r\n });\r\n \r\n collectorProcess.on('error', (err) => {\r\n globalCollectorStartError = err.message;\r\n logger.error(`[Collector] Failed to start: ${err.message}`);\r\n });\r\n \r\n collectorProcess.on('exit', (code, signal) => {\r\n globalCollectorExitCode = code;\r\n logger.warn(`[Collector] Process exited with code ${code}${signal ? `, signal ${signal}` : ''}`);\r\n \r\n // If process exited with an error code, log accumulated stderr\r\n if (code !== 0 && globalCollectorStderr.length > 0) {\r\n logger.error(`[Collector] Exit error - Last ${Math.min(10, globalCollectorStderr.length)} stderr lines:`);\r\n globalCollectorStderr.slice(-10).forEach((line) => {\r\n logger.error(`[Collector ERR] ${line}`);\r\n });\r\n }\r\n \r\n // Don't clear reference immediately - keep it for status checks\r\n // globalCollectorProcess = null; // Keep reference for getCollectorProcessStatus()\r\n });\r\n \r\n logger.info(`[Collector] Started with PID ${collectorProcess.pid}, endpoint: ${localEndpoint}`);\r\n \r\n // Give the process a moment to start and potentially write to stderr\r\n // This helps capture immediate startup errors\r\n // Wait a bit longer to ensure we catch immediate crashes\r\n await new Promise(resolve => setTimeout(resolve, 500));\r\n \r\n // Check if process already exited (immediate crash)\r\n if (globalCollectorExitCode !== null && globalCollectorExitCode !== 0) {\r\n const stderrMsg = globalCollectorStderr.length > 0 \r\n ? ` Stderr: ${globalCollectorStderr.join('; ')}` \r\n : ' No stderr output captured.';\r\n throw new Error(`Collector process exited immediately after startup with code ${globalCollectorExitCode}.${stderrMsg}`);\r\n }\r\n \r\n return {\r\n process: collectorProcess,\r\n endpoint: `http://${localEndpoint}`,\r\n };\r\n}\r\n\r\n/**\r\n * Gets detailed collector status including process info and errors\r\n */\r\nexport function getCollectorProcessStatus(): {\r\n hasProcess: boolean;\r\n pid: number | null;\r\n exitCode: number | null;\r\n startError: string | null;\r\n initError: string | null;\r\n stderr: string[];\r\n} {\r\n return {\r\n hasProcess: globalCollectorProcess !== null,\r\n pid: globalCollectorProcess?.pid ?? null,\r\n exitCode: globalCollectorExitCode,\r\n startError: globalCollectorStartError,\r\n initError: globalCollectorInitError,\r\n stderr: [...globalCollectorStderr], // Return a copy\r\n };\r\n}\r\n\r\n/**\r\n * Discovers or starts the collector and returns the OTLP endpoint\r\n */\r\nexport async function discoverOrStartCollector(\r\n logger: Logger,\r\n standardOtelEnabled: boolean,\r\n env?: EnvironmentConfig\r\n): Promise<string | null> {\r\n if (!standardOtelEnabled) {\r\n return null;\r\n }\r\n \r\n // CRITICAL: Check if collector startup is already in progress\r\n // This prevents duplicate collector starts if this function is called multiple times\r\n // (e.g., if setupCollectorBeforeLogging times out but the promise is still running)\r\n if (globalCollectorStartupPromise) {\r\n logger.info('[Collector] Collector startup already in progress, waiting for existing startup to complete...');\r\n try {\r\n const result = await globalCollectorStartupPromise;\r\n // Clear the promise after it completes (success or failure)\r\n globalCollectorStartupPromise = null;\r\n return result;\r\n } catch (error) {\r\n logger.error(`[Collector] Existing startup promise failed: ${error instanceof Error ? error.message : String(error)}`);\r\n // Clear the promise so we can retry\r\n globalCollectorStartupPromise = null;\r\n // Fall through to start a new one\r\n }\r\n }\r\n \r\n // CRITICAL: Check if we already have a collector process starting/running\r\n // This prevents duplicate collector starts if this function is called multiple times\r\n let existingEndpoint: string | undefined;\r\n if (globalCollectorProcess) {\r\n // Check if process is still alive\r\n const processAlive = globalCollectorProcess.exitCode === null && \r\n globalCollectorProcess.killed === false;\r\n \r\n if (processAlive) {\r\n logger.info(`[Collector] Collector process already exists (PID ${globalCollectorProcess.pid}), waiting for it to be ready...`);\r\n // Use the configured endpoint from environment (we started it earlier)\r\n existingEndpoint = process.env.BEAM_OTLP_HTTP_ENDPOINT ? \r\n `http://${process.env.BEAM_OTLP_HTTP_ENDPOINT}` : \r\n 'http://0.0.0.0:4318';\r\n // Fall through to the wait logic below (don't start a new collector)\r\n } else {\r\n // Process is dead, clear it and start fresh\r\n logger.warn(`[Collector] Previous collector process (PID ${globalCollectorProcess.pid}) is dead, starting new one...`);\r\n globalCollectorProcess = null;\r\n globalCollectorExitCode = null;\r\n globalCollectorStderr = [];\r\n }\r\n }\r\n \r\n // First, quick check if collector is already running (via UDP discovery)\r\n // Match C#: 10 attempts × 100ms = 1 second max (much faster than before)\r\n // Skip UDP discovery if we already have a process reference (faster)\r\n if (!globalCollectorProcess) {\r\n logger.info('[Collector] Quick check for existing collector via UDP discovery (timeout: 1s, matching C#)...');\r\n const udpStartTime = Date.now();\r\n logger.info('[Collector] Calling isCollectorRunning()...');\r\n const status = await isCollectorRunning();\r\n const udpElapsed = Date.now() - udpStartTime;\r\n logger.info(`[Collector] isCollectorRunning() returned after ${udpElapsed}ms: isRunning=${status.isRunning}, isReady=${status.isReady}, endpoint=${status.otlpEndpoint || 'none'}`);\r\n if (status.isRunning && status.isReady && status.otlpEndpoint) {\r\n logger.info(`[Collector] Found running collector at ${status.otlpEndpoint}, will reuse it`);\r\n return `http://${status.otlpEndpoint}`;\r\n }\r\n logger.info('[Collector] No existing collector found, will start new one...');\r\n } else {\r\n logger.info('[Collector] Collector process already exists, skipping UDP discovery...');\r\n }\r\n \r\n // Collector not running - start it (or wait for existing one to be ready)\r\n // Wrap the entire startup logic in a promise that we track globally\r\n // This prevents duplicate starts if this function is called multiple times\r\n logger.info('[Collector] Creating startup promise...');\r\n const startupPromise = (async (): Promise<string | null> => {\r\n logger.info('[Collector] Startup promise executing...');\r\n try {\r\n // Clear any previous init error\r\n globalCollectorInitError = null;\r\n logger.info(`[Collector] Checking existingEndpoint: ${existingEndpoint || 'none'}`);\r\n \r\n let endpoint: string;\r\n if (existingEndpoint) {\r\n // Collector already starting, just wait for it to be ready\r\n endpoint = existingEndpoint;\r\n logger.info(`[Collector] Waiting for existing collector to become ready at ${endpoint}...`);\r\n } else {\r\n // Start a new collector\r\n logger.info('[Collector] Starting new OpenTelemetry collector...');\r\n const startCollectorTime = Date.now();\r\n const startResult = await startCollector(logger, undefined, env);\r\n const startCollectorElapsed = Date.now() - startCollectorTime;\r\n logger.info(`[Collector] Collector process started in ${startCollectorElapsed}ms, endpoint: ${startResult.endpoint}`);\r\n endpoint = startResult.endpoint;\r\n \r\n // Check if collector process exited immediately (crashed)\r\n logger.info('[Collector] Checking if collector process is still running...');\r\n await new Promise(resolve => setTimeout(resolve, 200));\r\n \r\n if (globalCollectorExitCode !== null && globalCollectorExitCode !== 0) {\r\n const errorMsg = `Collector process exited immediately with code ${globalCollectorExitCode}. ${globalCollectorStderr.length > 0 ? `Stderr: ${globalCollectorStderr.join('; ')}` : 'No stderr output.'}`;\r\n globalCollectorInitError = errorMsg;\r\n logger.error(`[Collector] ${errorMsg}`);\r\n return null;\r\n }\r\n logger.info('[Collector] Collector process is still running, proceeding to readiness check...');\r\n }\r\n \r\n // CRITICAL: Wait for collector to be fully ready before returning\r\n // We'll wait up to 60 seconds, checking every 500ms\r\n // This ensures the collector is actually ready to receive logs before we continue\r\n const maxWaitTime = 60000; // 60 seconds\r\n const checkInterval = 500; // Check every 500ms\r\n const maxChecks = Math.floor(maxWaitTime / checkInterval);\r\n \r\n logger.info(`[Collector] Waiting for collector to become ready (checking every ${checkInterval}ms, max ${maxWaitTime / 1000}s)...`);\r\n const readinessStartTime = Date.now();\r\n \r\n for (let i = 0; i < maxChecks; i++) {\r\n await new Promise(resolve => setTimeout(resolve, checkInterval));\r\n const elapsed = Date.now() - readinessStartTime;\r\n \r\n // Check if process exited during wait\r\n if (globalCollectorExitCode !== null && globalCollectorExitCode !== 0) {\r\n const errorMsg = `Collector process exited during startup with code ${globalCollectorExitCode}. ${globalCollectorStderr.length > 0 ? `Stderr: ${globalCollectorStderr.join('; ')}` : 'No stderr output.'}`;\r\n globalCollectorInitError = errorMsg;\r\n logger.error(`[Collector] ${errorMsg} (after ${elapsed}ms)`);\r\n return null;\r\n }\r\n \r\n logger.info(`[Collector] Checking collector readiness... (${(elapsed / 1000).toFixed(1)}s elapsed, attempt ${i + 1}/${maxChecks})`);\r\n const newStatus = await isCollectorRunning();\r\n logger.info(`[Collector] Collector status: isRunning=${newStatus.isRunning}, isReady=${newStatus.isReady}, pid=${newStatus.pid}, endpoint=${newStatus.otlpEndpoint || 'none'}`);\r\n \r\n if (newStatus.isRunning && newStatus.isReady) {\r\n logger.info(`[Collector] Collector is ready at ${newStatus.otlpEndpoint || endpoint} (ready after ${elapsed}ms)`);\r\n return newStatus.otlpEndpoint ? `http://${newStatus.otlpEndpoint}` : endpoint;\r\n }\r\n \r\n // Log progress every second (every 2 checks)\r\n if (i > 0 && i % 2 === 0) {\r\n logger.info(`[Collector] Still waiting for collector to become ready... (${(elapsed / 1000).toFixed(1)}s elapsed)`);\r\n }\r\n }\r\n \r\n // Check one more time if process exited\r\n if (globalCollectorExitCode !== null && globalCollectorExitCode !== 0) {\r\n const errorMsg = `Collector process exited with code ${globalCollectorExitCode}. ${globalCollectorStderr.length > 0 ? `Stderr: ${globalCollectorStderr.join('; ')}` : 'No stderr output.'}`;\r\n globalCollectorInitError = errorMsg;\r\n logger.error(`[Collector] ${errorMsg}`);\r\n return null;\r\n }\r\n \r\n // Collector did not become ready within timeout\r\n logger.error(`[Collector] Collector did not become ready within ${maxWaitTime / 1000} seconds`);\r\n return null;\r\n } catch (err) {\r\n const errorMsg = err instanceof Error ? err.message : String(err);\r\n globalCollectorInitError = errorMsg;\r\n logger.error(`[Collector] Failed to start collector: ${errorMsg}`);\r\n return null;\r\n }\r\n })();\r\n \r\n // Store the promise globally so other calls to this function can wait for it\r\n globalCollectorStartupPromise = startupPromise;\r\n \r\n // Clear the promise when it completes (so we don't keep waiting on old promises)\r\n startupPromise.finally(() => {\r\n globalCollectorStartupPromise = null;\r\n });\r\n \r\n return await startupPromise;\r\n}\r\n\r\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@omen.foundation/node-microservice-runtime",
3
- "version": "0.1.59",
3
+ "version": "0.1.61",
4
4
  "description": "Beamable microservice runtime for Node.js/TypeScript services.",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -176,9 +176,20 @@ export async function fetchClickHouseCredentials(
176
176
 
177
177
  /**
178
178
  * Gets the collector storage directory (similar to C# LocalApplicationData/beam/collectors/version)
179
+ * Checks production location first (pre-installed in Docker), then falls back to temp directory
179
180
  */
180
181
  function getCollectorStoragePath(): string {
181
- // Use temp directory for now - in containers this should be writable
182
+ // Check production location first (pre-installed in Docker image at /opt/beam/collectors)
183
+ // This avoids runtime download delays (~12 seconds)
184
+ const productionPath = '/opt/beam/collectors';
185
+ const productionVersionPath = join(productionPath, COLLECTOR_VERSION);
186
+
187
+ // Use production path if it exists (Docker image pre-installed collector)
188
+ if (existsSync(productionPath)) {
189
+ return productionVersionPath;
190
+ }
191
+
192
+ // Fallback to temp directory (local development without Docker)
182
193
  const tempDir = process.env.TMPDIR || process.env.TMP || '/tmp';
183
194
  return join(tempDir, 'beam', 'collectors', COLLECTOR_VERSION);
184
195
  }
@@ -377,13 +388,46 @@ async function resolveCollector(allowDownload: boolean = true, logger?: Logger):
377
388
  /**
378
389
  * Discovers collector via UDP broadcast
379
390
  */
380
- function discoverCollectorViaUDP(timeoutMs: number = 5000): Promise<CollectorDiscoveryEntry | null> {
391
+ function discoverCollectorViaUDP(timeoutMs: number = 1000): Promise<CollectorDiscoveryEntry | null> {
381
392
  return new Promise((resolve) => {
382
393
  const socket = dgram.createSocket('udp4');
383
394
  const discovered: CollectorDiscoveryEntry[] = [];
384
395
  let timeout: NodeJS.Timeout;
396
+ let resolved = false; // Guard to prevent double resolution
385
397
  const startTime = Date.now();
386
398
 
399
+ // Safety timeout - force resolve after timeout + 100ms buffer
400
+ const safetyTimeout = setTimeout(() => {
401
+ if (!resolved) {
402
+ console.log(`[UDP Discovery] Safety timeout triggered - forcing resolution`);
403
+ resolved = true;
404
+ try {
405
+ socket.removeAllListeners();
406
+ socket.close();
407
+ } catch (e) {
408
+ // Ignore
409
+ }
410
+ clearTimeout(timeout);
411
+ resolve(discovered.length > 0 ? discovered[0] : null);
412
+ }
413
+ }, timeoutMs + 100);
414
+
415
+ const doResolve = (result: CollectorDiscoveryEntry | null) => {
416
+ if (!resolved) {
417
+ resolved = true;
418
+ clearTimeout(timeout);
419
+ clearTimeout(safetyTimeout);
420
+ try {
421
+ socket.removeAllListeners();
422
+ socket.close();
423
+ } catch (e) {
424
+ // Ignore
425
+ }
426
+ console.log(`[UDP Discovery] Resolving promise with result: ${result ? 'found' : 'null'}`);
427
+ resolve(result);
428
+ }
429
+ };
430
+
387
431
  socket.on('message', (msg) => {
388
432
  try {
389
433
  const message = JSON.parse(msg.toString()) as CollectorDiscoveryEntry;
@@ -392,6 +436,8 @@ function discoverCollectorViaUDP(timeoutMs: number = 5000): Promise<CollectorDis
392
436
  discovered.push(message);
393
437
  const elapsed = Date.now() - startTime;
394
438
  console.log(`[UDP Discovery] Found collector after ${elapsed}ms: ${message.otlpEndpoint}`);
439
+ // Resolve immediately when collector found
440
+ doResolve(discovered[0]);
395
441
  }
396
442
  } catch (error) {
397
443
  // Ignore parse errors
@@ -399,11 +445,9 @@ function discoverCollectorViaUDP(timeoutMs: number = 5000): Promise<CollectorDis
399
445
  });
400
446
 
401
447
  socket.on('error', (err) => {
402
- clearTimeout(timeout);
403
- socket.close();
404
448
  const elapsed = Date.now() - startTime;
405
449
  console.log(`[UDP Discovery] Socket error after ${elapsed}ms: ${err.message}`);
406
- resolve(null);
450
+ doResolve(null);
407
451
  });
408
452
 
409
453
  socket.bind(() => {
@@ -411,15 +455,13 @@ function discoverCollectorViaUDP(timeoutMs: number = 5000): Promise<CollectorDis
411
455
  console.log(`[UDP Discovery] Listening for collector broadcasts (timeout: ${timeoutMs}ms)...`);
412
456
 
413
457
  timeout = setTimeout(() => {
414
- socket.close();
415
458
  const elapsed = Date.now() - startTime;
416
459
  if (discovered.length > 0) {
417
460
  console.log(`[UDP Discovery] Timeout after ${elapsed}ms, found ${discovered.length} collector(s)`);
418
461
  } else {
419
462
  console.log(`[UDP Discovery] Timeout after ${elapsed}ms, no collector found`);
420
463
  }
421
- // Return the first discovered collector
422
- resolve(discovered.length > 0 ? discovered[0] : null);
464
+ doResolve(discovered.length > 0 ? discovered[0] : null);
423
465
  }, timeoutMs);
424
466
  });
425
467
  });
@@ -513,8 +555,11 @@ export async function isCollectorRunning(): Promise<CollectorStatus> {
513
555
  // Try UDP discovery as fallback
514
556
  try {
515
557
  const udpStartTime = Date.now();
516
- const discovered = await discoverCollectorViaUDP(2000);
558
+ console.log('[UDP Discovery] Starting UDP discovery in isCollectorRunning()...');
559
+ console.log('[UDP Discovery] Calling discoverCollectorViaUDP(1000)...');
560
+ const discovered = await discoverCollectorViaUDP(1000); // Match C#: 1 second max (10 attempts × 100ms)
517
561
  const udpElapsed = Date.now() - udpStartTime;
562
+ console.log(`[UDP Discovery] UDP discovery promise resolved after ${udpElapsed}ms, result: ${discovered ? 'found' : 'null'}`);
518
563
  if (discovered) {
519
564
  console.log(`[UDP Discovery] Found collector in ${udpElapsed}ms: ${discovered.otlpEndpoint}`);
520
565
  return {
@@ -525,13 +570,18 @@ export async function isCollectorRunning(): Promise<CollectorStatus> {
525
570
  version: discovered.version,
526
571
  };
527
572
  } else {
528
- console.log(`[UDP Discovery] No collector found after ${udpElapsed}ms`);
573
+ console.log(`[UDP Discovery] No collector found after ${udpElapsed}ms, returning not running status`);
529
574
  }
530
575
  } catch (error) {
531
576
  // Discovery failed, collector probably not running
532
- console.log(`[UDP Discovery] Error: ${error instanceof Error ? error.message : String(error)}`);
577
+ const errorMsg = error instanceof Error ? error.message : String(error);
578
+ console.log(`[UDP Discovery] Error in isCollectorRunning(): ${errorMsg}`);
579
+ if (error instanceof Error && error.stack) {
580
+ console.log(`[UDP Discovery] Error stack: ${error.stack}`);
581
+ }
533
582
  }
534
583
 
584
+ console.log('[UDP Discovery] Returning default not-running status from isCollectorRunning()');
535
585
  return {
536
586
  isRunning: false,
537
587
  isReady: false,
@@ -1064,16 +1114,18 @@ export async function discoverOrStartCollector(
1064
1114
  }
1065
1115
  }
1066
1116
 
1067
- // First, check if collector is already running (via UDP discovery)
1117
+ // First, quick check if collector is already running (via UDP discovery)
1118
+ // Match C#: 10 attempts × 100ms = 1 second max (much faster than before)
1068
1119
  // Skip UDP discovery if we already have a process reference (faster)
1069
1120
  if (!globalCollectorProcess) {
1070
- logger.info('[Collector] Checking for existing collector via UDP discovery (timeout: 2s)...');
1121
+ logger.info('[Collector] Quick check for existing collector via UDP discovery (timeout: 1s, matching C#)...');
1071
1122
  const udpStartTime = Date.now();
1123
+ logger.info('[Collector] Calling isCollectorRunning()...');
1072
1124
  const status = await isCollectorRunning();
1073
1125
  const udpElapsed = Date.now() - udpStartTime;
1074
- logger.info(`[Collector] UDP discovery completed in ${udpElapsed}ms: isRunning=${status.isRunning}, isReady=${status.isReady}, endpoint=${status.otlpEndpoint || 'none'}`);
1126
+ logger.info(`[Collector] isCollectorRunning() returned after ${udpElapsed}ms: isRunning=${status.isRunning}, isReady=${status.isReady}, endpoint=${status.otlpEndpoint || 'none'}`);
1075
1127
  if (status.isRunning && status.isReady && status.otlpEndpoint) {
1076
- logger.info(`[Collector] Found running collector at ${status.otlpEndpoint}`);
1128
+ logger.info(`[Collector] Found running collector at ${status.otlpEndpoint}, will reuse it`);
1077
1129
  return `http://${status.otlpEndpoint}`;
1078
1130
  }
1079
1131
  logger.info('[Collector] No existing collector found, will start new one...');