@ciq-dev/neoiq-foundation-node 1.0.1-beta.2 → 1.0.1-beta.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -1,123 +1,20 @@
1
1
  "use strict";
2
- //#region rolldown:runtime
3
- var __create = Object.create;
4
- var __defProp = Object.defineProperty;
5
- var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
6
- var __getOwnPropNames = Object.getOwnPropertyNames;
7
- var __getProtoOf = Object.getPrototypeOf;
8
- var __hasOwnProp = Object.prototype.hasOwnProperty;
9
- var __copyProps = (to, from, except, desc) => {
10
- if (from && typeof from === "object" || typeof from === "function") for (var keys = __getOwnPropNames(from), i = 0, n = keys.length, key; i < n; i++) {
11
- key = keys[i];
12
- if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, {
13
- get: ((k) => from[k]).bind(null, key),
14
- enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
15
- });
16
- }
17
- return to;
18
- };
19
- var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", {
20
- value: mod,
21
- enumerable: true
22
- }) : target, mod));
23
-
24
- //#endregion
25
- const zod = __toESM(require("zod"));
26
- const async_hooks = __toESM(require("async_hooks"));
27
- const __opentelemetry_api = __toESM(require("@opentelemetry/api"));
28
- const pino = __toESM(require("pino"));
29
- const __opentelemetry_sdk_node = __toESM(require("@opentelemetry/sdk-node"));
30
- const __opentelemetry_auto_instrumentations_node = __toESM(require("@opentelemetry/auto-instrumentations-node"));
31
- const __opentelemetry_exporter_trace_otlp_grpc = __toESM(require("@opentelemetry/exporter-trace-otlp-grpc"));
32
- const __opentelemetry_resources = __toESM(require("@opentelemetry/resources"));
33
- const __opentelemetry_semantic_conventions = __toESM(require("@opentelemetry/semantic-conventions"));
34
- const __opentelemetry_exporter_metrics_otlp_grpc = __toESM(require("@opentelemetry/exporter-metrics-otlp-grpc"));
35
- const __opentelemetry_sdk_metrics = __toESM(require("@opentelemetry/sdk-metrics"));
36
- const fastify_plugin = __toESM(require("fastify-plugin"));
37
- const crypto = __toESM(require("crypto"));
38
- const axios = __toESM(require("axios"));
39
- const axios_retry = __toESM(require("axios-retry"));
40
- const opossum = __toESM(require("opossum"));
41
- const node_stream = __toESM(require("node:stream"));
2
+ const require_tracing = require('./tracing-B8-Ntcll.js');
3
+ const __opentelemetry_resources = require_tracing.__toESM(require("@opentelemetry/resources"));
4
+ const __opentelemetry_semantic_conventions = require_tracing.__toESM(require("@opentelemetry/semantic-conventions"));
5
+ const __opentelemetry_api = require_tracing.__toESM(require("@opentelemetry/api"));
6
+ const async_hooks = require_tracing.__toESM(require("async_hooks"));
7
+ const pino = require_tracing.__toESM(require("pino"));
8
+ const __opentelemetry_exporter_metrics_otlp_grpc = require_tracing.__toESM(require("@opentelemetry/exporter-metrics-otlp-grpc"));
9
+ const __opentelemetry_sdk_metrics = require_tracing.__toESM(require("@opentelemetry/sdk-metrics"));
10
+ const fastify_plugin = require_tracing.__toESM(require("fastify-plugin"));
11
+ const crypto = require_tracing.__toESM(require("crypto"));
12
+ const axios = require_tracing.__toESM(require("axios"));
13
+ const axios_retry = require_tracing.__toESM(require("axios-retry"));
14
+ const opossum = require_tracing.__toESM(require("opossum"));
15
+ const node_crypto = require_tracing.__toESM(require("node:crypto"));
16
+ const node_stream = require_tracing.__toESM(require("node:stream"));
42
17
 
