apitally 0.24.0 → 0.25.0

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.
Files changed (152) hide show
  1. package/dist/adonisjs/index.cjs +3 -0
  2. package/dist/adonisjs/index.cjs.map +1 -1
  3. package/dist/adonisjs/index.d.cts +2 -0
  4. package/dist/adonisjs/index.d.ts +2 -0
  5. package/dist/adonisjs/index.js +2 -0
  6. package/dist/adonisjs/index.js.map +1 -1
  7. package/dist/adonisjs/middleware.cjs +6 -2
  8. package/dist/adonisjs/middleware.cjs.map +1 -1
  9. package/dist/adonisjs/middleware.d.cts +2 -0
  10. package/dist/adonisjs/middleware.d.ts +2 -0
  11. package/dist/adonisjs/middleware.js +6 -2
  12. package/dist/adonisjs/middleware.js.map +1 -1
  13. package/dist/adonisjs/provider.d.cts +2 -0
  14. package/dist/adonisjs/provider.d.ts +2 -0
  15. package/dist/adonisjs/stubs/config/apitally.stub +1 -0
  16. package/dist/common/client.cjs +4 -0
  17. package/dist/common/client.cjs.map +1 -1
  18. package/dist/common/client.d.cts +3 -0
  19. package/dist/common/client.d.ts +3 -0
  20. package/dist/common/client.js +4 -0
  21. package/dist/common/client.js.map +1 -1
  22. package/dist/common/consumerRegistry.d.cts +2 -0
  23. package/dist/common/consumerRegistry.d.ts +2 -0
  24. package/dist/common/requestCounter.d.cts +2 -0
  25. package/dist/common/requestCounter.d.ts +2 -0
  26. package/dist/common/requestLogger.cjs +11 -2
  27. package/dist/common/requestLogger.cjs.map +1 -1
  28. package/dist/common/requestLogger.d.cts +6 -1
  29. package/dist/common/requestLogger.d.ts +6 -1
  30. package/dist/common/requestLogger.js +11 -2
  31. package/dist/common/requestLogger.js.map +1 -1
  32. package/dist/common/serverErrorCounter.d.cts +2 -0
  33. package/dist/common/serverErrorCounter.d.ts +2 -0
  34. package/dist/common/spanCollector.cjs +217 -0
  35. package/dist/common/spanCollector.cjs.map +1 -0
  36. package/dist/common/spanCollector.d.cts +50 -0
  37. package/dist/common/spanCollector.d.ts +50 -0
  38. package/dist/common/spanCollector.js +194 -0
  39. package/dist/common/spanCollector.js.map +1 -0
  40. package/dist/common/types.d.cts +2 -0
  41. package/dist/common/types.d.ts +2 -0
  42. package/dist/common/validationErrorCounter.d.cts +2 -0
  43. package/dist/common/validationErrorCounter.d.ts +2 -0
  44. package/dist/elysia/index.cjs +3 -0
  45. package/dist/elysia/index.cjs.map +1 -1
  46. package/dist/elysia/index.d.cts +2 -0
  47. package/dist/elysia/index.d.ts +2 -0
  48. package/dist/elysia/index.js +2 -0
  49. package/dist/elysia/index.js.map +1 -1
  50. package/dist/elysia/plugin.cjs +9 -1
  51. package/dist/elysia/plugin.cjs.map +1 -1
  52. package/dist/elysia/plugin.d.cts +4 -0
  53. package/dist/elysia/plugin.d.ts +4 -0
  54. package/dist/elysia/plugin.js +9 -1
  55. package/dist/elysia/plugin.js.map +1 -1
  56. package/dist/elysia/utils.d.cts +2 -0
  57. package/dist/elysia/utils.d.ts +2 -0
  58. package/dist/express/index.cjs +3 -0
  59. package/dist/express/index.cjs.map +1 -1
  60. package/dist/express/index.d.cts +2 -0
  61. package/dist/express/index.d.ts +2 -0
  62. package/dist/express/index.js +2 -0
  63. package/dist/express/index.js.map +1 -1
  64. package/dist/express/middleware.cjs +85 -77
  65. package/dist/express/middleware.cjs.map +1 -1
  66. package/dist/express/middleware.d.cts +2 -0
  67. package/dist/express/middleware.d.ts +2 -0
  68. package/dist/express/middleware.js +85 -77
  69. package/dist/express/middleware.js.map +1 -1
  70. package/dist/fastify/index.cjs +3 -0
  71. package/dist/fastify/index.cjs.map +1 -1
  72. package/dist/fastify/index.d.cts +2 -0
  73. package/dist/fastify/index.d.ts +2 -0
  74. package/dist/fastify/index.js +2 -0
  75. package/dist/fastify/index.js.map +1 -1
  76. package/dist/fastify/plugin.cjs +14 -5
  77. package/dist/fastify/plugin.cjs.map +1 -1
  78. package/dist/fastify/plugin.d.cts +4 -0
  79. package/dist/fastify/plugin.d.ts +4 -0
  80. package/dist/fastify/plugin.js +14 -5
  81. package/dist/fastify/plugin.js.map +1 -1
  82. package/dist/h3/index.cjs +3 -0
  83. package/dist/h3/index.cjs.map +1 -1
  84. package/dist/h3/index.d.cts +2 -0
  85. package/dist/h3/index.d.ts +2 -0
  86. package/dist/h3/index.js +2 -0
  87. package/dist/h3/index.js.map +1 -1
  88. package/dist/h3/plugin.cjs +13 -5
  89. package/dist/h3/plugin.cjs.map +1 -1
  90. package/dist/h3/plugin.d.cts +4 -0
  91. package/dist/h3/plugin.d.ts +4 -0
  92. package/dist/h3/plugin.js +13 -5
  93. package/dist/h3/plugin.js.map +1 -1
  94. package/dist/hapi/index.cjs +3 -0
  95. package/dist/hapi/index.cjs.map +1 -1
  96. package/dist/hapi/index.d.cts +2 -0
  97. package/dist/hapi/index.d.ts +2 -0
  98. package/dist/hapi/index.js +2 -0
  99. package/dist/hapi/index.js.map +1 -1
  100. package/dist/hapi/plugin.cjs +10 -3
  101. package/dist/hapi/plugin.cjs.map +1 -1
  102. package/dist/hapi/plugin.d.cts +4 -0
  103. package/dist/hapi/plugin.d.ts +4 -0
  104. package/dist/hapi/plugin.js +10 -3
  105. package/dist/hapi/plugin.js.map +1 -1
  106. package/dist/hapi/utils.d.cts +2 -0
  107. package/dist/hapi/utils.d.ts +2 -0
  108. package/dist/hono/index.cjs +3 -0
  109. package/dist/hono/index.cjs.map +1 -1
  110. package/dist/hono/index.d.cts +2 -0
  111. package/dist/hono/index.d.ts +2 -0
  112. package/dist/hono/index.js +2 -0
  113. package/dist/hono/index.js.map +1 -1
  114. package/dist/hono/middleware.cjs +6 -2
  115. package/dist/hono/middleware.cjs.map +1 -1
  116. package/dist/hono/middleware.d.cts +2 -0
  117. package/dist/hono/middleware.d.ts +2 -0
  118. package/dist/hono/middleware.js +6 -2
  119. package/dist/hono/middleware.js.map +1 -1
  120. package/dist/hono/utils.d.cts +2 -0
  121. package/dist/hono/utils.d.ts +2 -0
  122. package/dist/koa/index.cjs +3 -0
  123. package/dist/koa/index.cjs.map +1 -1
  124. package/dist/koa/index.d.cts +2 -0
  125. package/dist/koa/index.d.ts +2 -0
  126. package/dist/koa/index.js +2 -0
  127. package/dist/koa/index.js.map +1 -1
  128. package/dist/koa/middleware.cjs +8 -4
  129. package/dist/koa/middleware.cjs.map +1 -1
  130. package/dist/koa/middleware.d.cts +2 -0
  131. package/dist/koa/middleware.d.ts +2 -0
  132. package/dist/koa/middleware.js +8 -4
  133. package/dist/koa/middleware.js.map +1 -1
  134. package/dist/loggers/console.d.cts +4 -0
  135. package/dist/loggers/console.d.ts +4 -0
  136. package/dist/loggers/hapi.d.cts +4 -0
  137. package/dist/loggers/hapi.d.ts +4 -0
  138. package/dist/loggers/index.d.cts +4 -0
  139. package/dist/loggers/index.d.ts +4 -0
  140. package/dist/loggers/nestjs.d.cts +4 -0
  141. package/dist/loggers/nestjs.d.ts +4 -0
  142. package/dist/loggers/pino.d.cts +4 -0
  143. package/dist/loggers/pino.d.ts +4 -0
  144. package/dist/loggers/winston.d.cts +4 -0
  145. package/dist/loggers/winston.d.ts +4 -0
  146. package/dist/nestjs/index.cjs +3 -0
  147. package/dist/nestjs/index.cjs.map +1 -1
  148. package/dist/nestjs/index.d.cts +2 -0
  149. package/dist/nestjs/index.d.ts +2 -0
  150. package/dist/nestjs/index.js +2 -0
  151. package/dist/nestjs/index.js.map +1 -1
  152. package/package.json +5 -2
