@omote/core 0.9.7 → 0.10.5

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.
@@ -1,927 +0,0 @@
1
- // src/logging/types.ts
2
- var LOG_LEVEL_PRIORITY = {
3
- error: 0,
4
- warn: 1,
5
- info: 2,
6
- debug: 3,
7
- trace: 4,
8
- verbose: 5
9
- };
10
- var DEFAULT_LOGGING_CONFIG = {
11
- level: "info",
12
- enabled: true,
13
- format: "pretty",
14
- timestamps: true,
15
- includeModule: true
16
- };
17
-
18
- // src/logging/formatters.ts
19
- var COLORS = {
20
- reset: "\x1B[0m",
21
- red: "\x1B[31m",
22
- yellow: "\x1B[33m",
23
- blue: "\x1B[34m",
24
- cyan: "\x1B[36m",
25
- gray: "\x1B[90m",
26
- white: "\x1B[37m",
27
- magenta: "\x1B[35m"
28
- };
29
- var LEVEL_COLORS = {
30
- error: COLORS.red,
31
- warn: COLORS.yellow,
32
- info: COLORS.blue,
33
- debug: COLORS.cyan,
34
- trace: COLORS.magenta,
35
- verbose: COLORS.gray
36
- };
37
- var LEVEL_NAMES = {
38
- error: "ERROR ",
39
- warn: "WARN ",
40
- info: "INFO ",
41
- debug: "DEBUG ",
42
- trace: "TRACE ",
43
- verbose: "VERBOSE"
44
- };
45
- var isBrowser = typeof window !== "undefined";
46
- function formatTimestamp(timestamp) {
47
- const date = new Date(timestamp);
48
- return date.toISOString().substring(11, 23);
49
- }
50
- function safeStringify(data) {
51
- const seen = /* @__PURE__ */ new WeakSet();
52
- return JSON.stringify(data, (key, value) => {
53
- if (typeof value === "object" && value !== null) {
54
- if (seen.has(value)) {
55
- return "[Circular]";
56
- }
57
- seen.add(value);
58
- }
59
- if (value instanceof Error) {
60
- return {
61
- name: value.name,
62
- message: value.message,
63
- stack: value.stack
64
- };
65
- }
66
- if (value instanceof Float32Array || value instanceof Int16Array) {
67
- return `${value.constructor.name}(${value.length})`;
68
- }
69
- if (ArrayBuffer.isView(value)) {
70
- return `${value.constructor.name}(${value.byteLength})`;
71
- }
72
- return value;
73
- });
74
- }
75
- var jsonFormatter = (entry) => {
76
- const output = {
77
- timestamp: entry.timestamp,
78
- level: entry.level,
79
- module: entry.module,
80
- message: entry.message
81
- };
82
- if (entry.data && Object.keys(entry.data).length > 0) {
83
- output.data = entry.data;
84
- }
85
- if (entry.error) {
86
- output.error = {
87
- name: entry.error.name,
88
- message: entry.error.message,
89
- stack: entry.error.stack
90
- };
91
- }
92
- return safeStringify(output);
93
- };
94
- var prettyFormatter = (entry) => {
95
- const time = formatTimestamp(entry.timestamp);
96
- const level = LEVEL_NAMES[entry.level];
97
- const module = entry.module;
98
- const message = entry.message;
99
- let output;
100
- if (isBrowser) {
101
- output = `${time} ${level} [${module}] ${message}`;
102
- } else {
103
- const color = LEVEL_COLORS[entry.level];
104
- output = `${COLORS.gray}${time}${COLORS.reset} ${color}${level}${COLORS.reset} ${COLORS.cyan}[${module}]${COLORS.reset} ${message}`;
105
- }
106
- if (entry.data && Object.keys(entry.data).length > 0) {
107
- const dataStr = safeStringify(entry.data);
108
- if (dataStr.length > 80) {
109
- output += "\n " + JSON.stringify(entry.data, null, 2).replace(/\n/g, "\n ");
110
- } else {
111
- output += " " + dataStr;
112
- }
113
- }
114
- if (entry.error) {
115
- output += `
116
- ${entry.error.name}: ${entry.error.message}`;
117
- if (entry.error.stack) {
118
- const stackLines = entry.error.stack.split("\n").slice(1, 4);
119
- output += "\n " + stackLines.join("\n ");
120
- }
121
- }
122
- return output;
123
- };
124
- function getFormatter(format) {
125
- return format === "json" ? jsonFormatter : prettyFormatter;
126
- }
127
- function createBrowserConsoleArgs(entry) {
128
- const time = formatTimestamp(entry.timestamp);
129
- const level = entry.level.toUpperCase().padEnd(7);
130
- const module = entry.module;
131
- const message = entry.message;
132
- const styles = {
133
- time: "color: gray;",
134
- error: "color: red; font-weight: bold;",
135
- warn: "color: orange; font-weight: bold;",
136
- info: "color: blue;",
137
- debug: "color: cyan;",
138
- trace: "color: magenta;",
139
- verbose: "color: gray;",
140
- module: "color: teal; font-weight: bold;",
141
- message: "color: inherit;"
142
- };
143
- let formatStr = "%c%s %c%s %c[%s]%c %s";
144
- const args = [
145
- styles.time,
146
- time,
147
- styles[entry.level],
148
- level,
149
- styles.module,
150
- module,
151
- styles.message,
152
- message
153
- ];
154
- if (entry.data && Object.keys(entry.data).length > 0) {
155
- formatStr += " %o";
156
- args.push(entry.data);
157
- }
158
- return [formatStr, ...args];
159
- }
160
-
161
- // src/telemetry/exporters/console.ts
162
- var ConsoleExporter = class {
163
- constructor(options = {}) {
164
- this.enabled = options.enabled ?? true;
165
- this.prefix = options.prefix ?? "[Omote Telemetry]";
166
- }
167
- exportSpan(span) {
168
- if (!this.enabled) return;
169
- const statusIcon = span.status === "ok" ? "\u2713" : "\u2717";
170
- const statusColor = span.status === "ok" ? "color: green" : "color: red";
171
- console.groupCollapsed(
172
- `%c${this.prefix} %c${statusIcon} ${span.name} %c(${span.durationMs.toFixed(2)}ms)`,
173
- "color: gray",
174
- statusColor,
175
- "color: gray"
176
- );
177
- console.log("Trace ID:", span.traceId);
178
- console.log("Span ID:", span.spanId);
179
- if (span.parentSpanId) {
180
- console.log("Parent Span ID:", span.parentSpanId);
181
- }
182
- console.log("Duration:", `${span.durationMs.toFixed(2)}ms`);
183
- console.log("Status:", span.status);
184
- if (Object.keys(span.attributes).length > 0) {
185
- console.log("Attributes:", span.attributes);
186
- }
187
- if (span.error) {
188
- console.error("Error:", span.error);
189
- }
190
- console.groupEnd();
191
- }
192
- exportMetric(metric) {
193
- if (!this.enabled) return;
194
- const typeIcon = metric.type === "counter" ? "\u2191" : "\u{1F4CA}";
195
- console.log(
196
- `%c${this.prefix} %c${typeIcon} ${metric.name}: %c${metric.value}`,
197
- "color: gray",
198
- "color: blue",
199
- "color: black; font-weight: bold",
200
- metric.attributes
201
- );
202
- }
203
- async flush() {
204
- }
205
- async shutdown() {
206
- this.enabled = false;
207
- }
208
- };
209
-
210
- // src/telemetry/exporters/otlp.ts
211
- var StatusCode = {
212
- UNSET: 0,
213
- OK: 1,
214
- ERROR: 2
215
- };
216
- function spanToOTLP(span, serviceName, serviceVersion) {
217
- const attributes = Object.entries(span.attributes).filter(([, v]) => v !== void 0).map(([key, value]) => ({
218
- key,
219
- value: typeof value === "string" ? { stringValue: value } : typeof value === "number" ? Number.isInteger(value) ? { intValue: value } : { doubleValue: value } : { boolValue: value }
220
- }));
221
- return {
222
- resourceSpans: [{
223
- resource: {
224
- attributes: [
225
- { key: "service.name", value: { stringValue: serviceName } },
226
- { key: "service.version", value: { stringValue: serviceVersion } },
227
- { key: "telemetry.sdk.name", value: { stringValue: "omote-sdk" } },
228
- { key: "telemetry.sdk.language", value: { stringValue: "javascript" } }
229
- ]
230
- },
231
- scopeSpans: [{
232
- scope: {
233
- name: "omote-sdk",
234
- version: serviceVersion
235
- },
236
- spans: [{
237
- traceId: span.traceId,
238
- spanId: span.spanId,
239
- parentSpanId: span.parentSpanId || "",
240
- name: span.name,
241
- kind: 1,
242
- // INTERNAL
243
- startTimeUnixNano: String(span.startTime * 1e6),
244
- endTimeUnixNano: String(span.endTime * 1e6),
245
- attributes,
246
- status: {
247
- code: span.status === "ok" ? StatusCode.OK : StatusCode.ERROR,
248
- message: span.error?.message || ""
249
- }
250
- }]
251
- }]
252
- }]
253
- };
254
- }
255
- function metricToOTLP(metric, serviceName, serviceVersion) {
256
- const attributes = Object.entries(metric.attributes).filter(([, v]) => v !== void 0).map(([key, value]) => ({
257
- key,
258
- value: typeof value === "string" ? { stringValue: value } : typeof value === "number" ? Number.isInteger(value) ? { intValue: value } : { doubleValue: value } : { boolValue: value }
259
- }));
260
- const dataPoint = {
261
- attributes,
262
- timeUnixNano: String(metric.timestamp * 1e6),
263
- ...metric.type === "counter" ? { asInt: metric.value } : { asDouble: metric.value }
264
- };
265
- return {
266
- resourceMetrics: [{
267
- resource: {
268
- attributes: [
269
- { key: "service.name", value: { stringValue: serviceName } },
270
- { key: "service.version", value: { stringValue: serviceVersion } }
271
- ]
272
- },
273
- scopeMetrics: [{
274
- scope: {
275
- name: "omote-sdk",
276
- version: serviceVersion
277
- },
278
- metrics: [{
279
- name: metric.name,
280
- ...metric.type === "counter" ? {
281
- sum: {
282
- dataPoints: [dataPoint],
283
- aggregationTemporality: 2,
284
- // CUMULATIVE
285
- isMonotonic: true
286
- }
287
- } : {
288
- gauge: {
289
- dataPoints: [dataPoint]
290
- }
291
- }
292
- }]
293
- }]
294
- }]
295
- };
296
- }
297
- var OTLPExporter = class {
298
- constructor(config, serviceName = "omote-sdk", serviceVersion = "0.1.0") {
299
- this.spanBuffer = [];
300
- this.metricBuffer = [];
301
- this.flushIntervalId = null;
302
- this.BUFFER_SIZE = 100;
303
- this.FLUSH_INTERVAL_MS = 5e3;
304
- this.isShutdown = false;
305
- const parsed = new URL(config.endpoint);
306
- if (parsed.protocol !== "https:") {
307
- const isLocalhost = parsed.hostname === "localhost" || parsed.hostname === "127.0.0.1" || parsed.hostname === "[::1]";
308
- if (!isLocalhost) {
309
- throw new Error("OTLP endpoint must use HTTPS (or localhost for development)");
310
- }
311
- }
312
- this.config = {
313
- endpoint: config.endpoint,
314
- timeoutMs: config.timeoutMs ?? 1e4,
315
- headers: config.headers ? { ...config.headers } : {}
316
- };
317
- this.serviceName = serviceName;
318
- this.serviceVersion = serviceVersion;
319
- this.flushIntervalId = setInterval(() => {
320
- this.flush().catch(console.error);
321
- }, this.FLUSH_INTERVAL_MS);
322
- }
323
- exportSpan(span) {
324
- if (this.isShutdown) return;
325
- this.spanBuffer.push(span);
326
- if (this.spanBuffer.length >= this.BUFFER_SIZE) {
327
- this.flush().catch(console.error);
328
- }
329
- }
330
- exportMetric(metric) {
331
- if (this.isShutdown) return;
332
- this.metricBuffer.push(metric);
333
- if (this.metricBuffer.length >= this.BUFFER_SIZE) {
334
- this.flush().catch(console.error);
335
- }
336
- }
337
- async flush() {
338
- if (this.isShutdown) return;
339
- const spans = this.spanBuffer.splice(0);
340
- const metrics = this.metricBuffer.splice(0);
341
- const promises = [];
342
- if (spans.length > 0) {
343
- promises.push(this.exportSpans(spans));
344
- }
345
- if (metrics.length > 0) {
346
- promises.push(this.exportMetrics(metrics));
347
- }
348
- await Promise.all(promises);
349
- }
350
- async shutdown() {
351
- if (this.flushIntervalId) {
352
- clearInterval(this.flushIntervalId);
353
- this.flushIntervalId = null;
354
- }
355
- await this.flush();
356
- this.isShutdown = true;
357
- }
358
- async exportSpans(spans) {
359
- const resourceSpans = spans.map(
360
- (span) => spanToOTLP(span, this.serviceName, this.serviceVersion).resourceSpans[0]
361
- );
362
- const body = { resourceSpans };
363
- const endpoint = this.config.endpoint.replace(/\/$/, "") + "/v1/traces";
364
- await this.sendRequest(endpoint, body);
365
- }
366
- async exportMetrics(metrics) {
367
- const resourceMetrics = metrics.map(
368
- (metric) => metricToOTLP(metric, this.serviceName, this.serviceVersion).resourceMetrics[0]
369
- );
370
- const body = { resourceMetrics };
371
- const endpoint = this.config.endpoint.replace(/\/$/, "") + "/v1/metrics";
372
- await this.sendRequest(endpoint, body);
373
- }
374
- async sendRequest(endpoint, body) {
375
- const controller = new AbortController();
376
- const timeoutId = setTimeout(() => controller.abort(), this.config.timeoutMs);
377
- try {
378
- const response = await fetch(endpoint, {
379
- method: "POST",
380
- headers: {
381
- "Content-Type": "application/json",
382
- ...this.config.headers
383
- },
384
- body: JSON.stringify(body),
385
- signal: controller.signal
386
- });
387
- if (!response.ok) {
388
- console.warn(`[OTLP] Export failed: ${response.status} ${response.statusText}`);
389
- }
390
- } catch (error) {
391
- if (error.name === "AbortError") {
392
- console.warn("[OTLP] Export timed out");
393
- } else {
394
- console.warn("[OTLP] Export error:", error);
395
- }
396
- } finally {
397
- clearTimeout(timeoutId);
398
- }
399
- }
400
- };
401
-
402
- // src/logging/Clock.ts
403
- var defaultClock = {
404
- now: () => performance.now(),
405
- timestamp: () => Date.now()
406
- };
407
- var activeClock = defaultClock;
408
- function configureClock(clock) {
409
- activeClock = clock;
410
- }
411
- function getClock() {
412
- return activeClock;
413
- }
414
-
415
- // src/telemetry/OmoteTelemetry.ts
416
- function generateId(length = 16) {
417
- const bytes = new Uint8Array(length);
418
- crypto.getRandomValues(bytes);
419
- return Array.from(bytes).map((b) => b.toString(16).padStart(2, "0")).join("");
420
- }
421
- var globalTelemetry = null;
422
- function configureTelemetry(config) {
423
- if (globalTelemetry) {
424
- globalTelemetry.shutdown();
425
- }
426
- globalTelemetry = new OmoteTelemetry(config);
427
- return globalTelemetry;
428
- }
429
- function getTelemetry() {
430
- return globalTelemetry;
431
- }
432
- var OmoteTelemetry = class {
433
- constructor(config) {
434
- this.exporter = null;
435
- this.activeTraceId = null;
436
- this.metricsIntervalId = null;
437
- // Span stack for log-to-span correlation
438
- this.spanStack = [];
439
- // Metric accumulators
440
- this.counters = /* @__PURE__ */ new Map();
441
- this.histograms = /* @__PURE__ */ new Map();
442
- this.config = {
443
- enabled: config.enabled ?? false,
444
- serviceName: config.serviceName ?? "omote-sdk",
445
- serviceVersion: config.serviceVersion ?? "0.1.0",
446
- exporter: config.exporter ?? "none",
447
- exporterConfig: config.exporterConfig,
448
- sampling: config.sampling ?? { ratio: 1, alwaysSampleErrors: true },
449
- metricsEnabled: config.metricsEnabled ?? true,
450
- metricsIntervalMs: config.metricsIntervalMs ?? 6e4
451
- };
452
- if (this.config.enabled) {
453
- this.initExporter();
454
- this.startMetricsCollection();
455
- }
456
- }
457
- /**
458
- * Initialize the configured exporter
459
- */
460
- initExporter() {
461
- switch (this.config.exporter) {
462
- case "console":
463
- this.exporter = new ConsoleExporter({ enabled: true });
464
- break;
465
- case "otlp":
466
- if (!this.config.exporterConfig) {
467
- console.warn("[Telemetry] OTLP exporter requires exporterConfig with endpoint");
468
- return;
469
- }
470
- this.exporter = new OTLPExporter(
471
- this.config.exporterConfig,
472
- this.config.serviceName,
473
- this.config.serviceVersion
474
- );
475
- break;
476
- case "none":
477
- default:
478
- this.exporter = null;
479
- }
480
- }
481
- /**
482
- * Start periodic metrics collection
483
- */
484
- startMetricsCollection() {
485
- if (!this.config.metricsEnabled || !this.exporter) return;
486
- this.metricsIntervalId = setInterval(() => {
487
- this.flushMetrics();
488
- }, this.config.metricsIntervalMs);
489
- }
490
- /**
491
- * Check if this operation should be sampled
492
- */
493
- shouldSample(isError = false) {
494
- if (!this.config.enabled) return false;
495
- const sampling = this.config.sampling;
496
- if (isError && sampling.alwaysSampleErrors) return true;
497
- const ratio = sampling.ratio ?? 1;
498
- return Math.random() < ratio;
499
- }
500
- /**
501
- * Start a new span
502
- *
503
- * @example
504
- * ```typescript
505
- * const span = telemetry.startSpan('Wav2Vec2.infer', {
506
- * 'inference.input_samples': samples.length,
507
- * 'model.backend': 'webgpu',
508
- * });
509
- *
510
- * try {
511
- * const result = await doInference();
512
- * span.setAttributes({ 'inference.output_frames': result.frames });
513
- * span.end();
514
- * } catch (error) {
515
- * span.endWithError(error);
516
- * }
517
- * ```
518
- */
519
- startSpan(name, attributes = {}, parentContext) {
520
- const traceId = parentContext?.traceId ?? this.activeTraceId ?? generateId(16);
521
- const spanId = generateId(8);
522
- const parentSpanId = parentContext?.spanId;
523
- const startTime = getClock().now();
524
- if (!parentContext && !this.activeTraceId) {
525
- this.activeTraceId = traceId;
526
- }
527
- let spanAttributes = { ...attributes };
528
- let ended = false;
529
- let sampled = this.shouldSample();
530
- const context = { traceId, spanId, parentSpanId };
531
- this.spanStack.push({ traceId, spanId });
532
- const endSpan = (status, error) => {
533
- if (ended) return;
534
- ended = true;
535
- const idx = this.spanStack.findIndex((s) => s.spanId === spanId);
536
- if (idx !== -1) this.spanStack.splice(idx, 1);
537
- const endTime = getClock().now();
538
- const durationMs = endTime - startTime;
539
- if (status === "error" && !sampled) {
540
- sampled = this.shouldSample(true);
541
- }
542
- if (!sampled || !this.exporter) return;
543
- const spanData = {
544
- name,
545
- traceId,
546
- spanId,
547
- parentSpanId,
548
- startTime,
549
- endTime,
550
- durationMs,
551
- status,
552
- attributes: spanAttributes,
553
- error
554
- };
555
- this.exporter.exportSpan(spanData);
556
- if (!parentSpanId && this.activeTraceId === traceId) {
557
- this.activeTraceId = null;
558
- }
559
- };
560
- return {
561
- end: () => endSpan("ok"),
562
- endWithError: (error) => endSpan("error", error),
563
- setAttributes: (attrs) => {
564
- spanAttributes = { ...spanAttributes, ...attrs };
565
- },
566
- getContext: () => context
567
- };
568
- }
569
- /**
570
- * Wrap an async function with a span
571
- *
572
- * @example
573
- * ```typescript
574
- * const result = await telemetry.withSpan('Model.load', async (span) => {
575
- * const model = await loadModel();
576
- * span.setAttributes({ 'model.size_bytes': model.size });
577
- * return model;
578
- * });
579
- * ```
580
- */
581
- async withSpan(name, fn, attributes = {}, parentContext) {
582
- const span = this.startSpan(name, attributes, parentContext);
583
- try {
584
- const result = await fn(span);
585
- span.end();
586
- return result;
587
- } catch (error) {
588
- span.endWithError(error);
589
- throw error;
590
- }
591
- }
592
- /**
593
- * Increment a counter metric
594
- *
595
- * @example
596
- * ```typescript
597
- * telemetry.incrementCounter('omote.inference.total', 1, {
598
- * model: 'wav2vec2',
599
- * backend: 'webgpu',
600
- * status: 'success',
601
- * });
602
- * ```
603
- */
604
- incrementCounter(name, value = 1, attributes = {}) {
605
- if (!this.config.enabled || !this.config.metricsEnabled) return;
606
- const key = this.getMetricKey(name, attributes);
607
- const existing = this.counters.get(key);
608
- if (existing) {
609
- existing.value += value;
610
- } else {
611
- this.counters.set(key, { value, attributes });
612
- }
613
- }
614
- /**
615
- * Record a histogram value
616
- *
617
- * @example
618
- * ```typescript
619
- * telemetry.recordHistogram('omote.inference.latency', durationMs, {
620
- * model: 'wav2vec2',
621
- * backend: 'webgpu',
622
- * });
623
- * ```
624
- */
625
- recordHistogram(name, value, attributes = {}) {
626
- if (!this.config.enabled || !this.config.metricsEnabled) return;
627
- const key = this.getMetricKey(name, attributes);
628
- const existing = this.histograms.get(key);
629
- if (existing) {
630
- existing.count++;
631
- existing.sum += value;
632
- if (value < existing.min) existing.min = value;
633
- if (value > existing.max) existing.max = value;
634
- } else {
635
- this.histograms.set(key, { count: 1, sum: value, min: value, max: value, attributes });
636
- }
637
- }
638
- /**
639
- * Generate unique key for metric with attributes
640
- */
641
- getMetricKey(name, attributes) {
642
- const keys = Object.keys(attributes);
643
- if (keys.length === 0) return name;
644
- const sortedAttrs = Object.entries(attributes).sort(([a], [b]) => a.localeCompare(b)).map(([k, v]) => `${k}=${v}`).join(",");
645
- return `${name}|${sortedAttrs}`;
646
- }
647
- /**
648
- * Flush accumulated metrics to exporter
649
- */
650
- flushMetrics() {
651
- if (!this.exporter) return;
652
- const timestamp = getClock().now();
653
- for (const [key, data] of this.counters) {
654
- if (data.value === 0) continue;
655
- const name = key.split("|")[0];
656
- const metric = {
657
- name,
658
- type: "counter",
659
- value: data.value,
660
- attributes: data.attributes,
661
- timestamp
662
- };
663
- this.exporter.exportMetric(metric);
664
- data.value = 0;
665
- }
666
- for (const [key, data] of this.histograms) {
667
- const name = key.split("|")[0];
668
- if (data.count === 0) continue;
669
- const avg = data.sum / data.count;
670
- const metric = {
671
- name,
672
- type: "histogram",
673
- value: avg,
674
- attributes: {
675
- ...data.attributes,
676
- count: data.count,
677
- sum: data.sum,
678
- min: data.min,
679
- max: data.max
680
- },
681
- timestamp
682
- };
683
- this.exporter.exportMetric(metric);
684
- data.count = 0;
685
- data.sum = 0;
686
- data.min = Infinity;
687
- data.max = -Infinity;
688
- }
689
- }
690
- /**
691
- * Force flush all pending data
692
- */
693
- async flush() {
694
- this.flushMetrics();
695
- await this.exporter?.flush();
696
- }
697
- /**
698
- * Shutdown telemetry
699
- */
700
- async shutdown() {
701
- if (this.metricsIntervalId) {
702
- clearInterval(this.metricsIntervalId);
703
- this.metricsIntervalId = null;
704
- }
705
- await this.flush();
706
- await this.exporter?.shutdown();
707
- this.exporter = null;
708
- }
709
- /**
710
- * Check if telemetry is enabled
711
- */
712
- isEnabled() {
713
- return this.config.enabled;
714
- }
715
- /**
716
- * Get current configuration
717
- */
718
- getConfig() {
719
- return { ...this.config };
720
- }
721
- /**
722
- * Get the active span context for log-to-span correlation.
723
- * Returns the most recent (top of stack) active span, or null if none.
724
- */
725
- getActiveContext() {
726
- return this.spanStack.length > 0 ? this.spanStack[this.spanStack.length - 1] : null;
727
- }
728
- };
729
-
730
- // src/logging/Logger.ts
731
- var isBrowser2 = typeof window !== "undefined";
732
- var globalConfig = { ...DEFAULT_LOGGING_CONFIG };
733
- function configureLogging(config) {
734
- globalConfig = { ...globalConfig, ...config };
735
- }
736
- function getLoggingConfig() {
737
- return { ...globalConfig };
738
- }
739
- function resetLoggingConfig() {
740
- globalConfig = { ...DEFAULT_LOGGING_CONFIG };
741
- }
742
- function setLogLevel(level) {
743
- globalConfig.level = level;
744
- }
745
- function setLoggingEnabled(enabled) {
746
- globalConfig.enabled = enabled;
747
- }
748
- var consoleSink = (entry) => {
749
- const consoleMethod = entry.level === "error" ? "error" : entry.level === "warn" ? "warn" : "log";
750
- if (globalConfig.format === "pretty" && isBrowser2) {
751
- const args = createBrowserConsoleArgs(entry);
752
- console[consoleMethod](...args);
753
- } else {
754
- const formatter = getFormatter(globalConfig.format);
755
- const formatted = formatter(entry);
756
- console[consoleMethod](formatted);
757
- }
758
- };
759
- function getActiveSink() {
760
- return globalConfig.sink || consoleSink;
761
- }
762
- function shouldLog(level) {
763
- if (!globalConfig.enabled) return false;
764
- return LOG_LEVEL_PRIORITY[level] <= LOG_LEVEL_PRIORITY[globalConfig.level];
765
- }
766
- var Logger = class _Logger {
767
- constructor(module) {
768
- this.module = module;
769
- }
770
- log(level, message, data) {
771
- if (!shouldLog(level)) return;
772
- const entry = {
773
- timestamp: getClock().timestamp(),
774
- level,
775
- module: this.module,
776
- message,
777
- data
778
- };
779
- const ctx = getTelemetry()?.getActiveContext();
780
- if (ctx) {
781
- entry.traceId = ctx.traceId;
782
- entry.spanId = ctx.spanId;
783
- }
784
- if (data?.error instanceof Error) {
785
- entry.error = data.error;
786
- const { error, ...rest } = data;
787
- entry.data = Object.keys(rest).length > 0 ? rest : void 0;
788
- }
789
- getActiveSink()(entry);
790
- }
791
- error(message, data) {
792
- this.log("error", message, data);
793
- }
794
- warn(message, data) {
795
- this.log("warn", message, data);
796
- }
797
- info(message, data) {
798
- this.log("info", message, data);
799
- }
800
- debug(message, data) {
801
- this.log("debug", message, data);
802
- }
803
- trace(message, data) {
804
- this.log("trace", message, data);
805
- }
806
- verbose(message, data) {
807
- this.log("verbose", message, data);
808
- }
809
- child(subModule) {
810
- return new _Logger(`${this.module}.${subModule}`);
811
- }
812
- };
813
- var loggerCache = /* @__PURE__ */ new Map();
814
- function createLogger(module) {
815
- let logger = loggerCache.get(module);
816
- if (!logger) {
817
- logger = new Logger(module);
818
- loggerCache.set(module, logger);
819
- }
820
- return logger;
821
- }
822
- function clearLoggerCache() {
823
- loggerCache.clear();
824
- }
825
- var noopLogger = {
826
- module: "noop",
827
- error: () => {
828
- },
829
- warn: () => {
830
- },
831
- info: () => {
832
- },
833
- debug: () => {
834
- },
835
- trace: () => {
836
- },
837
- verbose: () => {
838
- },
839
- child: () => noopLogger
840
- };
841
- function getNoopLogger() {
842
- return noopLogger;
843
- }
844
-
845
- // src/logging/ErrorCodes.ts
846
- var ErrorCodes = {
847
- // ── Inference ──────────────────────────────────────────────────────────
848
- /** Model failed to load (file not found, corrupted, unsupported format) */
849
- INF_LOAD_FAILED: "OMOTE_INF_001",
850
- /** ORT session poisoned after WebGPU device loss — must reload tab */
851
- INF_SESSION_POISON: "OMOTE_INF_002",
852
- /** Inference exceeded timeout threshold */
853
- INF_TIMEOUT: "OMOTE_INF_003",
854
- /** Out-of-memory during inference or model loading */
855
- INF_OOM: "OMOTE_INF_004",
856
- /** WebGPU unavailable, fell back to WASM */
857
- INF_WEBGPU_FALLBACK: "OMOTE_INF_005",
858
- /** Input tensor shape does not match model expectations */
859
- INF_SHAPE_MISMATCH: "OMOTE_INF_006",
860
- // ── Audio ──────────────────────────────────────────────────────────────
861
- /** AudioContext creation or resume failed */
862
- AUD_CONTEXT_FAILED: "OMOTE_AUD_001",
863
- /** Gap detected in audio scheduling (buffer underrun) */
864
- AUD_SCHEDULE_GAP: "OMOTE_AUD_002",
865
- /** Audio buffer decoding failed */
866
- AUD_DECODE_FAILED: "OMOTE_AUD_003",
867
- // ── Speech ─────────────────────────────────────────────────────────────
868
- /** Voice activity detection error */
869
- SPH_VAD_ERROR: "OMOTE_SPH_001",
870
- /** Automatic speech recognition error */
871
- SPH_ASR_ERROR: "OMOTE_SPH_002",
872
- /** Microphone access denied or unavailable */
873
- SPH_MIC_DENIED: "OMOTE_SPH_003",
874
- // ── TTS ────────────────────────────────────────────────────────────────
875
- /** TTS synthesis failed */
876
- TTS_SYNTH_FAILED: "OMOTE_TTS_001",
877
- /** TTS streaming error (chunk delivery failure) */
878
- TTS_STREAM_ERROR: "OMOTE_TTS_002",
879
- /** Phonemizer (eSpeak-NG WASM) ran out of memory */
880
- TTS_PHONEMIZER_OOM: "OMOTE_TTS_003",
881
- // ── Pipeline ───────────────────────────────────────────────────────────
882
- /** Invalid state transition in pipeline state machine */
883
- PIP_STATE_ERROR: "OMOTE_PIP_001",
884
- /** Pipeline operation aborted (user interrupt or signal) */
885
- PIP_ABORT: "OMOTE_PIP_002",
886
- // ── Cache ──────────────────────────────────────────────────────────────
887
- /** IndexedDB storage quota exceeded */
888
- CAC_QUOTA_EXCEEDED: "OMOTE_CAC_001",
889
- /** Cache entry evicted (LRU or manual) */
890
- CAC_EVICTION: "OMOTE_CAC_002",
891
- /** Cached model is stale (version mismatch) */
892
- CAC_STALE: "OMOTE_CAC_003",
893
- // ── Network ────────────────────────────────────────────────────────────
894
- /** HTTP fetch failed (model download, CDN) */
895
- NET_FETCH_FAILED: "OMOTE_NET_001",
896
- /** Network request timed out */
897
- NET_TIMEOUT: "OMOTE_NET_002",
898
- /** WebSocket connection error */
899
- NET_WEBSOCKET_ERROR: "OMOTE_NET_003"
900
- };
901
-
902
- export {
903
- LOG_LEVEL_PRIORITY,
904
- DEFAULT_LOGGING_CONFIG,
905
- jsonFormatter,
906
- prettyFormatter,
907
- getFormatter,
908
- ConsoleExporter,
909
- OTLPExporter,
910
- defaultClock,
911
- configureClock,
912
- getClock,
913
- configureTelemetry,
914
- getTelemetry,
915
- OmoteTelemetry,
916
- configureLogging,
917
- getLoggingConfig,
918
- resetLoggingConfig,
919
- setLogLevel,
920
- setLoggingEnabled,
921
- createLogger,
922
- clearLoggerCache,
923
- noopLogger,
924
- getNoopLogger,
925
- ErrorCodes
926
- };
927
- //# sourceMappingURL=chunk-X5OTUOE6.mjs.map