43
- //#region src/config.ts
44
- const AutoInstrumentationConfigSchema = zod.z.object({
45
- http: zod.z.boolean().default(true),
46
- fastify: zod.z.boolean().default(true),
47
- express: zod.z.boolean().default(true),
48
- mongodb: zod.z.boolean().default(true),
49
- pg: zod.z.boolean().default(true),
50
- mysql: zod.z.boolean().default(true),
51
- redis: zod.z.boolean().default(true),
52
- ioredis: zod.z.boolean().default(true),
53
- grpc: zod.z.boolean().default(true),
54
- fs: zod.z.boolean().default(false),
55
- dns: zod.z.boolean().default(false)
56
- }).partial();
57
- const FeaturesConfigSchema = zod.z.object({
58
- tracing: zod.z.boolean().default(true),
59
- metrics: zod.z.boolean().default(true),
60
- logging: zod.z.boolean().default(true),
61
- autoInstrumentation: AutoInstrumentationConfigSchema.default({})
62
- }).partial();
63
- const DEFAULT_OTEL_ENDPOINT = "http://otel-stack-deployment-collector.observability.svc.cluster.local:4317";
64
- const OtelConfigSchema = zod.z.object({
65
- endpoint: zod.z.string().default(DEFAULT_OTEL_ENDPOINT),
66
- metricsIntervalMs: zod.z.number().min(1e3).default(5e3),
67
- traceSampleRate: zod.z.number().min(0).max(1).default(1)
68
- }).partial();
69
- const LoggingConfigSchema = zod.z.object({
70
- level: zod.z.enum([
71
- "debug",
72
- "info",
73
- "warn",
74
- "error"
75
- ]).default("info"),
76
- prettyPrint: zod.z.boolean().optional()
77
- }).partial();
78
- const RequestLoggingConfigSchema = zod.z.object({
79
- logHeaders: zod.z.boolean().default(true),
80
- logBody: zod.z.boolean().default(false),
81
- logResponseBody: zod.z.boolean().default(false),
82
- maxBodySize: zod.z.number().default(10 * 1024),
83
- redactHeaders: zod.z.array(zod.z.string()).optional()
84
- }).partial();
85
- const RedactionConfigSchema = zod.z.object({ additionalPaths: zod.z.array(zod.z.string()).default([]) }).partial();
86
- const ShutdownConfigSchema = zod.z.object({
87
- flushOnCrash: zod.z.boolean().default(false),
88
- flushTimeoutMs: zod.z.number().min(100).default(5e3)
89
- }).partial();
90
- const FoundationConfigSchema = zod.z.object({
91
- serviceName: zod.z.string().min(1, "serviceName is required"),
92
- serviceVersion: zod.z.string().default(process.env.SERVICE_VERSION || "1.0.0"),
93
- environment: zod.z.enum([
94
- "development",
95
- "staging",
96
- "qa",
97
- "production"
98
- ]).default(process.env.NODE_ENV || "development"),
99
- features: FeaturesConfigSchema.default({}),
100
- otel: OtelConfigSchema.default({}),
101
- logging: LoggingConfigSchema.default({}),
102
- requestLogging: RequestLoggingConfigSchema.default({}),
103
- redaction: RedactionConfigSchema.default({}),
104
- shutdown: ShutdownConfigSchema.default({})
105
- });
106
- /** Parse and validate configuration */
107
- function parseConfig(input) {
108
- const result = FoundationConfigSchema.safeParse(input);
109
- if (!result.success) {
110
- const errors = result.error.errors.map((e) => ` - ${e.path.join(".")}: ${e.message}`).join("\n");
111
- throw new Error(`Invalid foundation configuration:\n${errors}`);
112
- }
113
- return result.data;
114
- }
115
- /** Get default OTEL endpoint */
116
- function getDefaultOtelEndpoint() {
117
- return process.env.OTEL_EXPORTER_OTLP_ENDPOINT || DEFAULT_OTEL_ENDPOINT;
118
- }
119
-
120
- //#endregion
121
18
  //#region src/features/context.ts
122
19
  const BAGGAGE_CORRELATION_KEY = "correlation.id";
123
20
  function setBaggageCorrelationId(correlationId) {
@@ -404,12 +301,13 @@ function wrapPinoLogger(pinoLogger) {
404
301
  };
405
302
  }
406
303
  /** Fallback logger when Pino is not available */
