@doclo/core 0.1.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.
- package/LICENSE +21 -0
- package/README.md +34 -0
- package/dist/index.d.ts +931 -0
- package/dist/index.js +2293 -0
- package/dist/index.js.map +1 -0
- package/dist/internal/validation-utils.d.ts +1 -0
- package/dist/internal/validation-utils.js +650 -0
- package/dist/internal/validation-utils.js.map +1 -0
- package/dist/observability/index.d.ts +933 -0
- package/dist/observability/index.js +630 -0
- package/dist/observability/index.js.map +1 -0
- package/dist/pdf-utils.d.ts +123 -0
- package/dist/pdf-utils.js +106 -0
- package/dist/pdf-utils.js.map +1 -0
- package/dist/runtime/base64.d.ts +100 -0
- package/dist/runtime/base64.js +52 -0
- package/dist/runtime/base64.js.map +1 -0
- package/dist/runtime/crypto.d.ts +56 -0
- package/dist/runtime/crypto.js +35 -0
- package/dist/runtime/crypto.js.map +1 -0
- package/dist/runtime/env.d.ts +130 -0
- package/dist/runtime/env.js +76 -0
- package/dist/runtime/env.js.map +1 -0
- package/dist/security/index.d.ts +236 -0
- package/dist/security/index.js +260 -0
- package/dist/security/index.js.map +1 -0
- package/dist/validation-CzOz6fwq.d.ts +1126 -0
- package/dist/validation.d.ts +1 -0
- package/dist/validation.js +445 -0
- package/dist/validation.js.map +1 -0
- package/package.json +70 -0
|
@@ -0,0 +1,630 @@
|
|
|
1
|
+
// src/observability/hook-executor.ts
|
|
2
|
+
var DEFAULT_HOOK_TIMEOUT = 5e3;
|
|
3
|
+
async function executeHook(hook, options) {
|
|
4
|
+
const { hookName, config, context, fireAndForget = false } = options;
|
|
5
|
+
if (!hook) {
|
|
6
|
+
return;
|
|
7
|
+
}
|
|
8
|
+
if (config.enabled === false) {
|
|
9
|
+
return;
|
|
10
|
+
}
|
|
11
|
+
if (fireAndForget || config.fireAndForget) {
|
|
12
|
+
executeHookWithErrorHandling(hook, hookName, context, config).catch(() => {
|
|
13
|
+
});
|
|
14
|
+
return;
|
|
15
|
+
}
|
|
16
|
+
const timeout = config.hookTimeout ?? DEFAULT_HOOK_TIMEOUT;
|
|
17
|
+
try {
|
|
18
|
+
await executeHookWithTimeout(hook, context, timeout, hookName, config);
|
|
19
|
+
} catch (error) {
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
async function executeHookWithErrorHandling(hook, hookName, context, config) {
|
|
23
|
+
try {
|
|
24
|
+
const result = hook(context);
|
|
25
|
+
if (result && typeof result.then === "function") {
|
|
26
|
+
await result;
|
|
27
|
+
}
|
|
28
|
+
} catch (error) {
|
|
29
|
+
handleHookError(error, hookName, context, config);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
async function executeHookWithTimeout(hook, context, timeoutMs, hookName, config) {
|
|
33
|
+
const timeoutPromise = new Promise((_, reject) => {
|
|
34
|
+
setTimeout(() => {
|
|
35
|
+
reject(new Error(`Hook '${hookName}' exceeded timeout of ${timeoutMs}ms`));
|
|
36
|
+
}, timeoutMs);
|
|
37
|
+
});
|
|
38
|
+
const hookPromise = executeHookWithErrorHandling(hook, hookName, context, config);
|
|
39
|
+
try {
|
|
40
|
+
await Promise.race([hookPromise, timeoutPromise]);
|
|
41
|
+
} catch (error) {
|
|
42
|
+
if (error instanceof Error && error.message.includes("exceeded timeout")) {
|
|
43
|
+
handleHookError(error, hookName, context, config);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
function handleHookError(error, hookName, context, config) {
|
|
48
|
+
const hookError = {
|
|
49
|
+
hookName,
|
|
50
|
+
error,
|
|
51
|
+
context,
|
|
52
|
+
timestamp: Date.now()
|
|
53
|
+
};
|
|
54
|
+
if (config.onHookError) {
|
|
55
|
+
try {
|
|
56
|
+
config.onHookError(hookError);
|
|
57
|
+
} catch (onHookErrorError) {
|
|
58
|
+
console.error("[Observability] onHookError handler failed:", onHookErrorError);
|
|
59
|
+
console.error("[Observability] Original hook error:", hookError);
|
|
60
|
+
}
|
|
61
|
+
} else {
|
|
62
|
+
console.warn(`[Observability] Hook '${hookName}' failed:`, error);
|
|
63
|
+
}
|
|
64
|
+
if (config.failOnHookError) {
|
|
65
|
+
throw error;
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
async function executeHooksSerial(hooks) {
|
|
69
|
+
for (const { hook, options } of hooks) {
|
|
70
|
+
await executeHook(hook, options);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
function isObservabilityEnabled(config) {
|
|
74
|
+
if (config.enabled === false) {
|
|
75
|
+
return false;
|
|
76
|
+
}
|
|
77
|
+
if (config.samplingRate === void 0 || config.samplingRate === 1) {
|
|
78
|
+
return true;
|
|
79
|
+
}
|
|
80
|
+
if (config.samplingRate === 0) {
|
|
81
|
+
return false;
|
|
82
|
+
}
|
|
83
|
+
return Math.random() < config.samplingRate;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
// src/runtime/crypto.ts
|
|
87
|
+
function getRandomBytes(length) {
|
|
88
|
+
const bytes = new Uint8Array(length);
|
|
89
|
+
if (typeof globalThis !== "undefined" && globalThis.crypto?.getRandomValues) {
|
|
90
|
+
globalThis.crypto.getRandomValues(bytes);
|
|
91
|
+
return bytes;
|
|
92
|
+
}
|
|
93
|
+
throw new Error(
|
|
94
|
+
"Web Crypto API not available. This SDK requires:\n- Node.js 18.0.0 or later (has globalThis.crypto)\n- Edge Runtime (Vercel, Cloudflare)\n- Modern browsers"
|
|
95
|
+
);
|
|
96
|
+
}
|
|
97
|
+
function bytesToHex(bytes) {
|
|
98
|
+
return Array.from(bytes).map((b) => b.toString(16).padStart(2, "0")).join("");
|
|
99
|
+
}
|
|
100
|
+
function randomHex(byteLength) {
|
|
101
|
+
const bytes = getRandomBytes(byteLength);
|
|
102
|
+
return bytesToHex(bytes);
|
|
103
|
+
}
|
|
104
|
+
function randomUUID() {
|
|
105
|
+
if (typeof globalThis !== "undefined" && globalThis.crypto?.randomUUID) {
|
|
106
|
+
return globalThis.crypto.randomUUID();
|
|
107
|
+
}
|
|
108
|
+
const bytes = getRandomBytes(16);
|
|
109
|
+
bytes[6] = bytes[6] & 15 | 64;
|
|
110
|
+
bytes[8] = bytes[8] & 63 | 128;
|
|
111
|
+
const hex = bytesToHex(bytes);
|
|
112
|
+
return `${hex.slice(0, 8)}-${hex.slice(8, 12)}-${hex.slice(12, 16)}-${hex.slice(16, 20)}-${hex.slice(20, 32)}`;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
// src/observability/trace-context.ts
|
|
116
|
+
var TRACE_CONTEXT_VERSION = "00";
|
|
117
|
+
var TRACE_FLAGS_SAMPLED = 1;
|
|
118
|
+
var TRACE_FLAGS_NOT_SAMPLED = 0;
|
|
119
|
+
function generateTraceId() {
|
|
120
|
+
return randomHex(16);
|
|
121
|
+
}
|
|
122
|
+
function generateSpanId() {
|
|
123
|
+
return randomHex(8);
|
|
124
|
+
}
|
|
125
|
+
function generateExecutionId() {
|
|
126
|
+
return randomUUID();
|
|
127
|
+
}
|
|
128
|
+
function createTraceContext(config, sampled) {
|
|
129
|
+
const traceIdGenerator = config.generateTraceId ?? generateTraceId;
|
|
130
|
+
const spanIdGenerator = config.generateSpanId ?? generateSpanId;
|
|
131
|
+
if (config.traceContext) {
|
|
132
|
+
const input = config.traceContext;
|
|
133
|
+
return {
|
|
134
|
+
traceId: input.traceId,
|
|
135
|
+
spanId: spanIdGenerator(),
|
|
136
|
+
parentSpanId: input.parentSpanId,
|
|
137
|
+
traceFlags: input.traceFlags ?? (sampled ? TRACE_FLAGS_SAMPLED : TRACE_FLAGS_NOT_SAMPLED),
|
|
138
|
+
traceState: input.traceState
|
|
139
|
+
};
|
|
140
|
+
}
|
|
141
|
+
return {
|
|
142
|
+
traceId: traceIdGenerator(),
|
|
143
|
+
spanId: spanIdGenerator(),
|
|
144
|
+
traceFlags: sampled ? TRACE_FLAGS_SAMPLED : TRACE_FLAGS_NOT_SAMPLED
|
|
145
|
+
};
|
|
146
|
+
}
|
|
147
|
+
function createChildSpanContext(parent, config) {
|
|
148
|
+
const spanIdGenerator = config?.generateSpanId ?? generateSpanId;
|
|
149
|
+
return {
|
|
150
|
+
traceId: parent.traceId,
|
|
151
|
+
spanId: spanIdGenerator(),
|
|
152
|
+
parentSpanId: parent.spanId,
|
|
153
|
+
traceFlags: parent.traceFlags,
|
|
154
|
+
traceState: parent.traceState
|
|
155
|
+
};
|
|
156
|
+
}
|
|
157
|
+
function formatTraceparent(context) {
|
|
158
|
+
const flags = context.traceFlags.toString(16).padStart(2, "0");
|
|
159
|
+
return `${TRACE_CONTEXT_VERSION}-${context.traceId}-${context.spanId}-${flags}`;
|
|
160
|
+
}
|
|
161
|
+
function parseTraceparent(traceparent) {
|
|
162
|
+
const parts = traceparent.split("-");
|
|
163
|
+
if (parts.length !== 4) {
|
|
164
|
+
return null;
|
|
165
|
+
}
|
|
166
|
+
const [version, traceId, spanId, flags] = parts;
|
|
167
|
+
if (version !== TRACE_CONTEXT_VERSION) {
|
|
168
|
+
return null;
|
|
169
|
+
}
|
|
170
|
+
if (!/^[0-9a-f]{32}$/.test(traceId)) {
|
|
171
|
+
return null;
|
|
172
|
+
}
|
|
173
|
+
if (!/^[0-9a-f]{16}$/.test(spanId)) {
|
|
174
|
+
return null;
|
|
175
|
+
}
|
|
176
|
+
if (!/^[0-9a-f]{2}$/.test(flags)) {
|
|
177
|
+
return null;
|
|
178
|
+
}
|
|
179
|
+
return {
|
|
180
|
+
traceId,
|
|
181
|
+
parentSpanId: spanId,
|
|
182
|
+
traceFlags: parseInt(flags, 16)
|
|
183
|
+
};
|
|
184
|
+
}
|
|
185
|
+
function formatTracestate(context) {
|
|
186
|
+
return context.traceState;
|
|
187
|
+
}
|
|
188
|
+
function isTraceSampled(context) {
|
|
189
|
+
return (context.traceFlags & TRACE_FLAGS_SAMPLED) === TRACE_FLAGS_SAMPLED;
|
|
190
|
+
}
|
|
191
|
+
function isValidTraceId(traceId) {
|
|
192
|
+
if (!/^[0-9a-f]{32}$/.test(traceId)) {
|
|
193
|
+
return false;
|
|
194
|
+
}
|
|
195
|
+
if (traceId === "00000000000000000000000000000000") {
|
|
196
|
+
return false;
|
|
197
|
+
}
|
|
198
|
+
return true;
|
|
199
|
+
}
|
|
200
|
+
function isValidSpanId(spanId) {
|
|
201
|
+
if (!/^[0-9a-f]{16}$/.test(spanId)) {
|
|
202
|
+
return false;
|
|
203
|
+
}
|
|
204
|
+
if (spanId === "0000000000000000") {
|
|
205
|
+
return false;
|
|
206
|
+
}
|
|
207
|
+
return true;
|
|
208
|
+
}
|
|
209
|
+
var TraceContextManager = class {
|
|
210
|
+
traceContext = null;
|
|
211
|
+
config;
|
|
212
|
+
constructor(config) {
|
|
213
|
+
this.config = config;
|
|
214
|
+
}
|
|
215
|
+
/**
|
|
216
|
+
* Initialize trace context for new execution
|
|
217
|
+
*/
|
|
218
|
+
initialize(sampled) {
|
|
219
|
+
this.traceContext = createTraceContext(this.config, sampled);
|
|
220
|
+
return this.traceContext;
|
|
221
|
+
}
|
|
222
|
+
/**
|
|
223
|
+
* Get current trace context
|
|
224
|
+
*/
|
|
225
|
+
getTraceContext() {
|
|
226
|
+
return this.traceContext;
|
|
227
|
+
}
|
|
228
|
+
/**
|
|
229
|
+
* Create child span context
|
|
230
|
+
*/
|
|
231
|
+
createChildSpan() {
|
|
232
|
+
if (!this.traceContext) {
|
|
233
|
+
throw new Error("Trace context not initialized");
|
|
234
|
+
}
|
|
235
|
+
return createChildSpanContext(this.traceContext, this.config);
|
|
236
|
+
}
|
|
237
|
+
/**
|
|
238
|
+
* Get traceparent header value
|
|
239
|
+
*/
|
|
240
|
+
getTraceparent() {
|
|
241
|
+
if (!this.traceContext) {
|
|
242
|
+
return null;
|
|
243
|
+
}
|
|
244
|
+
return formatTraceparent(this.traceContext);
|
|
245
|
+
}
|
|
246
|
+
/**
|
|
247
|
+
* Reset trace context (for testing)
|
|
248
|
+
*/
|
|
249
|
+
reset() {
|
|
250
|
+
this.traceContext = null;
|
|
251
|
+
}
|
|
252
|
+
};
|
|
253
|
+
|
|
254
|
+
// src/observability/otel-attributes.ts
|
|
255
|
+
var GEN_AI_SYSTEMS = {
|
|
256
|
+
openai: "openai",
|
|
257
|
+
"openai-compatible": "openai",
|
|
258
|
+
anthropic: "anthropic",
|
|
259
|
+
google: "vertex_ai",
|
|
260
|
+
// Google uses Vertex AI
|
|
261
|
+
"google-ai": "vertex_ai",
|
|
262
|
+
cohere: "cohere",
|
|
263
|
+
huggingface: "huggingface",
|
|
264
|
+
openrouter: "openrouter",
|
|
265
|
+
// Custom system
|
|
266
|
+
ollama: "ollama"
|
|
267
|
+
// Custom system
|
|
268
|
+
};
|
|
269
|
+
function mapProviderToSystem(provider) {
|
|
270
|
+
const normalized = provider.toLowerCase();
|
|
271
|
+
return GEN_AI_SYSTEMS[normalized] ?? normalized;
|
|
272
|
+
}
|
|
273
|
+
function buildOtelAttributes(data) {
|
|
274
|
+
const attributes = {};
|
|
275
|
+
if (data.provider) {
|
|
276
|
+
attributes["gen_ai.system"] = mapProviderToSystem(data.provider);
|
|
277
|
+
}
|
|
278
|
+
if (data.stepType) {
|
|
279
|
+
attributes["gen_ai.operation.name"] = data.stepType;
|
|
280
|
+
}
|
|
281
|
+
if (data.model) {
|
|
282
|
+
attributes["gen_ai.request.model"] = data.model;
|
|
283
|
+
}
|
|
284
|
+
if (data.modelUsed) {
|
|
285
|
+
attributes["gen_ai.response.model"] = data.modelUsed;
|
|
286
|
+
}
|
|
287
|
+
if (data.inputTokens !== void 0) {
|
|
288
|
+
attributes["gen_ai.usage.input_tokens"] = data.inputTokens;
|
|
289
|
+
}
|
|
290
|
+
if (data.outputTokens !== void 0) {
|
|
291
|
+
attributes["gen_ai.usage.output_tokens"] = data.outputTokens;
|
|
292
|
+
}
|
|
293
|
+
if (data.finishReason) {
|
|
294
|
+
attributes["gen_ai.response.finish_reason"] = data.finishReason;
|
|
295
|
+
}
|
|
296
|
+
if (data.temperature !== void 0) {
|
|
297
|
+
attributes["gen_ai.request.temperature"] = data.temperature;
|
|
298
|
+
}
|
|
299
|
+
if (data.maxTokens !== void 0) {
|
|
300
|
+
attributes["gen_ai.request.max_tokens"] = data.maxTokens;
|
|
301
|
+
}
|
|
302
|
+
if (data.topP !== void 0) {
|
|
303
|
+
attributes["gen_ai.request.top_p"] = data.topP;
|
|
304
|
+
}
|
|
305
|
+
if (data.topK !== void 0) {
|
|
306
|
+
attributes["gen_ai.request.top_k"] = data.topK;
|
|
307
|
+
}
|
|
308
|
+
return attributes;
|
|
309
|
+
}
|
|
310
|
+
function buildProviderRequestAttributes(data) {
|
|
311
|
+
return buildOtelAttributes({
|
|
312
|
+
provider: data.provider,
|
|
313
|
+
model: data.model,
|
|
314
|
+
temperature: data.config?.temperature,
|
|
315
|
+
maxTokens: data.config?.maxTokens,
|
|
316
|
+
topP: data.config?.topP,
|
|
317
|
+
topK: data.config?.topK
|
|
318
|
+
});
|
|
319
|
+
}
|
|
320
|
+
function buildProviderResponseAttributes(data) {
|
|
321
|
+
return buildOtelAttributes({
|
|
322
|
+
provider: data.provider,
|
|
323
|
+
model: data.model,
|
|
324
|
+
modelUsed: data.modelUsed,
|
|
325
|
+
inputTokens: data.inputTokens,
|
|
326
|
+
outputTokens: data.outputTokens,
|
|
327
|
+
finishReason: data.finishReason
|
|
328
|
+
});
|
|
329
|
+
}
|
|
330
|
+
function buildStepAttributes(data) {
|
|
331
|
+
return buildOtelAttributes({
|
|
332
|
+
stepType: data.stepType,
|
|
333
|
+
provider: data.provider,
|
|
334
|
+
model: data.model,
|
|
335
|
+
modelUsed: data.modelUsed,
|
|
336
|
+
inputTokens: data.inputTokens,
|
|
337
|
+
outputTokens: data.outputTokens,
|
|
338
|
+
finishReason: data.finishReason,
|
|
339
|
+
temperature: data.config?.temperature,
|
|
340
|
+
maxTokens: data.config?.maxTokens,
|
|
341
|
+
topP: data.config?.topP,
|
|
342
|
+
topK: data.config?.topK
|
|
343
|
+
});
|
|
344
|
+
}
|
|
345
|
+
var FINISH_REASON_MAPPING = {
|
|
346
|
+
// OpenAI
|
|
347
|
+
stop: "stop",
|
|
348
|
+
length: "length",
|
|
349
|
+
content_filter: "content_filter",
|
|
350
|
+
tool_calls: "tool_calls",
|
|
351
|
+
function_call: "function_call",
|
|
352
|
+
// Anthropic
|
|
353
|
+
end_turn: "stop",
|
|
354
|
+
max_tokens: "length",
|
|
355
|
+
stop_sequence: "stop",
|
|
356
|
+
// Google
|
|
357
|
+
STOP: "stop",
|
|
358
|
+
MAX_TOKENS: "length",
|
|
359
|
+
SAFETY: "content_filter",
|
|
360
|
+
RECITATION: "content_filter",
|
|
361
|
+
// Generic
|
|
362
|
+
complete: "stop",
|
|
363
|
+
truncated: "length",
|
|
364
|
+
filtered: "content_filter"
|
|
365
|
+
};
|
|
366
|
+
function normalizeFinishReason(reason) {
|
|
367
|
+
if (!reason) {
|
|
368
|
+
return void 0;
|
|
369
|
+
}
|
|
370
|
+
return FINISH_REASON_MAPPING[reason] ?? reason;
|
|
371
|
+
}
|
|
372
|
+
function addStandardSpanAttributes(attributes, data) {
|
|
373
|
+
if (data.spanKind) {
|
|
374
|
+
attributes["span.kind"] = data.spanKind;
|
|
375
|
+
}
|
|
376
|
+
if (data.serviceName) {
|
|
377
|
+
attributes["service.name"] = data.serviceName;
|
|
378
|
+
}
|
|
379
|
+
if (data.serviceVersion) {
|
|
380
|
+
attributes["service.version"] = data.serviceVersion;
|
|
381
|
+
}
|
|
382
|
+
}
|
|
383
|
+
function buildFullOtelContext(data) {
|
|
384
|
+
const attributes = buildOtelAttributes({
|
|
385
|
+
stepType: data.stepType,
|
|
386
|
+
provider: data.provider,
|
|
387
|
+
model: data.model,
|
|
388
|
+
modelUsed: data.modelUsed,
|
|
389
|
+
inputTokens: data.inputTokens,
|
|
390
|
+
outputTokens: data.outputTokens,
|
|
391
|
+
finishReason: data.finishReason,
|
|
392
|
+
temperature: data.config?.temperature,
|
|
393
|
+
maxTokens: data.config?.maxTokens,
|
|
394
|
+
topP: data.config?.topP,
|
|
395
|
+
topK: data.config?.topK
|
|
396
|
+
});
|
|
397
|
+
addStandardSpanAttributes(attributes, {
|
|
398
|
+
spanKind: data.spanKind,
|
|
399
|
+
serviceName: data.serviceName,
|
|
400
|
+
serviceVersion: data.serviceVersion
|
|
401
|
+
});
|
|
402
|
+
return attributes;
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
// src/observability/defaults.ts
|
|
406
|
+
var DEFAULT_OBSERVABILITY_CONFIG = {
|
|
407
|
+
enabled: true,
|
|
408
|
+
samplingRate: 1,
|
|
409
|
+
samplingStrategy: "random",
|
|
410
|
+
asyncHooks: true,
|
|
411
|
+
fireAndForget: false,
|
|
412
|
+
hookTimeout: 5e3,
|
|
413
|
+
failOnHookError: false
|
|
414
|
+
};
|
|
415
|
+
function mergeConfig(userConfig) {
|
|
416
|
+
if (!userConfig) {
|
|
417
|
+
return { ...DEFAULT_OBSERVABILITY_CONFIG };
|
|
418
|
+
}
|
|
419
|
+
return {
|
|
420
|
+
...DEFAULT_OBSERVABILITY_CONFIG,
|
|
421
|
+
...userConfig
|
|
422
|
+
};
|
|
423
|
+
}
|
|
424
|
+
function shouldSample(config) {
|
|
425
|
+
if (config.samplingRate === void 0 || config.samplingRate === 1) {
|
|
426
|
+
return true;
|
|
427
|
+
}
|
|
428
|
+
if (config.samplingRate === 0) {
|
|
429
|
+
return false;
|
|
430
|
+
}
|
|
431
|
+
if (config.samplingStrategy === "custom" && config.customSampler) {
|
|
432
|
+
return true;
|
|
433
|
+
}
|
|
434
|
+
return Math.random() < config.samplingRate;
|
|
435
|
+
}
|
|
436
|
+
function validateConfig(config) {
|
|
437
|
+
const warnings = [];
|
|
438
|
+
const errors = [];
|
|
439
|
+
if (config.samplingRate !== void 0) {
|
|
440
|
+
if (config.samplingRate < 0 || config.samplingRate > 1) {
|
|
441
|
+
errors.push("samplingRate must be between 0.0 and 1.0");
|
|
442
|
+
}
|
|
443
|
+
}
|
|
444
|
+
if (config.hookTimeout !== void 0) {
|
|
445
|
+
if (config.hookTimeout <= 0) {
|
|
446
|
+
errors.push("hookTimeout must be positive");
|
|
447
|
+
}
|
|
448
|
+
if (config.hookTimeout > 6e4) {
|
|
449
|
+
warnings.push("hookTimeout > 60s may cause long execution delays");
|
|
450
|
+
}
|
|
451
|
+
}
|
|
452
|
+
if (config.samplingStrategy === "custom" && !config.customSampler) {
|
|
453
|
+
errors.push('customSampler required when samplingStrategy is "custom"');
|
|
454
|
+
}
|
|
455
|
+
if (config.traceContext) {
|
|
456
|
+
const { traceId, parentSpanId } = config.traceContext;
|
|
457
|
+
if (!/^[0-9a-f]{32}$/.test(traceId)) {
|
|
458
|
+
errors.push("traceContext.traceId must be 32 lowercase hex characters");
|
|
459
|
+
}
|
|
460
|
+
if (!/^[0-9a-f]{16}$/.test(parentSpanId)) {
|
|
461
|
+
errors.push("traceContext.parentSpanId must be 16 lowercase hex characters");
|
|
462
|
+
}
|
|
463
|
+
if (traceId === "00000000000000000000000000000000") {
|
|
464
|
+
errors.push("traceContext.traceId cannot be all zeros");
|
|
465
|
+
}
|
|
466
|
+
if (parentSpanId === "0000000000000000") {
|
|
467
|
+
errors.push("traceContext.parentSpanId cannot be all zeros");
|
|
468
|
+
}
|
|
469
|
+
}
|
|
470
|
+
if (config.asyncHooks === false && config.hookTimeout !== void 0) {
|
|
471
|
+
warnings.push("hookTimeout has no effect when asyncHooks is false");
|
|
472
|
+
}
|
|
473
|
+
if (config.fireAndForget === true && config.hookTimeout !== void 0) {
|
|
474
|
+
warnings.push("hookTimeout has no effect when fireAndForget is true");
|
|
475
|
+
}
|
|
476
|
+
if (config.enabled === false && Object.keys(config).length > 1) {
|
|
477
|
+
warnings.push("Observability is disabled, other config options have no effect");
|
|
478
|
+
}
|
|
479
|
+
return {
|
|
480
|
+
valid: errors.length === 0,
|
|
481
|
+
warnings,
|
|
482
|
+
errors
|
|
483
|
+
};
|
|
484
|
+
}
|
|
485
|
+
function getObservabilityVersion(config) {
|
|
486
|
+
return config?.observabilityVersion ?? "1.0.0";
|
|
487
|
+
}
|
|
488
|
+
function isObservabilityDisabled(config) {
|
|
489
|
+
return config.enabled === false || config.samplingRate === 0;
|
|
490
|
+
}
|
|
491
|
+
function hasAnyHooks(config) {
|
|
492
|
+
return !!(config.onFlowStart || config.onFlowEnd || config.onFlowError || config.onStepStart || config.onStepEnd || config.onStepError || config.onConsensusStart || config.onConsensusRunRetry || config.onConsensusRunComplete || config.onConsensusComplete || config.onBatchStart || config.onBatchItemStart || config.onBatchItemEnd || config.onBatchEnd || config.onProviderRequest || config.onProviderResponse || config.onProviderRetry || config.onCircuitBreakerTriggered || config.onLog);
|
|
493
|
+
}
|
|
494
|
+
function createMinimalConfig(overrides) {
|
|
495
|
+
return {
|
|
496
|
+
enabled: true,
|
|
497
|
+
samplingRate: 1,
|
|
498
|
+
asyncHooks: false,
|
|
499
|
+
// Faster for tests
|
|
500
|
+
fireAndForget: false,
|
|
501
|
+
hookTimeout: 1e3,
|
|
502
|
+
// Shorter for tests
|
|
503
|
+
failOnHookError: false,
|
|
504
|
+
...overrides
|
|
505
|
+
};
|
|
506
|
+
}
|
|
507
|
+
|
|
508
|
+
// src/observability/logger.ts
|
|
509
|
+
var Logger = class {
|
|
510
|
+
options;
|
|
511
|
+
constructor(options = {}) {
|
|
512
|
+
this.options = options;
|
|
513
|
+
}
|
|
514
|
+
/**
|
|
515
|
+
* Log a debug message
|
|
516
|
+
*/
|
|
517
|
+
debug(message, data) {
|
|
518
|
+
this.log("debug", message, data);
|
|
519
|
+
}
|
|
520
|
+
/**
|
|
521
|
+
* Log an info message
|
|
522
|
+
*/
|
|
523
|
+
info(message, data) {
|
|
524
|
+
this.log("info", message, data);
|
|
525
|
+
}
|
|
526
|
+
/**
|
|
527
|
+
* Log a warning message
|
|
528
|
+
*/
|
|
529
|
+
warn(message, data) {
|
|
530
|
+
this.log("warn", message, data);
|
|
531
|
+
}
|
|
532
|
+
/**
|
|
533
|
+
* Log an error message
|
|
534
|
+
*/
|
|
535
|
+
error(message, error, data) {
|
|
536
|
+
this.log("error", message, data, error instanceof Error ? error : void 0);
|
|
537
|
+
}
|
|
538
|
+
/**
|
|
539
|
+
* Internal log method that sends to onLog hook
|
|
540
|
+
*/
|
|
541
|
+
log(level, message, data, error) {
|
|
542
|
+
const timestamp = Date.now();
|
|
543
|
+
const consoleMethod = level === "error" ? console.error : level === "warn" ? console.warn : console.log;
|
|
544
|
+
if (error) {
|
|
545
|
+
consoleMethod(`[${level.toUpperCase()}] ${message}`, data, error);
|
|
546
|
+
} else if (data !== void 0) {
|
|
547
|
+
consoleMethod(`[${level.toUpperCase()}] ${message}`, data);
|
|
548
|
+
} else {
|
|
549
|
+
consoleMethod(`[${level.toUpperCase()}] ${message}`);
|
|
550
|
+
}
|
|
551
|
+
if (this.options.observability?.onLog && this.options.traceContext) {
|
|
552
|
+
const combinedMetadata = {
|
|
553
|
+
...this.options.metadata || {}
|
|
554
|
+
};
|
|
555
|
+
if (data !== void 0) {
|
|
556
|
+
combinedMetadata.data = data;
|
|
557
|
+
}
|
|
558
|
+
if (error) {
|
|
559
|
+
combinedMetadata.error = {
|
|
560
|
+
name: error.name,
|
|
561
|
+
message: error.message,
|
|
562
|
+
stack: error.stack
|
|
563
|
+
};
|
|
564
|
+
}
|
|
565
|
+
const logContext = {
|
|
566
|
+
flowId: this.options.flowId ?? "unknown",
|
|
567
|
+
executionId: this.options.executionId ?? "unknown",
|
|
568
|
+
stepId: this.options.stepId,
|
|
569
|
+
timestamp,
|
|
570
|
+
level,
|
|
571
|
+
message,
|
|
572
|
+
metadata: combinedMetadata,
|
|
573
|
+
traceContext: this.options.traceContext
|
|
574
|
+
};
|
|
575
|
+
executeHook(this.options.observability.onLog, {
|
|
576
|
+
hookName: "onLog",
|
|
577
|
+
config: this.options.observability,
|
|
578
|
+
context: logContext,
|
|
579
|
+
fireAndForget: true
|
|
580
|
+
// Special handling for onLog
|
|
581
|
+
}).catch(() => {
|
|
582
|
+
});
|
|
583
|
+
}
|
|
584
|
+
}
|
|
585
|
+
};
|
|
586
|
+
function createLogger(options = {}) {
|
|
587
|
+
return new Logger(options);
|
|
588
|
+
}
|
|
589
|
+
|
|
590
|
+
// src/observability/index.ts
|
|
591
|
+
var OBSERVABILITY_VERSION = "1.0.0";
|
|
592
|
+
export {
|
|
593
|
+
DEFAULT_OBSERVABILITY_CONFIG,
|
|
594
|
+
FINISH_REASON_MAPPING,
|
|
595
|
+
Logger,
|
|
596
|
+
OBSERVABILITY_VERSION,
|
|
597
|
+
TRACE_FLAGS_NOT_SAMPLED,
|
|
598
|
+
TRACE_FLAGS_SAMPLED,
|
|
599
|
+
TraceContextManager,
|
|
600
|
+
addStandardSpanAttributes,
|
|
601
|
+
buildFullOtelContext,
|
|
602
|
+
buildOtelAttributes,
|
|
603
|
+
buildProviderRequestAttributes,
|
|
604
|
+
buildProviderResponseAttributes,
|
|
605
|
+
buildStepAttributes,
|
|
606
|
+
createChildSpanContext,
|
|
607
|
+
createLogger,
|
|
608
|
+
createMinimalConfig,
|
|
609
|
+
createTraceContext,
|
|
610
|
+
executeHook,
|
|
611
|
+
executeHooksSerial,
|
|
612
|
+
formatTraceparent,
|
|
613
|
+
formatTracestate,
|
|
614
|
+
generateExecutionId,
|
|
615
|
+
generateSpanId,
|
|
616
|
+
generateTraceId,
|
|
617
|
+
getObservabilityVersion,
|
|
618
|
+
hasAnyHooks,
|
|
619
|
+
isObservabilityDisabled,
|
|
620
|
+
isObservabilityEnabled,
|
|
621
|
+
isTraceSampled,
|
|
622
|
+
isValidSpanId,
|
|
623
|
+
isValidTraceId,
|
|
624
|
+
mergeConfig,
|
|
625
|
+
normalizeFinishReason,
|
|
626
|
+
parseTraceparent,
|
|
627
|
+
shouldSample,
|
|
628
|
+
validateConfig
|
|
629
|
+
};
|
|
630
|
+
//# sourceMappingURL=index.js.map
|