@@ -0,0 +1,217 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
7
+ var __export = (target, all) => {
8
+ for (var name in all)
9
+ __defProp(target, name, { get: all[name], enumerable: true });
10
+ };
11
+ var __copyProps = (to, from, except, desc) => {
12
+ if (from && typeof from === "object" || typeof from === "function") {
13
+ for (let key of __getOwnPropNames(from))
14
+ if (!__hasOwnProp.call(to, key) && key !== except)
15
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
16
+ }
17
+ return to;
18
+ };
19
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
20
+ var spanCollector_exports = {};
21
+ __export(spanCollector_exports, {
22
+ ApitallySpanProcessor: () => ApitallySpanProcessor,
23
+ default: () => SpanCollector
24
+ });
25
+ module.exports = __toCommonJS(spanCollector_exports);
26
+ var import_api = require("@opentelemetry/api");
27
+ var import_context_async_hooks = require("@opentelemetry/context-async-hooks");
28
+ var import_sdk_trace_base = require("@opentelemetry/sdk-trace-base");
29
+ var import_client = require("./client.js");
30
+ var _a;
31
+ let AsyncLocalStorageContextManager = (_a = class extends import_context_async_hooks.AsyncLocalStorageContextManager {
32
+ enterWith(ctx) {
33
+ this._asyncLocalStorage.enterWith(ctx);
34
+ }
35
+ }, __name(_a, "AsyncLocalStorageContextManager"), _a);
36
+ const TRACE_MAX_AGE = 5 * 60 * 1e3;
37
+ const _SpanCollector = class _SpanCollector {
38
+ enabled;
39
+ includedSpanIds = /* @__PURE__ */ new Map();
40
+ collectedSpans = /* @__PURE__ */ new Map();
41
+ traceStartTimes = /* @__PURE__ */ new Map();
42
+ maintainIntervalId;
43
+ contextManager;
44
+ tracer;
45
+ logger;
46
+ constructor(enabled, logger) {
47
+ this.enabled = enabled;
48
+ this.logger = logger;
49
+ if (enabled) {
50
+ this.setupTracerProvider();
51
+ this.maintainIntervalId = setInterval(() => {
52
+ this.maintain();
53
+ }, 6e4);
54
+ }
55
+ }
56
+ setupTracerProvider() {
57
+ this.contextManager = new AsyncLocalStorageContextManager();
58
+ import_api.context.setGlobalContextManager(this.contextManager);
59
+ const provider = new import_sdk_trace_base.BasicTracerProvider({
60
+ spanProcessors: [
61
+ this
62
+ ]
63
+ });
64
+ import_api.trace.setGlobalTracerProvider(provider);
65
+ this.tracer = import_api.trace.getTracer("apitally");
66
+ }
67
+ startSpan() {
68
+ if (!this.enabled || !this.tracer) {
69
+ return {
70
+ setName: /* @__PURE__ */ __name(() => void 0, "setName"),
71
+ runInContext: /* @__PURE__ */ __name((fn) => {
72
+ return fn();
73
+ }, "runInContext"),
74
+ enterContext: /* @__PURE__ */ __name(() => void 0, "enterContext"),
75
+ end: /* @__PURE__ */ __name(() => void 0, "end")
76
+ };
77
+ }
78
+ const span = this.tracer.startSpan("root");
79
+ const spanCtx = span.spanContext();
80
+ const traceId = spanCtx.traceId;
81
+ const ctx = import_api.trace.setSpan(import_api.context.active(), span);
82
+ let ended = false;
83
+ this.includedSpanIds.set(traceId, /* @__PURE__ */ new Set([
84
+ spanCtx.spanId
85
+ ]));
86
+ this.collectedSpans.set(traceId, []);
87
+ this.traceStartTimes.set(traceId, Date.now());
88
+ return {
89
+ traceId,
90
+ setName: /* @__PURE__ */ __name((name) => {
91
+ span.updateName(name);
92
+ }, "setName"),
93
+ runInContext: /* @__PURE__ */ __name((fn) => {
94
+ return import_api.context.with(ctx, fn);
95
+ }, "runInContext"),
96
+ enterContext: /* @__PURE__ */ __name(() => {
97
+ var _a2;
98
+ (_a2 = this.contextManager) == null ? void 0 : _a2.enterWith(ctx);
99
+ }, "enterContext"),
100
+ end: /* @__PURE__ */ __name(() => {
101
+ if (ended) return;
102
+ span.end();
103
+ ended = true;
104
+ return this.getAndClearSpans(traceId);
105
+ }, "end")
106
+ };
107
+ }
108
+ getAndClearSpans(traceId) {
109
+ const spans = this.collectedSpans.get(traceId) ?? [];
110
+ this.collectedSpans.delete(traceId);
111
+ this.includedSpanIds.delete(traceId);
112
+ this.traceStartTimes.delete(traceId);
113
+ return spans;
114
+ }
115
+ onStart(span) {
116
+ var _a2;
117
+ if (!this.enabled) return;
118
+ const ctx = span.spanContext();
119
+ const traceId = ctx.traceId;
120
+ const spanId = ctx.spanId;
121
+ const includedSpans = this.includedSpanIds.get(traceId);
122
+ if (!includedSpans) return;
123
+ const parentSpanId = (_a2 = span.parentSpanContext) == null ? void 0 : _a2.spanId;
124
+ if (parentSpanId && includedSpans.has(parentSpanId)) {
125
+ includedSpans.add(spanId);
126
+ }
127
+ }
128
+ onEnd(span) {
129
+ if (!this.enabled) return;
130
+ const ctx = span.spanContext();
131
+ const traceId = ctx.traceId;
132
+ const spanId = ctx.spanId;
133
+ const includedSpans = this.includedSpanIds.get(traceId);
134
+ if (!includedSpans || !includedSpans.has(spanId)) return;
135
+ const spans = this.collectedSpans.get(traceId);
136
+ if (spans) {
137
+ spans.push(this.serializeSpan(span));
138
+ }
139
+ }
140
+ serializeSpan(span) {
141
+ var _a2;
142
+ const ctx = span.spanContext();
143
+ const data = {
144
+ spanId: ctx.spanId,
145
+ parentSpanId: ((_a2 = span.parentSpanContext) == null ? void 0 : _a2.spanId) || null,
146
+ name: span.name,
147
+ kind: import_api.SpanKind[span.kind] ?? "INTERNAL",
148
+ // HrTime is [seconds, nanoseconds], convert to nanoseconds as string to avoid precision loss
149
+ startTime: (BigInt(span.startTime[0]) * 1000000000n + BigInt(span.startTime[1])).toString(),
150
+ endTime: (BigInt(span.endTime[0]) * 1000000000n + BigInt(span.endTime[1])).toString()
151
+ };
152
+ if (span.status.code !== import_api.SpanStatusCode.UNSET) {
153
+ data.status = import_api.SpanStatusCode[span.status.code];
154
+ }
155
+ if (span.attributes && Object.keys(span.attributes).length > 0) {
156
+ data.attributes = {
157
+ ...span.attributes
158
+ };
159
+ }
160
+ return data;
161
+ }
162
+ maintain() {
163
+ const now = Date.now();
164
+ for (const [traceId, startTime] of this.traceStartTimes) {
165
+ if (now - startTime > TRACE_MAX_AGE) {
166
+ this.collectedSpans.delete(traceId);
167
+ this.includedSpanIds.delete(traceId);
168
+ this.traceStartTimes.delete(traceId);
169
+ }
170
+ }
171
+ }
172
+ async shutdown() {
173
+ this.enabled = false;
174
+ this.includedSpanIds.clear();
175
+ this.collectedSpans.clear();
176
+ this.traceStartTimes.clear();
177
+ if (this.maintainIntervalId) {
178
+ clearInterval(this.maintainIntervalId);
179
+ }
180
+ }
181
+ async forceFlush() {
182
+ }
183
+ };
184
+ __name(_SpanCollector, "SpanCollector");
185
+ let SpanCollector = _SpanCollector;
186
+ const _ApitallySpanProcessor = class _ApitallySpanProcessor {
187
+ getCollector() {
188
+ try {
189
+ return import_client.ApitallyClient.getInstance().spanCollector;
190
+ } catch {
191
+ return void 0;
192
+ }
193
+ }
194
+ onStart(span) {
195
+ var _a2;
196
+ (_a2 = this.getCollector()) == null ? void 0 : _a2.onStart(span);
197
+ }
198
+ onEnd(span) {
199
+ var _a2;
200
+ (_a2 = this.getCollector()) == null ? void 0 : _a2.onEnd(span);
201
+ }
202
+ async shutdown() {
203
+ var _a2;
204
+ (_a2 = this.getCollector()) == null ? void 0 : _a2.shutdown();
205
+ }
206
+ async forceFlush() {
207
+ var _a2;
208
+ (_a2 = this.getCollector()) == null ? void 0 : _a2.forceFlush();
209
+ }
210
+ };
211
+ __name(_ApitallySpanProcessor, "ApitallySpanProcessor");
212
+ let ApitallySpanProcessor = _ApitallySpanProcessor;
213
+ // Annotate the CommonJS export names for ESM import in node:
214
+ 0 && (module.exports = {
215
+ ApitallySpanProcessor
216
+ });
217
+ //# sourceMappingURL=spanCollector.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/common/spanCollector.ts"],"sourcesContent":["import {\n context,\n type Context,\n SpanKind,\n SpanStatusCode,\n trace,\n type Tracer,\n} from \"@opentelemetry/api\";\nimport { AsyncLocalStorageContextManager as _AsyncLocalStorageContextManager } from \"@opentelemetry/context-async-hooks\";\nimport {\n BasicTracerProvider,\n type ReadableSpan,\n type Span,\n SpanProcessor,\n} from \"@opentelemetry/sdk-trace-base\";\n\nimport { ApitallyClient } from \"./client.js\";\nimport { Logger } from \"./logging.js\";\n\n/**\n * Extends the official AsyncLocalStorageContextManager to add enterWith support\n * for frameworks that need to persist context across hook boundaries (e.g. Elysia).\n */\nclass AsyncLocalStorageContextManager extends _AsyncLocalStorageContextManager {\n enterWith(ctx: Context): void {\n // @ts-expect-error: _asyncLocalStorage is private\n this._asyncLocalStorage.enterWith(ctx);\n }\n}\n\nexport type SpanData = {\n spanId: string;\n parentSpanId: string | null;\n name: string;\n kind: string;\n startTime: string; // bigint as string\n endTime: string; // bigint as string\n status?: string;\n attributes?: Record<string, unknown>;\n};\n\nexport type SpanHandle = {\n traceId?: string;\n setName: (name: string) => void;\n runInContext: <T>(fn: () => T) => T;\n enterContext: () => void;\n end: () => SpanData[] | undefined;\n};\n\nconst TRACE_MAX_AGE = 5 * 60 * 1000; // 5 minutes\n\nexport default class SpanCollector implements SpanProcessor {\n public enabled: boolean;\n private includedSpanIds: Map<string, Set<string>> = new Map();\n private collectedSpans: Map<string, SpanData[]> = new Map();\n private traceStartTimes: Map<string, number> = new Map();\n private maintainIntervalId?: NodeJS.Timeout;\n private contextManager?: AsyncLocalStorageContextManager;\n private tracer?: Tracer;\n private logger?: Logger;\n\n constructor(enabled: boolean, logger?: Logger) {\n this.enabled = enabled;\n this.logger = logger;\n\n if (enabled) {\n this.setupTracerProvider();\n this.maintainIntervalId = setInterval(() => {\n this.maintain();\n }, 60_000);\n }\n }\n\n private setupTracerProvider() {\n this.contextManager = new AsyncLocalStorageContextManager();\n context.setGlobalContextManager(this.contextManager);\n\n const provider = new BasicTracerProvider({\n spanProcessors: [this],\n });\n trace.setGlobalTracerProvider(provider);\n this.tracer = trace.getTracer(\"apitally\");\n }\n\n startSpan(): SpanHandle {\n if (!this.enabled || !this.tracer) {\n return {\n setName: () => void 0,\n runInContext: <T>(fn: () => T): T => {\n return fn();\n },\n enterContext: () => void 0,\n end: () => undefined,\n };\n }\n\n const span = this.tracer.startSpan(\"root\");\n const spanCtx = span.spanContext();\n const traceId = spanCtx.traceId;\n const ctx = trace.setSpan(context.active(), span);\n let ended = false;\n\n this.includedSpanIds.set(traceId, new Set([spanCtx.spanId]));\n this.collectedSpans.set(traceId, []);\n this.traceStartTimes.set(traceId, Date.now());\n\n return {\n traceId,\n setName: (name: string) => {\n span.updateName(name);\n },\n runInContext: <T>(fn: () => T): T => {\n return context.with(ctx, fn);\n },\n enterContext: () => {\n this.contextManager?.enterWith(ctx);\n },\n end: () => {\n if (ended) return;\n span.end();\n ended = true;\n return this.getAndClearSpans(traceId);\n },\n };\n }\n\n private getAndClearSpans(traceId: string): SpanData[] {\n const spans = this.collectedSpans.get(traceId) ?? [];\n this.collectedSpans.delete(traceId);\n this.includedSpanIds.delete(traceId);\n this.traceStartTimes.delete(traceId);\n return spans;\n }\n\n onStart(span: Span): void {\n if (!this.enabled) return;\n\n const ctx = span.spanContext();\n const traceId = ctx.traceId;\n const spanId = ctx.spanId;\n\n const includedSpans = this.includedSpanIds.get(traceId);\n if (!includedSpans) return;\n\n const parentSpanId = span.parentSpanContext?.spanId;\n if (parentSpanId && includedSpans.has(parentSpanId)) {\n includedSpans.add(spanId);\n }\n }\n\n onEnd(span: ReadableSpan): void {\n if (!this.enabled) return;\n\n const ctx = span.spanContext();\n const traceId = ctx.traceId;\n const spanId = ctx.spanId;\n\n const includedSpans = this.includedSpanIds.get(traceId);\n if (!includedSpans || !includedSpans.has(spanId)) return;\n\n const spans = this.collectedSpans.get(traceId);\n if (spans) {\n spans.push(this.serializeSpan(span));\n }\n }\n\n private serializeSpan(span: ReadableSpan): SpanData {\n const ctx = span.spanContext();\n\n const data: SpanData = {\n spanId: ctx.spanId,\n parentSpanId: span.parentSpanContext?.spanId || null,\n name: span.name,\n kind: SpanKind[span.kind] ?? \"INTERNAL\",\n // HrTime is [seconds, nanoseconds], convert to nanoseconds as string to avoid precision loss\n startTime: (\n BigInt(span.startTime[0]) * 1_000_000_000n +\n BigInt(span.startTime[1])\n ).toString(),\n endTime: (\n BigInt(span.endTime[0]) * 1_000_000_000n +\n BigInt(span.endTime[1])\n ).toString(),\n };\n\n if (span.status.code !== SpanStatusCode.UNSET) {\n data.status = SpanStatusCode[span.status.code];\n }\n\n if (span.attributes && Object.keys(span.attributes).length > 0) {\n data.attributes = { ...span.attributes };\n }\n\n return data;\n }\n\n private maintain() {\n const now = Date.now();\n for (const [traceId, startTime] of this.traceStartTimes) {\n if (now - startTime > TRACE_MAX_AGE) {\n this.collectedSpans.delete(traceId);\n this.includedSpanIds.delete(traceId);\n this.traceStartTimes.delete(traceId);\n }\n }\n }\n\n async shutdown(): Promise<void> {\n this.enabled = false;\n this.includedSpanIds.clear();\n this.collectedSpans.clear();\n this.traceStartTimes.clear();\n if (this.maintainIntervalId) {\n clearInterval(this.maintainIntervalId);\n }\n }\n\n async forceFlush(): Promise<void> {\n // Nothing to flush since we collect spans synchronously\n }\n}\n\nexport class ApitallySpanProcessor implements SpanProcessor {\n private getCollector(): SpanCollector | undefined {\n try {\n return ApitallyClient.getInstance().spanCollector;\n } catch {\n return undefined;\n }\n }\n\n onStart(span: Span) {\n this.getCollector()?.onStart(span);\n }\n\n onEnd(span: ReadableSpan) {\n this.getCollector()?.onEnd(span);\n }\n\n async shutdown() {\n this.getCollector()?.shutdown();\n }\n\n async forceFlush() {\n this.getCollector()?.forceFlush();\n }\n}\n"],"mappings":"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","names":["AsyncLocalStorageContextManager","_AsyncLocalStorageContextManager","enterWith","ctx","_asyncLocalStorage","TRACE_MAX_AGE","SpanCollector","enabled","includedSpanIds","Map","collectedSpans","traceStartTimes","maintainIntervalId","contextManager","tracer","logger","setupTracerProvider","setInterval","maintain","context","setGlobalContextManager","provider","BasicTracerProvider","spanProcessors","trace","setGlobalTracerProvider","getTracer","startSpan","setName","runInContext","fn","enterContext","end","undefined","span","spanCtx","spanContext","traceId","setSpan","active","ended","set","Set","spanId","Date","now","name","updateName","with","_a","getAndClearSpans","spans","get","delete","onStart","includedSpans","parentSpanId","parentSpanContext","has","add","onEnd","push","serializeSpan","data","kind","SpanKind","startTime","BigInt","toString","endTime","status","code","SpanStatusCode","UNSET","attributes","Object","keys","length","shutdown","clear","clearInterval","forceFlush","ApitallySpanProcessor","getCollector","ApitallyClient","getInstance","spanCollector"]}
@@ -0,0 +1,50 @@
1
+ import { SpanProcessor, Span, ReadableSpan } from '@opentelemetry/sdk-trace-base';
2
+ import { Logger } from './logging.cjs';
3
+ import 'winston';
4
+
5
+ type SpanData = {
6
+ spanId: string;
7
+ parentSpanId: string | null;
8
+ name: string;
9
+ kind: string;
10
+ startTime: string;
11
+ endTime: string;
12
+ status?: string;
13
+ attributes?: Record<string, unknown>;
14
+ };
15
+ type SpanHandle = {
16
+ traceId?: string;
17
+ setName: (name: string) => void;
18
+ runInContext: <T>(fn: () => T) => T;
19
+ enterContext: () => void;
20
+ end: () => SpanData[] | undefined;
21
+ };
22
+ declare class SpanCollector implements SpanProcessor {
23
+ enabled: boolean;
24
+ private includedSpanIds;
25
+ private collectedSpans;
26
+ private traceStartTimes;
27
+ private maintainIntervalId?;
28
+ private contextManager?;
29
+ private tracer?;
30
+ private logger?;
31
+ constructor(enabled: boolean, logger?: Logger);
32
+ private setupTracerProvider;
33
+ startSpan(): SpanHandle;
34
+ private getAndClearSpans;
35
+ onStart(span: Span): void;
36
+ onEnd(span: ReadableSpan): void;
37
+ private serializeSpan;
38
+ private maintain;
39
+ shutdown(): Promise<void>;
40
+ forceFlush(): Promise<void>;
41
+ }
42
+ declare class ApitallySpanProcessor implements SpanProcessor {
43
+ private getCollector;
44
+ onStart(span: Span): void;
45
+ onEnd(span: ReadableSpan): void;
46
+ shutdown(): Promise<void>;
47
+ forceFlush(): Promise<void>;
48
+ }
49
+
50
+ export { ApitallySpanProcessor, type SpanData, type SpanHandle, SpanCollector as default };
@@ -0,0 +1,50 @@
1
+ import { SpanProcessor, Span, ReadableSpan } from '@opentelemetry/sdk-trace-base';
2
+ import { Logger } from './logging.js';
3
+ import 'winston';
4
+
5
+ type SpanData = {
6
+ spanId: string;
7
+ parentSpanId: string | null;
8
+ name: string;
9
+ kind: string;
10
+ startTime: string;
11
+ endTime: string;
12
+ status?: string;
13
+ attributes?: Record<string, unknown>;
14
+ };
15
+ type SpanHandle = {
16
+ traceId?: string;
17
+ setName: (name: string) => void;
18
+ runInContext: <T>(fn: () => T) => T;
19
+ enterContext: () => void;
20
+ end: () => SpanData[] | undefined;
21
+ };
22
+ declare class SpanCollector implements SpanProcessor {
23
+ enabled: boolean;
24
+ private includedSpanIds;
25
+ private collectedSpans;
26
+ private traceStartTimes;
27
+ private maintainIntervalId?;
28
+ private contextManager?;
29
+ private tracer?;
30
+ private logger?;
31
+ constructor(enabled: boolean, logger?: Logger);
32
+ private setupTracerProvider;
33
+ startSpan(): SpanHandle;
34
+ private getAndClearSpans;
35
+ onStart(span: Span): void;
36
+ onEnd(span: ReadableSpan): void;
37
+ private serializeSpan;
38
+ private maintain;
39
+ shutdown(): Promise<void>;
40
+ forceFlush(): Promise<void>;
41
+ }
42
+ declare class ApitallySpanProcessor implements SpanProcessor {
43
+ private getCollector;
44
+ onStart(span: Span): void;
45
+ onEnd(span: ReadableSpan): void;
46
+ shutdown(): Promise<void>;
47
+ forceFlush(): Promise<void>;
48
+ }
49
+
50
+ export { ApitallySpanProcessor, type SpanData, type SpanHandle, SpanCollector as default };
@@ -0,0 +1,194 @@
1
+ var __defProp = Object.defineProperty;
2
+ var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
3
+ var _a;
4
+ import { context, SpanKind, SpanStatusCode, trace } from "@opentelemetry/api";
5
+ import { AsyncLocalStorageContextManager as _AsyncLocalStorageContextManager } from "@opentelemetry/context-async-hooks";
6
+ import { BasicTracerProvider } from "@opentelemetry/sdk-trace-base";
7
+ import { ApitallyClient } from "./client.js";
8
+ let AsyncLocalStorageContextManager = (_a = class extends _AsyncLocalStorageContextManager {
9
+ enterWith(ctx) {
10
+ this._asyncLocalStorage.enterWith(ctx);
11
+ }
12
+ }, __name(_a, "AsyncLocalStorageContextManager"), _a);
13
+ const TRACE_MAX_AGE = 5 * 60 * 1e3;
14
+ const _SpanCollector = class _SpanCollector {
15
+ enabled;
16
+ includedSpanIds = /* @__PURE__ */ new Map();
17
+ collectedSpans = /* @__PURE__ */ new Map();
18
+ traceStartTimes = /* @__PURE__ */ new Map();
19
+ maintainIntervalId;
20
+ contextManager;
21
+ tracer;
22
+ logger;
23
+ constructor(enabled, logger) {
24
+ this.enabled = enabled;
25
+ this.logger = logger;
26
+ if (enabled) {
27
+ this.setupTracerProvider();
28
+ this.maintainIntervalId = setInterval(() => {
29
+ this.maintain();
30
+ }, 6e4);
31
+ }
32
+ }
33
+ setupTracerProvider() {
34
+ this.contextManager = new AsyncLocalStorageContextManager();
35
+ context.setGlobalContextManager(this.contextManager);
36
+ const provider = new BasicTracerProvider({
37
+ spanProcessors: [
38
+ this
39
+ ]
40
+ });
41
+ trace.setGlobalTracerProvider(provider);
42
+ this.tracer = trace.getTracer("apitally");
43
+ }
44
+ startSpan() {
45
+ if (!this.enabled || !this.tracer) {
46
+ return {
47
+ setName: /* @__PURE__ */ __name(() => void 0, "setName"),
48
+ runInContext: /* @__PURE__ */ __name((fn) => {
49
+ return fn();
50
+ }, "runInContext"),
51
+ enterContext: /* @__PURE__ */ __name(() => void 0, "enterContext"),
52
+ end: /* @__PURE__ */ __name(() => void 0, "end")
53
+ };
54
+ }
55
+ const span = this.tracer.startSpan("root");
56
+ const spanCtx = span.spanContext();
57
+ const traceId = spanCtx.traceId;
58
+ const ctx = trace.setSpan(context.active(), span);
59
+ let ended = false;
60
+ this.includedSpanIds.set(traceId, /* @__PURE__ */ new Set([
61
+ spanCtx.spanId
62
+ ]));
63
+ this.collectedSpans.set(traceId, []);
64
+ this.traceStartTimes.set(traceId, Date.now());
65
+ return {
66
+ traceId,
67
+ setName: /* @__PURE__ */ __name((name) => {
68
+ span.updateName(name);
69
+ }, "setName"),
70
+ runInContext: /* @__PURE__ */ __name((fn) => {
71
+ return context.with(ctx, fn);
72
+ }, "runInContext"),
73
+ enterContext: /* @__PURE__ */ __name(() => {
74
+ var _a2;
75
+ (_a2 = this.contextManager) == null ? void 0 : _a2.enterWith(ctx);
76
+ }, "enterContext"),
77
+ end: /* @__PURE__ */ __name(() => {
78
+ if (ended) return;
79
+ span.end();
80
+ ended = true;
81
+ return this.getAndClearSpans(traceId);
82
+ }, "end")
83
+ };
84
+ }
85
+ getAndClearSpans(traceId) {
86
+ const spans = this.collectedSpans.get(traceId) ?? [];
87
+ this.collectedSpans.delete(traceId);
88
+ this.includedSpanIds.delete(traceId);
89
+ this.traceStartTimes.delete(traceId);
90
+ return spans;
91
+ }
92
+ onStart(span) {
93
+ var _a2;
94
+ if (!this.enabled) return;
95
+ const ctx = span.spanContext();
96
+ const traceId = ctx.traceId;
97
+ const spanId = ctx.spanId;
98
+ const includedSpans = this.includedSpanIds.get(traceId);
99
+ if (!includedSpans) return;
100
+ const parentSpanId = (_a2 = span.parentSpanContext) == null ? void 0 : _a2.spanId;
101
+ if (parentSpanId && includedSpans.has(parentSpanId)) {
102
+ includedSpans.add(spanId);
103
+ }
104
+ }
105
+ onEnd(span) {
106
+ if (!this.enabled) return;
107
+ const ctx = span.spanContext();
108
+ const traceId = ctx.traceId;
109
+ const spanId = ctx.spanId;
110
+ const includedSpans = this.includedSpanIds.get(traceId);
111
+ if (!includedSpans || !includedSpans.has(spanId)) return;
112
+ const spans = this.collectedSpans.get(traceId);
113
+ if (spans) {
114
+ spans.push(this.serializeSpan(span));
115
+ }
116
+ }
117
+ serializeSpan(span) {
118
+ var _a2;
119
+ const ctx = span.spanContext();
120
+ const data = {
121
+ spanId: ctx.spanId,
122
+ parentSpanId: ((_a2 = span.parentSpanContext) == null ? void 0 : _a2.spanId) || null,
123
+ name: span.name,
124
+ kind: SpanKind[span.kind] ?? "INTERNAL",
125
+ // HrTime is [seconds, nanoseconds], convert to nanoseconds as string to avoid precision loss
126
+ startTime: (BigInt(span.startTime[0]) * 1000000000n + BigInt(span.startTime[1])).toString(),
127
+ endTime: (BigInt(span.endTime[0]) * 1000000000n + BigInt(span.endTime[1])).toString()
128
+ };
129
+ if (span.status.code !== SpanStatusCode.UNSET) {
130
+ data.status = SpanStatusCode[span.status.code];
131
+ }
132
+ if (span.attributes && Object.keys(span.attributes).length > 0) {
133
+ data.attributes = {
134
+ ...span.attributes
135
+ };
136
+ }
137
+ return data;
138
+ }
139
+ maintain() {
140
+ const now = Date.now();
141
+ for (const [traceId, startTime] of this.traceStartTimes) {
142
+ if (now - startTime > TRACE_MAX_AGE) {
143
+ this.collectedSpans.delete(traceId);
144
+ this.includedSpanIds.delete(traceId);
145
+ this.traceStartTimes.delete(traceId);
146
+ }
147
+ }
148
+ }
149
+ async shutdown() {
150
+ this.enabled = false;
151
+ this.includedSpanIds.clear();
152
+ this.collectedSpans.clear();
153
+ this.traceStartTimes.clear();
154
+ if (this.maintainIntervalId) {
155
+ clearInterval(this.maintainIntervalId);
156
+ }
157
+ }
158
+ async forceFlush() {
159
+ }
160
+ };
161
+ __name(_SpanCollector, "SpanCollector");
162
+ let SpanCollector = _SpanCollector;
163
+ const _ApitallySpanProcessor = class _ApitallySpanProcessor {
164
+ getCollector() {
165
+ try {
166
+ return ApitallyClient.getInstance().spanCollector;
167
+ } catch {
168
+ return void 0;
169
+ }
170
+ }
171
+ onStart(span) {
172
+ var _a2;
173
+ (_a2 = this.getCollector()) == null ? void 0 : _a2.onStart(span);
174
+ }
175
+ onEnd(span) {
176
+ var _a2;
177
+ (_a2 = this.getCollector()) == null ? void 0 : _a2.onEnd(span);
178
+ }
179
+ async shutdown() {
180
+ var _a2;
181
+ (_a2 = this.getCollector()) == null ? void 0 : _a2.shutdown();
182
+ }
183
+ async forceFlush() {
184
+ var _a2;
185
+ (_a2 = this.getCollector()) == null ? void 0 : _a2.forceFlush();
186
+ }
187
+ };
188
+ __name(_ApitallySpanProcessor, "ApitallySpanProcessor");
189
+ let ApitallySpanProcessor = _ApitallySpanProcessor;
190
+ export {
191
+ ApitallySpanProcessor,
192
+ SpanCollector as default
193
+ };
194
+ //# sourceMappingURL=spanCollector.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/common/spanCollector.ts"],"sourcesContent":["import {\n context,\n type Context,\n SpanKind,\n SpanStatusCode,\n trace,\n type Tracer,\n} from \"@opentelemetry/api\";\nimport { AsyncLocalStorageContextManager as _AsyncLocalStorageContextManager } from \"@opentelemetry/context-async-hooks\";\nimport {\n BasicTracerProvider,\n type ReadableSpan,\n type Span,\n SpanProcessor,\n} from \"@opentelemetry/sdk-trace-base\";\n\nimport { ApitallyClient } from \"./client.js\";\nimport { Logger } from \"./logging.js\";\n\n/**\n * Extends the official AsyncLocalStorageContextManager to add enterWith support\n * for frameworks that need to persist context across hook boundaries (e.g. Elysia).\n */\nclass AsyncLocalStorageContextManager extends _AsyncLocalStorageContextManager {\n enterWith(ctx: Context): void {\n // @ts-expect-error: _asyncLocalStorage is private\n this._asyncLocalStorage.enterWith(ctx);\n }\n}\n\nexport type SpanData = {\n spanId: string;\n parentSpanId: string | null;\n name: string;\n kind: string;\n startTime: string; // bigint as string\n endTime: string; // bigint as string\n status?: string;\n attributes?: Record<string, unknown>;\n};\n\nexport type SpanHandle = {\n traceId?: string;\n setName: (name: string) => void;\n runInContext: <T>(fn: () => T) => T;\n enterContext: () => void;\n end: () => SpanData[] | undefined;\n};\n\nconst TRACE_MAX_AGE = 5 * 60 * 1000; // 5 minutes\n\nexport default class SpanCollector implements SpanProcessor {\n public enabled: boolean;\n private includedSpanIds: Map<string, Set<string>> = new Map();\n private collectedSpans: Map<string, SpanData[]> = new Map();\n private traceStartTimes: Map<string, number> = new Map();\n private maintainIntervalId?: NodeJS.Timeout;\n private contextManager?: AsyncLocalStorageContextManager;\n private tracer?: Tracer;\n private logger?: Logger;\n\n constructor(enabled: boolean, logger?: Logger) {\n this.enabled = enabled;\n this.logger = logger;\n\n if (enabled) {\n this.setupTracerProvider();\n this.maintainIntervalId = setInterval(() => {\n this.maintain();\n }, 60_000);\n }\n }\n\n private setupTracerProvider() {\n this.contextManager = new AsyncLocalStorageContextManager();\n context.setGlobalContextManager(this.contextManager);\n\n const provider = new BasicTracerProvider({\n spanProcessors: [this],\n });\n trace.setGlobalTracerProvider(provider);\n this.tracer = trace.getTracer(\"apitally\");\n }\n\n startSpan(): SpanHandle {\n if (!this.enabled || !this.tracer) {\n return {\n setName: () => void 0,\n runInContext: <T>(fn: () => T): T => {\n return fn();\n },\n enterContext: () => void 0,\n end: () => undefined,\n };\n }\n\n const span = this.tracer.startSpan(\"root\");\n const spanCtx = span.spanContext();\n const traceId = spanCtx.traceId;\n const ctx = trace.setSpan(context.active(), span);\n let ended = false;\n\n this.includedSpanIds.set(traceId, new Set([spanCtx.spanId]));\n this.collectedSpans.set(traceId, []);\n this.traceStartTimes.set(traceId, Date.now());\n\n return {\n traceId,\n setName: (name: string) => {\n span.updateName(name);\n },\n runInContext: <T>(fn: () => T): T => {\n return context.with(ctx, fn);\n },\n enterContext: () => {\n this.contextManager?.enterWith(ctx);\n },\n end: () => {\n if (ended) return;\n span.end();\n ended = true;\n return this.getAndClearSpans(traceId);\n },\n };\n }\n\n private getAndClearSpans(traceId: string): SpanData[] {\n const spans = this.collectedSpans.get(traceId) ?? [];\n this.collectedSpans.delete(traceId);\n this.includedSpanIds.delete(traceId);\n this.traceStartTimes.delete(traceId);\n return spans;\n }\n\n onStart(span: Span): void {\n if (!this.enabled) return;\n\n const ctx = span.spanContext();\n const traceId = ctx.traceId;\n const spanId = ctx.spanId;\n\n const includedSpans = this.includedSpanIds.get(traceId);\n if (!includedSpans) return;\n\n const parentSpanId = span.parentSpanContext?.spanId;\n if (parentSpanId && includedSpans.has(parentSpanId)) {\n includedSpans.add(spanId);\n }\n }\n\n onEnd(span: ReadableSpan): void {\n if (!this.enabled) return;\n\n const ctx = span.spanContext();\n const traceId = ctx.traceId;\n const spanId = ctx.spanId;\n\n const includedSpans = this.includedSpanIds.get(traceId);\n if (!includedSpans || !includedSpans.has(spanId)) return;\n\n const spans = this.collectedSpans.get(traceId);\n if (spans) {\n spans.push(this.serializeSpan(span));\n }\n }\n\n private serializeSpan(span: ReadableSpan): SpanData {\n const ctx = span.spanContext();\n\n const data: SpanData = {\n spanId: ctx.spanId,\n parentSpanId: span.parentSpanContext?.spanId || null,\n name: span.name,\n kind: SpanKind[span.kind] ?? \"INTERNAL\",\n // HrTime is [seconds, nanoseconds], convert to nanoseconds as string to avoid precision loss\n startTime: (\n BigInt(span.startTime[0]) * 1_000_000_000n +\n BigInt(span.startTime[1])\n ).toString(),\n endTime: (\n BigInt(span.endTime[0]) * 1_000_000_000n +\n BigInt(span.endTime[1])\n ).toString(),\n };\n\n if (span.status.code !== SpanStatusCode.UNSET) {\n data.status = SpanStatusCode[span.status.code];\n }\n\n if (span.attributes && Object.keys(span.attributes).length > 0) {\n data.attributes = { ...span.attributes };\n }\n\n return data;\n }\n\n private maintain() {\n const now = Date.now();\n for (const [traceId, startTime] of this.traceStartTimes) {\n if (now - startTime > TRACE_MAX_AGE) {\n this.collectedSpans.delete(traceId);\n this.includedSpanIds.delete(traceId);\n this.traceStartTimes.delete(traceId);\n }\n }\n }\n\n async shutdown(): Promise<void> {\n this.enabled = false;\n this.includedSpanIds.clear();\n this.collectedSpans.clear();\n this.traceStartTimes.clear();\n if (this.maintainIntervalId) {\n clearInterval(this.maintainIntervalId);\n }\n }\n\n async forceFlush(): Promise<void> {\n // Nothing to flush since we collect spans synchronously\n }\n}\n\nexport class ApitallySpanProcessor implements SpanProcessor {\n private getCollector(): SpanCollector | undefined {\n try {\n return ApitallyClient.getInstance().spanCollector;\n } catch {\n return undefined;\n }\n }\n\n onStart(span: Span) {\n this.getCollector()?.onStart(span);\n }\n\n onEnd(span: ReadableSpan) {\n this.getCollector()?.onEnd(span);\n }\n\n async shutdown() {\n this.getCollector()?.shutdown();\n }\n\n async forceFlush() {\n this.getCollector()?.forceFlush();\n }\n}\n"],"mappings":"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","names":["context","SpanKind","SpanStatusCode","trace","AsyncLocalStorageContextManager","_AsyncLocalStorageContextManager","BasicTracerProvider","ApitallyClient","enterWith","ctx","_asyncLocalStorage","TRACE_MAX_AGE","SpanCollector","enabled","includedSpanIds","Map","collectedSpans","traceStartTimes","maintainIntervalId","contextManager","tracer","logger","setupTracerProvider","setInterval","maintain","setGlobalContextManager","provider","spanProcessors","setGlobalTracerProvider","getTracer","startSpan","setName","runInContext","fn","enterContext","end","undefined","span","spanCtx","spanContext","traceId","setSpan","active","ended","set","Set","spanId","Date","now","name","updateName","with","_a","getAndClearSpans","spans","get","delete","onStart","includedSpans","parentSpanId","parentSpanContext","has","add","onEnd","push","serializeSpan","data","kind","startTime","BigInt","toString","endTime","status","code","UNSET","attributes","Object","keys","length","shutdown","clear","clearInterval","forceFlush","ApitallySpanProcessor","getCollector","getInstance","spanCollector"]}
@@ -3,6 +3,8 @@ import { RequestLoggingConfig } from './requestLogger.cjs';
3
3
  import 'winston';