407
- function createFallbackLogger(serviceName = "unknown") {
304
+ function createFallbackLogger(serviceName = "unknown", baseBindings = {}) {
408
305
  const log = (level, obj, msg) => {
409
306
  const logObj = {
410
307
  timestamp: new Date().toISOString(),
411
308
  level,
412
309
  service: serviceName,
310
+ ...baseBindings,
413
311
  ...obj,
414
312
  msg
415
313
  };
@@ -423,7 +321,10 @@ function createFallbackLogger(serviceName = "unknown") {
423
321
  info: (obj, msg) => log("info", obj, msg),
424
322
  warn: (obj, msg) => log("warn", obj, msg),
425
323
  error: (obj, msg) => log("error", obj, msg),
426
- child: () => fallback,
324
+ child: (bindings) => createFallbackLogger(serviceName, {
325
+ ...baseBindings,
326
+ ...bindings
327
+ }),
427
328
  pino: null
428
329
  };
429
330
  return fallback;
@@ -436,98 +337,6 @@ function getGlobalLogger() {
436
337
  return globalLogger || createFallbackLogger();
437
338
  }
438
339
 
439
- //#endregion
440
- //#region src/features/tracing.ts
441
- let sdk = null;
442
- let isInitialized$1 = false;
443
- const MONITORED_MODULES = [
444
- "pg",
445
- "mongodb",
446
- "ioredis",
447
- "mysql2",
448
- "express",
449
- "@grpc/grpc-js"
450
- ];
451
- function warnPreloadedModules() {
452
- for (const mod of MONITORED_MODULES) try {
453
- if (require.resolve(mod) in (require.cache || {})) console.warn(`[neoiq-foundation] "${mod}" was imported before tracing init. Auto-instrumentation may not work for this module. Use node -r @ciq-dev/neoiq-foundation-node/bootstrap or call createFoundation() first.`);
454
- } catch {}
455
- }
456
- /** Initialize OpenTelemetry tracing */
457
- function setupTracing(options) {
458
- if (isInitialized$1) {
459
- console.warn("[neoiq-foundation] Tracing already initialized");
460
- return;
461
- }
462
- warnPreloadedModules();
463
- const { serviceName, serviceVersion, environment, endpoint = getDefaultOtelEndpoint(), autoInstrumentation = {} } = options;
464
- const resource = (0, __opentelemetry_resources.resourceFromAttributes)({
465
- [__opentelemetry_semantic_conventions.ATTR_SERVICE_NAME]: serviceName,
466
- [__opentelemetry_semantic_conventions.ATTR_SERVICE_VERSION]: serviceVersion,
467
- "deployment.environment": environment
468
- });
469
- const traceExporter = new __opentelemetry_exporter_trace_otlp_grpc.OTLPTraceExporter({ url: endpoint });
470
- const instrumentationConfig = buildInstrumentationConfig(autoInstrumentation);
471
- sdk = new __opentelemetry_sdk_node.NodeSDK({
472
- resource,
473
- traceExporter,
474
- instrumentations: [(0, __opentelemetry_auto_instrumentations_node.getNodeAutoInstrumentations)(instrumentationConfig)]
475
- });
476
- sdk.start();
477
- isInitialized$1 = true;
478
- }
479
- function buildInstrumentationConfig(config) {
480
- const mapping = {
481
- http: "@opentelemetry/instrumentation-http",
482
- fastify: "@opentelemetry/instrumentation-fastify",
483
- express: "@opentelemetry/instrumentation-express",
484
- mongodb: "@opentelemetry/instrumentation-mongodb",
485
- pg: "@opentelemetry/instrumentation-pg",
486
- mysql: "@opentelemetry/instrumentation-mysql",
487
- redis: "@opentelemetry/instrumentation-redis",
488
- ioredis: "@opentelemetry/instrumentation-ioredis",
489
- grpc: "@opentelemetry/instrumentation-grpc",
490
- fs: "@opentelemetry/instrumentation-fs",
491
- dns: "@opentelemetry/instrumentation-dns"
492
- };
493
- const result = {};
494
- for (const [key, instrumentationName] of Object.entries(mapping)) {
495
- const userSetting = config[key];
496
- const defaultValue = key !== "fs" && key !== "dns";
497
- result[instrumentationName] = { enabled: userSetting ?? defaultValue };
498
- }
499
- return result;
500
- }
501
- /** Shutdown tracing gracefully */
502
- async function shutdownTracing() {
503
- if (!sdk) return;
504
- try {
505
- await sdk.shutdown();
506
- isInitialized$1 = false;
507
- sdk = null;
508
- } catch (error) {
509
- console.error("[neoiq-foundation] Error shutting down tracing:", error);
510
- }
511
- }
512
- function getTracer(name) {
513
- return __opentelemetry_api.trace.getTracer(name);
514
- }
515
- function getActiveSpan() {
516
- return __opentelemetry_api.trace.getActiveSpan();
517
- }
518
- function getTraceContext() {
519
- const span = __opentelemetry_api.trace.getActiveSpan();
520
- if (!span) return {};
521
- const ctx = span.spanContext();
522
- return {
523
- traceId: ctx.traceId,
524
- spanId: ctx.spanId
525
- };
526
- }
527
- function isTracingEnabled() {
528
- return isInitialized$1;
529
- }
530
-
531
340
  //#endregion
532
341
  //#region src/features/metrics.ts
533
342
  let meterProvider = null;
@@ -538,7 +347,7 @@ function setupMetrics(options) {
538
347
  console.warn("[neoiq-foundation] Metrics already initialized");
539
348
  return;
540
349
  }
541
- const { serviceName, serviceVersion, environment, endpoint = getDefaultOtelEndpoint(), intervalMs = 5e3 } = options;
350
+ const { serviceName, serviceVersion, environment, endpoint = require_tracing.getDefaultOtelEndpoint(), intervalMs = 5e3 } = options;
542
351
  const resource = (0, __opentelemetry_resources.resourceFromAttributes)({
543
352
  [__opentelemetry_semantic_conventions.ATTR_SERVICE_NAME]: serviceName,
544
353
  [__opentelemetry_semantic_conventions.ATTR_SERVICE_VERSION]: serviceVersion,
@@ -565,6 +374,7 @@ async function shutdownMetrics() {
565
374
  meterProvider = null;
566
375
  } catch (error) {
567
376
  console.error("[neoiq-foundation] Error shutting down metrics:", error);
377
+ throw error;
568
378
  }
569
379
  }
570
380
  function getMeter(name, version = "1.0.0") {
@@ -842,31 +652,43 @@ function createHttpClient(options) {
842
652
  }
843
653
  return Promise.reject(error);
844
654
  });
845
- const retryConfig = {
846
- retries: retry.retries ?? 3,
847
- retryDelay: (retryCount) => (retry.retryDelay ?? 1e3) * Math.pow(2, retryCount - 1),
848
- retryCondition: (error) => {
849
- const retryStatusCodes = retry.retryStatusCodes ?? [
850
- 408,
851
- 429,
852
- 500,
853
- 502,
854
- 503,
855
- 504
856
- ];
857
- return !error.response || retryStatusCodes.includes(error.response?.status || 0);
858
- },
859
- onRetry: (retryCount, error, requestConfig) => {
860
- logger.warn({
861
- retryCount,
862
- url: `${requestConfig.baseURL || ""}${requestConfig.url}`,
863
- error: error.message
864
- }, "Retrying request");
865
- }
866
- };
867
- (0, axios_retry.default)(client, retryConfig);
868
- if (cbOptions.enabled !== false) {
869
- const breaker = new opossum.default(async (config) => client.request(config), {
655
+ if (retry.enabled !== false) {
656
+ const retryConfig = {
657
+ retries: retry.retries ?? 3,
658
+ retryDelay: (retryCount) => (retry.retryDelay ?? 1e3) * Math.pow(2, retryCount - 1),
659
+ retryCondition: (error) => {
660
+ const method = (error.config?.method ?? "get").toUpperCase();
661
+ const IDEMPOTENT = new Set([
662
+ "GET",
663
+ "HEAD",
664
+ "OPTIONS",
665
+ "PUT",
666
+ "DELETE"
667
+ ]);
668
+ if (!retry.retryNonIdempotent && !IDEMPOTENT.has(method)) return false;
669
+ const retryStatusCodes = retry.retryStatusCodes ?? [
670
+ 408,
671
+ 429,
672
+ 500,
673
+ 502,
674
+ 503,
675
+ 504
676
+ ];
677
+ return !error.response || retryStatusCodes.includes(error.response?.status || 0);
678
+ },
679
+ onRetry: (retryCount, error, requestConfig) => {
680
+ logger.warn({
681
+ retryCount,
682
+ url: `${requestConfig.baseURL || ""}${requestConfig.url}`,
683
+ error: error.message
684
+ }, "Retrying request");
685
+ }
686
+ };
687
+ (0, axios_retry.default)(client, retryConfig);
688
+ }
689
+ if (cbOptions.enabled === true) {
690
+ const originalRequest = client.request.bind(client);
691
+ const breaker = new opossum.default(async (config) => originalRequest(config), {
870
692
  timeout,
871
693
  resetTimeout: cbOptions.resetTimeout ?? 3e4,
872
694
  errorThresholdPercentage: cbOptions.errorThresholdPercentage ?? 50,
@@ -875,7 +697,6 @@ function createHttpClient(options) {
875
697
  breaker.on("open", () => logger.warn({ targetService: serviceName }, "Circuit breaker OPEN"));
876
698
  breaker.on("halfOpen", () => logger.info({ targetService: serviceName }, "Circuit breaker HALF-OPEN"));
877
699
  breaker.on("close", () => logger.info({ targetService: serviceName }, "Circuit breaker CLOSED"));
878
- const originalRequest = client.request.bind(client);
879
700
  client.request = (config) => breaker.fire(config);
880
701
  client.get = (url, config) => breaker.fire({
881
702
  ...config,
@@ -913,15 +734,20 @@ function createHttpClient(options) {
913
734
  //#endregion
914
735
  //#region src/foundation.ts
915
736
  const deprecationWarnings = new Set();
916
- function warnDeprecation(oldPath, newPath) {
737
+ function warnDeprecation(oldPath, newPath, logger) {
917
738
  if (deprecationWarnings.has(oldPath)) return;
918
739
  deprecationWarnings.add(oldPath);
919
- console.warn(`[neoiq-foundation] DEPRECATED: foundation.${oldPath}() is deprecated. Use foundation.${newPath}() instead. This alias will be removed in the next major version.`);
740
+ const msg = `foundation.${oldPath}() is deprecated. Use foundation.${newPath}() instead. This alias will be removed in the next major version.`;
741
+ if (logger) logger.warn({
742
+ deprecated: oldPath,
743
+ replacement: newPath
744
+ }, msg);
745
+ else console.warn(`[neoiq-foundation] DEPRECATED: ${msg}`);
920
746
  }
921
747
  /** Create a fully configured observability foundation */
922
748
  function createFoundation(input) {
923
749
  const startTime = Date.now();
924
- const config = parseConfig(input);
750
+ const config = require_tracing.parseConfig(input);
925
751
  const { serviceName, serviceVersion, environment, features: featuresConfig, otel, logging: loggingConfig, requestLogging: requestLoggingConfig, redaction: redactionConfig, shutdown: shutdownConfig } = config;
926
752
  const features = {
927
753
  tracing: featuresConfig.tracing ?? true,
@@ -969,15 +795,14 @@ function createFoundation(input) {
969
795
  let tracerInstance = null;
970
796
  let tracingError;
971
797
  if (features.tracing) try {
972
- setupTracing({
798
+ require_tracing.setupTracing({
973
799
  serviceName,
974
800
  serviceVersion,
975
801
  environment,
976
802
  endpoint: otel.endpoint,
977
- sampleRate: otel.traceSampleRate,
978
803
  autoInstrumentation: featuresConfig.autoInstrumentation
979
804
  });
980
- tracerInstance = getTracer(serviceName);
805
+ tracerInstance = require_tracing.getTracer(serviceName);
981
806
  logger.info({
982
807
  feature: "tracing",
983
808
  endpoint: otel.endpoint
@@ -1021,7 +846,7 @@ function createFoundation(input) {
1021
846
  origin
1022
847
  }, "Process crash detected, flushing telemetry");
1023
848
  const flushPromises = [];
1024
- if (features.tracing && isTracingEnabled()) flushPromises.push(shutdownTracing());
849
+ if (features.tracing && require_tracing.isTracingEnabled()) flushPromises.push(require_tracing.shutdownTracing());
1025
850
  if (features.metrics && isMetricsEnabled()) flushPromises.push(shutdownMetrics());
1026
851
  const timeout = new Promise((resolve) => setTimeout(resolve, flushTimeoutMs));
1027
852
  Promise.race([Promise.allSettled(flushPromises), timeout]).finally(() => {
@@ -1033,7 +858,7 @@ function createFoundation(input) {
1033
858
  logger.info({ flushTimeoutMs }, "Crash-flush handlers registered");
1034
859
  }
1035
860
  const traceInSpan = async (name, fn) => {
1036
- const tracer = tracerInstance || getTracer(serviceName);
861
+ const tracer = tracerInstance || require_tracing.getTracer(serviceName);
1037
862
  return new Promise((resolve, reject) => {
1038
863
  tracer.startActiveSpan(name, async (span) => {
1039
864
  try {
@@ -1062,10 +887,10 @@ function createFoundation(input) {
1062
887
  logger,
1063
888
  tracer: tracerInstance,
1064
889
  meter: meterInstance,
1065
- getTracer: (name) => getTracer(name || serviceName),
890
+ getTracer: (name) => require_tracing.getTracer(name || serviceName),
1066
891
  getMeter: (name, version) => getMeter(name, version),
1067
- getTraceContext,
1068
- getActiveSpan,
892
+ getTraceContext: require_tracing.getTraceContext,
893
+ getActiveSpan: require_tracing.getActiveSpan,
1069
894
  trace: traceInSpan
1070
895
  };
1071
896
  const httpModule = { createClient: (options) => createHttpClient({
@@ -1073,13 +898,15 @@ function createFoundation(input) {
1073
898
  foundation
1074
899
  }) };
1075
900
  const buildHealthStatus = () => {
1076
- const tracingUp = !features.tracing || !tracingError && isTracingEnabled();
901
+ const tracingUp = !features.tracing || !tracingError && require_tracing.isTracingEnabled();
1077
902
  const metricsUp = !features.metrics || !metricsError && isMetricsEnabled();
1078
903
  const loggingUp = !loggingError;
1079
904
  const allUp = tracingUp && metricsUp && loggingUp;
1080
- const anyDown = features.tracing && tracingError || features.metrics && metricsError || loggingError;
905
+ const allDown = (!tracingUp || !features.tracing) && (!metricsUp || !features.metrics) && !loggingUp;
906
+ let status = "healthy";
907
+ if (!allUp) status = allDown ? "unhealthy" : "degraded";
1081
908
  return {
1082
- status: allUp ? "healthy" : anyDown ? "degraded" : "unhealthy",
909
+ status,
1083
910
  timestamp: new Date().toISOString(),
1084
911
  service: serviceName,
1085
912
  version: serviceVersion,
@@ -1106,13 +933,13 @@ function createFoundation(input) {
1106
933
  const shutdownFn = async () => {
1107
934
  logger.info({}, "Shutting down foundation...");
1108
935
  const promises = [];
1109
- if (features.tracing && isTracingEnabled()) promises.push(shutdownTracing());
936
+ if (features.tracing && require_tracing.isTracingEnabled()) promises.push(require_tracing.shutdownTracing());
1110
937
  if (features.metrics && isMetricsEnabled()) promises.push(shutdownMetrics());
1111
938
  await Promise.all(promises);
1112
939
  logger.info({}, "Foundation shutdown complete");
1113
940
  };
1114
941
  const isReadyFn = () => {
1115
- if (features.tracing && !tracingError && !isTracingEnabled()) return false;
942
+ if (features.tracing && !tracingError && !require_tracing.isTracingEnabled()) return false;
1116
943
  if (features.metrics && !metricsError && !isMetricsEnabled()) return false;
1117
944
  return true;
1118
945
  };
@@ -1153,43 +980,43 @@ function createFoundation(input) {
1153
980
  tracer: tracerInstance,
1154
981
  meter: meterInstance,
1155
982
  getTracer: (name) => {
1156
- warnDeprecation("getTracer", "observability.getTracer");
983
+ warnDeprecation("getTracer", "observability.getTracer", logger);
1157
984
  return observability.getTracer(name);
1158
985
  },
1159
986
  getMeter: (name, version) => {
1160
- warnDeprecation("getMeter", "observability.getMeter");
987
+ warnDeprecation("getMeter", "observability.getMeter", logger);
1161
988
  return observability.getMeter(name, version);
1162
989
  },
1163
990
  getTraceContext: () => {
1164
- warnDeprecation("getTraceContext", "observability.getTraceContext");
991
+ warnDeprecation("getTraceContext", "observability.getTraceContext", logger);
1165
992
  return observability.getTraceContext();
1166
993
  },
1167
994
  getActiveSpan: () => {
1168
- warnDeprecation("getActiveSpan", "observability.getActiveSpan");
995
+ warnDeprecation("getActiveSpan", "observability.getActiveSpan", logger);
1169
996
  return observability.getActiveSpan();
1170
997
  },
1171
998
  createHttpClient: (options) => {
1172
- warnDeprecation("createHttpClient", "http.createClient");
999
+ warnDeprecation("createHttpClient", "http.createClient", logger);
1173
1000
  return httpModule.createClient(options);
1174
1001
  },
1175
1002
  shutdown: () => {
1176
- warnDeprecation("shutdown", "lifecycle.shutdown");
1003
+ warnDeprecation("shutdown", "lifecycle.shutdown", logger);
1177
1004
  return lifecycle.shutdown();
1178
1005
  },
1179
1006
  isReady: () => {
1180
- warnDeprecation("isReady", "lifecycle.isReady");
1007
+ warnDeprecation("isReady", "lifecycle.isReady", logger);
1181
1008
  return lifecycle.isReady();
1182
1009
  },
1183
1010
  health: () => {
1184
- warnDeprecation("health", "lifecycle.health");
1011
+ warnDeprecation("health", "lifecycle.health", logger);
1185
1012
  return lifecycle.health();
1186
1013
  },
1187
1014
  trace: (name, fn) => {
1188
- warnDeprecation("trace", "observability.trace");
1015
+ warnDeprecation("trace", "observability.trace", logger);
1189
1016
  return observability.trace(name, fn);
1190
1017
  },
1191
1018
  safeRun: (fn, fallback) => {
1192
- warnDeprecation("safeRun", "lifecycle.safeRun");
1019
+ warnDeprecation("safeRun", "lifecycle.safeRun", logger);
1193
1020
  return lifecycle.safeRun(fn, fallback);
1194
1021
  }
1195
1022
  };
@@ -1200,6 +1027,9 @@ const setupObservability = createFoundation;
1200
1027
 
1201
1028
  //#endregion
1202
1029
  //#region src/integrations/object-store/aws-s3.ts
1030
+ function isAwsError(err) {
1031
+ return typeof err === "object" && err !== null;
1032
+ }
1203
1033
  async function loadAwsS3() {
1204
1034
  try {
1205
1035
  const clientMod = await import("@aws-sdk/client-s3");
@@ -1214,13 +1044,10 @@ async function loadAwsS3() {
1214
1044
  getSignedUrl: presignerMod.getSignedUrl
1215
1045
  };
1216
1046
  } catch (err) {
1217
- const e = err;
1047
+ const e = err instanceof Error ? err : new Error(String(err));
1218
1048
  throw new Error(`AWS SDK not available. Install optional peer deps: @aws-sdk/client-s3 and @aws-sdk/s3-request-presigner. Original error: ${e.message}`);
1219
1049
  }
1220
1050
  }
1221
- function normalizeBody(body) {
1222
- return body;
1223
- }
1224
1051
  /**
1225
1052
  * AwsS3ObjectStore - wraps AWS S3 behind the provider-agnostic `ObjectStore` interface.
1226
1053
  *
@@ -1249,7 +1076,7 @@ var AwsS3ObjectStore = class {
1249
1076
  const res = await s3.send(new aws.PutObjectCommand({
1250
1077
  Bucket: ref.bucket,
1251
1078
  Key: ref.key,
1252
- Body: normalizeBody(body),
1079
+ Body: body,
1253
1080
  ContentType: options.contentType,
1254
1081
  CacheControl: options.cacheControl,
1255
1082
  Metadata: options.metadata
@@ -1299,10 +1126,12 @@ var AwsS3ObjectStore = class {
1299
1126
  lastModified: res.LastModified
1300
1127
  };
1301
1128
  } catch (err) {
1302
- const e = err;
1303
- const name = String(e?.name || "");
1304
- const httpStatus = e?.$metadata?.httpStatusCode;
1305
- if (httpStatus === 404 || name.includes("NotFound") || name.includes("NoSuchKey")) return { exists: false };
1129
+ if (isAwsError(err)) {
1130
+ const name = String(err.name ?? "");
1131
+ if (name === "NoSuchBucket") throw err;
1132
+ const httpStatus = err.$metadata?.httpStatusCode;
1133
+ if (httpStatus === 404 || name.includes("NotFound") || name.includes("NoSuchKey")) return { exists: false };
1134
+ }
1306
1135
  throw err;
1307
1136
  }
1308
1137
  }
@@ -1323,8 +1152,9 @@ var AwsS3ObjectStore = class {
1323
1152
  ContinuationToken: options.continuationToken,
1324
1153
  MaxKeys: options.maxKeys
1325
1154
  }));
1155
+ const contents = res?.Contents ?? [];
1326
1156
  return {
1327
- objects: (res?.Contents ?? []).map((o) => ({
1157
+ objects: contents.filter((o) => typeof o.Key === "string").map((o) => ({
1328
1158
  key: o.Key,
1329
1159
  size: o.Size,
1330
1160
  etag: o.ETag,
@@ -1355,19 +1185,31 @@ var AwsS3ObjectStore = class {
1355
1185
 
1356
1186
  //#endregion
1357
1187
  //#region src/integrations/object-store/in-memory.ts
1188
+ const DEFAULT_MAX_OBJECTS = 1e4;
1189
+ const STREAM_TIMEOUT_MS = 3e4;
1358
1190
  function toBuffer(body) {
1359
1191
  if (typeof body === "string") return Buffer.from(body);
1360
1192
  if (Buffer.isBuffer(body)) return body;
1361
1193
  if (body instanceof Uint8Array) return Buffer.from(body);
1362
1194
  return new Promise((resolve, reject) => {
1363
1195
  const chunks = [];
1196
+ const timer = setTimeout(() => {
1197
+ body.destroy(new Error("InMemoryObjectStore: stream read timed out"));
1198
+ reject(new Error("InMemoryObjectStore: stream read timed out"));
1199
+ }, STREAM_TIMEOUT_MS);
1364
1200
  body.on("data", (chunk) => chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk)));
1365
- body.on("end", () => resolve(Buffer.concat(chunks)));
1366
- body.on("error", reject);
1201
+ body.on("end", () => {
1202
+ clearTimeout(timer);
1203
+ resolve(Buffer.concat(chunks));
1204
+ });
1205
+ body.on("error", (err) => {
1206
+ clearTimeout(timer);
1207
+ reject(err);
1208
+ });
1367
1209
  });
1368
1210
  }
1369
- function simpleEtag(buf) {
1370
- return `mem-${buf.length}-${buf.subarray(0, 8).toString("hex")}`;
1211
+ function computeEtag(buf) {
1212
+ return `"${(0, node_crypto.createHash)("md5").update(buf).digest("hex")}"`;
1371
1213
  }
1372
1214
  /**
1373
1215
  * InMemoryObjectStore - useful for local dev, unit tests, and as a safe default.
@@ -1376,6 +1218,11 @@ function simpleEtag(buf) {
1376
1218
  var InMemoryObjectStore = class {
1377
1219
  provider = "in-memory";
1378
1220
  buckets = new Map();
1221
+ maxObjects;
1222
+ objectCount = 0;
1223
+ constructor(options = {}) {
1224
+ this.maxObjects = options.maxObjects ?? DEFAULT_MAX_OBJECTS;
1225
+ }
1379
1226
  bucketMap(bucket) {
1380
1227
  let m = this.buckets.get(bucket);
1381
1228
  if (!m) {
@@ -1386,15 +1233,19 @@ var InMemoryObjectStore = class {
1386
1233
  }
1387
1234
  async putObject(ref, body, options = {}) {
1388
1235
  const buf = await toBuffer(body);
1236
+ const map = this.bucketMap(ref.bucket);
1237
+ const isNew = !map.has(ref.key);
1238
+ if (isNew && this.objectCount >= this.maxObjects) throw new Error(`InMemoryObjectStore: max object limit reached (${this.maxObjects})`);
1389
1239
  const obj = {
1390
1240
  body: buf,
1391
1241
  contentType: options.contentType,
1392
1242
  cacheControl: options.cacheControl,
1393
1243
  metadata: options.metadata,
1394
- etag: simpleEtag(buf),
1244
+ etag: computeEtag(buf),
1395
1245
  lastModified: new Date()
1396
1246
  };
1397
- this.bucketMap(ref.bucket).set(ref.key, obj);
1247
+ map.set(ref.key, obj);
1248
+ if (isNew) this.objectCount++;
1398
1249
  return { etag: obj.etag };
1399
1250
  }
1400
1251
  async getObject(ref) {
@@ -1426,18 +1277,31 @@ var InMemoryObjectStore = class {
1426
1277
  };
1427
1278
  }
1428
1279
  async deleteObject(ref) {
1429
- this.bucketMap(ref.bucket).delete(ref.key);
1280
+ const map = this.bucketMap(ref.bucket);
1281
+ if (map.delete(ref.key)) this.objectCount--;
1430
1282
  }
1431
1283
  async listObjects(options) {
1432
- const { bucket, prefix = "" } = options;
1284
+ const { bucket, prefix = "", continuationToken } = options;
1285
+ const maxKeys = Math.max(1, Math.floor(options.maxKeys ?? 1e3));
1433
1286
  const map = this.bucketMap(bucket);
1434
- const objects = [...map.entries()].filter(([key]) => key.startsWith(prefix)).map(([key, obj]) => ({
1287
+ const all = [...map.entries()].filter(([key]) => key.startsWith(prefix)).map(([key, obj]) => ({
1435
1288
  key,
1436
1289
  size: obj.body.length,
1437
1290
  etag: obj.etag,
1438
1291
  lastModified: obj.lastModified
1439
1292
  })).sort((a, b) => a.key.localeCompare(b.key));
1440
- return { objects };
1293
+ let startIndex = 0;
1294
+ if (continuationToken) {
1295
+ const idx = all.findIndex((o) => o.key === continuationToken);
1296
+ if (idx === -1) throw new Error(`InMemoryObjectStore: invalid continuationToken "${continuationToken}"`);
1297
+ startIndex = idx + 1;
1298
+ }
1299
+ const page = all.slice(startIndex, startIndex + maxKeys);
1300
+ const hasMore = startIndex + maxKeys < all.length;
1301
+ return {
1302
+ objects: page,
1303
+ nextContinuationToken: hasMore ? page[page.length - 1]?.key : void 0
1304
+ };
1441
1305
  }
1442
1306
  async presignGetObject(_ref, _options) {
1443
1307
  throw new Error("InMemoryObjectStore does not support presigned URLs");
@@ -1448,17 +1312,17 @@ var InMemoryObjectStore = class {
1448
1312
  };
1449
1313
 
1450
1314
  //#endregion
1451
- exports.AutoInstrumentationConfigSchema = AutoInstrumentationConfigSchema
1315
+ exports.AutoInstrumentationConfigSchema = require_tracing.AutoInstrumentationConfigSchema
1452
1316
  exports.AwsS3ObjectStore = AwsS3ObjectStore
1453
- exports.FeaturesConfigSchema = FeaturesConfigSchema
1454
- exports.FoundationConfigSchema = FoundationConfigSchema
1317
+ exports.FeaturesConfigSchema = require_tracing.FeaturesConfigSchema
1318
+ exports.FoundationConfigSchema = require_tracing.FoundationConfigSchema
1455
1319
  exports.InMemoryObjectStore = InMemoryObjectStore
1456
- exports.LoggingConfigSchema = LoggingConfigSchema
1457
- exports.OtelConfigSchema = OtelConfigSchema
1320
+ exports.LoggingConfigSchema = require_tracing.LoggingConfigSchema
1321
+ exports.OtelConfigSchema = require_tracing.OtelConfigSchema
1458
1322
  exports.REDACT_PATHS = REDACT_PATHS
1459
- exports.RedactionConfigSchema = RedactionConfigSchema
1460
- exports.RequestLoggingConfigSchema = RequestLoggingConfigSchema
1461
- exports.ShutdownConfigSchema = ShutdownConfigSchema
1323
+ exports.RedactionConfigSchema = require_tracing.RedactionConfigSchema
1324
+ exports.RequestLoggingConfigSchema = require_tracing.RequestLoggingConfigSchema
1325
+ exports.ShutdownConfigSchema = require_tracing.ShutdownConfigSchema
1462
1326
  exports.SpanStatusCode = __opentelemetry_api.SpanStatusCode
1463
1327
  exports.buildPinoRedactConfig = buildPinoRedactConfig
1464
1328
  exports.context = __opentelemetry_api.context
@@ -1468,23 +1332,23 @@ exports.createFoundation = createFoundation
1468
1332
  exports.createHttpClient = createHttpClient
1469
1333
  exports.createLogger = createLogger
1470
1334
  exports.createObservabilityPlugin = createObservabilityPlugin
1471
- exports.getActiveSpan = getActiveSpan
1472
- exports.getDefaultOtelEndpoint = getDefaultOtelEndpoint
1335
+ exports.getActiveSpan = require_tracing.getActiveSpan
1336
+ exports.getDefaultOtelEndpoint = require_tracing.getDefaultOtelEndpoint
1473
1337
  exports.getGlobalLogger = getGlobalLogger
1474
1338
  exports.getMeter = getMeter
1475
- exports.getTraceContext = getTraceContext
1476
- exports.getTracer = getTracer
1339
+ exports.getTraceContext = require_tracing.getTraceContext
1340
+ exports.getTracer = require_tracing.getTracer
1477
1341
  exports.isMetricsEnabled = isMetricsEnabled
1478
- exports.isTracingEnabled = isTracingEnabled
1342
+ exports.isTracingEnabled = require_tracing.isTracingEnabled
1479
1343
  exports.metrics = __opentelemetry_api.metrics
1480
- exports.parseConfig = parseConfig
1344
+ exports.parseConfig = require_tracing.parseConfig
1481
1345
  exports.propagation = __opentelemetry_api.propagation
1482
1346
  exports.sanitizeBody = sanitizeBody
1483
1347
  exports.setGlobalLogger = setGlobalLogger
1484
1348
  exports.setupMetrics = setupMetrics
1485
1349
  exports.setupObservability = setupObservability
1486
- exports.setupTracing = setupTracing
1350
+ exports.setupTracing = require_tracing.setupTracing
1487
1351
  exports.shutdownMetrics = shutdownMetrics
1488
- exports.shutdownTracing = shutdownTracing
1352
+ exports.shutdownTracing = require_tracing.shutdownTracing
1489
1353
  exports.trace = __opentelemetry_api.trace
1490
1354
  //# sourceMappingURL=index.js.map