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

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-DM5OFo7l.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,34 @@ 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 retryStatusCodes = retry.retryStatusCodes ?? [
661
+ 408,
662
+ 429,
663
+ 500,
664
+ 502,
665
+ 503,
666
+ 504
667
+ ];
668
+ return !error.response || retryStatusCodes.includes(error.response?.status || 0);
669
+ },
670
+ onRetry: (retryCount, error, requestConfig) => {
671
+ logger.warn({
672
+ retryCount,
673
+ url: `${requestConfig.baseURL || ""}${requestConfig.url}`,
674
+ error: error.message
675
+ }, "Retrying request");
676
+ }
677
+ };
678
+ (0, axios_retry.default)(client, retryConfig);
679
+ }
680
+ if (cbOptions.enabled === true) {
681
+ const originalRequest = client.request.bind(client);
682
+ const breaker = new opossum.default(async (config) => originalRequest(config), {
870
683
  timeout,
871
684
  resetTimeout: cbOptions.resetTimeout ?? 3e4,
872
685
  errorThresholdPercentage: cbOptions.errorThresholdPercentage ?? 50,
@@ -875,7 +688,6 @@ function createHttpClient(options) {
875
688
  breaker.on("open", () => logger.warn({ targetService: serviceName }, "Circuit breaker OPEN"));
876
689
  breaker.on("halfOpen", () => logger.info({ targetService: serviceName }, "Circuit breaker HALF-OPEN"));
877
690
  breaker.on("close", () => logger.info({ targetService: serviceName }, "Circuit breaker CLOSED"));
878
- const originalRequest = client.request.bind(client);
879
691
  client.request = (config) => breaker.fire(config);
880
692
  client.get = (url, config) => breaker.fire({
881
693
  ...config,
@@ -913,15 +725,20 @@ function createHttpClient(options) {
913
725
  //#endregion
914
726
  //#region src/foundation.ts
915
727
  const deprecationWarnings = new Set();
916
- function warnDeprecation(oldPath, newPath) {
728
+ function warnDeprecation(oldPath, newPath, logger) {
917
729
  if (deprecationWarnings.has(oldPath)) return;
918
730
  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.`);
731
+ const msg = `foundation.${oldPath}() is deprecated. Use foundation.${newPath}() instead. This alias will be removed in the next major version.`;
732
+ if (logger) logger.warn({
733
+ deprecated: oldPath,
734
+ replacement: newPath
735
+ }, msg);
736
+ else console.warn(`[neoiq-foundation] DEPRECATED: ${msg}`);
920
737
  }
921
738
  /** Create a fully configured observability foundation */
922
739
  function createFoundation(input) {
923
740
  const startTime = Date.now();
924
- const config = parseConfig(input);
741
+ const config = require_tracing.parseConfig(input);
925
742
  const { serviceName, serviceVersion, environment, features: featuresConfig, otel, logging: loggingConfig, requestLogging: requestLoggingConfig, redaction: redactionConfig, shutdown: shutdownConfig } = config;
926
743
  const features = {
927
744
  tracing: featuresConfig.tracing ?? true,
@@ -969,7 +786,7 @@ function createFoundation(input) {
969
786
  let tracerInstance = null;
970
787
  let tracingError;
971
788
  if (features.tracing) try {
972
- setupTracing({
789
+ require_tracing.setupTracing({
973
790
  serviceName,
974
791
  serviceVersion,
975
792
  environment,
@@ -977,7 +794,7 @@ function createFoundation(input) {
977
794
  sampleRate: otel.traceSampleRate,
978
795
  autoInstrumentation: featuresConfig.autoInstrumentation
979
796
  });
980
- tracerInstance = getTracer(serviceName);
797
+ tracerInstance = require_tracing.getTracer(serviceName);
981
798
  logger.info({
982
799
  feature: "tracing",
983
800
  endpoint: otel.endpoint
@@ -1021,7 +838,7 @@ function createFoundation(input) {
1021
838
  origin
1022
839
  }, "Process crash detected, flushing telemetry");
1023
840
  const flushPromises = [];
1024
- if (features.tracing && isTracingEnabled()) flushPromises.push(shutdownTracing());
841
+ if (features.tracing && require_tracing.isTracingEnabled()) flushPromises.push(require_tracing.shutdownTracing());
1025
842
  if (features.metrics && isMetricsEnabled()) flushPromises.push(shutdownMetrics());
1026
843
  const timeout = new Promise((resolve) => setTimeout(resolve, flushTimeoutMs));
1027
844
  Promise.race([Promise.allSettled(flushPromises), timeout]).finally(() => {
@@ -1033,7 +850,7 @@ function createFoundation(input) {
1033
850
  logger.info({ flushTimeoutMs }, "Crash-flush handlers registered");
1034
851
  }
1035
852
  const traceInSpan = async (name, fn) => {
1036
- const tracer = tracerInstance || getTracer(serviceName);
853
+ const tracer = tracerInstance || require_tracing.getTracer(serviceName);
1037
854
  return new Promise((resolve, reject) => {
1038
855
  tracer.startActiveSpan(name, async (span) => {
1039
856
  try {
@@ -1062,10 +879,10 @@ function createFoundation(input) {
1062
879
  logger,
1063
880
  tracer: tracerInstance,
1064
881
  meter: meterInstance,
1065
- getTracer: (name) => getTracer(name || serviceName),
882
+ getTracer: (name) => require_tracing.getTracer(name || serviceName),
1066
883
  getMeter: (name, version) => getMeter(name, version),
1067
- getTraceContext,
1068
- getActiveSpan,
884
+ getTraceContext: require_tracing.getTraceContext,
885
+ getActiveSpan: require_tracing.getActiveSpan,
1069
886
  trace: traceInSpan
1070
887
  };
1071
888
  const httpModule = { createClient: (options) => createHttpClient({
@@ -1073,13 +890,15 @@ function createFoundation(input) {
1073
890
  foundation
1074
891
  }) };
1075
892
  const buildHealthStatus = () => {
1076
- const tracingUp = !features.tracing || !tracingError && isTracingEnabled();
893
+ const tracingUp = !features.tracing || !tracingError && require_tracing.isTracingEnabled();
1077
894
  const metricsUp = !features.metrics || !metricsError && isMetricsEnabled();
1078
895
  const loggingUp = !loggingError;
1079
896
  const allUp = tracingUp && metricsUp && loggingUp;
1080
- const anyDown = features.tracing && tracingError || features.metrics && metricsError || loggingError;
897
+ const allDown = (!tracingUp || !features.tracing) && (!metricsUp || !features.metrics) && !loggingUp;
898
+ let status = "healthy";
899
+ if (!allUp) status = allDown ? "unhealthy" : "degraded";
1081
900
  return {
1082
- status: allUp ? "healthy" : anyDown ? "degraded" : "unhealthy",
901
+ status,
1083
902
  timestamp: new Date().toISOString(),
1084
903
  service: serviceName,
1085
904
  version: serviceVersion,
@@ -1106,13 +925,13 @@ function createFoundation(input) {
1106
925
  const shutdownFn = async () => {
1107
926
  logger.info({}, "Shutting down foundation...");
1108
927
  const promises = [];
1109
- if (features.tracing && isTracingEnabled()) promises.push(shutdownTracing());
928
+ if (features.tracing && require_tracing.isTracingEnabled()) promises.push(require_tracing.shutdownTracing());
1110
929
  if (features.metrics && isMetricsEnabled()) promises.push(shutdownMetrics());
1111
930
  await Promise.all(promises);
1112
931
  logger.info({}, "Foundation shutdown complete");
1113
932
  };
1114
933
  const isReadyFn = () => {
1115
- if (features.tracing && !tracingError && !isTracingEnabled()) return false;
934
+ if (features.tracing && !tracingError && !require_tracing.isTracingEnabled()) return false;
1116
935
  if (features.metrics && !metricsError && !isMetricsEnabled()) return false;
1117
936
  return true;
1118
937
  };
@@ -1153,43 +972,43 @@ function createFoundation(input) {
1153
972
  tracer: tracerInstance,
1154
973
  meter: meterInstance,
1155
974
  getTracer: (name) => {
1156
- warnDeprecation("getTracer", "observability.getTracer");
975
+ warnDeprecation("getTracer", "observability.getTracer", logger);
1157
976
  return observability.getTracer(name);
1158
977
  },
1159
978
  getMeter: (name, version) => {
1160
- warnDeprecation("getMeter", "observability.getMeter");
979
+ warnDeprecation("getMeter", "observability.getMeter", logger);
1161
980
  return observability.getMeter(name, version);
1162
981
  },
1163
982
  getTraceContext: () => {
1164
- warnDeprecation("getTraceContext", "observability.getTraceContext");
983
+ warnDeprecation("getTraceContext", "observability.getTraceContext", logger);
1165
984
  return observability.getTraceContext();
1166
985
  },
1167
986
  getActiveSpan: () => {
1168
- warnDeprecation("getActiveSpan", "observability.getActiveSpan");
987
+ warnDeprecation("getActiveSpan", "observability.getActiveSpan", logger);
1169
988
  return observability.getActiveSpan();
1170
989
  },
1171
990
  createHttpClient: (options) => {
1172
- warnDeprecation("createHttpClient", "http.createClient");
991
+ warnDeprecation("createHttpClient", "http.createClient", logger);
1173
992
  return httpModule.createClient(options);
1174
993
  },
1175
994
  shutdown: () => {
1176
- warnDeprecation("shutdown", "lifecycle.shutdown");
995
+ warnDeprecation("shutdown", "lifecycle.shutdown", logger);
1177
996
  return lifecycle.shutdown();
1178
997
  },
1179
998
  isReady: () => {
1180
- warnDeprecation("isReady", "lifecycle.isReady");
999
+ warnDeprecation("isReady", "lifecycle.isReady", logger);
1181
1000
  return lifecycle.isReady();
1182
1001
  },
1183
1002
  health: () => {
1184
- warnDeprecation("health", "lifecycle.health");
1003
+ warnDeprecation("health", "lifecycle.health", logger);
1185
1004
  return lifecycle.health();
1186
1005
  },
1187
1006
  trace: (name, fn) => {
1188
- warnDeprecation("trace", "observability.trace");
1007
+ warnDeprecation("trace", "observability.trace", logger);
1189
1008
  return observability.trace(name, fn);
1190
1009
  },
1191
1010
  safeRun: (fn, fallback) => {
1192
- warnDeprecation("safeRun", "lifecycle.safeRun");
1011
+ warnDeprecation("safeRun", "lifecycle.safeRun", logger);
1193
1012
  return lifecycle.safeRun(fn, fallback);
1194
1013
  }
1195
1014
  };
@@ -1200,6 +1019,9 @@ const setupObservability = createFoundation;
1200
1019
 
1201
1020
  //#endregion
1202
1021
  //#region src/integrations/object-store/aws-s3.ts
1022
+ function isAwsError(err) {
1023
+ return typeof err === "object" && err !== null;
1024
+ }
1203
1025
  async function loadAwsS3() {
1204
1026
  try {
1205
1027
  const clientMod = await import("@aws-sdk/client-s3");
@@ -1214,13 +1036,10 @@ async function loadAwsS3() {
1214
1036
  getSignedUrl: presignerMod.getSignedUrl
1215
1037
  };
1216
1038
  } catch (err) {
1217
- const e = err;
1039
+ const e = err instanceof Error ? err : new Error(String(err));
1218
1040
  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
1041
  }
1220
1042
  }
1221
- function normalizeBody(body) {
1222
- return body;
1223
- }
1224
1043
  /**
1225
1044
  * AwsS3ObjectStore - wraps AWS S3 behind the provider-agnostic `ObjectStore` interface.
1226
1045
  *
@@ -1249,7 +1068,7 @@ var AwsS3ObjectStore = class {
1249
1068
  const res = await s3.send(new aws.PutObjectCommand({
1250
1069
  Bucket: ref.bucket,
1251
1070
  Key: ref.key,
1252
- Body: normalizeBody(body),
1071
+ Body: body,
1253
1072
  ContentType: options.contentType,
1254
1073
  CacheControl: options.cacheControl,
1255
1074
  Metadata: options.metadata
@@ -1299,10 +1118,11 @@ var AwsS3ObjectStore = class {
1299
1118
  lastModified: res.LastModified
1300
1119
  };
1301
1120
  } 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 };
1121
+ if (isAwsError(err)) {
1122
+ const name = String(err.name ?? "");
1123
+ const httpStatus = err.$metadata?.httpStatusCode;
1124
+ if (httpStatus === 404 || name.includes("NotFound") || name.includes("NoSuchKey")) return { exists: false };
1125
+ }
1306
1126
  throw err;
1307
1127
  }
1308
1128
  }
@@ -1323,8 +1143,9 @@ var AwsS3ObjectStore = class {
1323
1143
  ContinuationToken: options.continuationToken,
1324
1144
  MaxKeys: options.maxKeys
1325
1145
  }));
1146
+ const contents = res?.Contents ?? [];
1326
1147
  return {
1327
- objects: (res?.Contents ?? []).map((o) => ({
1148
+ objects: contents.filter((o) => typeof o.Key === "string").map((o) => ({
1328
1149
  key: o.Key,
1329
1150
  size: o.Size,
1330
1151
  etag: o.ETag,
@@ -1355,19 +1176,31 @@ var AwsS3ObjectStore = class {
1355
1176
 
1356
1177
  //#endregion
1357
1178
  //#region src/integrations/object-store/in-memory.ts
1179
+ const DEFAULT_MAX_OBJECTS = 1e4;
1180
+ const STREAM_TIMEOUT_MS = 3e4;
1358
1181
  function toBuffer(body) {
1359
1182
  if (typeof body === "string") return Buffer.from(body);
1360
1183
  if (Buffer.isBuffer(body)) return body;
1361
1184
  if (body instanceof Uint8Array) return Buffer.from(body);
1362
1185
  return new Promise((resolve, reject) => {
1363
1186
  const chunks = [];
1187
+ const timer = setTimeout(() => {
1188
+ body.destroy(new Error("InMemoryObjectStore: stream read timed out"));
1189
+ reject(new Error("InMemoryObjectStore: stream read timed out"));
1190
+ }, STREAM_TIMEOUT_MS);
1364
1191
  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);
1192
+ body.on("end", () => {
1193
+ clearTimeout(timer);
1194
+ resolve(Buffer.concat(chunks));
1195
+ });
1196
+ body.on("error", (err) => {
1197
+ clearTimeout(timer);
1198
+ reject(err);
1199
+ });
1367
1200
  });
1368
1201
  }
1369
- function simpleEtag(buf) {
1370
- return `mem-${buf.length}-${buf.subarray(0, 8).toString("hex")}`;
1202
+ function computeEtag(buf) {
1203
+ return `"${(0, node_crypto.createHash)("md5").update(buf).digest("hex")}"`;
1371
1204
  }
1372
1205
  /**
1373
1206
  * InMemoryObjectStore - useful for local dev, unit tests, and as a safe default.
@@ -1376,6 +1209,11 @@ function simpleEtag(buf) {
1376
1209
  var InMemoryObjectStore = class {
1377
1210
  provider = "in-memory";
1378
1211
  buckets = new Map();
1212
+ maxObjects;
1213
+ objectCount = 0;
1214
+ constructor(options = {}) {
1215
+ this.maxObjects = options.maxObjects ?? DEFAULT_MAX_OBJECTS;
1216
+ }
1379
1217
  bucketMap(bucket) {
1380
1218
  let m = this.buckets.get(bucket);
1381
1219
  if (!m) {
@@ -1385,16 +1223,20 @@ var InMemoryObjectStore = class {
1385
1223
  return m;
1386
1224
  }
1387
1225
  async putObject(ref, body, options = {}) {
1226
+ const map = this.bucketMap(ref.bucket);
1227
+ const isNew = !map.has(ref.key);
1228
+ if (isNew && this.objectCount >= this.maxObjects) throw new Error(`InMemoryObjectStore: max object limit reached (${this.maxObjects})`);
1388
1229
  const buf = await toBuffer(body);
1389
1230
  const obj = {
1390
1231
  body: buf,
1391
1232
  contentType: options.contentType,
1392
1233
  cacheControl: options.cacheControl,
1393
1234
  metadata: options.metadata,
1394
- etag: simpleEtag(buf),
1235
+ etag: computeEtag(buf),
1395
1236
  lastModified: new Date()
1396
1237
  };
1397
- this.bucketMap(ref.bucket).set(ref.key, obj);
1238
+ map.set(ref.key, obj);
1239
+ if (isNew) this.objectCount++;
1398
1240
  return { etag: obj.etag };
1399
1241
  }
1400
1242
  async getObject(ref) {
@@ -1426,18 +1268,30 @@ var InMemoryObjectStore = class {
1426
1268
  };
1427
1269
  }
1428
1270
  async deleteObject(ref) {
1429
- this.bucketMap(ref.bucket).delete(ref.key);
1271
+ const map = this.bucketMap(ref.bucket);
1272
+ if (map.delete(ref.key)) this.objectCount--;
1430
1273
  }
1431
1274
  async listObjects(options) {
1432
- const { bucket, prefix = "" } = options;
1275
+ const { bucket, prefix = "", continuationToken, maxKeys = 1e3 } = options;
1433
1276
  const map = this.bucketMap(bucket);
1434
- const objects = [...map.entries()].filter(([key]) => key.startsWith(prefix)).map(([key, obj]) => ({
1277
+ const all = [...map.entries()].filter(([key]) => key.startsWith(prefix)).map(([key, obj]) => ({
1435
1278
  key,
1436
1279
  size: obj.body.length,
1437
1280
  etag: obj.etag,
1438
1281
  lastModified: obj.lastModified
1439
1282
  })).sort((a, b) => a.key.localeCompare(b.key));
1440
- return { objects };
1283
+ let startIndex = 0;
1284
+ if (continuationToken) {
1285
+ const idx = all.findIndex((o) => o.key === continuationToken);
1286
+ if (idx === -1) throw new Error(`InMemoryObjectStore: invalid continuationToken "${continuationToken}"`);
1287
+ startIndex = idx + 1;
1288
+ }
1289
+ const page = all.slice(startIndex, startIndex + maxKeys);
1290
+ const hasMore = startIndex + maxKeys < all.length;
1291
+ return {
1292
+ objects: page,
1293
+ nextContinuationToken: hasMore ? page[page.length - 1]?.key : void 0
1294
+ };
1441
1295
  }
1442
1296
  async presignGetObject(_ref, _options) {
1443
1297
  throw new Error("InMemoryObjectStore does not support presigned URLs");
@@ -1448,17 +1302,17 @@ var InMemoryObjectStore = class {
1448
1302
  };
1449
1303
 
1450
1304
  //#endregion
1451
- exports.AutoInstrumentationConfigSchema = AutoInstrumentationConfigSchema
1305
+ exports.AutoInstrumentationConfigSchema = require_tracing.AutoInstrumentationConfigSchema
1452
1306
  exports.AwsS3ObjectStore = AwsS3ObjectStore
1453
- exports.FeaturesConfigSchema = FeaturesConfigSchema
1454
- exports.FoundationConfigSchema = FoundationConfigSchema
1307
+ exports.FeaturesConfigSchema = require_tracing.FeaturesConfigSchema
1308
+ exports.FoundationConfigSchema = require_tracing.FoundationConfigSchema
1455
1309
  exports.InMemoryObjectStore = InMemoryObjectStore
1456
- exports.LoggingConfigSchema = LoggingConfigSchema
1457
- exports.OtelConfigSchema = OtelConfigSchema
1310
+ exports.LoggingConfigSchema = require_tracing.LoggingConfigSchema
1311
+ exports.OtelConfigSchema = require_tracing.OtelConfigSchema
1458
1312
  exports.REDACT_PATHS = REDACT_PATHS
1459
- exports.RedactionConfigSchema = RedactionConfigSchema
1460
- exports.RequestLoggingConfigSchema = RequestLoggingConfigSchema
1461
- exports.ShutdownConfigSchema = ShutdownConfigSchema
1313
+ exports.RedactionConfigSchema = require_tracing.RedactionConfigSchema
1314
+ exports.RequestLoggingConfigSchema = require_tracing.RequestLoggingConfigSchema
1315
+ exports.ShutdownConfigSchema = require_tracing.ShutdownConfigSchema
1462
1316
  exports.SpanStatusCode = __opentelemetry_api.SpanStatusCode
1463
1317
  exports.buildPinoRedactConfig = buildPinoRedactConfig
1464
1318
  exports.context = __opentelemetry_api.context
@@ -1468,23 +1322,23 @@ exports.createFoundation = createFoundation
1468
1322
  exports.createHttpClient = createHttpClient
1469
1323
  exports.createLogger = createLogger
1470
1324
  exports.createObservabilityPlugin = createObservabilityPlugin
1471
- exports.getActiveSpan = getActiveSpan
1472
- exports.getDefaultOtelEndpoint = getDefaultOtelEndpoint
1325
+ exports.getActiveSpan = require_tracing.getActiveSpan
1326
+ exports.getDefaultOtelEndpoint = require_tracing.getDefaultOtelEndpoint
1473
1327
  exports.getGlobalLogger = getGlobalLogger
1474
1328
  exports.getMeter = getMeter
1475
- exports.getTraceContext = getTraceContext
1476
- exports.getTracer = getTracer
1329
+ exports.getTraceContext = require_tracing.getTraceContext
1330
+ exports.getTracer = require_tracing.getTracer
1477
1331
  exports.isMetricsEnabled = isMetricsEnabled
1478
- exports.isTracingEnabled = isTracingEnabled
1332
+ exports.isTracingEnabled = require_tracing.isTracingEnabled
1479
1333
  exports.metrics = __opentelemetry_api.metrics
1480
- exports.parseConfig = parseConfig
1334
+ exports.parseConfig = require_tracing.parseConfig
1481
1335
  exports.propagation = __opentelemetry_api.propagation
1482
1336
  exports.sanitizeBody = sanitizeBody
1483
1337
  exports.setGlobalLogger = setGlobalLogger
1484
1338
  exports.setupMetrics = setupMetrics
1485
1339
  exports.setupObservability = setupObservability
1486
- exports.setupTracing = setupTracing
1340
+ exports.setupTracing = require_tracing.setupTracing
1487
1341
  exports.shutdownMetrics = shutdownMetrics
1488
- exports.shutdownTracing = shutdownTracing
1342
+ exports.shutdownTracing = require_tracing.shutdownTracing
1489
1343
  exports.trace = __opentelemetry_api.trace
1490
1344
  //# sourceMappingURL=index.js.map