4
4
  import 'node:buffer';
5
5
  import 'node:http';
6
+ import './spanCollector.cjs';
7
+ import '@opentelemetry/sdk-trace-base';
6
8
  import './tempGzipFile.cjs';
7
9
 
8
10
  type ApitallyConfig = {
@@ -3,6 +3,8 @@ import { RequestLoggingConfig } from './requestLogger.js';
3
3
  import 'winston';
4
4
  import 'node:buffer';
5
5
  import 'node:http';
6
+ import './spanCollector.js';
7
+ import '@opentelemetry/sdk-trace-base';
6
8
  import './tempGzipFile.js';
7
9
 
8
10
  type ApitallyConfig = {
@@ -4,6 +4,8 @@ import 'winston';
4
4
  import './requestLogger.cjs';
5
5
  import 'node:buffer';
6
6
  import 'node:http';
7
+ import './spanCollector.cjs';
8
+ import '@opentelemetry/sdk-trace-base';
7
9
  import './tempGzipFile.cjs';
8
10
 
9
11
  declare class ValidationErrorCounter {
@@ -4,6 +4,8 @@ import 'winston';
4
4
  import './requestLogger.js';
5
5
  import 'node:buffer';
6
6
  import 'node:http';
7
+ import './spanCollector.js';
8
+ import '@opentelemetry/sdk-trace-base';
7
9
  import './tempGzipFile.js';
8
10
 
9
11
  declare class ValidationErrorCounter {
@@ -28,12 +28,15 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
28
28
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
29
  var elysia_exports = {};
30
30
  __export(elysia_exports, {
31
+ ApitallySpanProcessor: () => import_spanCollector.ApitallySpanProcessor,
31
32
  apitallyPlugin: () => import_plugin.default
32
33
  });
33
34
  module.exports = __toCommonJS(elysia_exports);
35
+ var import_spanCollector = require("../common/spanCollector.js");
34
36
  var import_plugin = __toESM(require("./plugin.js"), 1);
35
37
  // Annotate the CommonJS export names for ESM import in node:
36
38
  0 && (module.exports = {
39
+ ApitallySpanProcessor,
37
40
  apitallyPlugin
38
41
  });
39
42
  //# sourceMappingURL=index.cjs.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/elysia/index.ts"],"sourcesContent":["export type { ApitallyConfig, ApitallyConsumer } from \"../common/types.js\";\nexport { default as apitallyPlugin } from \"./plugin.js\";\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;AACA;;;;;oBAA0C;","names":[]}
1
+ {"version":3,"sources":["../../src/elysia/index.ts"],"sourcesContent":["export { ApitallySpanProcessor } from \"../common/spanCollector.js\";\nexport type { ApitallyConfig, ApitallyConsumer } from \"../common/types.js\";\nexport { default as apitallyPlugin } from \"./plugin.js\";\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;;;;;;2BAAsC;AAEtC,oBAA0C;","names":[]}
@@ -1,5 +1,7 @@
1
+ export { ApitallySpanProcessor } from '../common/spanCollector.cjs';
1
2
  export { ApitallyConfig, ApitallyConsumer } from '../common/types.cjs';
2
3
  export { default as apitallyPlugin } from './plugin.cjs';
4
+ import '@opentelemetry/sdk-trace-base';
3
5
  import '../common/logging.cjs';
4
6
  import 'winston';
5
7
  import '../common/requestLogger.cjs';
@@ -1,5 +1,7 @@
1
+ export { ApitallySpanProcessor } from '../common/spanCollector.js';
1
2
  export { ApitallyConfig, ApitallyConsumer } from '../common/types.js';
2
3
  export { default as apitallyPlugin } from './plugin.js';
4
+ import '@opentelemetry/sdk-trace-base';
3
5
  import '../common/logging.js';
4
6
  import 'winston';
5
7
  import '../common/requestLogger.js';
@@ -1,5 +1,7 @@
1
+ import { ApitallySpanProcessor } from "../common/spanCollector.js";
1
2
  import { default as default2 } from "./plugin.js";
2
3
  export {
4
+ ApitallySpanProcessor,
3
5
  default2 as apitallyPlugin
4
6
  };
5
7
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/elysia/index.ts"],"sourcesContent":["export type { ApitallyConfig, ApitallyConsumer } from \"../common/types.js\";\nexport { default as apitallyPlugin } from \"./plugin.js\";\n"],"mappings":"AACA,SAAoBA,WAAXC,gBAAiC;","names":["apitallyPlugin","default"]}
1
+ {"version":3,"sources":["../../src/elysia/index.ts"],"sourcesContent":["export { ApitallySpanProcessor } from \"../common/spanCollector.js\";\nexport type { ApitallyConfig, ApitallyConsumer } from \"../common/types.js\";\nexport { default as apitallyPlugin } from \"./plugin.js\";\n"],"mappings":"AAAA,SAASA,6BAA6B;AAEtC,SAAoBC,WAAXC,gBAAiC;","names":["ApitallySpanProcessor","apitallyPlugin","default"]}