@omote/core 0.9.7 → 0.10.6
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/README.md +77 -35
- package/dist/{chunk-X5OTUOE6.mjs → chunk-3FILA2CD.mjs} +63 -205
- package/dist/chunk-3FILA2CD.mjs.map +1 -0
- package/dist/{chunk-CYBTTLG7.mjs → chunk-5WIOGMJA.mjs} +77 -219
- package/dist/chunk-5WIOGMJA.mjs.map +1 -0
- package/dist/{chunk-3NDJA3I4.mjs → chunk-NWZMIQK4.mjs} +135 -206
- package/dist/chunk-NWZMIQK4.mjs.map +1 -0
- package/dist/{chunk-Y3DTP5P3.mjs → chunk-VSYYT4HO.mjs} +1 -1
- package/dist/{chunk-X5OTUOE6.mjs.map → chunk-VSYYT4HO.mjs.map} +1 -1
- package/dist/chunk-WW4XAUJ3.mjs +208 -0
- package/dist/chunk-WW4XAUJ3.mjs.map +1 -0
- package/dist/index.d.mts +336 -1375
- package/dist/index.d.ts +336 -1375
- package/dist/index.js +6738 -11284
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +6099 -10719
- package/dist/index.mjs.map +1 -1
- package/dist/logging/index.js +5 -0
- package/dist/logging/index.js.map +1 -1
- package/dist/logging/index.mjs +1 -1
- package/dist/otlp-2BML6FIK.mjs +7 -0
- package/dist/otlp-2BML6FIK.mjs.map +1 -0
- package/package.json +1 -2
- package/dist/Logger-BeUI6jG7.d.mts +0 -145
- package/dist/Logger-BeUI6jG7.d.ts +0 -145
- package/dist/Logger-DSoGAYJu.d.mts +0 -141
- package/dist/Logger-DSoGAYJu.d.ts +0 -141
- package/dist/chunk-3NDJA3I4.mjs.map +0 -1
- package/dist/chunk-CYBTTLG7.mjs.map +0 -1
- package/dist/chunk-ESU52TDS.mjs +0 -287
- package/dist/chunk-ESU52TDS.mjs.map +0 -1
- package/dist/chunk-MXKJOF4I.mjs +0 -38
- package/dist/chunk-MXKJOF4I.mjs.map +0 -1
- package/dist/chunk-XK22BRG4.mjs +0 -38
- package/dist/chunk-XK22BRG4.mjs.map +0 -1
- package/dist/chunk-Y3DTP5P3.mjs.map +0 -1
package/README.md
CHANGED
|
@@ -14,8 +14,8 @@
|
|
|
14
14
|
- **TTSSpeaker** — High-level speak(text) with abort, queueing, and LLM streaming
|
|
15
15
|
- **SpeechListener** — Mic → VAD → ASR orchestration with adaptive silence detection
|
|
16
16
|
- **createTTSPlayer()** — Factory composing Kokoro TTS + TTSSpeaker for zero-config playback
|
|
17
|
-
- **
|
|
18
|
-
- **
|
|
17
|
+
- **VoiceOrchestrator** — Full conversational agent loop with local TTS support (cloud or offline)
|
|
18
|
+
- **configureModelUrls()** — Self-host model files from your own CDN
|
|
19
19
|
- **Animation Graph** — State machine (idle/listening/thinking/speaking) with emotion blending
|
|
20
20
|
- **Emotion Controller** — Preset-based emotion system with smooth transitions
|
|
21
21
|
- **Model Caching** — IndexedDB with versioning, LRU eviction, and quota monitoring
|
|
@@ -81,15 +81,15 @@ const { blendshapes } = await a2e.infer(audioSamples); // Float32Array (16kHz)
|
|
|
81
81
|
// → 52 ARKit blendshape weights
|
|
82
82
|
```
|
|
83
83
|
|
|
84
|
-
####
|
|
84
|
+
#### Custom Configuration
|
|
85
85
|
|
|
86
86
|
```typescript
|
|
87
|
-
import {
|
|
87
|
+
import { createA2E, ARKIT_BLENDSHAPES } from '@omote/core';
|
|
88
88
|
|
|
89
|
-
const
|
|
90
|
-
await
|
|
89
|
+
const a2e = createA2E({ backend: 'wasm' }); // Force WASM for testing
|
|
90
|
+
await a2e.load();
|
|
91
91
|
|
|
92
|
-
const { blendshapes } = await
|
|
92
|
+
const { blendshapes } = await a2e.infer(audioSamples);
|
|
93
93
|
const jawOpen = blendshapes[ARKIT_BLENDSHAPES.indexOf('jawOpen')];
|
|
94
94
|
```
|
|
95
95
|
|
|
@@ -136,11 +136,9 @@ const frame = processor.getFrameForTime(audioContext.currentTime);
|
|
|
136
136
|
SenseVoice ASR — 15x faster than Whisper, with progressive transcription and emotion detection.
|
|
137
137
|
|
|
138
138
|
```typescript
|
|
139
|
-
import {
|
|
139
|
+
import { createSenseVoice } from '@omote/core';
|
|
140
140
|
|
|
141
|
-
const asr =
|
|
142
|
-
modelUrl: '/models/sensevoice/model.int8.onnx',
|
|
143
|
-
});
|
|
141
|
+
const asr = createSenseVoice(); // Auto-detects platform, fetches from HF CDN
|
|
144
142
|
await asr.load();
|
|
145
143
|
|
|
146
144
|
const { text, emotion, language } = await asr.transcribe(audioSamples);
|
|
@@ -149,22 +147,19 @@ const { text, emotion, language } = await asr.transcribe(audioSamples);
|
|
|
149
147
|
#### Platform-Aware ASR
|
|
150
148
|
|
|
151
149
|
```typescript
|
|
152
|
-
import { shouldUseNativeASR, SafariSpeechRecognition,
|
|
150
|
+
import { shouldUseNativeASR, SafariSpeechRecognition, createSenseVoice } from '@omote/core';
|
|
153
151
|
|
|
154
152
|
const asr = shouldUseNativeASR()
|
|
155
153
|
? new SafariSpeechRecognition({ language: 'en-US' })
|
|
156
|
-
:
|
|
154
|
+
: createSenseVoice();
|
|
157
155
|
```
|
|
158
156
|
|
|
159
157
|
### Voice Activity Detection (Silero VAD)
|
|
160
158
|
|
|
161
|
-
#### Factory API (Recommended)
|
|
162
|
-
|
|
163
159
|
```typescript
|
|
164
160
|
import { createSileroVAD } from '@omote/core';
|
|
165
161
|
|
|
166
162
|
const vad = createSileroVAD({
|
|
167
|
-
modelUrl: '/models/silero-vad.onnx',
|
|
168
163
|
threshold: 0.5,
|
|
169
164
|
// useWorker: true // Force off-main-thread
|
|
170
165
|
// useWorker: false // Force main thread
|
|
@@ -174,18 +169,6 @@ await vad.load();
|
|
|
174
169
|
const { isSpeech, probability } = await vad.process(audioSamples);
|
|
175
170
|
```
|
|
176
171
|
|
|
177
|
-
#### Direct API
|
|
178
|
-
|
|
179
|
-
```typescript
|
|
180
|
-
import { SileroVADInference, SileroVADWorker } from '@omote/core';
|
|
181
|
-
|
|
182
|
-
// Main thread (mobile-friendly)
|
|
183
|
-
const vad = new SileroVADInference({ modelUrl: '/models/silero-vad.onnx' });
|
|
184
|
-
|
|
185
|
-
// Web Worker (desktop, off-main-thread)
|
|
186
|
-
const vadWorker = new SileroVADWorker({ modelUrl: '/models/silero-vad.onnx' });
|
|
187
|
-
```
|
|
188
|
-
|
|
189
172
|
### Animation Graph
|
|
190
173
|
|
|
191
174
|
State machine for avatar animation states with emotion blending and audio energy.
|
|
@@ -248,7 +231,7 @@ const data = await fetchWithCache('/models/model.onnx', {
|
|
|
248
231
|
});
|
|
249
232
|
|
|
250
233
|
// Cache quota monitoring
|
|
251
|
-
import { configureCacheLimit
|
|
234
|
+
import { configureCacheLimit } from '@omote/core';
|
|
252
235
|
|
|
253
236
|
configureCacheLimit({
|
|
254
237
|
maxSizeBytes: 500 * 1024 * 1024, // 500MB limit
|
|
@@ -307,17 +290,76 @@ const span = telemetry.startSpan('custom-operation');
|
|
|
307
290
|
span.end();
|
|
308
291
|
```
|
|
309
292
|
|
|
310
|
-
|
|
293
|
+
### Text-to-Speech (Kokoro TTS)
|
|
294
|
+
|
|
295
|
+
```typescript
|
|
296
|
+
import { createKokoroTTS } from '@omote/core';
|
|
311
297
|
|
|
312
|
-
|
|
298
|
+
const tts = createKokoroTTS({ defaultVoice: 'af_heart' });
|
|
299
|
+
await tts.load();
|
|
313
300
|
|
|
301
|
+
const audio = await tts.synthesize('Hello world!');
|
|
302
|
+
// audio: Float32Array @ 24kHz
|
|
314
303
|
```
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
304
|
+
|
|
305
|
+
Kokoro auto-detects the platform: mixed-fp16 WebGPU model (156MB) on Chrome/Edge, q8 WASM model (92MB) on Safari/iOS/Firefox.
|
|
306
|
+
|
|
307
|
+
### Eager Load & Warmup
|
|
308
|
+
|
|
309
|
+
Use `eagerLoad` to preload models at construction time:
|
|
310
|
+
|
|
311
|
+
```typescript
|
|
312
|
+
const tts = createKokoroTTS({ eagerLoad: true }); // Starts loading immediately
|
|
319
313
|
```
|
|
320
314
|
|
|
315
|
+
Use `warmup()` to prime AudioContext for iOS/Safari autoplay policy. Call from a user gesture handler:
|
|
316
|
+
|
|
317
|
+
```typescript
|
|
318
|
+
button.onclick = async () => {
|
|
319
|
+
await avatar.warmup(); // Primes AudioContext
|
|
320
|
+
await avatar.connectVoice({ ... });
|
|
321
|
+
};
|
|
322
|
+
```
|
|
323
|
+
|
|
324
|
+
### Observability
|
|
325
|
+
|
|
326
|
+
The SDK includes built-in OpenTelemetry-compatible tracing and metrics:
|
|
327
|
+
|
|
328
|
+
```typescript
|
|
329
|
+
import { configureTelemetry, getTelemetry, MetricNames } from '@omote/core';
|
|
330
|
+
|
|
331
|
+
configureTelemetry({
|
|
332
|
+
enabled: true,
|
|
333
|
+
serviceName: 'my-app',
|
|
334
|
+
exporter: 'console', // or OTLPExporter for production
|
|
335
|
+
});
|
|
336
|
+
```
|
|
337
|
+
|
|
338
|
+
All inference calls, model loads, cache operations, and voice turns are automatically instrumented.
|
|
339
|
+
|
|
340
|
+
## Models
|
|
341
|
+
|
|
342
|
+
All models default to the HuggingFace CDN and are auto-downloaded on first use. Self-host with `configureModelUrls()`:
|
|
343
|
+
|
|
344
|
+
```typescript
|
|
345
|
+
import { configureModelUrls } from '@omote/core';
|
|
346
|
+
|
|
347
|
+
configureModelUrls({
|
|
348
|
+
lam: 'https://your-cdn.com/models/lam.onnx',
|
|
349
|
+
lamData: 'https://your-cdn.com/models/lam.onnx.data',
|
|
350
|
+
senseVoice: 'https://your-cdn.com/models/sensevoice.onnx',
|
|
351
|
+
sileroVad: 'https://your-cdn.com/models/silero_vad.onnx',
|
|
352
|
+
});
|
|
353
|
+
```
|
|
354
|
+
|
|
355
|
+
| Model | HuggingFace Repo | Size |
|
|
356
|
+
|-------|-------------------|------|
|
|
357
|
+
| LAM A2E | `omote-ai/lam-a2e` | `lam.onnx` (230KB) + `lam.onnx.data` (192MB) |
|
|
358
|
+
| SenseVoice | `omote-ai/sensevoice-asr` | 228MB |
|
|
359
|
+
| Silero VAD | `deepghs/silero-vad-onnx` | ~2MB |
|
|
360
|
+
| Kokoro TTS (WASM) | `onnx-community/Kokoro-82M-v1.0-ONNX` | 92MB q8 |
|
|
361
|
+
| Kokoro TTS (WebGPU) | `omote-ai/kokoro-tts` | 156MB mixed-fp16 |
|
|
362
|
+
|
|
321
363
|
## Browser Compatibility
|
|
322
364
|
|
|
323
365
|
WebGPU-first with automatic WASM fallback.
|
|
@@ -82,6 +82,8 @@ var jsonFormatter = (entry) => {
|
|
|
82
82
|
if (entry.data && Object.keys(entry.data).length > 0) {
|
|
83
83
|
output.data = entry.data;
|
|
84
84
|
}
|
|
85
|
+
if (entry.traceId) output.traceId = entry.traceId;
|
|
86
|
+
if (entry.spanId) output.spanId = entry.spanId;
|
|
85
87
|
if (entry.error) {
|
|
86
88
|
output.error = {
|
|
87
89
|
name: entry.error.name,
|
|
@@ -103,6 +105,9 @@ var prettyFormatter = (entry) => {
|
|
|
103
105
|
const color = LEVEL_COLORS[entry.level];
|
|
104
106
|
output = `${COLORS.gray}${time}${COLORS.reset} ${color}${level}${COLORS.reset} ${COLORS.cyan}[${module}]${COLORS.reset} ${message}`;
|
|
105
107
|
}
|
|
108
|
+
if (entry.traceId) {
|
|
109
|
+
output += ` [trace:${entry.traceId.slice(0, 8)}]`;
|
|
110
|
+
}
|
|
106
111
|
if (entry.data && Object.keys(entry.data).length > 0) {
|
|
107
112
|
const dataStr = safeStringify(entry.data);
|
|
108
113
|
if (dataStr.length > 80) {
|
|
@@ -207,198 +212,6 @@ var ConsoleExporter = class {
|
|
|
207
212
|
}
|
|
208
213
|
};
|
|
209
214
|
|
|
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
215
|
// src/logging/Clock.ts
|
|
403
216
|
var defaultClock = {
|
|
404
217
|
now: () => performance.now(),
|
|
@@ -413,6 +226,7 @@ function getClock() {
|
|
|
413
226
|
}
|
|
414
227
|
|
|
415
228
|
// src/telemetry/OmoteTelemetry.ts
|
|
229
|
+
var DEFAULT_HISTOGRAM_BUCKETS = [1, 5, 10, 25, 50, 100, 250, 500, 1e3, 2500, 5e3, 1e4, 3e4, 6e4];
|
|
416
230
|
function generateId(length = 16) {
|
|
417
231
|
const bytes = new Uint8Array(length);
|
|
418
232
|
crypto.getRandomValues(bytes);
|
|
@@ -432,6 +246,7 @@ function getTelemetry() {
|
|
|
432
246
|
var OmoteTelemetry = class {
|
|
433
247
|
constructor(config) {
|
|
434
248
|
this.exporter = null;
|
|
249
|
+
this.exporterReady = null;
|
|
435
250
|
this.activeTraceId = null;
|
|
436
251
|
this.metricsIntervalId = null;
|
|
437
252
|
// Span stack for log-to-span correlation
|
|
@@ -450,14 +265,22 @@ var OmoteTelemetry = class {
|
|
|
450
265
|
metricsIntervalMs: config.metricsIntervalMs ?? 6e4
|
|
451
266
|
};
|
|
452
267
|
if (this.config.enabled) {
|
|
453
|
-
|
|
268
|
+
if (config.customExporter) {
|
|
269
|
+
this.exporter = config.customExporter;
|
|
270
|
+
} else {
|
|
271
|
+
this.exporterReady = this.initExporter();
|
|
272
|
+
}
|
|
454
273
|
this.startMetricsCollection();
|
|
455
274
|
}
|
|
456
275
|
}
|
|
457
276
|
/**
|
|
458
277
|
* Initialize the configured exporter
|
|
459
278
|
*/
|
|
460
|
-
initExporter() {
|
|
279
|
+
async initExporter() {
|
|
280
|
+
if (this.config.customExporter) {
|
|
281
|
+
this.exporter = this.config.customExporter;
|
|
282
|
+
return;
|
|
283
|
+
}
|
|
461
284
|
switch (this.config.exporter) {
|
|
462
285
|
case "console":
|
|
463
286
|
this.exporter = new ConsoleExporter({ enabled: true });
|
|
@@ -467,11 +290,14 @@ var OmoteTelemetry = class {
|
|
|
467
290
|
console.warn("[Telemetry] OTLP exporter requires exporterConfig with endpoint");
|
|
468
291
|
return;
|
|
469
292
|
}
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
this.
|
|
473
|
-
|
|
474
|
-
|
|
293
|
+
{
|
|
294
|
+
const { OTLPExporter } = await import("./otlp-2BML6FIK.mjs");
|
|
295
|
+
this.exporter = new OTLPExporter(
|
|
296
|
+
this.config.exporterConfig,
|
|
297
|
+
this.config.serviceName,
|
|
298
|
+
this.config.serviceVersion
|
|
299
|
+
);
|
|
300
|
+
}
|
|
475
301
|
break;
|
|
476
302
|
case "none":
|
|
477
303
|
default:
|
|
@@ -521,6 +347,7 @@ var OmoteTelemetry = class {
|
|
|
521
347
|
const spanId = generateId(8);
|
|
522
348
|
const parentSpanId = parentContext?.spanId;
|
|
523
349
|
const startTime = getClock().now();
|
|
350
|
+
const epochMs = Date.now();
|
|
524
351
|
if (!parentContext && !this.activeTraceId) {
|
|
525
352
|
this.activeTraceId = traceId;
|
|
526
353
|
}
|
|
@@ -536,6 +363,7 @@ var OmoteTelemetry = class {
|
|
|
536
363
|
if (idx !== -1) this.spanStack.splice(idx, 1);
|
|
537
364
|
const endTime = getClock().now();
|
|
538
365
|
const durationMs = endTime - startTime;
|
|
366
|
+
const endEpochMs = epochMs + (endTime - startTime);
|
|
539
367
|
if (status === "error" && !sampled) {
|
|
540
368
|
sampled = this.shouldSample(true);
|
|
541
369
|
}
|
|
@@ -548,6 +376,8 @@ var OmoteTelemetry = class {
|
|
|
548
376
|
startTime,
|
|
549
377
|
endTime,
|
|
550
378
|
durationMs,
|
|
379
|
+
epochMs,
|
|
380
|
+
endEpochMs,
|
|
551
381
|
status,
|
|
552
382
|
attributes: spanAttributes,
|
|
553
383
|
error
|
|
@@ -622,7 +452,7 @@ var OmoteTelemetry = class {
|
|
|
622
452
|
* });
|
|
623
453
|
* ```
|
|
624
454
|
*/
|
|
625
|
-
recordHistogram(name, value, attributes = {}) {
|
|
455
|
+
recordHistogram(name, value, attributes = {}, bucketBoundaries = DEFAULT_HISTOGRAM_BUCKETS) {
|
|
626
456
|
if (!this.config.enabled || !this.config.metricsEnabled) return;
|
|
627
457
|
const key = this.getMetricKey(name, attributes);
|
|
628
458
|
const existing = this.histograms.get(key);
|
|
@@ -631,8 +461,27 @@ var OmoteTelemetry = class {
|
|
|
631
461
|
existing.sum += value;
|
|
632
462
|
if (value < existing.min) existing.min = value;
|
|
633
463
|
if (value > existing.max) existing.max = value;
|
|
464
|
+
let placed = false;
|
|
465
|
+
for (let i = 0; i < existing.bucketBoundaries.length; i++) {
|
|
466
|
+
if (value <= existing.bucketBoundaries[i]) {
|
|
467
|
+
existing.bucketCounts[i]++;
|
|
468
|
+
placed = true;
|
|
469
|
+
break;
|
|
470
|
+
}
|
|
471
|
+
}
|
|
472
|
+
if (!placed) existing.bucketCounts[existing.bucketCounts.length - 1]++;
|
|
634
473
|
} else {
|
|
635
|
-
|
|
474
|
+
const bucketCounts = new Array(bucketBoundaries.length + 1).fill(0);
|
|
475
|
+
let placed = false;
|
|
476
|
+
for (let i = 0; i < bucketBoundaries.length; i++) {
|
|
477
|
+
if (value <= bucketBoundaries[i]) {
|
|
478
|
+
bucketCounts[i]++;
|
|
479
|
+
placed = true;
|
|
480
|
+
break;
|
|
481
|
+
}
|
|
482
|
+
}
|
|
483
|
+
if (!placed) bucketCounts[bucketCounts.length - 1]++;
|
|
484
|
+
this.histograms.set(key, { count: 1, sum: value, min: value, max: value, bucketBoundaries, bucketCounts, attributes });
|
|
636
485
|
}
|
|
637
486
|
}
|
|
638
487
|
/**
|
|
@@ -649,7 +498,7 @@ var OmoteTelemetry = class {
|
|
|
649
498
|
*/
|
|
650
499
|
flushMetrics() {
|
|
651
500
|
if (!this.exporter) return;
|
|
652
|
-
const timestamp =
|
|
501
|
+
const timestamp = Date.now();
|
|
653
502
|
for (const [key, data] of this.counters) {
|
|
654
503
|
if (data.value === 0) continue;
|
|
655
504
|
const name = key.split("|")[0];
|
|
@@ -678,19 +527,29 @@ var OmoteTelemetry = class {
|
|
|
678
527
|
min: data.min,
|
|
679
528
|
max: data.max
|
|
680
529
|
},
|
|
681
|
-
timestamp
|
|
530
|
+
timestamp,
|
|
531
|
+
histogramData: {
|
|
532
|
+
count: data.count,
|
|
533
|
+
sum: data.sum,
|
|
534
|
+
min: data.min,
|
|
535
|
+
max: data.max,
|
|
536
|
+
bucketBoundaries: [...data.bucketBoundaries],
|
|
537
|
+
bucketCounts: [...data.bucketCounts]
|
|
538
|
+
}
|
|
682
539
|
};
|
|
683
540
|
this.exporter.exportMetric(metric);
|
|
684
541
|
data.count = 0;
|
|
685
542
|
data.sum = 0;
|
|
686
543
|
data.min = Infinity;
|
|
687
544
|
data.max = -Infinity;
|
|
545
|
+
data.bucketCounts.fill(0);
|
|
688
546
|
}
|
|
689
547
|
}
|
|
690
548
|
/**
|
|
691
549
|
* Force flush all pending data
|
|
692
550
|
*/
|
|
693
551
|
async flush() {
|
|
552
|
+
if (this.exporterReady) await this.exporterReady;
|
|
694
553
|
this.flushMetrics();
|
|
695
554
|
await this.exporter?.flush();
|
|
696
555
|
}
|
|
@@ -906,7 +765,6 @@ export {
|
|
|
906
765
|
prettyFormatter,
|
|
907
766
|
getFormatter,
|
|
908
767
|
ConsoleExporter,
|
|
909
|
-
OTLPExporter,
|
|
910
768
|
defaultClock,
|
|
911
769
|
configureClock,
|
|
912
770
|
getClock,
|
|
@@ -924,4 +782,4 @@ export {
|
|
|
924
782
|
getNoopLogger,
|
|
925
783
|
ErrorCodes
|
|
926
784
|
};
|
|
927
|
-
//# sourceMappingURL=chunk-
|
|
785
|
+
//# sourceMappingURL=chunk-3FILA2CD.mjs.map
|