@elsium-ai/app 0.1.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/dist/index.js ADDED
@@ -0,0 +1,3890 @@
1
+ // @bun
2
+ // ../core/src/errors.ts
3
+ class ElsiumError extends Error {
4
+ code;
5
+ provider;
6
+ model;
7
+ statusCode;
8
+ retryable;
9
+ retryAfterMs;
10
+ cause;
11
+ metadata;
12
+ constructor(details) {
13
+ super(details.message);
14
+ this.name = "ElsiumError";
15
+ this.code = details.code;
16
+ this.provider = details.provider;
17
+ this.model = details.model;
18
+ this.statusCode = details.statusCode;
19
+ this.retryable = details.retryable;
20
+ this.retryAfterMs = details.retryAfterMs;
21
+ this.cause = details.cause;
22
+ this.metadata = details.metadata;
23
+ }
24
+ toJSON() {
25
+ return {
26
+ name: this.name,
27
+ code: this.code,
28
+ message: this.message,
29
+ provider: this.provider,
30
+ model: this.model,
31
+ statusCode: this.statusCode,
32
+ retryable: this.retryable,
33
+ retryAfterMs: this.retryAfterMs,
34
+ metadata: this.metadata
35
+ };
36
+ }
37
+ static providerError(message, opts) {
38
+ return new ElsiumError({
39
+ code: "PROVIDER_ERROR",
40
+ message,
41
+ provider: opts.provider,
42
+ statusCode: opts.statusCode,
43
+ retryable: opts.retryable ?? false,
44
+ cause: opts.cause
45
+ });
46
+ }
47
+ static rateLimit(provider, retryAfterMs) {
48
+ return new ElsiumError({
49
+ code: "RATE_LIMIT",
50
+ message: `Rate limited by ${provider}`,
51
+ provider,
52
+ statusCode: 429,
53
+ retryable: true,
54
+ retryAfterMs
55
+ });
56
+ }
57
+ static authError(provider) {
58
+ return new ElsiumError({
59
+ code: "AUTH_ERROR",
60
+ message: `Authentication failed for ${provider}. Check your API key.`,
61
+ provider,
62
+ statusCode: 401,
63
+ retryable: false
64
+ });
65
+ }
66
+ static timeout(provider, timeoutMs) {
67
+ return new ElsiumError({
68
+ code: "TIMEOUT",
69
+ message: `Request to ${provider} timed out after ${timeoutMs}ms`,
70
+ provider,
71
+ retryable: true
72
+ });
73
+ }
74
+ static validation(message, metadata) {
75
+ return new ElsiumError({
76
+ code: "VALIDATION_ERROR",
77
+ message,
78
+ retryable: false,
79
+ metadata
80
+ });
81
+ }
82
+ static budgetExceeded(spent, budget) {
83
+ return new ElsiumError({
84
+ code: "BUDGET_EXCEEDED",
85
+ message: `Token budget exceeded: spent ${spent}, budget ${budget}`,
86
+ retryable: false,
87
+ metadata: { spent, budget }
88
+ });
89
+ }
90
+ }
91
+ // ../core/src/utils.ts
92
+ import { randomBytes } from "crypto";
93
+ function cryptoHex(bytes) {
94
+ return randomBytes(bytes).toString("hex");
95
+ }
96
+ function generateId(prefix = "els") {
97
+ const timestamp = Date.now().toString(36);
98
+ const random = cryptoHex(4);
99
+ return `${prefix}_${timestamp}_${random}`;
100
+ }
101
+ function generateTraceId() {
102
+ const timestamp = Date.now().toString(36);
103
+ const random = cryptoHex(6);
104
+ return `trc_${timestamp}_${random}`;
105
+ }
106
+ async function sleep(ms) {
107
+ return new Promise((resolve) => setTimeout(resolve, ms));
108
+ }
109
+ function getRetryDelay(error, attempt, baseDelayMs, maxDelayMs) {
110
+ if (error && typeof error === "object" && "retryAfterMs" in error && typeof error.retryAfterMs === "number") {
111
+ return error.retryAfterMs;
112
+ }
113
+ return Math.min(baseDelayMs * 2 ** attempt, maxDelayMs);
114
+ }
115
+ function retry(fn, options = {}) {
116
+ const {
117
+ maxRetries = 3,
118
+ baseDelayMs = 1000,
119
+ maxDelayMs = 30000,
120
+ shouldRetry = (error) => {
121
+ if (error && typeof error === "object" && "retryable" in error) {
122
+ return error.retryable === true;
123
+ }
124
+ return false;
125
+ }
126
+ } = options;
127
+ return (async () => {
128
+ let lastError;
129
+ for (let attempt = 0;attempt <= maxRetries; attempt++) {
130
+ try {
131
+ return await fn();
132
+ } catch (error) {
133
+ lastError = error;
134
+ if (attempt === maxRetries || !shouldRetry(error)) {
135
+ throw error;
136
+ }
137
+ const delay = getRetryDelay(error, attempt, baseDelayMs, maxDelayMs);
138
+ const jitter = delay * (0.5 + Math.random() * 0.5);
139
+ await sleep(jitter);
140
+ }
141
+ }
142
+ throw lastError;
143
+ })();
144
+ }
145
+
146
+ // ../core/src/stream.ts
147
+ function shouldEmitCheckpoint(lastCheckpointTime, intervalMs, textLength) {
148
+ const elapsed = Date.now() - lastCheckpointTime;
149
+ return elapsed >= intervalMs && textLength > 0;
150
+ }
151
+ function createCheckpoint(textAccumulator, eventIndex, now) {
152
+ return {
153
+ id: generateId("ckpt"),
154
+ timestamp: now,
155
+ text: textAccumulator,
156
+ tokensSoFar: Math.ceil(textAccumulator.length / 1.5),
157
+ eventIndex
158
+ };
159
+ }
160
+ function toError(err) {
161
+ return err instanceof Error ? err : new Error(String(err));
162
+ }
163
+ function* emitErrorEvent(err, textAccumulator, onPartialRecovery) {
164
+ const error = toError(err);
165
+ if (textAccumulator.length > 0) {
166
+ onPartialRecovery?.(textAccumulator, error);
167
+ yield { type: "recovery", partialText: textAccumulator, error };
168
+ } else {
169
+ yield { type: "error", error };
170
+ }
171
+ }
172
+
173
+ class ElsiumStream {
174
+ source;
175
+ iterating = false;
176
+ constructor(source) {
177
+ this.source = source;
178
+ }
179
+ async* [Symbol.asyncIterator]() {
180
+ if (this.iterating) {
181
+ throw new Error("ElsiumStream supports only a single consumer");
182
+ }
183
+ this.iterating = true;
184
+ yield* this.source;
185
+ }
186
+ text() {
187
+ const source = this.source;
188
+ return {
189
+ async* [Symbol.asyncIterator]() {
190
+ for await (const event of source) {
191
+ if (event.type === "text_delta") {
192
+ yield event.text;
193
+ }
194
+ }
195
+ }
196
+ };
197
+ }
198
+ async toText() {
199
+ const parts = [];
200
+ for await (const text of this.text()) {
201
+ parts.push(text);
202
+ }
203
+ return parts.join("");
204
+ }
205
+ async toTextWithTimeout(timeoutMs) {
206
+ const parts = [];
207
+ const deadline = Date.now() + timeoutMs;
208
+ const iterator = this.source[Symbol.asyncIterator]();
209
+ try {
210
+ while (true) {
211
+ const remaining = deadline - Date.now();
212
+ if (remaining <= 0)
213
+ break;
214
+ let timer;
215
+ const timeoutPromise = new Promise((resolve) => {
216
+ timer = setTimeout(() => resolve({ value: undefined, done: true }), remaining);
217
+ });
218
+ const result = await Promise.race([iterator.next(), timeoutPromise]);
219
+ if (timer !== undefined)
220
+ clearTimeout(timer);
221
+ if (result.done)
222
+ break;
223
+ const event = result.value;
224
+ if (event.type === "text_delta") {
225
+ parts.push(event.text);
226
+ }
227
+ }
228
+ } catch (err) {
229
+ if (parts.length === 0)
230
+ throw err;
231
+ } finally {
232
+ await iterator.return?.();
233
+ }
234
+ return parts.join("");
235
+ }
236
+ async toResponse() {
237
+ const parts = [];
238
+ let usage = null;
239
+ let stopReason = null;
240
+ for await (const event of this.source) {
241
+ switch (event.type) {
242
+ case "text_delta":
243
+ parts.push(event.text);
244
+ break;
245
+ case "message_end":
246
+ usage = event.usage;
247
+ stopReason = event.stopReason;
248
+ break;
249
+ }
250
+ }
251
+ return { text: parts.join(""), usage, stopReason };
252
+ }
253
+ pipe(transform) {
254
+ return new ElsiumStream(transform(this.source));
255
+ }
256
+ resilient(options = {}) {
257
+ const { checkpointIntervalMs = 1000, onCheckpoint, onPartialRecovery } = options;
258
+ const source = this.source;
259
+ const resilientSource = {
260
+ async* [Symbol.asyncIterator]() {
261
+ let lastCheckpointTime = Date.now();
262
+ let textAccumulator = "";
263
+ let eventIndex = 0;
264
+ try {
265
+ for await (const event of source) {
266
+ eventIndex++;
267
+ if (event.type === "text_delta") {
268
+ textAccumulator += event.text;
269
+ }
270
+ yield event;
271
+ if (shouldEmitCheckpoint(lastCheckpointTime, checkpointIntervalMs, textAccumulator.length)) {
272
+ const now = Date.now();
273
+ const checkpoint = createCheckpoint(textAccumulator, eventIndex, now);
274
+ onCheckpoint?.(checkpoint);
275
+ yield { type: "checkpoint", checkpoint };
276
+ lastCheckpointTime = now;
277
+ }
278
+ }
279
+ } catch (err) {
280
+ yield* emitErrorEvent(err, textAccumulator, onPartialRecovery);
281
+ }
282
+ }
283
+ };
284
+ return new ElsiumStream(resilientSource);
285
+ }
286
+ }
287
+ var MAX_BUFFER_SIZE = 1e4;
288
+ function createStream(executor) {
289
+ let resolve = null;
290
+ const buffer = [];
291
+ let done = false;
292
+ let error = null;
293
+ let dropped = 0;
294
+ const source = {
295
+ [Symbol.asyncIterator]() {
296
+ return {
297
+ next() {
298
+ if (buffer.length > 0) {
299
+ const value = buffer.shift();
300
+ return Promise.resolve({ value, done: false });
301
+ }
302
+ if (done) {
303
+ return Promise.resolve({ value: undefined, done: true });
304
+ }
305
+ if (error) {
306
+ return Promise.reject(error);
307
+ }
308
+ return new Promise((r) => {
309
+ resolve = r;
310
+ });
311
+ }
312
+ };
313
+ }
314
+ };
315
+ const emit = (event) => {
316
+ if (resolve) {
317
+ const r = resolve;
318
+ resolve = null;
319
+ r({ value: event, done: false });
320
+ } else {
321
+ if (buffer.length < MAX_BUFFER_SIZE) {
322
+ buffer.push(event);
323
+ } else {
324
+ dropped++;
325
+ }
326
+ }
327
+ };
328
+ executor(emit).then(() => {
329
+ if (dropped > 0) {
330
+ emit({
331
+ type: "error",
332
+ error: new Error(`Stream buffer overflow: ${dropped} events dropped`)
333
+ });
334
+ }
335
+ done = true;
336
+ if (resolve) {
337
+ const r = resolve;
338
+ resolve = null;
339
+ r({ value: undefined, done: true });
340
+ }
341
+ }).catch((e) => {
342
+ error = e instanceof Error ? e : new Error(String(e));
343
+ if (resolve) {
344
+ resolve({ value: { type: "error", error }, done: false });
345
+ resolve = null;
346
+ }
347
+ });
348
+ return new ElsiumStream(source);
349
+ }
350
+ // ../core/src/logger.ts
351
+ var LOG_LEVELS = {
352
+ debug: 0,
353
+ info: 1,
354
+ warn: 2,
355
+ error: 3
356
+ };
357
+ function createLogger(options = {}) {
358
+ const { level = "info", pretty = false, context = {} } = options;
359
+ const minLevel = LOG_LEVELS[level];
360
+ function log(logLevel, message, data) {
361
+ if (LOG_LEVELS[logLevel] < minLevel)
362
+ return;
363
+ const entry = {
364
+ ...context,
365
+ level: logLevel,
366
+ message,
367
+ timestamp: new Date().toISOString(),
368
+ ...data ? { data } : {}
369
+ };
370
+ const output = pretty ? JSON.stringify(entry, null, 2) : JSON.stringify(entry);
371
+ if (logLevel === "error") {
372
+ console.error(output);
373
+ } else if (logLevel === "warn") {
374
+ console.warn(output);
375
+ } else {
376
+ console.log(output);
377
+ }
378
+ }
379
+ return {
380
+ debug: (msg, data) => log("debug", msg, data),
381
+ info: (msg, data) => log("info", msg, data),
382
+ warn: (msg, data) => log("warn", msg, data),
383
+ error: (msg, data) => log("error", msg, data),
384
+ child(childContext) {
385
+ return createLogger({
386
+ level,
387
+ pretty,
388
+ context: { ...context, ...childContext }
389
+ });
390
+ }
391
+ };
392
+ }
393
+ // ../gateway/src/provider.ts
394
+ var providerRegistry = new Map;
395
+ var metadataRegistry = new Map;
396
+ function registerProviderMetadata(name, metadata) {
397
+ metadataRegistry.set(name, metadata);
398
+ }
399
+ function getProviderMetadata(name) {
400
+ return metadataRegistry.get(name);
401
+ }
402
+
403
+ // ../gateway/src/middleware.ts
404
+ function composeMiddleware(middlewares) {
405
+ return (ctx, finalNext) => {
406
+ let index = -1;
407
+ function dispatch(i) {
408
+ if (i <= index) {
409
+ return Promise.reject(new Error("Middleware next() called multiple times"));
410
+ }
411
+ index = i;
412
+ const fn = i < middlewares.length ? middlewares[i] : finalNext;
413
+ if (i === middlewares.length) {
414
+ return finalNext(ctx);
415
+ }
416
+ return fn(ctx, () => dispatch(i + 1));
417
+ }
418
+ return dispatch(0);
419
+ };
420
+ }
421
+ var SENSITIVE_HEADERS = ["x-api-key", "authorization", "api-key"];
422
+ function redactHeaders(headers) {
423
+ const redacted = {};
424
+ for (const [key, value] of Object.entries(headers)) {
425
+ if (SENSITIVE_HEADERS.includes(key.toLowerCase())) {
426
+ redacted[key] = "[REDACTED]";
427
+ } else {
428
+ redacted[key] = value;
429
+ }
430
+ }
431
+ return redacted;
432
+ }
433
+ var PROVIDER_URLS = {
434
+ anthropic: "https://api.anthropic.com/v1/messages",
435
+ openai: "https://api.openai.com/v1/chat/completions",
436
+ google: "https://generativelanguage.googleapis.com/v1beta/models"
437
+ };
438
+ function buildProviderHeaders(provider, metadata) {
439
+ const headers = { "Content-Type": "application/json" };
440
+ const apiKey = metadata._apiKey ?? "***";
441
+ const providerMeta = getProviderMetadata(provider);
442
+ const authStyle = providerMeta?.authStyle;
443
+ if (authStyle === "x-api-key" || provider === "anthropic") {
444
+ headers["x-api-key"] = apiKey;
445
+ } else {
446
+ headers.Authorization = apiKey;
447
+ }
448
+ return redactHeaders(headers);
449
+ }
450
+ function truncateContent(content) {
451
+ if (typeof content !== "string")
452
+ return "[complex content]";
453
+ if (content.length > 200)
454
+ return `${content.slice(0, 200)}...`;
455
+ return content;
456
+ }
457
+ function buildXRayRequest(ctx) {
458
+ const providerMeta = getProviderMetadata(ctx.provider);
459
+ return {
460
+ url: PROVIDER_URLS[ctx.provider] ?? providerMeta?.baseUrl ?? `https://${ctx.provider}.api/v1/messages`,
461
+ method: "POST",
462
+ headers: buildProviderHeaders(ctx.provider, ctx.metadata),
463
+ body: {
464
+ model: ctx.model,
465
+ messages: ctx.request.messages.map((m) => ({
466
+ role: m.role,
467
+ content: truncateContent(m.content)
468
+ })),
469
+ max_tokens: ctx.request.maxTokens,
470
+ ...ctx.request.temperature !== undefined ? { temperature: ctx.request.temperature } : {},
471
+ ...ctx.request.tools?.length ? { tools: ctx.request.tools.map((t) => t.name) } : {}
472
+ }
473
+ };
474
+ }
475
+ function buildXRayResponse(response) {
476
+ return {
477
+ status: 200,
478
+ headers: { "content-type": "application/json" },
479
+ body: {
480
+ id: response.id,
481
+ model: response.model,
482
+ stop_reason: response.stopReason,
483
+ content_preview: truncateContent(response.message.content)
484
+ }
485
+ };
486
+ }
487
+ function buildXRayData(ctx, response, latencyMs) {
488
+ return {
489
+ traceId: ctx.traceId,
490
+ timestamp: Date.now(),
491
+ provider: ctx.provider,
492
+ model: ctx.model,
493
+ latencyMs,
494
+ request: buildXRayRequest(ctx),
495
+ response: buildXRayResponse(response),
496
+ usage: response.usage,
497
+ cost: response.cost
498
+ };
499
+ }
500
+ function xrayMiddleware(options = {}) {
501
+ const maxHistory = options.maxHistory ?? 100;
502
+ const history = [];
503
+ const middleware = async (ctx, next) => {
504
+ const startTime = performance.now();
505
+ const response = await next(ctx);
506
+ const latencyMs = Math.round(performance.now() - startTime);
507
+ const xrayData = buildXRayData(ctx, response, latencyMs);
508
+ history.unshift(xrayData);
509
+ if (history.length > maxHistory) {
510
+ history.length = maxHistory;
511
+ }
512
+ return response;
513
+ };
514
+ middleware.lastCall = () => history[0] ?? null;
515
+ middleware.callHistory = (limit = 10) => history.slice(0, limit);
516
+ middleware.getByTraceId = (traceId) => history.find((d) => d.traceId === traceId);
517
+ middleware.clear = () => {
518
+ history.length = 0;
519
+ };
520
+ return middleware;
521
+ }
522
+
523
+ // ../gateway/src/pricing.ts
524
+ var log = createLogger();
525
+ var PRICING = {
526
+ "claude-opus-4-6": { inputPerMillion: 15, outputPerMillion: 75 },
527
+ "claude-sonnet-4-6": { inputPerMillion: 3, outputPerMillion: 15 },
528
+ "claude-haiku-4-5-20251001": { inputPerMillion: 1, outputPerMillion: 5 },
529
+ "gpt-4o": { inputPerMillion: 2.5, outputPerMillion: 10 },
530
+ "gpt-4o-mini": { inputPerMillion: 0.15, outputPerMillion: 0.6 },
531
+ "gpt-4.1": { inputPerMillion: 2, outputPerMillion: 8 },
532
+ "gpt-4.1-mini": { inputPerMillion: 0.4, outputPerMillion: 1.6 },
533
+ "gpt-4.1-nano": { inputPerMillion: 0.1, outputPerMillion: 0.4 },
534
+ "gpt-5": { inputPerMillion: 1.25, outputPerMillion: 10 },
535
+ "gpt-5-mini": { inputPerMillion: 0.25, outputPerMillion: 2 },
536
+ "gpt-5-nano": { inputPerMillion: 0.05, outputPerMillion: 0.4 },
537
+ o1: { inputPerMillion: 15, outputPerMillion: 60 },
538
+ "o1-mini": { inputPerMillion: 1.1, outputPerMillion: 4.4 },
539
+ o3: { inputPerMillion: 2, outputPerMillion: 8 },
540
+ "o3-mini": { inputPerMillion: 1.1, outputPerMillion: 4.4 },
541
+ "o3-pro": { inputPerMillion: 20, outputPerMillion: 80 },
542
+ "o4-mini": { inputPerMillion: 1.1, outputPerMillion: 4.4 },
543
+ "gemini-2.0-flash": { inputPerMillion: 0.1, outputPerMillion: 0.4 },
544
+ "gemini-2.0-flash-lite": { inputPerMillion: 0.075, outputPerMillion: 0.3 },
545
+ "gemini-2.5-pro": { inputPerMillion: 1.25, outputPerMillion: 10 },
546
+ "gemini-2.5-pro-preview-05-06": { inputPerMillion: 1.25, outputPerMillion: 10 },
547
+ "gemini-2.5-flash": { inputPerMillion: 0.15, outputPerMillion: 0.6 },
548
+ "gemini-2.5-flash-preview-04-17": { inputPerMillion: 0.15, outputPerMillion: 0.6 },
549
+ "gemini-2.5-flash-lite": { inputPerMillion: 0.075, outputPerMillion: 0.3 }
550
+ };
551
+ function resolveModelName(model) {
552
+ if (PRICING[model])
553
+ return model;
554
+ const base = model.replace(/-\d{4}-\d{2}-\d{2}$/, "");
555
+ if (base !== model && PRICING[base])
556
+ return base;
557
+ return model;
558
+ }
559
+ function calculateCost(model, usage) {
560
+ const pricing = PRICING[resolveModelName(model)];
561
+ if (!pricing) {
562
+ log.warn(`Unknown model "${model}" \u2014 cost will be reported as $0. Register pricing with registerPricing().`);
563
+ return {
564
+ inputCost: 0,
565
+ outputCost: 0,
566
+ totalCost: 0,
567
+ currency: "USD"
568
+ };
569
+ }
570
+ const inputCost = usage.inputTokens / 1e6 * pricing.inputPerMillion;
571
+ const outputCost = usage.outputTokens / 1e6 * pricing.outputPerMillion;
572
+ return {
573
+ inputCost: Math.round(inputCost * 1e6) / 1e6,
574
+ outputCost: Math.round(outputCost * 1e6) / 1e6,
575
+ totalCost: Math.round((inputCost + outputCost) * 1e6) / 1e6,
576
+ currency: "USD"
577
+ };
578
+ }
579
+ function registerPricing(model, pricing) {
580
+ PRICING[model] = pricing;
581
+ }
582
+
583
+ // ../gateway/src/providers/anthropic.ts
584
+ var DEFAULT_BASE_URL = "https://api.anthropic.com";
585
+ var API_VERSION = "2023-06-01";
586
+ var DEFAULT_MAX_TOKENS = 4096;
587
+ function createAnthropicProvider(config) {
588
+ const { apiKey, baseUrl = DEFAULT_BASE_URL, timeout = 60000, maxRetries = 2 } = config;
589
+ async function request(path, body, signal) {
590
+ const url = `${baseUrl}/v1${path}`;
591
+ const response = await fetch(url, {
592
+ method: "POST",
593
+ headers: {
594
+ "Content-Type": "application/json",
595
+ "x-api-key": apiKey,
596
+ "anthropic-version": API_VERSION
597
+ },
598
+ body: JSON.stringify(body),
599
+ signal
600
+ });
601
+ if (!response.ok) {
602
+ const errorBody = await response.text().catch(() => "Unknown error");
603
+ if (response.status === 401)
604
+ throw ElsiumError.authError("anthropic");
605
+ if (response.status === 429) {
606
+ const retryAfter = response.headers.get("retry-after");
607
+ throw ElsiumError.rateLimit("anthropic", retryAfter ? Number.parseInt(retryAfter) * 1000 : undefined);
608
+ }
609
+ throw ElsiumError.providerError(`Anthropic API error ${response.status}: ${errorBody}`, {
610
+ provider: "anthropic",
611
+ statusCode: response.status,
612
+ retryable: response.status >= 500
613
+ });
614
+ }
615
+ return response;
616
+ }
617
+ function extractSystemText(msg) {
618
+ if (typeof msg.content === "string")
619
+ return msg.content;
620
+ return msg.content.filter((p) => p.type === "text").map((p) => p.text).join(`
621
+ `);
622
+ }
623
+ function formatToolResultMessage(msg) {
624
+ const blocks = (msg.toolResults ?? []).map((tr) => ({
625
+ type: "tool_result",
626
+ tool_use_id: tr.toolCallId,
627
+ content: tr.content
628
+ }));
629
+ return { role: "user", content: blocks };
630
+ }
631
+ function formatStringContent(msg, role) {
632
+ const blocks = [];
633
+ const text = msg.content;
634
+ if (text) {
635
+ blocks.push({ type: "text", text });
636
+ }
637
+ if (msg.toolCalls?.length) {
638
+ for (const tc of msg.toolCalls) {
639
+ blocks.push({
640
+ type: "tool_use",
641
+ id: tc.id,
642
+ name: tc.name,
643
+ input: tc.arguments
644
+ });
645
+ }
646
+ }
647
+ if (blocks.length === 0) {
648
+ return { role, content: text };
649
+ }
650
+ return { role, content: blocks };
651
+ }
652
+ function convertContentPart(part) {
653
+ if (part.type === "text")
654
+ return { type: "text", text: part.text };
655
+ if (part.type === "image" && part.source?.type === "base64") {
656
+ return {
657
+ type: "image",
658
+ source: {
659
+ type: "base64",
660
+ media_type: part.source.mediaType,
661
+ data: part.source.data
662
+ }
663
+ };
664
+ }
665
+ return { type: "text", text: "[unsupported content]" };
666
+ }
667
+ function formatMultipartContent(msg, role) {
668
+ const content = msg.content;
669
+ const blocks = content.map(convertContentPart);
670
+ return { role, content: blocks };
671
+ }
672
+ function formatMessages(messages) {
673
+ let system;
674
+ const formatted = [];
675
+ for (const msg of messages) {
676
+ if (msg.role === "system") {
677
+ system = extractSystemText(msg);
678
+ continue;
679
+ }
680
+ if (msg.role === "tool") {
681
+ formatted.push(formatToolResultMessage(msg));
682
+ continue;
683
+ }
684
+ const role = msg.role === "assistant" ? "assistant" : "user";
685
+ if (typeof msg.content === "string") {
686
+ formatted.push(formatStringContent(msg, role));
687
+ } else {
688
+ formatted.push(formatMultipartContent(msg, role));
689
+ }
690
+ }
691
+ return { system, messages: formatted };
692
+ }
693
+ function buildSeedMetadata(req) {
694
+ if (req.seed === undefined)
695
+ return {};
696
+ return { metadata: { ...req.metadata ?? {}, seed: req.seed } };
697
+ }
698
+ function formatTools(tools) {
699
+ if (!tools?.length)
700
+ return;
701
+ return tools.map((t) => ({
702
+ name: t.name,
703
+ description: t.description,
704
+ input_schema: t.inputSchema
705
+ }));
706
+ }
707
+ function extractContentBlocks(content) {
708
+ const toolCalls = [];
709
+ const textParts = [];
710
+ for (const block of content) {
711
+ if (block.type === "text" && block.text) {
712
+ textParts.push(block.text);
713
+ } else if (block.type === "tool_use" && block.id && block.name) {
714
+ toolCalls.push({
715
+ id: block.id,
716
+ name: block.name,
717
+ arguments: block.input ?? {}
718
+ });
719
+ }
720
+ }
721
+ return { textParts, toolCalls };
722
+ }
723
+ function parseResponse(raw, latencyMs) {
724
+ const traceId = generateTraceId();
725
+ const { textParts, toolCalls } = extractContentBlocks(raw.content);
726
+ const usage = {
727
+ inputTokens: raw.usage.input_tokens,
728
+ outputTokens: raw.usage.output_tokens,
729
+ totalTokens: raw.usage.input_tokens + raw.usage.output_tokens,
730
+ cacheReadTokens: raw.usage.cache_read_input_tokens,
731
+ cacheWriteTokens: raw.usage.cache_creation_input_tokens
732
+ };
733
+ return {
734
+ id: raw.id,
735
+ message: {
736
+ role: "assistant",
737
+ content: textParts.join(""),
738
+ toolCalls: toolCalls.length > 0 ? toolCalls : undefined
739
+ },
740
+ usage,
741
+ cost: calculateCost(raw.model, usage),
742
+ model: raw.model,
743
+ provider: "anthropic",
744
+ stopReason: mapAnthropicStopReason(raw.stop_reason),
745
+ latencyMs,
746
+ traceId
747
+ };
748
+ }
749
+ return {
750
+ name: "anthropic",
751
+ defaultModel: "claude-sonnet-4-6",
752
+ metadata: {
753
+ baseUrl: "https://api.anthropic.com/v1/messages",
754
+ capabilities: ["tools", "vision", "streaming", "system"],
755
+ authStyle: "x-api-key"
756
+ },
757
+ async complete(req) {
758
+ const { system, messages } = formatMessages(req.messages);
759
+ const model = req.model ?? "claude-sonnet-4-6";
760
+ const body = {
761
+ model,
762
+ messages,
763
+ max_tokens: req.maxTokens ?? DEFAULT_MAX_TOKENS,
764
+ ...system || req.system ? { system: req.system ?? system } : {},
765
+ ...req.temperature !== undefined ? { temperature: req.temperature } : {},
766
+ ...req.topP !== undefined ? { top_p: req.topP } : {},
767
+ ...req.stopSequences?.length ? { stop_sequences: req.stopSequences } : {},
768
+ ...buildSeedMetadata(req)
769
+ };
770
+ const tools = formatTools(req.tools);
771
+ if (tools)
772
+ body.tools = tools;
773
+ const startTime = performance.now();
774
+ const raw = await retry(async () => {
775
+ const controller = new AbortController;
776
+ const timer = setTimeout(() => controller.abort(), timeout);
777
+ try {
778
+ const signals = [controller.signal, req.signal].filter(Boolean);
779
+ const mergedSignal = signals.length > 1 ? AbortSignal.any(signals) : signals[0];
780
+ const resp = await request("/messages", body, mergedSignal);
781
+ return await resp.json();
782
+ } finally {
783
+ clearTimeout(timer);
784
+ }
785
+ }, {
786
+ maxRetries,
787
+ baseDelayMs: 1000,
788
+ shouldRetry: (e) => e instanceof ElsiumError && e.retryable
789
+ });
790
+ const latencyMs = Math.round(performance.now() - startTime);
791
+ return parseResponse(raw, latencyMs);
792
+ },
793
+ stream(req) {
794
+ const { system, messages } = formatMessages(req.messages);
795
+ const model = req.model ?? "claude-sonnet-4-6";
796
+ const body = {
797
+ model,
798
+ messages,
799
+ max_tokens: req.maxTokens ?? DEFAULT_MAX_TOKENS,
800
+ stream: true,
801
+ ...system || req.system ? { system: req.system ?? system } : {},
802
+ ...req.temperature !== undefined ? { temperature: req.temperature } : {},
803
+ ...req.topP !== undefined ? { top_p: req.topP } : {},
804
+ ...req.stopSequences?.length ? { stop_sequences: req.stopSequences } : {},
805
+ ...buildSeedMetadata(req)
806
+ };
807
+ const tools = formatTools(req.tools);
808
+ if (tools)
809
+ body.tools = tools;
810
+ return createStream(async (emit) => {
811
+ const controller = new AbortController;
812
+ const timer = setTimeout(() => controller.abort(), timeout);
813
+ try {
814
+ const signals = [controller.signal, req.signal].filter(Boolean);
815
+ const mergedSignal = signals.length > 1 ? AbortSignal.any(signals) : signals[0];
816
+ const resp = await request("/messages", body, mergedSignal);
817
+ if (!resp.body)
818
+ throw new ElsiumError({
819
+ code: "STREAM_ERROR",
820
+ message: "Response body is null",
821
+ provider: "anthropic",
822
+ retryable: false
823
+ });
824
+ await processAnthropicSSEStream(resp.body, model, emit);
825
+ } finally {
826
+ clearTimeout(timer);
827
+ }
828
+ });
829
+ },
830
+ async listModels() {
831
+ return ["claude-opus-4-6", "claude-sonnet-4-6", "claude-haiku-4-5-20251001"];
832
+ }
833
+ };
834
+ }
835
+ function mapAnthropicStopReason(reason) {
836
+ if (reason === "end_turn")
837
+ return "end_turn";
838
+ if (reason === "max_tokens")
839
+ return "max_tokens";
840
+ if (reason === "tool_use")
841
+ return "tool_use";
842
+ return "end_turn";
843
+ }
844
+ function processSSELine(line, model, emit) {
845
+ if (!line.startsWith("data: "))
846
+ return;
847
+ const data = line.slice(6).trim();
848
+ if (data === "[DONE]")
849
+ return;
850
+ try {
851
+ const event = JSON.parse(data);
852
+ const mapped = mapSSEEvent(event, model);
853
+ if (mapped)
854
+ emit(mapped);
855
+ } catch (err2) {
856
+ emit({ type: "error", error: err2 instanceof Error ? err2 : new Error(String(err2)) });
857
+ }
858
+ }
859
+ async function processAnthropicSSEStream(body, model, emit) {
860
+ const reader = body.getReader();
861
+ const decoder = new TextDecoder;
862
+ let buffer = "";
863
+ while (true) {
864
+ const { done, value } = await reader.read();
865
+ if (done)
866
+ break;
867
+ buffer += decoder.decode(value, { stream: true });
868
+ const lines = buffer.split(`
869
+ `);
870
+ buffer = lines.pop() ?? "";
871
+ for (const line of lines) {
872
+ processSSELine(line, model, emit);
873
+ }
874
+ }
875
+ }
876
+ function mapSSEEventMessageStart(event, model) {
877
+ const msg = event.message;
878
+ return {
879
+ type: "message_start",
880
+ id: msg?.id ?? generateId("msg"),
881
+ model
882
+ };
883
+ }
884
+ function mapSSEEventContentBlockStart(event) {
885
+ const block = event.content_block;
886
+ if (block?.type === "tool_use") {
887
+ return {
888
+ type: "tool_call_start",
889
+ toolCall: { id: block.id ?? "", name: block.name ?? "" }
890
+ };
891
+ }
892
+ return null;
893
+ }
894
+ function mapSSEEventContentBlockDelta(event) {
895
+ const delta = event.delta;
896
+ if (delta?.type === "text_delta" && delta.text) {
897
+ return { type: "text_delta", text: delta.text };
898
+ }
899
+ if (delta?.type === "input_json_delta" && delta.partial_json) {
900
+ return {
901
+ type: "tool_call_delta",
902
+ toolCallId: "",
903
+ arguments: delta.partial_json
904
+ };
905
+ }
906
+ return null;
907
+ }
908
+ function mapSSEEventMessageDelta(event) {
909
+ const delta = event.delta;
910
+ const usage = event.usage;
911
+ if (!delta?.stop_reason)
912
+ return null;
913
+ const inputTokens = usage?.input_tokens ?? 0;
914
+ const outputTokens = usage?.output_tokens ?? 0;
915
+ return {
916
+ type: "message_end",
917
+ usage: {
918
+ inputTokens,
919
+ outputTokens,
920
+ totalTokens: inputTokens + outputTokens
921
+ },
922
+ stopReason: mapAnthropicStopReason(delta.stop_reason)
923
+ };
924
+ }
925
+ function mapSSEEvent(event, model) {
926
+ switch (event.type) {
927
+ case "message_start":
928
+ return mapSSEEventMessageStart(event, model);
929
+ case "content_block_start":
930
+ return mapSSEEventContentBlockStart(event);
931
+ case "content_block_delta":
932
+ return mapSSEEventContentBlockDelta(event);
933
+ case "content_block_stop":
934
+ return null;
935
+ case "message_delta":
936
+ return mapSSEEventMessageDelta(event);
937
+ default:
938
+ return null;
939
+ }
940
+ }
941
+
942
+ // ../gateway/src/providers/google.ts
943
+ var DEFAULT_BASE_URL2 = "https://generativelanguage.googleapis.com";
944
+ function createGoogleProvider(config) {
945
+ const { apiKey, baseUrl = DEFAULT_BASE_URL2, timeout = 60000, maxRetries = 2 } = config;
946
+ function extractGeminiSystemText(msg) {
947
+ if (typeof msg.content === "string")
948
+ return msg.content;
949
+ return msg.content.filter((p) => p.type === "text").map((p) => p.text).join(`
950
+ `);
951
+ }
952
+ function formatToolResultContents(msg) {
953
+ const results = [];
954
+ for (const tr of msg.toolResults ?? []) {
955
+ const name = tr.toolName ?? tr.toolCallId;
956
+ results.push({
957
+ role: "user",
958
+ parts: [
959
+ {
960
+ functionResponse: {
961
+ name,
962
+ response: { content: tr.content }
963
+ }
964
+ }
965
+ ]
966
+ });
967
+ }
968
+ return results;
969
+ }
970
+ function formatGeminiStringContent(msg, role) {
971
+ const parts = [{ text: msg.content }];
972
+ if (msg.toolCalls?.length) {
973
+ for (const tc of msg.toolCalls) {
974
+ parts.push({
975
+ functionCall: { name: tc.name, args: tc.arguments }
976
+ });
977
+ }
978
+ }
979
+ return { role, parts };
980
+ }
981
+ function formatGeminiMultipartContent(msg, role) {
982
+ const parts = msg.content.filter((p) => p.type === "text").map((p) => ({ text: p.text }));
983
+ return { role, parts };
984
+ }
985
+ function formatMessages(messages) {
986
+ let systemInstruction;
987
+ const contents = [];
988
+ for (const msg of messages) {
989
+ if (msg.role === "system") {
990
+ systemInstruction = { parts: [{ text: extractGeminiSystemText(msg) }] };
991
+ continue;
992
+ }
993
+ if (msg.role === "tool") {
994
+ contents.push(...formatToolResultContents(msg));
995
+ continue;
996
+ }
997
+ const role = msg.role === "assistant" ? "model" : "user";
998
+ if (typeof msg.content === "string") {
999
+ contents.push(formatGeminiStringContent(msg, role));
1000
+ } else {
1001
+ contents.push(formatGeminiMultipartContent(msg, role));
1002
+ }
1003
+ }
1004
+ return { systemInstruction, contents };
1005
+ }
1006
+ function formatTools(tools) {
1007
+ if (!tools?.length)
1008
+ return;
1009
+ return [
1010
+ {
1011
+ functionDeclarations: tools.map((t) => ({
1012
+ name: t.name,
1013
+ description: t.description,
1014
+ parameters: t.inputSchema
1015
+ }))
1016
+ }
1017
+ ];
1018
+ }
1019
+ function extractGeminiParts(parts) {
1020
+ const toolCalls = [];
1021
+ const textParts = [];
1022
+ for (const part of parts) {
1023
+ if (part.text) {
1024
+ textParts.push(part.text);
1025
+ }
1026
+ if (part.functionCall) {
1027
+ toolCalls.push({
1028
+ id: generateId("tc"),
1029
+ name: part.functionCall.name,
1030
+ arguments: part.functionCall.args ?? {}
1031
+ });
1032
+ }
1033
+ }
1034
+ return { textParts, toolCalls };
1035
+ }
1036
+ function parseResponse(raw, model, latencyMs) {
1037
+ const traceId = generateTraceId();
1038
+ const candidate = raw.candidates?.[0];
1039
+ const parts = candidate?.content?.parts ?? [];
1040
+ const { textParts, toolCalls } = extractGeminiParts(parts);
1041
+ const usage = {
1042
+ inputTokens: raw.usageMetadata?.promptTokenCount ?? 0,
1043
+ outputTokens: raw.usageMetadata?.candidatesTokenCount ?? 0,
1044
+ totalTokens: raw.usageMetadata?.totalTokenCount ?? 0
1045
+ };
1046
+ return {
1047
+ id: generateId("msg"),
1048
+ message: {
1049
+ role: "assistant",
1050
+ content: textParts.join(""),
1051
+ toolCalls: toolCalls.length > 0 ? toolCalls : undefined
1052
+ },
1053
+ usage,
1054
+ cost: calculateCost(model, usage),
1055
+ model,
1056
+ provider: "google",
1057
+ stopReason: mapGeminiStopReason(candidate?.finishReason, toolCalls.length > 0),
1058
+ latencyMs,
1059
+ traceId
1060
+ };
1061
+ }
1062
+ function resolveSystemInstruction(reqSystem, parsed) {
1063
+ if (reqSystem)
1064
+ return { parts: [{ text: reqSystem }] };
1065
+ return parsed;
1066
+ }
1067
+ function buildGenerationConfig(req) {
1068
+ const config2 = {
1069
+ maxOutputTokens: req.maxTokens ?? 4096
1070
+ };
1071
+ if (req.temperature !== undefined)
1072
+ config2.temperature = req.temperature;
1073
+ if (req.seed !== undefined)
1074
+ config2.seed = req.seed;
1075
+ if (req.topP !== undefined)
1076
+ config2.topP = req.topP;
1077
+ if (req.stopSequences?.length)
1078
+ config2.stopSequences = req.stopSequences;
1079
+ return config2;
1080
+ }
1081
+ function buildRequestBody(req) {
1082
+ const { systemInstruction, contents } = formatMessages(req.messages);
1083
+ const resolved = resolveSystemInstruction(req.system, systemInstruction);
1084
+ const body = {
1085
+ contents,
1086
+ generationConfig: buildGenerationConfig(req)
1087
+ };
1088
+ if (resolved)
1089
+ body.systemInstruction = resolved;
1090
+ const tools = formatTools(req.tools);
1091
+ if (tools)
1092
+ body.tools = tools;
1093
+ return body;
1094
+ }
1095
+ return {
1096
+ name: "google",
1097
+ defaultModel: "gemini-2.0-flash",
1098
+ metadata: {
1099
+ baseUrl: "https://generativelanguage.googleapis.com/v1beta/models",
1100
+ capabilities: ["tools", "vision", "streaming", "system"],
1101
+ authStyle: "bearer"
1102
+ },
1103
+ async complete(req) {
1104
+ const model = req.model ?? "gemini-2.0-flash";
1105
+ const body = buildRequestBody(req);
1106
+ const startTime = performance.now();
1107
+ const raw = await retry(() => googleRequest(baseUrl, model, apiKey, body, timeout, req.signal), {
1108
+ maxRetries,
1109
+ baseDelayMs: 1000,
1110
+ shouldRetry: (e) => e instanceof ElsiumError && e.retryable
1111
+ });
1112
+ const latencyMs = Math.round(performance.now() - startTime);
1113
+ return parseResponse(raw, model, latencyMs);
1114
+ },
1115
+ stream(req) {
1116
+ const model = req.model ?? "gemini-2.0-flash";
1117
+ const body = buildRequestBody(req);
1118
+ return createStream(async (emit) => {
1119
+ const controller = new AbortController;
1120
+ const timer = setTimeout(() => controller.abort(), timeout);
1121
+ try {
1122
+ const signals = [controller.signal, req.signal].filter(Boolean);
1123
+ const mergedSignal = signals.length > 1 ? AbortSignal.any(signals) : signals[0];
1124
+ const response = await fetchGoogleStream(baseUrl, model, apiKey, body, mergedSignal);
1125
+ emit({ type: "message_start", id: generateId("msg"), model });
1126
+ await processGeminiSSEStream(response.body, emit);
1127
+ } finally {
1128
+ clearTimeout(timer);
1129
+ }
1130
+ });
1131
+ },
1132
+ async listModels() {
1133
+ return [
1134
+ "gemini-2.0-flash",
1135
+ "gemini-2.0-flash-lite",
1136
+ "gemini-2.5-pro-preview-05-06",
1137
+ "gemini-2.5-flash-preview-04-17"
1138
+ ];
1139
+ }
1140
+ };
1141
+ }
1142
+ function mapGeminiStopReason(finishReason, hasToolCalls = false) {
1143
+ if (finishReason === "STOP")
1144
+ return "end_turn";
1145
+ if (finishReason === "MAX_TOKENS")
1146
+ return "max_tokens";
1147
+ if (finishReason === "TOOL_CALLS" || hasToolCalls)
1148
+ return "tool_use";
1149
+ return "end_turn";
1150
+ }
1151
+ async function handleGoogleErrorResponse(response) {
1152
+ const errorBody = await response.text().catch(() => "Unknown error");
1153
+ if (response.status === 401 || response.status === 403) {
1154
+ throw ElsiumError.authError("google");
1155
+ }
1156
+ if (response.status === 429) {
1157
+ throw ElsiumError.rateLimit("google");
1158
+ }
1159
+ throw ElsiumError.providerError(`Google API error ${response.status}: ${errorBody}`, {
1160
+ provider: "google",
1161
+ statusCode: response.status,
1162
+ retryable: response.status >= 500
1163
+ });
1164
+ }
1165
+ async function googleRequest(baseUrl, model, apiKey, body, timeout, reqSignal) {
1166
+ const controller = new AbortController;
1167
+ const timer = setTimeout(() => controller.abort(), timeout);
1168
+ try {
1169
+ const signals = [controller.signal, reqSignal].filter(Boolean);
1170
+ const mergedSignal = signals.length > 1 ? AbortSignal.any(signals) : signals[0];
1171
+ const url = `${baseUrl}/v1beta/models/${model}:generateContent`;
1172
+ const response = await fetch(url, {
1173
+ method: "POST",
1174
+ headers: { "Content-Type": "application/json", "x-goog-api-key": apiKey },
1175
+ body: JSON.stringify(body),
1176
+ signal: mergedSignal
1177
+ });
1178
+ if (!response.ok) {
1179
+ await handleGoogleErrorResponse(response);
1180
+ }
1181
+ return await response.json();
1182
+ } finally {
1183
+ clearTimeout(timer);
1184
+ }
1185
+ }
1186
+ async function fetchGoogleStream(baseUrl, model, apiKey, body, signal) {
1187
+ const url = `${baseUrl}/v1beta/models/${model}:streamGenerateContent?alt=sse`;
1188
+ const response = await fetch(url, {
1189
+ method: "POST",
1190
+ headers: { "Content-Type": "application/json", "x-goog-api-key": apiKey },
1191
+ body: JSON.stringify(body),
1192
+ signal
1193
+ });
1194
+ if (!response.ok) {
1195
+ const errorBody = await response.text().catch(() => "Unknown error");
1196
+ throw ElsiumError.providerError(`Google API error ${response.status}: ${errorBody}`, {
1197
+ provider: "google",
1198
+ retryable: response.status >= 500
1199
+ });
1200
+ }
1201
+ if (!response.body) {
1202
+ throw new ElsiumError({
1203
+ code: "STREAM_ERROR",
1204
+ message: "Response body is null",
1205
+ provider: "google",
1206
+ retryable: false
1207
+ });
1208
+ }
1209
+ return response;
1210
+ }
1211
+ function emitGeminiPartEvents(part, emit) {
1212
+ if (part.text) {
1213
+ emit({ type: "text_delta", text: part.text });
1214
+ }
1215
+ if (part.functionCall) {
1216
+ const toolCallId = generateId("tc");
1217
+ emit({
1218
+ type: "tool_call_start",
1219
+ toolCall: { id: toolCallId, name: part.functionCall.name }
1220
+ });
1221
+ emit({
1222
+ type: "tool_call_delta",
1223
+ toolCallId,
1224
+ arguments: JSON.stringify(part.functionCall.args)
1225
+ });
1226
+ emit({ type: "tool_call_end", toolCallId });
1227
+ }
1228
+ }
1229
+ function emitGeminiFinishEvent(event, emit) {
1230
+ const finishReason = event.candidates?.[0]?.finishReason;
1231
+ if (!finishReason)
1232
+ return;
1233
+ const usage = {
1234
+ inputTokens: event.usageMetadata?.promptTokenCount ?? 0,
1235
+ outputTokens: event.usageMetadata?.candidatesTokenCount ?? 0,
1236
+ totalTokens: event.usageMetadata?.totalTokenCount ?? 0
1237
+ };
1238
+ emit({
1239
+ type: "message_end",
1240
+ usage,
1241
+ stopReason: mapGeminiStopReason(finishReason, false)
1242
+ });
1243
+ }
1244
+ function processGeminiSSEEvent(event, emit) {
1245
+ const parts = event.candidates?.[0]?.content?.parts ?? [];
1246
+ for (const part of parts) {
1247
+ emitGeminiPartEvents(part, emit);
1248
+ }
1249
+ emitGeminiFinishEvent(event, emit);
1250
+ }
1251
+ function processGeminiSSELine(line, emit) {
1252
+ if (!line.startsWith("data: "))
1253
+ return;
1254
+ const data = line.slice(6).trim();
1255
+ try {
1256
+ const event = JSON.parse(data);
1257
+ processGeminiSSEEvent(event, emit);
1258
+ } catch (err2) {
1259
+ emit({ type: "error", error: err2 instanceof Error ? err2 : new Error(String(err2)) });
1260
+ }
1261
+ }
1262
+ async function processGeminiSSEStream(body, emit) {
1263
+ const reader = body.getReader();
1264
+ const decoder = new TextDecoder;
1265
+ let buffer = "";
1266
+ while (true) {
1267
+ const { done, value } = await reader.read();
1268
+ if (done)
1269
+ break;
1270
+ buffer += decoder.decode(value, { stream: true });
1271
+ const lines = buffer.split(`
1272
+ `);
1273
+ buffer = lines.pop() ?? "";
1274
+ for (const line of lines) {
1275
+ processGeminiSSELine(line, emit);
1276
+ }
1277
+ }
1278
+ }
1279
+
1280
+ // ../gateway/src/providers/openai.ts
1281
+ var DEFAULT_BASE_URL3 = "https://api.openai.com";
1282
+ var DEFAULT_MAX_TOKENS2 = 4096;
1283
+ function createOpenAIProvider(config) {
1284
+ const { apiKey, baseUrl = DEFAULT_BASE_URL3, timeout = 60000, maxRetries = 2 } = config;
1285
+ async function request(path, body, signal) {
1286
+ const url = `${baseUrl}/v1${path}`;
1287
+ const response = await fetch(url, {
1288
+ method: "POST",
1289
+ headers: {
1290
+ "Content-Type": "application/json",
1291
+ Authorization: `Bearer ${apiKey}`
1292
+ },
1293
+ body: JSON.stringify(body),
1294
+ signal
1295
+ });
1296
+ if (!response.ok) {
1297
+ const errorBody = await response.text().catch(() => "Unknown error");
1298
+ if (response.status === 401)
1299
+ throw ElsiumError.authError("openai");
1300
+ if (response.status === 429) {
1301
+ const retryAfter = response.headers.get("retry-after");
1302
+ throw ElsiumError.rateLimit("openai", retryAfter ? Number.parseInt(retryAfter) * 1000 : undefined);
1303
+ }
1304
+ throw ElsiumError.providerError(`OpenAI API error ${response.status}: ${errorBody}`, {
1305
+ provider: "openai",
1306
+ statusCode: response.status,
1307
+ retryable: response.status >= 500
1308
+ });
1309
+ }
1310
+ return response;
1311
+ }
1312
+ function extractTextContent(msg) {
1313
+ if (typeof msg.content === "string")
1314
+ return msg.content;
1315
+ return msg.content.filter((p) => p.type === "text").map((p) => p.text).join(`
1316
+ `);
1317
+ }
1318
+ function formatSystemMessage(msg) {
1319
+ return { role: "system", content: extractTextContent(msg) };
1320
+ }
1321
+ function formatToolMessages(msg) {
1322
+ return (msg.toolResults ?? []).map((tr) => ({
1323
+ role: "tool",
1324
+ content: tr.content,
1325
+ tool_call_id: tr.toolCallId
1326
+ }));
1327
+ }
1328
+ function formatAssistantMessage(msg) {
1329
+ const content = extractTextContent(msg);
1330
+ const openaiMsg = { role: "assistant", content: content || null };
1331
+ if (msg.toolCalls?.length) {
1332
+ openaiMsg.tool_calls = msg.toolCalls.map((tc) => ({
1333
+ id: tc.id,
1334
+ type: "function",
1335
+ function: {
1336
+ name: tc.name,
1337
+ arguments: JSON.stringify(tc.arguments)
1338
+ }
1339
+ }));
1340
+ }
1341
+ return openaiMsg;
1342
+ }
1343
+ function formatMessages(messages) {
1344
+ const formatted = [];
1345
+ for (const msg of messages) {
1346
+ if (msg.role === "system") {
1347
+ formatted.push(formatSystemMessage(msg));
1348
+ continue;
1349
+ }
1350
+ if (msg.role === "tool") {
1351
+ formatted.push(...formatToolMessages(msg));
1352
+ continue;
1353
+ }
1354
+ if (msg.role === "assistant") {
1355
+ formatted.push(formatAssistantMessage(msg));
1356
+ continue;
1357
+ }
1358
+ formatted.push({ role: "user", content: extractTextContent(msg) });
1359
+ }
1360
+ return formatted;
1361
+ }
1362
+ function formatTools(tools) {
1363
+ if (!tools?.length)
1364
+ return;
1365
+ return tools.map((t) => ({
1366
+ type: "function",
1367
+ function: {
1368
+ name: t.name,
1369
+ description: t.description,
1370
+ parameters: t.inputSchema
1371
+ }
1372
+ }));
1373
+ }
1374
+ function parseResponse(raw, latencyMs) {
1375
+ const traceId = generateTraceId();
1376
+ const choice = raw.choices[0];
1377
+ const toolCalls = (choice?.message.tool_calls ?? []).map((tc) => {
1378
+ let args = {};
1379
+ try {
1380
+ args = JSON.parse(tc.function.arguments);
1381
+ } catch {
1382
+ args = { _raw: tc.function.arguments };
1383
+ }
1384
+ return { id: tc.id, name: tc.function.name, arguments: args };
1385
+ });
1386
+ const usage = {
1387
+ inputTokens: raw.usage.prompt_tokens,
1388
+ outputTokens: raw.usage.completion_tokens,
1389
+ totalTokens: raw.usage.total_tokens
1390
+ };
1391
+ const finishReason = choice?.finish_reason;
1392
+ const stopReason = finishReason === "stop" ? "end_turn" : finishReason === "length" ? "max_tokens" : finishReason === "tool_calls" ? "tool_use" : "end_turn";
1393
+ return {
1394
+ id: raw.id,
1395
+ message: {
1396
+ role: "assistant",
1397
+ content: choice?.message.content ?? "",
1398
+ toolCalls: toolCalls.length > 0 ? toolCalls : undefined
1399
+ },
1400
+ usage,
1401
+ cost: calculateCost(raw.model, usage),
1402
+ model: raw.model,
1403
+ provider: "openai",
1404
+ stopReason,
1405
+ latencyMs,
1406
+ traceId
1407
+ };
1408
+ }
1409
+ return {
1410
+ name: "openai",
1411
+ defaultModel: "gpt-4o",
1412
+ metadata: {
1413
+ baseUrl: "https://api.openai.com/v1/chat/completions",
1414
+ capabilities: ["tools", "vision", "streaming", "system", "json_mode"],
1415
+ authStyle: "bearer"
1416
+ },
1417
+ async complete(req) {
1418
+ const messages = formatMessages(req.messages);
1419
+ const model = req.model ?? "gpt-4o";
1420
+ if (req.system) {
1421
+ messages.unshift({ role: "system", content: req.system });
1422
+ }
1423
+ const body = {
1424
+ model,
1425
+ messages,
1426
+ max_tokens: req.maxTokens ?? DEFAULT_MAX_TOKENS2,
1427
+ ...req.temperature !== undefined ? { temperature: req.temperature } : {},
1428
+ ...req.seed !== undefined ? { seed: req.seed } : {},
1429
+ ...req.topP !== undefined ? { top_p: req.topP } : {},
1430
+ ...req.stopSequences?.length ? { stop: req.stopSequences } : {}
1431
+ };
1432
+ const tools = formatTools(req.tools);
1433
+ if (tools)
1434
+ body.tools = tools;
1435
+ const startTime = performance.now();
1436
+ const raw = await retry(async () => {
1437
+ const controller = new AbortController;
1438
+ const timer = setTimeout(() => controller.abort(), timeout);
1439
+ try {
1440
+ const signals = [controller.signal, req.signal].filter(Boolean);
1441
+ const mergedSignal = signals.length > 1 ? AbortSignal.any(signals) : signals[0];
1442
+ const resp = await request("/chat/completions", body, mergedSignal);
1443
+ return await resp.json();
1444
+ } finally {
1445
+ clearTimeout(timer);
1446
+ }
1447
+ }, {
1448
+ maxRetries,
1449
+ baseDelayMs: 1000,
1450
+ shouldRetry: (e) => e instanceof ElsiumError && e.retryable
1451
+ });
1452
+ const latencyMs = Math.round(performance.now() - startTime);
1453
+ return parseResponse(raw, latencyMs);
1454
+ },
1455
+ stream(req) {
1456
+ const messages = formatMessages(req.messages);
1457
+ const model = req.model ?? "gpt-4o";
1458
+ if (req.system) {
1459
+ messages.unshift({ role: "system", content: req.system });
1460
+ }
1461
+ const body = {
1462
+ model,
1463
+ messages,
1464
+ max_tokens: req.maxTokens ?? DEFAULT_MAX_TOKENS2,
1465
+ stream: true,
1466
+ stream_options: { include_usage: true },
1467
+ ...req.temperature !== undefined ? { temperature: req.temperature } : {},
1468
+ ...req.seed !== undefined ? { seed: req.seed } : {},
1469
+ ...req.topP !== undefined ? { top_p: req.topP } : {},
1470
+ ...req.stopSequences?.length ? { stop: req.stopSequences } : {}
1471
+ };
1472
+ const tools = formatTools(req.tools);
1473
+ if (tools)
1474
+ body.tools = tools;
1475
+ return createStream(async (emit) => {
1476
+ const controller = new AbortController;
1477
+ const timer = setTimeout(() => controller.abort(), timeout);
1478
+ try {
1479
+ const signals = [controller.signal, req.signal].filter(Boolean);
1480
+ const mergedSignal = signals.length > 1 ? AbortSignal.any(signals) : signals[0];
1481
+ const resp = await request("/chat/completions", body, mergedSignal);
1482
+ if (!resp.body)
1483
+ throw new ElsiumError({
1484
+ code: "STREAM_ERROR",
1485
+ message: "Response body is null",
1486
+ provider: "openai",
1487
+ retryable: false
1488
+ });
1489
+ emit({ type: "message_start", id: generateId("msg"), model });
1490
+ await processOpenAISSEStream(resp.body, emit);
1491
+ } finally {
1492
+ clearTimeout(timer);
1493
+ }
1494
+ });
1495
+ },
1496
+ async listModels() {
1497
+ return ["gpt-4o", "gpt-4o-mini", "o1", "o1-mini", "o3-mini"];
1498
+ }
1499
+ };
1500
+ }
1501
+ function emitOpenAIToolCallEvents(toolCalls, emit) {
1502
+ for (const tc of toolCalls) {
1503
+ if (tc.function?.name) {
1504
+ emit({
1505
+ type: "tool_call_start",
1506
+ toolCall: { id: tc.id ?? "", name: tc.function.name }
1507
+ });
1508
+ }
1509
+ if (tc.function?.arguments) {
1510
+ emit({
1511
+ type: "tool_call_delta",
1512
+ toolCallId: tc.id ?? "",
1513
+ arguments: tc.function.arguments
1514
+ });
1515
+ }
1516
+ }
1517
+ }
1518
+ function processOpenAISSEChunk(event, emit, state) {
1519
+ const eventUsage = event.usage;
1520
+ if (eventUsage) {
1521
+ state.usage = {
1522
+ inputTokens: eventUsage.prompt_tokens ?? 0,
1523
+ outputTokens: eventUsage.completion_tokens ?? 0,
1524
+ totalTokens: eventUsage.total_tokens ?? 0
1525
+ };
1526
+ }
1527
+ const delta = event.choices?.[0]?.delta;
1528
+ if (delta?.content) {
1529
+ emit({ type: "text_delta", text: delta.content });
1530
+ }
1531
+ if (delta?.tool_calls) {
1532
+ emitOpenAIToolCallEvents(delta.tool_calls, emit);
1533
+ }
1534
+ const finishReason = event.choices?.[0]?.finish_reason;
1535
+ if (finishReason === "tool_calls" && !state.endEmitted) {
1536
+ state.endEmitted = true;
1537
+ emit({
1538
+ type: "message_end",
1539
+ usage: state.usage,
1540
+ stopReason: "tool_use"
1541
+ });
1542
+ }
1543
+ }
1544
+ function processOpenAISSELine(line, emit, state) {
1545
+ if (!line.startsWith("data: "))
1546
+ return;
1547
+ const data = line.slice(6).trim();
1548
+ if (data === "[DONE]") {
1549
+ if (!state.endEmitted) {
1550
+ state.endEmitted = true;
1551
+ emit({
1552
+ type: "message_end",
1553
+ usage: state.usage,
1554
+ stopReason: "end_turn"
1555
+ });
1556
+ }
1557
+ return;
1558
+ }
1559
+ try {
1560
+ const event = JSON.parse(data);
1561
+ processOpenAISSEChunk(event, emit, state);
1562
+ } catch (err2) {
1563
+ emit({ type: "error", error: err2 instanceof Error ? err2 : new Error(String(err2)) });
1564
+ }
1565
+ }
1566
+ async function processOpenAISSEStream(body, emit) {
1567
+ const reader = body.getReader();
1568
+ const decoder = new TextDecoder;
1569
+ let buffer = "";
1570
+ const state = {
1571
+ endEmitted: false,
1572
+ usage: { inputTokens: 0, outputTokens: 0, totalTokens: 0 }
1573
+ };
1574
+ while (true) {
1575
+ const { done, value } = await reader.read();
1576
+ if (done)
1577
+ break;
1578
+ buffer += decoder.decode(value, { stream: true });
1579
+ const lines = buffer.split(`
1580
+ `);
1581
+ buffer = lines.pop() ?? "";
1582
+ for (const line of lines) {
1583
+ processOpenAISSELine(line, emit, state);
1584
+ }
1585
+ }
1586
+ }
1587
+
1588
+ // ../gateway/src/gateway.ts
1589
+ var PROVIDER_FACTORIES = {
1590
+ anthropic: createAnthropicProvider,
1591
+ openai: createOpenAIProvider,
1592
+ google: createGoogleProvider
1593
+ };
1594
+ function gateway(config) {
1595
+ const factory = PROVIDER_FACTORIES[config.provider];
1596
+ if (!factory) {
1597
+ throw new ElsiumError({
1598
+ code: "CONFIG_ERROR",
1599
+ message: `Unknown provider: ${config.provider}. Available: ${Object.keys(PROVIDER_FACTORIES).join(", ")}`,
1600
+ retryable: false
1601
+ });
1602
+ }
1603
+ const provider = factory({
1604
+ apiKey: config.apiKey,
1605
+ baseUrl: config.baseUrl,
1606
+ timeout: config.timeout,
1607
+ maxRetries: config.maxRetries
1608
+ });
1609
+ if (provider.metadata) {
1610
+ registerProviderMetadata(provider.name, provider.metadata);
1611
+ if (provider.metadata.pricing) {
1612
+ for (const [model, pricing] of Object.entries(provider.metadata.pricing)) {
1613
+ registerPricing(model, pricing);
1614
+ }
1615
+ }
1616
+ }
1617
+ const defaultModel = config.model ?? provider.defaultModel;
1618
+ let xrayStore = null;
1619
+ const allMiddleware = [...config.middleware ?? []];
1620
+ if (config.xray) {
1621
+ const xrayOpts = typeof config.xray === "object" ? config.xray : {};
1622
+ const xm = xrayMiddleware(xrayOpts);
1623
+ xrayStore = xm;
1624
+ allMiddleware.push(xm);
1625
+ }
1626
+ const composedMiddleware = allMiddleware.length ? composeMiddleware(allMiddleware) : null;
1627
+ async function executeWithMiddleware(request) {
1628
+ const req = { ...request, model: request.model ?? defaultModel };
1629
+ if (!composedMiddleware) {
1630
+ return provider.complete(req);
1631
+ }
1632
+ const ctx = {
1633
+ request: req,
1634
+ provider: provider.name,
1635
+ model: req.model ?? defaultModel,
1636
+ traceId: generateTraceId(),
1637
+ startTime: performance.now(),
1638
+ metadata: request.metadata ?? {}
1639
+ };
1640
+ return composedMiddleware(ctx, async (c) => provider.complete(c.request));
1641
+ }
1642
+ return {
1643
+ provider,
1644
+ lastCall() {
1645
+ return xrayStore?.lastCall() ?? null;
1646
+ },
1647
+ callHistory(limit) {
1648
+ return xrayStore?.callHistory(limit) ?? [];
1649
+ },
1650
+ async complete(request) {
1651
+ return executeWithMiddleware(request);
1652
+ },
1653
+ stream(request) {
1654
+ const req = { ...request, model: request.model ?? defaultModel };
1655
+ if (composedMiddleware) {
1656
+ const ctx = {
1657
+ request: req,
1658
+ provider: provider.name,
1659
+ model: req.model ?? defaultModel,
1660
+ traceId: generateTraceId(),
1661
+ startTime: performance.now(),
1662
+ metadata: request.metadata ?? {}
1663
+ };
1664
+ return createStream(async (emit) => {
1665
+ await composedMiddleware(ctx, async (c) => {
1666
+ const stream = provider.stream(c.request);
1667
+ for await (const event of stream) {
1668
+ emit(event);
1669
+ }
1670
+ return {
1671
+ id: "",
1672
+ message: { role: "assistant", content: "" },
1673
+ usage: { inputTokens: 0, outputTokens: 0, totalTokens: 0 },
1674
+ cost: { inputCost: 0, outputCost: 0, totalCost: 0, currency: "USD" },
1675
+ model: c.model,
1676
+ provider: provider.name,
1677
+ stopReason: "end_turn",
1678
+ latencyMs: 0,
1679
+ traceId: ctx.traceId
1680
+ };
1681
+ });
1682
+ });
1683
+ }
1684
+ return provider.stream(req);
1685
+ },
1686
+ async generate(request) {
1687
+ const { schema, ...rest } = request;
1688
+ const jsonSchema = schemaToJsonSchema(schema);
1689
+ const systemPrompt = [
1690
+ rest.system ?? "",
1691
+ "You MUST respond with valid JSON matching this schema:",
1692
+ JSON.stringify(jsonSchema, null, 2),
1693
+ "Respond ONLY with the JSON object, no markdown or explanation."
1694
+ ].filter(Boolean).join(`
1695
+
1696
+ `);
1697
+ const response = await executeWithMiddleware({
1698
+ ...rest,
1699
+ system: systemPrompt
1700
+ });
1701
+ const text = typeof response.message.content === "string" ? response.message.content : "";
1702
+ const jsonMatch = text.match(/\{[\s\S]*\}/);
1703
+ if (!jsonMatch) {
1704
+ throw ElsiumError.validation("LLM response did not contain valid JSON", {
1705
+ response: text
1706
+ });
1707
+ }
1708
+ const parsed = JSON.parse(jsonMatch[0]);
1709
+ const result = schema.safeParse(parsed);
1710
+ if (!result.success) {
1711
+ throw ElsiumError.validation("LLM response did not match schema", {
1712
+ errors: result.error.issues,
1713
+ response: text
1714
+ });
1715
+ }
1716
+ return { data: result.data, response };
1717
+ }
1718
+ };
1719
+ }
1720
+ function schemaToJsonSchema(schema) {
1721
+ try {
1722
+ if ("_def" in schema) {
1723
+ const def = schema._def;
1724
+ const result = convertZodDef(def);
1725
+ if (result)
1726
+ return result;
1727
+ }
1728
+ } catch {}
1729
+ return { type: "string" };
1730
+ }
1731
+ function zodDefKind(def) {
1732
+ return typeof def.type === "string" ? def.type : def.typeName;
1733
+ }
1734
+ function convertZodDef(def) {
1735
+ const kind = zodDefKind(def);
1736
+ switch (kind) {
1737
+ case "object":
1738
+ case "ZodObject":
1739
+ return convertZodObject(def);
1740
+ case "string":
1741
+ case "ZodString":
1742
+ return { type: "string" };
1743
+ case "number":
1744
+ case "ZodNumber":
1745
+ return { type: "number" };
1746
+ case "boolean":
1747
+ case "ZodBoolean":
1748
+ return { type: "boolean" };
1749
+ case "array":
1750
+ case "ZodArray":
1751
+ return convertZodArray(def);
1752
+ case "enum":
1753
+ case "ZodEnum": {
1754
+ const values = def.values ?? (def.entries ? Object.values(def.entries) : []);
1755
+ return { type: "string", enum: values };
1756
+ }
1757
+ case "optional":
1758
+ case "ZodOptional":
1759
+ return convertZodOptional(def);
1760
+ default:
1761
+ return null;
1762
+ }
1763
+ }
1764
+ function convertZodObject(def) {
1765
+ if (!def.shape)
1766
+ return null;
1767
+ const shape = typeof def.shape === "function" ? def.shape() : def.shape;
1768
+ const properties = {};
1769
+ const required = [];
1770
+ for (const [key, value] of Object.entries(shape)) {
1771
+ properties[key] = schemaToJsonSchema(value);
1772
+ const valDef = value._def;
1773
+ const valKind = zodDefKind(valDef);
1774
+ if (valKind !== "optional" && valKind !== "ZodOptional") {
1775
+ required.push(key);
1776
+ }
1777
+ }
1778
+ return { type: "object", properties, required };
1779
+ }
1780
+ function convertZodArray(def) {
1781
+ return {
1782
+ type: "array",
1783
+ items: schemaToJsonSchema(def.element ?? def.type)
1784
+ };
1785
+ }
1786
+ function convertZodOptional(def) {
1787
+ return schemaToJsonSchema(def.innerType ?? def.innerType);
1788
+ }
1789
+ // ../observe/src/span.ts
1790
+ function createSpan(name, options = {}) {
1791
+ const id = generateId("spn");
1792
+ const traceId = options.traceId ?? generateId("trc");
1793
+ const kind = options.kind ?? "custom";
1794
+ const startTime = Date.now();
1795
+ const metadata = {};
1796
+ const events = [];
1797
+ let status = "running";
1798
+ let endTime;
1799
+ const span = {
1800
+ id,
1801
+ traceId,
1802
+ name,
1803
+ kind,
1804
+ addEvent(eventName, data) {
1805
+ events.push({
1806
+ name: eventName,
1807
+ timestamp: Date.now(),
1808
+ data
1809
+ });
1810
+ },
1811
+ setMetadata(key, value) {
1812
+ if (key === "__proto__" || key === "constructor" || key === "prototype")
1813
+ return;
1814
+ metadata[key] = value;
1815
+ },
1816
+ end(result) {
1817
+ if (endTime !== undefined)
1818
+ return;
1819
+ endTime = Date.now();
1820
+ status = result?.status ?? "ok";
1821
+ if (result?.metadata) {
1822
+ for (const [key, value] of Object.entries(result.metadata)) {
1823
+ if (key === "__proto__" || key === "constructor" || key === "prototype")
1824
+ continue;
1825
+ metadata[key] = value;
1826
+ }
1827
+ }
1828
+ options.onEnd?.(span.toJSON());
1829
+ },
1830
+ child(childName, childKind) {
1831
+ return createSpan(childName, {
1832
+ traceId,
1833
+ parentId: id,
1834
+ kind: childKind ?? kind,
1835
+ onEnd: options.onEnd
1836
+ });
1837
+ },
1838
+ toJSON() {
1839
+ const duration = endTime !== undefined ? endTime - startTime : undefined;
1840
+ return {
1841
+ id,
1842
+ traceId,
1843
+ parentId: options.parentId,
1844
+ name,
1845
+ kind,
1846
+ status,
1847
+ startTime,
1848
+ endTime,
1849
+ durationMs: duration !== undefined ? Math.round(duration) : undefined,
1850
+ metadata,
1851
+ events
1852
+ };
1853
+ }
1854
+ };
1855
+ return span;
1856
+ }
1857
+ // ../observe/src/tracer.ts
1858
+ var log2 = createLogger();
1859
+ function observe(config = {}) {
1860
+ const {
1861
+ output = ["console"],
1862
+ costTracking = true,
1863
+ samplingRate = 1,
1864
+ maxSpans = 1e4
1865
+ } = config;
1866
+ const spans = [];
1867
+ const llmCalls = [];
1868
+ const exporters = [];
1869
+ const handlers = [];
1870
+ for (const out of output) {
1871
+ if (out === "console") {
1872
+ handlers.push(consoleHandler);
1873
+ } else if (out === "json-file") {} else {
1874
+ exporters.push(out);
1875
+ }
1876
+ }
1877
+ function shouldSample() {
1878
+ if (samplingRate >= 1)
1879
+ return true;
1880
+ return Math.random() < samplingRate;
1881
+ }
1882
+ function onSpanEnd(span) {
1883
+ if (spans.length >= maxSpans) {
1884
+ spans.shift();
1885
+ }
1886
+ spans.push(span);
1887
+ for (const handler of handlers) {
1888
+ handler(span);
1889
+ }
1890
+ }
1891
+ return {
1892
+ startSpan(name, kind) {
1893
+ if (!shouldSample()) {
1894
+ return createNoopSpan(name, kind);
1895
+ }
1896
+ return createSpan(name, { kind, onEnd: onSpanEnd });
1897
+ },
1898
+ getSpans() {
1899
+ return [...spans];
1900
+ },
1901
+ getCostReport() {
1902
+ const byModel = {};
1903
+ for (const call of llmCalls) {
1904
+ if (!byModel[call.model]) {
1905
+ byModel[call.model] = { cost: 0, tokens: 0, calls: 0 };
1906
+ }
1907
+ byModel[call.model].cost += call.cost;
1908
+ byModel[call.model].tokens += call.inputTokens + call.outputTokens;
1909
+ byModel[call.model].calls++;
1910
+ }
1911
+ return {
1912
+ totalCost: llmCalls.reduce((sum, c) => sum + c.cost, 0),
1913
+ totalTokens: llmCalls.reduce((sum, c) => sum + c.inputTokens + c.outputTokens, 0),
1914
+ totalInputTokens: llmCalls.reduce((sum, c) => sum + c.inputTokens, 0),
1915
+ totalOutputTokens: llmCalls.reduce((sum, c) => sum + c.outputTokens, 0),
1916
+ callCount: llmCalls.length,
1917
+ byModel
1918
+ };
1919
+ },
1920
+ trackLLMCall(data) {
1921
+ if (!costTracking)
1922
+ return;
1923
+ llmCalls.push(data);
1924
+ if (llmCalls.length > maxSpans) {
1925
+ llmCalls.shift();
1926
+ }
1927
+ },
1928
+ reset() {
1929
+ spans.length = 0;
1930
+ llmCalls.length = 0;
1931
+ },
1932
+ async flush() {
1933
+ for (const exporter of exporters) {
1934
+ await exporter.export([...spans]);
1935
+ }
1936
+ }
1937
+ };
1938
+ }
1939
+ function consoleHandler(span) {
1940
+ const duration = span.durationMs !== undefined ? `${span.durationMs}ms` : "running";
1941
+ const status = span.status === "error" ? "[ERROR]" : span.status === "ok" ? "[OK]" : "[...]";
1942
+ log2.info("span", {
1943
+ trace: span.traceId,
1944
+ span: span.name,
1945
+ kind: span.kind,
1946
+ status,
1947
+ duration,
1948
+ ...Object.keys(span.metadata).length > 0 ? { metadata: span.metadata } : {}
1949
+ });
1950
+ }
1951
+ function createNoopSpan(name, kind) {
1952
+ const id = generateId("spn");
1953
+ const traceId = generateId("trc");
1954
+ return {
1955
+ id,
1956
+ traceId,
1957
+ name,
1958
+ kind: kind ?? "custom",
1959
+ addEvent() {},
1960
+ setMetadata() {},
1961
+ end() {},
1962
+ child(childName, childKind) {
1963
+ return createNoopSpan(childName, childKind);
1964
+ },
1965
+ toJSON() {
1966
+ return {
1967
+ id,
1968
+ traceId,
1969
+ name,
1970
+ kind: kind ?? "custom",
1971
+ status: "ok",
1972
+ startTime: 0,
1973
+ metadata: {},
1974
+ events: []
1975
+ };
1976
+ }
1977
+ };
1978
+ }
1979
+ // ../observe/src/otel.ts
1980
+ var log3 = createLogger();
1981
+ // ../../node_modules/.bun/hono@4.12.3/node_modules/hono/dist/compose.js
1982
+ var compose = (middleware, onError, onNotFound) => {
1983
+ return (context, next) => {
1984
+ let index = -1;
1985
+ return dispatch(0);
1986
+ async function dispatch(i) {
1987
+ if (i <= index) {
1988
+ throw new Error("next() called multiple times");
1989
+ }
1990
+ index = i;
1991
+ let res;
1992
+ let isError = false;
1993
+ let handler;
1994
+ if (middleware[i]) {
1995
+ handler = middleware[i][0][0];
1996
+ context.req.routeIndex = i;
1997
+ } else {
1998
+ handler = i === middleware.length && next || undefined;
1999
+ }
2000
+ if (handler) {
2001
+ try {
2002
+ res = await handler(context, () => dispatch(i + 1));
2003
+ } catch (err2) {
2004
+ if (err2 instanceof Error && onError) {
2005
+ context.error = err2;
2006
+ res = await onError(err2, context);
2007
+ isError = true;
2008
+ } else {
2009
+ throw err2;
2010
+ }
2011
+ }
2012
+ } else {
2013
+ if (context.finalized === false && onNotFound) {
2014
+ res = await onNotFound(context);
2015
+ }
2016
+ }
2017
+ if (res && (context.finalized === false || isError)) {
2018
+ context.res = res;
2019
+ }
2020
+ return context;
2021
+ }
2022
+ };
2023
+ };
2024
+
2025
+ // ../../node_modules/.bun/hono@4.12.3/node_modules/hono/dist/request/constants.js
2026
+ var GET_MATCH_RESULT = /* @__PURE__ */ Symbol();
2027
+
2028
+ // ../../node_modules/.bun/hono@4.12.3/node_modules/hono/dist/utils/body.js
2029
+ var parseBody = async (request, options = /* @__PURE__ */ Object.create(null)) => {
2030
+ const { all = false, dot = false } = options;
2031
+ const headers = request instanceof HonoRequest ? request.raw.headers : request.headers;
2032
+ const contentType = headers.get("Content-Type");
2033
+ if (contentType?.startsWith("multipart/form-data") || contentType?.startsWith("application/x-www-form-urlencoded")) {
2034
+ return parseFormData(request, { all, dot });
2035
+ }
2036
+ return {};
2037
+ };
2038
+ async function parseFormData(request, options) {
2039
+ const formData = await request.formData();
2040
+ if (formData) {
2041
+ return convertFormDataToBodyData(formData, options);
2042
+ }
2043
+ return {};
2044
+ }
2045
+ function convertFormDataToBodyData(formData, options) {
2046
+ const form = /* @__PURE__ */ Object.create(null);
2047
+ formData.forEach((value, key) => {
2048
+ const shouldParseAllValues = options.all || key.endsWith("[]");
2049
+ if (!shouldParseAllValues) {
2050
+ form[key] = value;
2051
+ } else {
2052
+ handleParsingAllValues(form, key, value);
2053
+ }
2054
+ });
2055
+ if (options.dot) {
2056
+ Object.entries(form).forEach(([key, value]) => {
2057
+ const shouldParseDotValues = key.includes(".");
2058
+ if (shouldParseDotValues) {
2059
+ handleParsingNestedValues(form, key, value);
2060
+ delete form[key];
2061
+ }
2062
+ });
2063
+ }
2064
+ return form;
2065
+ }
2066
+ var handleParsingAllValues = (form, key, value) => {
2067
+ if (form[key] !== undefined) {
2068
+ if (Array.isArray(form[key])) {
2069
+ form[key].push(value);
2070
+ } else {
2071
+ form[key] = [form[key], value];
2072
+ }
2073
+ } else {
2074
+ if (!key.endsWith("[]")) {
2075
+ form[key] = value;
2076
+ } else {
2077
+ form[key] = [value];
2078
+ }
2079
+ }
2080
+ };
2081
+ var handleParsingNestedValues = (form, key, value) => {
2082
+ let nestedForm = form;
2083
+ const keys = key.split(".");
2084
+ keys.forEach((key2, index) => {
2085
+ if (index === keys.length - 1) {
2086
+ nestedForm[key2] = value;
2087
+ } else {
2088
+ if (!nestedForm[key2] || typeof nestedForm[key2] !== "object" || Array.isArray(nestedForm[key2]) || nestedForm[key2] instanceof File) {
2089
+ nestedForm[key2] = /* @__PURE__ */ Object.create(null);
2090
+ }
2091
+ nestedForm = nestedForm[key2];
2092
+ }
2093
+ });
2094
+ };
2095
+
2096
+ // ../../node_modules/.bun/hono@4.12.3/node_modules/hono/dist/utils/url.js
2097
+ var splitPath = (path) => {
2098
+ const paths = path.split("/");
2099
+ if (paths[0] === "") {
2100
+ paths.shift();
2101
+ }
2102
+ return paths;
2103
+ };
2104
+ var splitRoutingPath = (routePath) => {
2105
+ const { groups, path } = extractGroupsFromPath(routePath);
2106
+ const paths = splitPath(path);
2107
+ return replaceGroupMarks(paths, groups);
2108
+ };
2109
+ var extractGroupsFromPath = (path) => {
2110
+ const groups = [];
2111
+ path = path.replace(/\{[^}]+\}/g, (match, index) => {
2112
+ const mark = `@${index}`;
2113
+ groups.push([mark, match]);
2114
+ return mark;
2115
+ });
2116
+ return { groups, path };
2117
+ };
2118
+ var replaceGroupMarks = (paths, groups) => {
2119
+ for (let i = groups.length - 1;i >= 0; i--) {
2120
+ const [mark] = groups[i];
2121
+ for (let j = paths.length - 1;j >= 0; j--) {
2122
+ if (paths[j].includes(mark)) {
2123
+ paths[j] = paths[j].replace(mark, groups[i][1]);
2124
+ break;
2125
+ }
2126
+ }
2127
+ }
2128
+ return paths;
2129
+ };
2130
+ var patternCache = {};
2131
+ var getPattern = (label, next) => {
2132
+ if (label === "*") {
2133
+ return "*";
2134
+ }
2135
+ const match = label.match(/^\:([^\{\}]+)(?:\{(.+)\})?$/);
2136
+ if (match) {
2137
+ const cacheKey = `${label}#${next}`;
2138
+ if (!patternCache[cacheKey]) {
2139
+ if (match[2]) {
2140
+ patternCache[cacheKey] = next && next[0] !== ":" && next[0] !== "*" ? [cacheKey, match[1], new RegExp(`^${match[2]}(?=/${next})`)] : [label, match[1], new RegExp(`^${match[2]}$`)];
2141
+ } else {
2142
+ patternCache[cacheKey] = [label, match[1], true];
2143
+ }
2144
+ }
2145
+ return patternCache[cacheKey];
2146
+ }
2147
+ return null;
2148
+ };
2149
+ var tryDecode = (str, decoder) => {
2150
+ try {
2151
+ return decoder(str);
2152
+ } catch {
2153
+ return str.replace(/(?:%[0-9A-Fa-f]{2})+/g, (match) => {
2154
+ try {
2155
+ return decoder(match);
2156
+ } catch {
2157
+ return match;
2158
+ }
2159
+ });
2160
+ }
2161
+ };
2162
+ var tryDecodeURI = (str) => tryDecode(str, decodeURI);
2163
+ var getPath = (request) => {
2164
+ const url = request.url;
2165
+ const start = url.indexOf("/", url.indexOf(":") + 4);
2166
+ let i = start;
2167
+ for (;i < url.length; i++) {
2168
+ const charCode = url.charCodeAt(i);
2169
+ if (charCode === 37) {
2170
+ const queryIndex = url.indexOf("?", i);
2171
+ const hashIndex = url.indexOf("#", i);
2172
+ const end = queryIndex === -1 ? hashIndex === -1 ? undefined : hashIndex : hashIndex === -1 ? queryIndex : Math.min(queryIndex, hashIndex);
2173
+ const path = url.slice(start, end);
2174
+ return tryDecodeURI(path.includes("%25") ? path.replace(/%25/g, "%2525") : path);
2175
+ } else if (charCode === 63 || charCode === 35) {
2176
+ break;
2177
+ }
2178
+ }
2179
+ return url.slice(start, i);
2180
+ };
2181
+ var getPathNoStrict = (request) => {
2182
+ const result = getPath(request);
2183
+ return result.length > 1 && result.at(-1) === "/" ? result.slice(0, -1) : result;
2184
+ };
2185
+ var mergePath = (base, sub, ...rest) => {
2186
+ if (rest.length) {
2187
+ sub = mergePath(sub, ...rest);
2188
+ }
2189
+ return `${base?.[0] === "/" ? "" : "/"}${base}${sub === "/" ? "" : `${base?.at(-1) === "/" ? "" : "/"}${sub?.[0] === "/" ? sub.slice(1) : sub}`}`;
2190
+ };
2191
+ var checkOptionalParameter = (path) => {
2192
+ if (path.charCodeAt(path.length - 1) !== 63 || !path.includes(":")) {
2193
+ return null;
2194
+ }
2195
+ const segments = path.split("/");
2196
+ const results = [];
2197
+ let basePath = "";
2198
+ segments.forEach((segment) => {
2199
+ if (segment !== "" && !/\:/.test(segment)) {
2200
+ basePath += "/" + segment;
2201
+ } else if (/\:/.test(segment)) {
2202
+ if (/\?/.test(segment)) {
2203
+ if (results.length === 0 && basePath === "") {
2204
+ results.push("/");
2205
+ } else {
2206
+ results.push(basePath);
2207
+ }
2208
+ const optionalSegment = segment.replace("?", "");
2209
+ basePath += "/" + optionalSegment;
2210
+ results.push(basePath);
2211
+ } else {
2212
+ basePath += "/" + segment;
2213
+ }
2214
+ }
2215
+ });
2216
+ return results.filter((v, i, a) => a.indexOf(v) === i);
2217
+ };
2218
+ var _decodeURI = (value) => {
2219
+ if (!/[%+]/.test(value)) {
2220
+ return value;
2221
+ }
2222
+ if (value.indexOf("+") !== -1) {
2223
+ value = value.replace(/\+/g, " ");
2224
+ }
2225
+ return value.indexOf("%") !== -1 ? tryDecode(value, decodeURIComponent_) : value;
2226
+ };
2227
+ var _getQueryParam = (url, key, multiple) => {
2228
+ let encoded;
2229
+ if (!multiple && key && !/[%+]/.test(key)) {
2230
+ let keyIndex2 = url.indexOf("?", 8);
2231
+ if (keyIndex2 === -1) {
2232
+ return;
2233
+ }
2234
+ if (!url.startsWith(key, keyIndex2 + 1)) {
2235
+ keyIndex2 = url.indexOf(`&${key}`, keyIndex2 + 1);
2236
+ }
2237
+ while (keyIndex2 !== -1) {
2238
+ const trailingKeyCode = url.charCodeAt(keyIndex2 + key.length + 1);
2239
+ if (trailingKeyCode === 61) {
2240
+ const valueIndex = keyIndex2 + key.length + 2;
2241
+ const endIndex = url.indexOf("&", valueIndex);
2242
+ return _decodeURI(url.slice(valueIndex, endIndex === -1 ? undefined : endIndex));
2243
+ } else if (trailingKeyCode == 38 || isNaN(trailingKeyCode)) {
2244
+ return "";
2245
+ }
2246
+ keyIndex2 = url.indexOf(`&${key}`, keyIndex2 + 1);
2247
+ }
2248
+ encoded = /[%+]/.test(url);
2249
+ if (!encoded) {
2250
+ return;
2251
+ }
2252
+ }
2253
+ const results = {};
2254
+ encoded ??= /[%+]/.test(url);
2255
+ let keyIndex = url.indexOf("?", 8);
2256
+ while (keyIndex !== -1) {
2257
+ const nextKeyIndex = url.indexOf("&", keyIndex + 1);
2258
+ let valueIndex = url.indexOf("=", keyIndex);
2259
+ if (valueIndex > nextKeyIndex && nextKeyIndex !== -1) {
2260
+ valueIndex = -1;
2261
+ }
2262
+ let name = url.slice(keyIndex + 1, valueIndex === -1 ? nextKeyIndex === -1 ? undefined : nextKeyIndex : valueIndex);
2263
+ if (encoded) {
2264
+ name = _decodeURI(name);
2265
+ }
2266
+ keyIndex = nextKeyIndex;
2267
+ if (name === "") {
2268
+ continue;
2269
+ }
2270
+ let value;
2271
+ if (valueIndex === -1) {
2272
+ value = "";
2273
+ } else {
2274
+ value = url.slice(valueIndex + 1, nextKeyIndex === -1 ? undefined : nextKeyIndex);
2275
+ if (encoded) {
2276
+ value = _decodeURI(value);
2277
+ }
2278
+ }
2279
+ if (multiple) {
2280
+ if (!(results[name] && Array.isArray(results[name]))) {
2281
+ results[name] = [];
2282
+ }
2283
+ results[name].push(value);
2284
+ } else {
2285
+ results[name] ??= value;
2286
+ }
2287
+ }
2288
+ return key ? results[key] : results;
2289
+ };
2290
+ var getQueryParam = _getQueryParam;
2291
+ var getQueryParams = (url, key) => {
2292
+ return _getQueryParam(url, key, true);
2293
+ };
2294
+ var decodeURIComponent_ = decodeURIComponent;
2295
+
2296
+ // ../../node_modules/.bun/hono@4.12.3/node_modules/hono/dist/request.js
2297
+ var tryDecodeURIComponent = (str) => tryDecode(str, decodeURIComponent_);
2298
+ var HonoRequest = class {
2299
+ raw;
2300
+ #validatedData;
2301
+ #matchResult;
2302
+ routeIndex = 0;
2303
+ path;
2304
+ bodyCache = {};
2305
+ constructor(request, path = "/", matchResult = [[]]) {
2306
+ this.raw = request;
2307
+ this.path = path;
2308
+ this.#matchResult = matchResult;
2309
+ this.#validatedData = {};
2310
+ }
2311
+ param(key) {
2312
+ return key ? this.#getDecodedParam(key) : this.#getAllDecodedParams();
2313
+ }
2314
+ #getDecodedParam(key) {
2315
+ const paramKey = this.#matchResult[0][this.routeIndex][1][key];
2316
+ const param = this.#getParamValue(paramKey);
2317
+ return param && /\%/.test(param) ? tryDecodeURIComponent(param) : param;
2318
+ }
2319
+ #getAllDecodedParams() {
2320
+ const decoded = {};
2321
+ const keys = Object.keys(this.#matchResult[0][this.routeIndex][1]);
2322
+ for (const key of keys) {
2323
+ const value = this.#getParamValue(this.#matchResult[0][this.routeIndex][1][key]);
2324
+ if (value !== undefined) {
2325
+ decoded[key] = /\%/.test(value) ? tryDecodeURIComponent(value) : value;
2326
+ }
2327
+ }
2328
+ return decoded;
2329
+ }
2330
+ #getParamValue(paramKey) {
2331
+ return this.#matchResult[1] ? this.#matchResult[1][paramKey] : paramKey;
2332
+ }
2333
+ query(key) {
2334
+ return getQueryParam(this.url, key);
2335
+ }
2336
+ queries(key) {
2337
+ return getQueryParams(this.url, key);
2338
+ }
2339
+ header(name) {
2340
+ if (name) {
2341
+ return this.raw.headers.get(name) ?? undefined;
2342
+ }
2343
+ const headerData = {};
2344
+ this.raw.headers.forEach((value, key) => {
2345
+ headerData[key] = value;
2346
+ });
2347
+ return headerData;
2348
+ }
2349
+ async parseBody(options) {
2350
+ return this.bodyCache.parsedBody ??= await parseBody(this, options);
2351
+ }
2352
+ #cachedBody = (key) => {
2353
+ const { bodyCache, raw } = this;
2354
+ const cachedBody = bodyCache[key];
2355
+ if (cachedBody) {
2356
+ return cachedBody;
2357
+ }
2358
+ const anyCachedKey = Object.keys(bodyCache)[0];
2359
+ if (anyCachedKey) {
2360
+ return bodyCache[anyCachedKey].then((body) => {
2361
+ if (anyCachedKey === "json") {
2362
+ body = JSON.stringify(body);
2363
+ }
2364
+ return new Response(body)[key]();
2365
+ });
2366
+ }
2367
+ return bodyCache[key] = raw[key]();
2368
+ };
2369
+ json() {
2370
+ return this.#cachedBody("text").then((text) => JSON.parse(text));
2371
+ }
2372
+ text() {
2373
+ return this.#cachedBody("text");
2374
+ }
2375
+ arrayBuffer() {
2376
+ return this.#cachedBody("arrayBuffer");
2377
+ }
2378
+ blob() {
2379
+ return this.#cachedBody("blob");
2380
+ }
2381
+ formData() {
2382
+ return this.#cachedBody("formData");
2383
+ }
2384
+ addValidatedData(target, data) {
2385
+ this.#validatedData[target] = data;
2386
+ }
2387
+ valid(target) {
2388
+ return this.#validatedData[target];
2389
+ }
2390
+ get url() {
2391
+ return this.raw.url;
2392
+ }
2393
+ get method() {
2394
+ return this.raw.method;
2395
+ }
2396
+ get [GET_MATCH_RESULT]() {
2397
+ return this.#matchResult;
2398
+ }
2399
+ get matchedRoutes() {
2400
+ return this.#matchResult[0].map(([[, route]]) => route);
2401
+ }
2402
+ get routePath() {
2403
+ return this.#matchResult[0].map(([[, route]]) => route)[this.routeIndex].path;
2404
+ }
2405
+ };
2406
+
2407
+ // ../../node_modules/.bun/hono@4.12.3/node_modules/hono/dist/utils/html.js
2408
+ var HtmlEscapedCallbackPhase = {
2409
+ Stringify: 1,
2410
+ BeforeStream: 2,
2411
+ Stream: 3
2412
+ };
2413
+ var raw = (value, callbacks) => {
2414
+ const escapedString = new String(value);
2415
+ escapedString.isEscaped = true;
2416
+ escapedString.callbacks = callbacks;
2417
+ return escapedString;
2418
+ };
2419
+ var resolveCallback = async (str, phase, preserveCallbacks, context, buffer) => {
2420
+ if (typeof str === "object" && !(str instanceof String)) {
2421
+ if (!(str instanceof Promise)) {
2422
+ str = str.toString();
2423
+ }
2424
+ if (str instanceof Promise) {
2425
+ str = await str;
2426
+ }
2427
+ }
2428
+ const callbacks = str.callbacks;
2429
+ if (!callbacks?.length) {
2430
+ return Promise.resolve(str);
2431
+ }
2432
+ if (buffer) {
2433
+ buffer[0] += str;
2434
+ } else {
2435
+ buffer = [str];
2436
+ }
2437
+ const resStr = Promise.all(callbacks.map((c) => c({ phase, buffer, context }))).then((res) => Promise.all(res.filter(Boolean).map((str2) => resolveCallback(str2, phase, false, context, buffer))).then(() => buffer[0]));
2438
+ if (preserveCallbacks) {
2439
+ return raw(await resStr, callbacks);
2440
+ } else {
2441
+ return resStr;
2442
+ }
2443
+ };
2444
+
2445
+ // ../../node_modules/.bun/hono@4.12.3/node_modules/hono/dist/context.js
2446
+ var TEXT_PLAIN = "text/plain; charset=UTF-8";
2447
+ var setDefaultContentType = (contentType, headers) => {
2448
+ return {
2449
+ "Content-Type": contentType,
2450
+ ...headers
2451
+ };
2452
+ };
2453
+ var createResponseInstance = (body, init) => new Response(body, init);
2454
+ var Context = class {
2455
+ #rawRequest;
2456
+ #req;
2457
+ env = {};
2458
+ #var;
2459
+ finalized = false;
2460
+ error;
2461
+ #status;
2462
+ #executionCtx;
2463
+ #res;
2464
+ #layout;
2465
+ #renderer;
2466
+ #notFoundHandler;
2467
+ #preparedHeaders;
2468
+ #matchResult;
2469
+ #path;
2470
+ constructor(req, options) {
2471
+ this.#rawRequest = req;
2472
+ if (options) {
2473
+ this.#executionCtx = options.executionCtx;
2474
+ this.env = options.env;
2475
+ this.#notFoundHandler = options.notFoundHandler;
2476
+ this.#path = options.path;
2477
+ this.#matchResult = options.matchResult;
2478
+ }
2479
+ }
2480
+ get req() {
2481
+ this.#req ??= new HonoRequest(this.#rawRequest, this.#path, this.#matchResult);
2482
+ return this.#req;
2483
+ }
2484
+ get event() {
2485
+ if (this.#executionCtx && "respondWith" in this.#executionCtx) {
2486
+ return this.#executionCtx;
2487
+ } else {
2488
+ throw Error("This context has no FetchEvent");
2489
+ }
2490
+ }
2491
+ get executionCtx() {
2492
+ if (this.#executionCtx) {
2493
+ return this.#executionCtx;
2494
+ } else {
2495
+ throw Error("This context has no ExecutionContext");
2496
+ }
2497
+ }
2498
+ get res() {
2499
+ return this.#res ||= createResponseInstance(null, {
2500
+ headers: this.#preparedHeaders ??= new Headers
2501
+ });
2502
+ }
2503
+ set res(_res) {
2504
+ if (this.#res && _res) {
2505
+ _res = createResponseInstance(_res.body, _res);
2506
+ for (const [k, v] of this.#res.headers.entries()) {
2507
+ if (k === "content-type") {
2508
+ continue;
2509
+ }
2510
+ if (k === "set-cookie") {
2511
+ const cookies = this.#res.headers.getSetCookie();
2512
+ _res.headers.delete("set-cookie");
2513
+ for (const cookie of cookies) {
2514
+ _res.headers.append("set-cookie", cookie);
2515
+ }
2516
+ } else {
2517
+ _res.headers.set(k, v);
2518
+ }
2519
+ }
2520
+ }
2521
+ this.#res = _res;
2522
+ this.finalized = true;
2523
+ }
2524
+ render = (...args) => {
2525
+ this.#renderer ??= (content) => this.html(content);
2526
+ return this.#renderer(...args);
2527
+ };
2528
+ setLayout = (layout) => this.#layout = layout;
2529
+ getLayout = () => this.#layout;
2530
+ setRenderer = (renderer) => {
2531
+ this.#renderer = renderer;
2532
+ };
2533
+ header = (name, value, options) => {
2534
+ if (this.finalized) {
2535
+ this.#res = createResponseInstance(this.#res.body, this.#res);
2536
+ }
2537
+ const headers = this.#res ? this.#res.headers : this.#preparedHeaders ??= new Headers;
2538
+ if (value === undefined) {
2539
+ headers.delete(name);
2540
+ } else if (options?.append) {
2541
+ headers.append(name, value);
2542
+ } else {
2543
+ headers.set(name, value);
2544
+ }
2545
+ };
2546
+ status = (status) => {
2547
+ this.#status = status;
2548
+ };
2549
+ set = (key, value) => {
2550
+ this.#var ??= /* @__PURE__ */ new Map;
2551
+ this.#var.set(key, value);
2552
+ };
2553
+ get = (key) => {
2554
+ return this.#var ? this.#var.get(key) : undefined;
2555
+ };
2556
+ get var() {
2557
+ if (!this.#var) {
2558
+ return {};
2559
+ }
2560
+ return Object.fromEntries(this.#var);
2561
+ }
2562
+ #newResponse(data, arg, headers) {
2563
+ const responseHeaders = this.#res ? new Headers(this.#res.headers) : this.#preparedHeaders ?? new Headers;
2564
+ if (typeof arg === "object" && "headers" in arg) {
2565
+ const argHeaders = arg.headers instanceof Headers ? arg.headers : new Headers(arg.headers);
2566
+ for (const [key, value] of argHeaders) {
2567
+ if (key.toLowerCase() === "set-cookie") {
2568
+ responseHeaders.append(key, value);
2569
+ } else {
2570
+ responseHeaders.set(key, value);
2571
+ }
2572
+ }
2573
+ }
2574
+ if (headers) {
2575
+ for (const [k, v] of Object.entries(headers)) {
2576
+ if (typeof v === "string") {
2577
+ responseHeaders.set(k, v);
2578
+ } else {
2579
+ responseHeaders.delete(k);
2580
+ for (const v2 of v) {
2581
+ responseHeaders.append(k, v2);
2582
+ }
2583
+ }
2584
+ }
2585
+ }
2586
+ const status = typeof arg === "number" ? arg : arg?.status ?? this.#status;
2587
+ return createResponseInstance(data, { status, headers: responseHeaders });
2588
+ }
2589
+ newResponse = (...args) => this.#newResponse(...args);
2590
+ body = (data, arg, headers) => this.#newResponse(data, arg, headers);
2591
+ text = (text, arg, headers) => {
2592
+ return !this.#preparedHeaders && !this.#status && !arg && !headers && !this.finalized ? new Response(text) : this.#newResponse(text, arg, setDefaultContentType(TEXT_PLAIN, headers));
2593
+ };
2594
+ json = (object, arg, headers) => {
2595
+ return this.#newResponse(JSON.stringify(object), arg, setDefaultContentType("application/json", headers));
2596
+ };
2597
+ html = (html, arg, headers) => {
2598
+ const res = (html2) => this.#newResponse(html2, arg, setDefaultContentType("text/html; charset=UTF-8", headers));
2599
+ return typeof html === "object" ? resolveCallback(html, HtmlEscapedCallbackPhase.Stringify, false, {}).then(res) : res(html);
2600
+ };
2601
+ redirect = (location, status) => {
2602
+ const locationString = String(location);
2603
+ this.header("Location", !/[^\x00-\xFF]/.test(locationString) ? locationString : encodeURI(locationString));
2604
+ return this.newResponse(null, status ?? 302);
2605
+ };
2606
+ notFound = () => {
2607
+ this.#notFoundHandler ??= () => createResponseInstance();
2608
+ return this.#notFoundHandler(this);
2609
+ };
2610
+ };
2611
+
2612
+ // ../../node_modules/.bun/hono@4.12.3/node_modules/hono/dist/router.js
2613
+ var METHOD_NAME_ALL = "ALL";
2614
+ var METHOD_NAME_ALL_LOWERCASE = "all";
2615
+ var METHODS = ["get", "post", "put", "delete", "options", "patch"];
2616
+ var MESSAGE_MATCHER_IS_ALREADY_BUILT = "Can not add a route since the matcher is already built.";
2617
+ var UnsupportedPathError = class extends Error {
2618
+ };
2619
+
2620
+ // ../../node_modules/.bun/hono@4.12.3/node_modules/hono/dist/utils/constants.js
2621
+ var COMPOSED_HANDLER = "__COMPOSED_HANDLER";
2622
+
2623
+ // ../../node_modules/.bun/hono@4.12.3/node_modules/hono/dist/hono-base.js
2624
+ var notFoundHandler = (c) => {
2625
+ return c.text("404 Not Found", 404);
2626
+ };
2627
+ var errorHandler = (err2, c) => {
2628
+ if ("getResponse" in err2) {
2629
+ const res = err2.getResponse();
2630
+ return c.newResponse(res.body, res);
2631
+ }
2632
+ console.error(err2);
2633
+ return c.text("Internal Server Error", 500);
2634
+ };
2635
+ var Hono = class _Hono {
2636
+ get;
2637
+ post;
2638
+ put;
2639
+ delete;
2640
+ options;
2641
+ patch;
2642
+ all;
2643
+ on;
2644
+ use;
2645
+ router;
2646
+ getPath;
2647
+ _basePath = "/";
2648
+ #path = "/";
2649
+ routes = [];
2650
+ constructor(options = {}) {
2651
+ const allMethods = [...METHODS, METHOD_NAME_ALL_LOWERCASE];
2652
+ allMethods.forEach((method) => {
2653
+ this[method] = (args1, ...args) => {
2654
+ if (typeof args1 === "string") {
2655
+ this.#path = args1;
2656
+ } else {
2657
+ this.#addRoute(method, this.#path, args1);
2658
+ }
2659
+ args.forEach((handler) => {
2660
+ this.#addRoute(method, this.#path, handler);
2661
+ });
2662
+ return this;
2663
+ };
2664
+ });
2665
+ this.on = (method, path, ...handlers) => {
2666
+ for (const p of [path].flat()) {
2667
+ this.#path = p;
2668
+ for (const m of [method].flat()) {
2669
+ handlers.map((handler) => {
2670
+ this.#addRoute(m.toUpperCase(), this.#path, handler);
2671
+ });
2672
+ }
2673
+ }
2674
+ return this;
2675
+ };
2676
+ this.use = (arg1, ...handlers) => {
2677
+ if (typeof arg1 === "string") {
2678
+ this.#path = arg1;
2679
+ } else {
2680
+ this.#path = "*";
2681
+ handlers.unshift(arg1);
2682
+ }
2683
+ handlers.forEach((handler) => {
2684
+ this.#addRoute(METHOD_NAME_ALL, this.#path, handler);
2685
+ });
2686
+ return this;
2687
+ };
2688
+ const { strict, ...optionsWithoutStrict } = options;
2689
+ Object.assign(this, optionsWithoutStrict);
2690
+ this.getPath = strict ?? true ? options.getPath ?? getPath : getPathNoStrict;
2691
+ }
2692
+ #clone() {
2693
+ const clone = new _Hono({
2694
+ router: this.router,
2695
+ getPath: this.getPath
2696
+ });
2697
+ clone.errorHandler = this.errorHandler;
2698
+ clone.#notFoundHandler = this.#notFoundHandler;
2699
+ clone.routes = this.routes;
2700
+ return clone;
2701
+ }
2702
+ #notFoundHandler = notFoundHandler;
2703
+ errorHandler = errorHandler;
2704
+ route(path, app) {
2705
+ const subApp = this.basePath(path);
2706
+ app.routes.map((r) => {
2707
+ let handler;
2708
+ if (app.errorHandler === errorHandler) {
2709
+ handler = r.handler;
2710
+ } else {
2711
+ handler = async (c, next) => (await compose([], app.errorHandler)(c, () => r.handler(c, next))).res;
2712
+ handler[COMPOSED_HANDLER] = r.handler;
2713
+ }
2714
+ subApp.#addRoute(r.method, r.path, handler);
2715
+ });
2716
+ return this;
2717
+ }
2718
+ basePath(path) {
2719
+ const subApp = this.#clone();
2720
+ subApp._basePath = mergePath(this._basePath, path);
2721
+ return subApp;
2722
+ }
2723
+ onError = (handler) => {
2724
+ this.errorHandler = handler;
2725
+ return this;
2726
+ };
2727
+ notFound = (handler) => {
2728
+ this.#notFoundHandler = handler;
2729
+ return this;
2730
+ };
2731
+ mount(path, applicationHandler, options) {
2732
+ let replaceRequest;
2733
+ let optionHandler;
2734
+ if (options) {
2735
+ if (typeof options === "function") {
2736
+ optionHandler = options;
2737
+ } else {
2738
+ optionHandler = options.optionHandler;
2739
+ if (options.replaceRequest === false) {
2740
+ replaceRequest = (request) => request;
2741
+ } else {
2742
+ replaceRequest = options.replaceRequest;
2743
+ }
2744
+ }
2745
+ }
2746
+ const getOptions = optionHandler ? (c) => {
2747
+ const options2 = optionHandler(c);
2748
+ return Array.isArray(options2) ? options2 : [options2];
2749
+ } : (c) => {
2750
+ let executionContext = undefined;
2751
+ try {
2752
+ executionContext = c.executionCtx;
2753
+ } catch {}
2754
+ return [c.env, executionContext];
2755
+ };
2756
+ replaceRequest ||= (() => {
2757
+ const mergedPath = mergePath(this._basePath, path);
2758
+ const pathPrefixLength = mergedPath === "/" ? 0 : mergedPath.length;
2759
+ return (request) => {
2760
+ const url = new URL(request.url);
2761
+ url.pathname = url.pathname.slice(pathPrefixLength) || "/";
2762
+ return new Request(url, request);
2763
+ };
2764
+ })();
2765
+ const handler = async (c, next) => {
2766
+ const res = await applicationHandler(replaceRequest(c.req.raw), ...getOptions(c));
2767
+ if (res) {
2768
+ return res;
2769
+ }
2770
+ await next();
2771
+ };
2772
+ this.#addRoute(METHOD_NAME_ALL, mergePath(path, "*"), handler);
2773
+ return this;
2774
+ }
2775
+ #addRoute(method, path, handler) {
2776
+ method = method.toUpperCase();
2777
+ path = mergePath(this._basePath, path);
2778
+ const r = { basePath: this._basePath, path, method, handler };
2779
+ this.router.add(method, path, [handler, r]);
2780
+ this.routes.push(r);
2781
+ }
2782
+ #handleError(err2, c) {
2783
+ if (err2 instanceof Error) {
2784
+ return this.errorHandler(err2, c);
2785
+ }
2786
+ throw err2;
2787
+ }
2788
+ #dispatch(request, executionCtx, env2, method) {
2789
+ if (method === "HEAD") {
2790
+ return (async () => new Response(null, await this.#dispatch(request, executionCtx, env2, "GET")))();
2791
+ }
2792
+ const path = this.getPath(request, { env: env2 });
2793
+ const matchResult = this.router.match(method, path);
2794
+ const c = new Context(request, {
2795
+ path,
2796
+ matchResult,
2797
+ env: env2,
2798
+ executionCtx,
2799
+ notFoundHandler: this.#notFoundHandler
2800
+ });
2801
+ if (matchResult[0].length === 1) {
2802
+ let res;
2803
+ try {
2804
+ res = matchResult[0][0][0][0](c, async () => {
2805
+ c.res = await this.#notFoundHandler(c);
2806
+ });
2807
+ } catch (err2) {
2808
+ return this.#handleError(err2, c);
2809
+ }
2810
+ return res instanceof Promise ? res.then((resolved) => resolved || (c.finalized ? c.res : this.#notFoundHandler(c))).catch((err2) => this.#handleError(err2, c)) : res ?? this.#notFoundHandler(c);
2811
+ }
2812
+ const composed = compose(matchResult[0], this.errorHandler, this.#notFoundHandler);
2813
+ return (async () => {
2814
+ try {
2815
+ const context = await composed(c);
2816
+ if (!context.finalized) {
2817
+ throw new Error("Context is not finalized. Did you forget to return a Response object or `await next()`?");
2818
+ }
2819
+ return context.res;
2820
+ } catch (err2) {
2821
+ return this.#handleError(err2, c);
2822
+ }
2823
+ })();
2824
+ }
2825
+ fetch = (request, ...rest) => {
2826
+ return this.#dispatch(request, rest[1], rest[0], request.method);
2827
+ };
2828
+ request = (input, requestInit, Env, executionCtx) => {
2829
+ if (input instanceof Request) {
2830
+ return this.fetch(requestInit ? new Request(input, requestInit) : input, Env, executionCtx);
2831
+ }
2832
+ input = input.toString();
2833
+ return this.fetch(new Request(/^https?:\/\//.test(input) ? input : `http://localhost${mergePath("/", input)}`, requestInit), Env, executionCtx);
2834
+ };
2835
+ fire = () => {
2836
+ addEventListener("fetch", (event) => {
2837
+ event.respondWith(this.#dispatch(event.request, event, undefined, event.request.method));
2838
+ });
2839
+ };
2840
+ };
2841
+
2842
+ // ../../node_modules/.bun/hono@4.12.3/node_modules/hono/dist/router/reg-exp-router/matcher.js
2843
+ var emptyParam = [];
2844
+ function match(method, path) {
2845
+ const matchers = this.buildAllMatchers();
2846
+ const match2 = (method2, path2) => {
2847
+ const matcher = matchers[method2] || matchers[METHOD_NAME_ALL];
2848
+ const staticMatch = matcher[2][path2];
2849
+ if (staticMatch) {
2850
+ return staticMatch;
2851
+ }
2852
+ const match3 = path2.match(matcher[0]);
2853
+ if (!match3) {
2854
+ return [[], emptyParam];
2855
+ }
2856
+ const index = match3.indexOf("", 1);
2857
+ return [matcher[1][index], match3];
2858
+ };
2859
+ this.match = match2;
2860
+ return match2(method, path);
2861
+ }
2862
+
2863
+ // ../../node_modules/.bun/hono@4.12.3/node_modules/hono/dist/router/reg-exp-router/node.js
2864
+ var LABEL_REG_EXP_STR = "[^/]+";
2865
+ var ONLY_WILDCARD_REG_EXP_STR = ".*";
2866
+ var TAIL_WILDCARD_REG_EXP_STR = "(?:|/.*)";
2867
+ var PATH_ERROR = /* @__PURE__ */ Symbol();
2868
+ var regExpMetaChars = new Set(".\\+*[^]$()");
2869
+ function compareKey(a, b) {
2870
+ if (a.length === 1) {
2871
+ return b.length === 1 ? a < b ? -1 : 1 : -1;
2872
+ }
2873
+ if (b.length === 1) {
2874
+ return 1;
2875
+ }
2876
+ if (a === ONLY_WILDCARD_REG_EXP_STR || a === TAIL_WILDCARD_REG_EXP_STR) {
2877
+ return 1;
2878
+ } else if (b === ONLY_WILDCARD_REG_EXP_STR || b === TAIL_WILDCARD_REG_EXP_STR) {
2879
+ return -1;
2880
+ }
2881
+ if (a === LABEL_REG_EXP_STR) {
2882
+ return 1;
2883
+ } else if (b === LABEL_REG_EXP_STR) {
2884
+ return -1;
2885
+ }
2886
+ return a.length === b.length ? a < b ? -1 : 1 : b.length - a.length;
2887
+ }
2888
+ var Node = class _Node {
2889
+ #index;
2890
+ #varIndex;
2891
+ #children = /* @__PURE__ */ Object.create(null);
2892
+ insert(tokens, index, paramMap, context, pathErrorCheckOnly) {
2893
+ if (tokens.length === 0) {
2894
+ if (this.#index !== undefined) {
2895
+ throw PATH_ERROR;
2896
+ }
2897
+ if (pathErrorCheckOnly) {
2898
+ return;
2899
+ }
2900
+ this.#index = index;
2901
+ return;
2902
+ }
2903
+ const [token, ...restTokens] = tokens;
2904
+ const pattern = token === "*" ? restTokens.length === 0 ? ["", "", ONLY_WILDCARD_REG_EXP_STR] : ["", "", LABEL_REG_EXP_STR] : token === "/*" ? ["", "", TAIL_WILDCARD_REG_EXP_STR] : token.match(/^\:([^\{\}]+)(?:\{(.+)\})?$/);
2905
+ let node;
2906
+ if (pattern) {
2907
+ const name = pattern[1];
2908
+ let regexpStr = pattern[2] || LABEL_REG_EXP_STR;
2909
+ if (name && pattern[2]) {
2910
+ if (regexpStr === ".*") {
2911
+ throw PATH_ERROR;
2912
+ }
2913
+ regexpStr = regexpStr.replace(/^\((?!\?:)(?=[^)]+\)$)/, "(?:");
2914
+ if (/\((?!\?:)/.test(regexpStr)) {
2915
+ throw PATH_ERROR;
2916
+ }
2917
+ }
2918
+ node = this.#children[regexpStr];
2919
+ if (!node) {
2920
+ if (Object.keys(this.#children).some((k) => k !== ONLY_WILDCARD_REG_EXP_STR && k !== TAIL_WILDCARD_REG_EXP_STR)) {
2921
+ throw PATH_ERROR;
2922
+ }
2923
+ if (pathErrorCheckOnly) {
2924
+ return;
2925
+ }
2926
+ node = this.#children[regexpStr] = new _Node;
2927
+ if (name !== "") {
2928
+ node.#varIndex = context.varIndex++;
2929
+ }
2930
+ }
2931
+ if (!pathErrorCheckOnly && name !== "") {
2932
+ paramMap.push([name, node.#varIndex]);
2933
+ }
2934
+ } else {
2935
+ node = this.#children[token];
2936
+ if (!node) {
2937
+ if (Object.keys(this.#children).some((k) => k.length > 1 && k !== ONLY_WILDCARD_REG_EXP_STR && k !== TAIL_WILDCARD_REG_EXP_STR)) {
2938
+ throw PATH_ERROR;
2939
+ }
2940
+ if (pathErrorCheckOnly) {
2941
+ return;
2942
+ }
2943
+ node = this.#children[token] = new _Node;
2944
+ }
2945
+ }
2946
+ node.insert(restTokens, index, paramMap, context, pathErrorCheckOnly);
2947
+ }
2948
+ buildRegExpStr() {
2949
+ const childKeys = Object.keys(this.#children).sort(compareKey);
2950
+ const strList = childKeys.map((k) => {
2951
+ const c = this.#children[k];
2952
+ return (typeof c.#varIndex === "number" ? `(${k})@${c.#varIndex}` : regExpMetaChars.has(k) ? `\\${k}` : k) + c.buildRegExpStr();
2953
+ });
2954
+ if (typeof this.#index === "number") {
2955
+ strList.unshift(`#${this.#index}`);
2956
+ }
2957
+ if (strList.length === 0) {
2958
+ return "";
2959
+ }
2960
+ if (strList.length === 1) {
2961
+ return strList[0];
2962
+ }
2963
+ return "(?:" + strList.join("|") + ")";
2964
+ }
2965
+ };
2966
+
2967
+ // ../../node_modules/.bun/hono@4.12.3/node_modules/hono/dist/router/reg-exp-router/trie.js
2968
+ var Trie = class {
2969
+ #context = { varIndex: 0 };
2970
+ #root = new Node;
2971
+ insert(path, index, pathErrorCheckOnly) {
2972
+ const paramAssoc = [];
2973
+ const groups = [];
2974
+ for (let i = 0;; ) {
2975
+ let replaced = false;
2976
+ path = path.replace(/\{[^}]+\}/g, (m) => {
2977
+ const mark = `@\\${i}`;
2978
+ groups[i] = [mark, m];
2979
+ i++;
2980
+ replaced = true;
2981
+ return mark;
2982
+ });
2983
+ if (!replaced) {
2984
+ break;
2985
+ }
2986
+ }
2987
+ const tokens = path.match(/(?::[^\/]+)|(?:\/\*$)|./g) || [];
2988
+ for (let i = groups.length - 1;i >= 0; i--) {
2989
+ const [mark] = groups[i];
2990
+ for (let j = tokens.length - 1;j >= 0; j--) {
2991
+ if (tokens[j].indexOf(mark) !== -1) {
2992
+ tokens[j] = tokens[j].replace(mark, groups[i][1]);
2993
+ break;
2994
+ }
2995
+ }
2996
+ }
2997
+ this.#root.insert(tokens, index, paramAssoc, this.#context, pathErrorCheckOnly);
2998
+ return paramAssoc;
2999
+ }
3000
+ buildRegExp() {
3001
+ let regexp = this.#root.buildRegExpStr();
3002
+ if (regexp === "") {
3003
+ return [/^$/, [], []];
3004
+ }
3005
+ let captureIndex = 0;
3006
+ const indexReplacementMap = [];
3007
+ const paramReplacementMap = [];
3008
+ regexp = regexp.replace(/#(\d+)|@(\d+)|\.\*\$/g, (_, handlerIndex, paramIndex) => {
3009
+ if (handlerIndex !== undefined) {
3010
+ indexReplacementMap[++captureIndex] = Number(handlerIndex);
3011
+ return "$()";
3012
+ }
3013
+ if (paramIndex !== undefined) {
3014
+ paramReplacementMap[Number(paramIndex)] = ++captureIndex;
3015
+ return "";
3016
+ }
3017
+ return "";
3018
+ });
3019
+ return [new RegExp(`^${regexp}`), indexReplacementMap, paramReplacementMap];
3020
+ }
3021
+ };
3022
+
3023
+ // ../../node_modules/.bun/hono@4.12.3/node_modules/hono/dist/router/reg-exp-router/router.js
3024
+ var nullMatcher = [/^$/, [], /* @__PURE__ */ Object.create(null)];
3025
+ var wildcardRegExpCache = /* @__PURE__ */ Object.create(null);
3026
+ function buildWildcardRegExp(path) {
3027
+ return wildcardRegExpCache[path] ??= new RegExp(path === "*" ? "" : `^${path.replace(/\/\*$|([.\\+*[^\]$()])/g, (_, metaChar) => metaChar ? `\\${metaChar}` : "(?:|/.*)")}$`);
3028
+ }
3029
+ function clearWildcardRegExpCache() {
3030
+ wildcardRegExpCache = /* @__PURE__ */ Object.create(null);
3031
+ }
3032
+ function buildMatcherFromPreprocessedRoutes(routes) {
3033
+ const trie = new Trie;
3034
+ const handlerData = [];
3035
+ if (routes.length === 0) {
3036
+ return nullMatcher;
3037
+ }
3038
+ const routesWithStaticPathFlag = routes.map((route) => [!/\*|\/:/.test(route[0]), ...route]).sort(([isStaticA, pathA], [isStaticB, pathB]) => isStaticA ? 1 : isStaticB ? -1 : pathA.length - pathB.length);
3039
+ const staticMap = /* @__PURE__ */ Object.create(null);
3040
+ for (let i = 0, j = -1, len = routesWithStaticPathFlag.length;i < len; i++) {
3041
+ const [pathErrorCheckOnly, path, handlers] = routesWithStaticPathFlag[i];
3042
+ if (pathErrorCheckOnly) {
3043
+ staticMap[path] = [handlers.map(([h]) => [h, /* @__PURE__ */ Object.create(null)]), emptyParam];
3044
+ } else {
3045
+ j++;
3046
+ }
3047
+ let paramAssoc;
3048
+ try {
3049
+ paramAssoc = trie.insert(path, j, pathErrorCheckOnly);
3050
+ } catch (e) {
3051
+ throw e === PATH_ERROR ? new UnsupportedPathError(path) : e;
3052
+ }
3053
+ if (pathErrorCheckOnly) {
3054
+ continue;
3055
+ }
3056
+ handlerData[j] = handlers.map(([h, paramCount]) => {
3057
+ const paramIndexMap = /* @__PURE__ */ Object.create(null);
3058
+ paramCount -= 1;
3059
+ for (;paramCount >= 0; paramCount--) {
3060
+ const [key, value] = paramAssoc[paramCount];
3061
+ paramIndexMap[key] = value;
3062
+ }
3063
+ return [h, paramIndexMap];
3064
+ });
3065
+ }
3066
+ const [regexp, indexReplacementMap, paramReplacementMap] = trie.buildRegExp();
3067
+ for (let i = 0, len = handlerData.length;i < len; i++) {
3068
+ for (let j = 0, len2 = handlerData[i].length;j < len2; j++) {
3069
+ const map = handlerData[i][j]?.[1];
3070
+ if (!map) {
3071
+ continue;
3072
+ }
3073
+ const keys = Object.keys(map);
3074
+ for (let k = 0, len3 = keys.length;k < len3; k++) {
3075
+ map[keys[k]] = paramReplacementMap[map[keys[k]]];
3076
+ }
3077
+ }
3078
+ }
3079
+ const handlerMap = [];
3080
+ for (const i in indexReplacementMap) {
3081
+ handlerMap[i] = handlerData[indexReplacementMap[i]];
3082
+ }
3083
+ return [regexp, handlerMap, staticMap];
3084
+ }
3085
+ function findMiddleware(middleware, path) {
3086
+ if (!middleware) {
3087
+ return;
3088
+ }
3089
+ for (const k of Object.keys(middleware).sort((a, b) => b.length - a.length)) {
3090
+ if (buildWildcardRegExp(k).test(path)) {
3091
+ return [...middleware[k]];
3092
+ }
3093
+ }
3094
+ return;
3095
+ }
3096
+ var RegExpRouter = class {
3097
+ name = "RegExpRouter";
3098
+ #middleware;
3099
+ #routes;
3100
+ constructor() {
3101
+ this.#middleware = { [METHOD_NAME_ALL]: /* @__PURE__ */ Object.create(null) };
3102
+ this.#routes = { [METHOD_NAME_ALL]: /* @__PURE__ */ Object.create(null) };
3103
+ }
3104
+ add(method, path, handler) {
3105
+ const middleware = this.#middleware;
3106
+ const routes = this.#routes;
3107
+ if (!middleware || !routes) {
3108
+ throw new Error(MESSAGE_MATCHER_IS_ALREADY_BUILT);
3109
+ }
3110
+ if (!middleware[method]) {
3111
+ [middleware, routes].forEach((handlerMap) => {
3112
+ handlerMap[method] = /* @__PURE__ */ Object.create(null);
3113
+ Object.keys(handlerMap[METHOD_NAME_ALL]).forEach((p) => {
3114
+ handlerMap[method][p] = [...handlerMap[METHOD_NAME_ALL][p]];
3115
+ });
3116
+ });
3117
+ }
3118
+ if (path === "/*") {
3119
+ path = "*";
3120
+ }
3121
+ const paramCount = (path.match(/\/:/g) || []).length;
3122
+ if (/\*$/.test(path)) {
3123
+ const re = buildWildcardRegExp(path);
3124
+ if (method === METHOD_NAME_ALL) {
3125
+ Object.keys(middleware).forEach((m) => {
3126
+ middleware[m][path] ||= findMiddleware(middleware[m], path) || findMiddleware(middleware[METHOD_NAME_ALL], path) || [];
3127
+ });
3128
+ } else {
3129
+ middleware[method][path] ||= findMiddleware(middleware[method], path) || findMiddleware(middleware[METHOD_NAME_ALL], path) || [];
3130
+ }
3131
+ Object.keys(middleware).forEach((m) => {
3132
+ if (method === METHOD_NAME_ALL || method === m) {
3133
+ Object.keys(middleware[m]).forEach((p) => {
3134
+ re.test(p) && middleware[m][p].push([handler, paramCount]);
3135
+ });
3136
+ }
3137
+ });
3138
+ Object.keys(routes).forEach((m) => {
3139
+ if (method === METHOD_NAME_ALL || method === m) {
3140
+ Object.keys(routes[m]).forEach((p) => re.test(p) && routes[m][p].push([handler, paramCount]));
3141
+ }
3142
+ });
3143
+ return;
3144
+ }
3145
+ const paths = checkOptionalParameter(path) || [path];
3146
+ for (let i = 0, len = paths.length;i < len; i++) {
3147
+ const path2 = paths[i];
3148
+ Object.keys(routes).forEach((m) => {
3149
+ if (method === METHOD_NAME_ALL || method === m) {
3150
+ routes[m][path2] ||= [
3151
+ ...findMiddleware(middleware[m], path2) || findMiddleware(middleware[METHOD_NAME_ALL], path2) || []
3152
+ ];
3153
+ routes[m][path2].push([handler, paramCount - len + i + 1]);
3154
+ }
3155
+ });
3156
+ }
3157
+ }
3158
+ match = match;
3159
+ buildAllMatchers() {
3160
+ const matchers = /* @__PURE__ */ Object.create(null);
3161
+ Object.keys(this.#routes).concat(Object.keys(this.#middleware)).forEach((method) => {
3162
+ matchers[method] ||= this.#buildMatcher(method);
3163
+ });
3164
+ this.#middleware = this.#routes = undefined;
3165
+ clearWildcardRegExpCache();
3166
+ return matchers;
3167
+ }
3168
+ #buildMatcher(method) {
3169
+ const routes = [];
3170
+ let hasOwnRoute = method === METHOD_NAME_ALL;
3171
+ [this.#middleware, this.#routes].forEach((r) => {
3172
+ const ownRoute = r[method] ? Object.keys(r[method]).map((path) => [path, r[method][path]]) : [];
3173
+ if (ownRoute.length !== 0) {
3174
+ hasOwnRoute ||= true;
3175
+ routes.push(...ownRoute);
3176
+ } else if (method !== METHOD_NAME_ALL) {
3177
+ routes.push(...Object.keys(r[METHOD_NAME_ALL]).map((path) => [path, r[METHOD_NAME_ALL][path]]));
3178
+ }
3179
+ });
3180
+ if (!hasOwnRoute) {
3181
+ return null;
3182
+ } else {
3183
+ return buildMatcherFromPreprocessedRoutes(routes);
3184
+ }
3185
+ }
3186
+ };
3187
+
3188
+ // ../../node_modules/.bun/hono@4.12.3/node_modules/hono/dist/router/reg-exp-router/prepared-router.js
3189
+ var PreparedRegExpRouter = class {
3190
+ name = "PreparedRegExpRouter";
3191
+ #matchers;
3192
+ #relocateMap;
3193
+ constructor(matchers, relocateMap) {
3194
+ this.#matchers = matchers;
3195
+ this.#relocateMap = relocateMap;
3196
+ }
3197
+ #addWildcard(method, handlerData) {
3198
+ const matcher = this.#matchers[method];
3199
+ matcher[1].forEach((list) => list && list.push(handlerData));
3200
+ Object.values(matcher[2]).forEach((list) => list[0].push(handlerData));
3201
+ }
3202
+ #addPath(method, path, handler, indexes, map) {
3203
+ const matcher = this.#matchers[method];
3204
+ if (!map) {
3205
+ matcher[2][path][0].push([handler, {}]);
3206
+ } else {
3207
+ indexes.forEach((index) => {
3208
+ if (typeof index === "number") {
3209
+ matcher[1][index].push([handler, map]);
3210
+ } else {
3211
+ matcher[2][index || path][0].push([handler, map]);
3212
+ }
3213
+ });
3214
+ }
3215
+ }
3216
+ add(method, path, handler) {
3217
+ if (!this.#matchers[method]) {
3218
+ const all = this.#matchers[METHOD_NAME_ALL];
3219
+ const staticMap = {};
3220
+ for (const key in all[2]) {
3221
+ staticMap[key] = [all[2][key][0].slice(), emptyParam];
3222
+ }
3223
+ this.#matchers[method] = [
3224
+ all[0],
3225
+ all[1].map((list) => Array.isArray(list) ? list.slice() : 0),
3226
+ staticMap
3227
+ ];
3228
+ }
3229
+ if (path === "/*" || path === "*") {
3230
+ const handlerData = [handler, {}];
3231
+ if (method === METHOD_NAME_ALL) {
3232
+ for (const m in this.#matchers) {
3233
+ this.#addWildcard(m, handlerData);
3234
+ }
3235
+ } else {
3236
+ this.#addWildcard(method, handlerData);
3237
+ }
3238
+ return;
3239
+ }
3240
+ const data = this.#relocateMap[path];
3241
+ if (!data) {
3242
+ throw new Error(`Path ${path} is not registered`);
3243
+ }
3244
+ for (const [indexes, map] of data) {
3245
+ if (method === METHOD_NAME_ALL) {
3246
+ for (const m in this.#matchers) {
3247
+ this.#addPath(m, path, handler, indexes, map);
3248
+ }
3249
+ } else {
3250
+ this.#addPath(method, path, handler, indexes, map);
3251
+ }
3252
+ }
3253
+ }
3254
+ buildAllMatchers() {
3255
+ return this.#matchers;
3256
+ }
3257
+ match = match;
3258
+ };
3259
+
3260
+ // ../../node_modules/.bun/hono@4.12.3/node_modules/hono/dist/router/smart-router/router.js
3261
+ var SmartRouter = class {
3262
+ name = "SmartRouter";
3263
+ #routers = [];
3264
+ #routes = [];
3265
+ constructor(init) {
3266
+ this.#routers = init.routers;
3267
+ }
3268
+ add(method, path, handler) {
3269
+ if (!this.#routes) {
3270
+ throw new Error(MESSAGE_MATCHER_IS_ALREADY_BUILT);
3271
+ }
3272
+ this.#routes.push([method, path, handler]);
3273
+ }
3274
+ match(method, path) {
3275
+ if (!this.#routes) {
3276
+ throw new Error("Fatal error");
3277
+ }
3278
+ const routers = this.#routers;
3279
+ const routes = this.#routes;
3280
+ const len = routers.length;
3281
+ let i = 0;
3282
+ let res;
3283
+ for (;i < len; i++) {
3284
+ const router = routers[i];
3285
+ try {
3286
+ for (let i2 = 0, len2 = routes.length;i2 < len2; i2++) {
3287
+ router.add(...routes[i2]);
3288
+ }
3289
+ res = router.match(method, path);
3290
+ } catch (e) {
3291
+ if (e instanceof UnsupportedPathError) {
3292
+ continue;
3293
+ }
3294
+ throw e;
3295
+ }
3296
+ this.match = router.match.bind(router);
3297
+ this.#routers = [router];
3298
+ this.#routes = undefined;
3299
+ break;
3300
+ }
3301
+ if (i === len) {
3302
+ throw new Error("Fatal error");
3303
+ }
3304
+ this.name = `SmartRouter + ${this.activeRouter.name}`;
3305
+ return res;
3306
+ }
3307
+ get activeRouter() {
3308
+ if (this.#routes || this.#routers.length !== 1) {
3309
+ throw new Error("No active router has been determined yet.");
3310
+ }
3311
+ return this.#routers[0];
3312
+ }
3313
+ };
3314
+
3315
+ // ../../node_modules/.bun/hono@4.12.3/node_modules/hono/dist/router/trie-router/node.js
3316
+ var emptyParams = /* @__PURE__ */ Object.create(null);
3317
+ var hasChildren = (children) => {
3318
+ for (const _ in children) {
3319
+ return true;
3320
+ }
3321
+ return false;
3322
+ };
3323
+ var Node2 = class _Node2 {
3324
+ #methods;
3325
+ #children;
3326
+ #patterns;
3327
+ #order = 0;
3328
+ #params = emptyParams;
3329
+ constructor(method, handler, children) {
3330
+ this.#children = children || /* @__PURE__ */ Object.create(null);
3331
+ this.#methods = [];
3332
+ if (method && handler) {
3333
+ const m = /* @__PURE__ */ Object.create(null);
3334
+ m[method] = { handler, possibleKeys: [], score: 0 };
3335
+ this.#methods = [m];
3336
+ }
3337
+ this.#patterns = [];
3338
+ }
3339
+ insert(method, path, handler) {
3340
+ this.#order = ++this.#order;
3341
+ let curNode = this;
3342
+ const parts = splitRoutingPath(path);
3343
+ const possibleKeys = [];
3344
+ for (let i = 0, len = parts.length;i < len; i++) {
3345
+ const p = parts[i];
3346
+ const nextP = parts[i + 1];
3347
+ const pattern = getPattern(p, nextP);
3348
+ const key = Array.isArray(pattern) ? pattern[0] : p;
3349
+ if (key in curNode.#children) {
3350
+ curNode = curNode.#children[key];
3351
+ if (pattern) {
3352
+ possibleKeys.push(pattern[1]);
3353
+ }
3354
+ continue;
3355
+ }
3356
+ curNode.#children[key] = new _Node2;
3357
+ if (pattern) {
3358
+ curNode.#patterns.push(pattern);
3359
+ possibleKeys.push(pattern[1]);
3360
+ }
3361
+ curNode = curNode.#children[key];
3362
+ }
3363
+ curNode.#methods.push({
3364
+ [method]: {
3365
+ handler,
3366
+ possibleKeys: possibleKeys.filter((v, i, a) => a.indexOf(v) === i),
3367
+ score: this.#order
3368
+ }
3369
+ });
3370
+ return curNode;
3371
+ }
3372
+ #pushHandlerSets(handlerSets, node, method, nodeParams, params) {
3373
+ for (let i = 0, len = node.#methods.length;i < len; i++) {
3374
+ const m = node.#methods[i];
3375
+ const handlerSet = m[method] || m[METHOD_NAME_ALL];
3376
+ const processedSet = {};
3377
+ if (handlerSet !== undefined) {
3378
+ handlerSet.params = /* @__PURE__ */ Object.create(null);
3379
+ handlerSets.push(handlerSet);
3380
+ if (nodeParams !== emptyParams || params && params !== emptyParams) {
3381
+ for (let i2 = 0, len2 = handlerSet.possibleKeys.length;i2 < len2; i2++) {
3382
+ const key = handlerSet.possibleKeys[i2];
3383
+ const processed = processedSet[handlerSet.score];
3384
+ handlerSet.params[key] = params?.[key] && !processed ? params[key] : nodeParams[key] ?? params?.[key];
3385
+ processedSet[handlerSet.score] = true;
3386
+ }
3387
+ }
3388
+ }
3389
+ }
3390
+ }
3391
+ search(method, path) {
3392
+ const handlerSets = [];
3393
+ this.#params = emptyParams;
3394
+ const curNode = this;
3395
+ let curNodes = [curNode];
3396
+ const parts = splitPath(path);
3397
+ const curNodesQueue = [];
3398
+ const len = parts.length;
3399
+ let partOffsets = null;
3400
+ for (let i = 0;i < len; i++) {
3401
+ const part = parts[i];
3402
+ const isLast = i === len - 1;
3403
+ const tempNodes = [];
3404
+ for (let j = 0, len2 = curNodes.length;j < len2; j++) {
3405
+ const node = curNodes[j];
3406
+ const nextNode = node.#children[part];
3407
+ if (nextNode) {
3408
+ nextNode.#params = node.#params;
3409
+ if (isLast) {
3410
+ if (nextNode.#children["*"]) {
3411
+ this.#pushHandlerSets(handlerSets, nextNode.#children["*"], method, node.#params);
3412
+ }
3413
+ this.#pushHandlerSets(handlerSets, nextNode, method, node.#params);
3414
+ } else {
3415
+ tempNodes.push(nextNode);
3416
+ }
3417
+ }
3418
+ for (let k = 0, len3 = node.#patterns.length;k < len3; k++) {
3419
+ const pattern = node.#patterns[k];
3420
+ const params = node.#params === emptyParams ? {} : { ...node.#params };
3421
+ if (pattern === "*") {
3422
+ const astNode = node.#children["*"];
3423
+ if (astNode) {
3424
+ this.#pushHandlerSets(handlerSets, astNode, method, node.#params);
3425
+ astNode.#params = params;
3426
+ tempNodes.push(astNode);
3427
+ }
3428
+ continue;
3429
+ }
3430
+ const [key, name, matcher] = pattern;
3431
+ if (!part && !(matcher instanceof RegExp)) {
3432
+ continue;
3433
+ }
3434
+ const child = node.#children[key];
3435
+ if (matcher instanceof RegExp) {
3436
+ if (partOffsets === null) {
3437
+ partOffsets = new Array(len);
3438
+ let offset = path[0] === "/" ? 1 : 0;
3439
+ for (let p = 0;p < len; p++) {
3440
+ partOffsets[p] = offset;
3441
+ offset += parts[p].length + 1;
3442
+ }
3443
+ }
3444
+ const restPathString = path.substring(partOffsets[i]);
3445
+ const m = matcher.exec(restPathString);
3446
+ if (m) {
3447
+ params[name] = m[0];
3448
+ this.#pushHandlerSets(handlerSets, child, method, node.#params, params);
3449
+ if (hasChildren(child.#children)) {
3450
+ child.#params = params;
3451
+ const componentCount = m[0].match(/\//)?.length ?? 0;
3452
+ const targetCurNodes = curNodesQueue[componentCount] ||= [];
3453
+ targetCurNodes.push(child);
3454
+ }
3455
+ continue;
3456
+ }
3457
+ }
3458
+ if (matcher === true || matcher.test(part)) {
3459
+ params[name] = part;
3460
+ if (isLast) {
3461
+ this.#pushHandlerSets(handlerSets, child, method, params, node.#params);
3462
+ if (child.#children["*"]) {
3463
+ this.#pushHandlerSets(handlerSets, child.#children["*"], method, params, node.#params);
3464
+ }
3465
+ } else {
3466
+ child.#params = params;
3467
+ tempNodes.push(child);
3468
+ }
3469
+ }
3470
+ }
3471
+ }
3472
+ const shifted = curNodesQueue.shift();
3473
+ curNodes = shifted ? tempNodes.concat(shifted) : tempNodes;
3474
+ }
3475
+ if (handlerSets.length > 1) {
3476
+ handlerSets.sort((a, b) => {
3477
+ return a.score - b.score;
3478
+ });
3479
+ }
3480
+ return [handlerSets.map(({ handler, params }) => [handler, params])];
3481
+ }
3482
+ };
3483
+
3484
+ // ../../node_modules/.bun/hono@4.12.3/node_modules/hono/dist/router/trie-router/router.js
3485
+ var TrieRouter = class {
3486
+ name = "TrieRouter";
3487
+ #node;
3488
+ constructor() {
3489
+ this.#node = new Node2;
3490
+ }
3491
+ add(method, path, handler) {
3492
+ const results = checkOptionalParameter(path);
3493
+ if (results) {
3494
+ for (let i = 0, len = results.length;i < len; i++) {
3495
+ this.#node.insert(method, results[i], handler);
3496
+ }
3497
+ return;
3498
+ }
3499
+ this.#node.insert(method, path, handler);
3500
+ }
3501
+ match(method, path) {
3502
+ return this.#node.search(method, path);
3503
+ }
3504
+ };
3505
+
3506
+ // ../../node_modules/.bun/hono@4.12.3/node_modules/hono/dist/hono.js
3507
+ var Hono2 = class extends Hono {
3508
+ constructor(options = {}) {
3509
+ super(options);
3510
+ this.router = options.router ?? new SmartRouter({
3511
+ routers: [new RegExpRouter, new TrieRouter]
3512
+ });
3513
+ }
3514
+ };
3515
+
3516
+ // src/middleware.ts
3517
+ import { timingSafeEqual } from "crypto";
3518
+ function corsMiddleware(config = true) {
3519
+ const opts = typeof config === "boolean" ? { origin: [], methods: ["GET", "POST", "OPTIONS"] } : config;
3520
+ return async (c, next) => {
3521
+ const requestOrigin = c.req.header("Origin") ?? "";
3522
+ let allowedOrigin;
3523
+ if (Array.isArray(opts.origin)) {
3524
+ allowedOrigin = opts.origin.includes(requestOrigin) ? requestOrigin : "";
3525
+ } else {
3526
+ allowedOrigin = opts.origin ?? "";
3527
+ }
3528
+ if (allowedOrigin) {
3529
+ c.res.headers.set("Access-Control-Allow-Origin", allowedOrigin);
3530
+ c.res.headers.set("Vary", "Origin");
3531
+ }
3532
+ c.res.headers.set("Access-Control-Allow-Methods", (opts.methods ?? ["GET", "POST", "OPTIONS"]).join(", "));
3533
+ c.res.headers.set("Access-Control-Allow-Headers", (opts.headers ?? ["Content-Type", "Authorization"]).join(", "));
3534
+ if (opts.credentials) {
3535
+ c.res.headers.set("Access-Control-Allow-Credentials", "true");
3536
+ }
3537
+ if (c.req.method === "OPTIONS") {
3538
+ return c.body(null, 200);
3539
+ }
3540
+ await next();
3541
+ };
3542
+ }
3543
+ function authMiddleware(config) {
3544
+ return async (c, next) => {
3545
+ if (c.req.path === "/health") {
3546
+ return next();
3547
+ }
3548
+ const authorization = c.req.header("Authorization");
3549
+ if (!authorization) {
3550
+ return c.json({ error: "Missing Authorization header" }, 401);
3551
+ }
3552
+ if (config.type === "bearer") {
3553
+ const token = authorization.replace(/^Bearer\s+/, "");
3554
+ const expected = config.token;
3555
+ const tokenBuf = Buffer.from(token);
3556
+ const expectedBuf = Buffer.from(expected);
3557
+ if (tokenBuf.length !== expectedBuf.length || !timingSafeEqual(tokenBuf, expectedBuf)) {
3558
+ return c.json({ error: "Invalid token" }, 401);
3559
+ }
3560
+ }
3561
+ await next();
3562
+ };
3563
+ }
3564
+ function cleanupExpiredEntries(requests, now) {
3565
+ for (const [key, entry] of requests) {
3566
+ if (now > entry.resetTime)
3567
+ requests.delete(key);
3568
+ }
3569
+ }
3570
+ function rateLimitMiddleware(config) {
3571
+ const requests = new Map;
3572
+ return async (c, next) => {
3573
+ const clientId = c.req.header("CF-Connecting-IP") ?? c.req.header("X-Real-IP") ?? "anonymous";
3574
+ const now = Date.now();
3575
+ if (requests.size > 1e4) {
3576
+ cleanupExpiredEntries(requests, now);
3577
+ }
3578
+ if (requests.size > 1e5) {
3579
+ return c.json({ error: "Too many requests", retryAfterMs: config.windowMs }, 429);
3580
+ }
3581
+ let record = requests.get(clientId);
3582
+ if (!record || now > record.resetTime) {
3583
+ record = { count: 0, resetTime: now + config.windowMs };
3584
+ requests.set(clientId, record);
3585
+ }
3586
+ record.count++;
3587
+ c.res.headers.set("X-RateLimit-Limit", String(config.maxRequests));
3588
+ c.res.headers.set("X-RateLimit-Remaining", String(Math.max(0, config.maxRequests - record.count)));
3589
+ c.res.headers.set("X-RateLimit-Reset", String(Math.ceil(record.resetTime / 1000)));
3590
+ if (record.count > config.maxRequests) {
3591
+ return c.json({ error: "Too many requests", retryAfterMs: record.resetTime - now }, 429);
3592
+ }
3593
+ await next();
3594
+ };
3595
+ }
3596
+
3597
+ // src/routes.ts
3598
+ function createRoutes(deps) {
3599
+ const app = new Hono2;
3600
+ let totalRequests = 0;
3601
+ app.get("/health", (c) => {
3602
+ const response = {
3603
+ status: "ok",
3604
+ version: deps.version,
3605
+ uptime: Math.round((Date.now() - deps.startTime) / 1000),
3606
+ providers: deps.providers
3607
+ };
3608
+ return c.json(response);
3609
+ });
3610
+ app.get("/metrics", (c) => {
3611
+ const costReport = deps.tracer?.getCostReport();
3612
+ const byModel = {};
3613
+ if (costReport?.byModel) {
3614
+ for (const [model, data] of Object.entries(costReport.byModel)) {
3615
+ byModel[model] = {
3616
+ requests: data.calls,
3617
+ tokens: data.tokens,
3618
+ cost: data.cost
3619
+ };
3620
+ }
3621
+ }
3622
+ const response = {
3623
+ uptime: Math.round((Date.now() - deps.startTime) / 1000),
3624
+ totalRequests,
3625
+ totalTokens: costReport?.totalTokens ?? 0,
3626
+ totalCost: costReport?.totalCost ?? 0,
3627
+ byModel
3628
+ };
3629
+ return c.json(response);
3630
+ });
3631
+ app.post("/chat", async (c) => {
3632
+ totalRequests++;
3633
+ const MAX_BODY_SIZE = 1048576;
3634
+ const rawText = await c.req.text();
3635
+ if (rawText.length > MAX_BODY_SIZE) {
3636
+ return c.json({ error: "Request body too large (max 1MB)" }, 413);
3637
+ }
3638
+ const body = JSON.parse(rawText);
3639
+ if (!body.message) {
3640
+ return c.json({ error: "message is required" }, 400);
3641
+ }
3642
+ const agent = body.agent ? deps.agents.get(body.agent) : deps.defaultAgent;
3643
+ if (!agent) {
3644
+ return c.json({
3645
+ error: body.agent ? `Agent "${body.agent}" not found` : "No default agent configured"
3646
+ }, 404);
3647
+ }
3648
+ const result = await agent.run(body.message);
3649
+ deps.tracer?.trackLLMCall({
3650
+ model: "unknown",
3651
+ inputTokens: result.usage.totalInputTokens,
3652
+ outputTokens: result.usage.totalOutputTokens,
3653
+ cost: result.usage.totalCost,
3654
+ latencyMs: 0
3655
+ });
3656
+ const content = typeof result.message.content === "string" ? result.message.content : "";
3657
+ const response = {
3658
+ message: content,
3659
+ usage: {
3660
+ inputTokens: result.usage.totalInputTokens,
3661
+ outputTokens: result.usage.totalOutputTokens,
3662
+ totalTokens: result.usage.totalTokens,
3663
+ cost: result.usage.totalCost
3664
+ },
3665
+ model: agent.config.model ?? "default",
3666
+ traceId: result.traceId
3667
+ };
3668
+ return c.json(response);
3669
+ });
3670
+ app.post("/complete", async (c) => {
3671
+ totalRequests++;
3672
+ const MAX_BODY_SIZE = 1048576;
3673
+ const rawText = await c.req.text();
3674
+ if (rawText.length > MAX_BODY_SIZE) {
3675
+ return c.json({ error: "Request body too large (max 1MB)" }, 413);
3676
+ }
3677
+ const body = JSON.parse(rawText);
3678
+ if (!body.messages?.length) {
3679
+ return c.json({ error: "messages array is required" }, 400);
3680
+ }
3681
+ const messages = body.messages.map((m) => ({
3682
+ role: m.role,
3683
+ content: m.content
3684
+ }));
3685
+ const response = await deps.gateway.complete({
3686
+ messages,
3687
+ model: body.model,
3688
+ system: body.system,
3689
+ maxTokens: body.maxTokens,
3690
+ temperature: body.temperature
3691
+ });
3692
+ deps.tracer?.trackLLMCall({
3693
+ model: response.model,
3694
+ inputTokens: response.usage.inputTokens,
3695
+ outputTokens: response.usage.outputTokens,
3696
+ cost: response.cost.totalCost,
3697
+ latencyMs: response.latencyMs
3698
+ });
3699
+ return c.json({
3700
+ id: response.id,
3701
+ message: response.message.content,
3702
+ model: response.model,
3703
+ usage: response.usage,
3704
+ cost: response.cost,
3705
+ traceId: response.traceId
3706
+ });
3707
+ });
3708
+ app.get("/agents", (c) => {
3709
+ const agents = Array.from(deps.agents.entries()).map(([name, agent]) => ({
3710
+ name,
3711
+ model: agent.config.model ?? "default",
3712
+ tools: agent.config.tools?.map((t) => t.name) ?? []
3713
+ }));
3714
+ return c.json({ agents });
3715
+ });
3716
+ return app;
3717
+ }
3718
+
3719
+ // src/app.ts
3720
+ var log4 = createLogger();
3721
+ function createApp(config) {
3722
+ const app = new Hono2;
3723
+ const providerNames = Object.keys(config.gateway.providers);
3724
+ const primaryProvider = providerNames[0];
3725
+ const primaryConfig = config.gateway.providers[primaryProvider];
3726
+ const gw = gateway({
3727
+ provider: primaryProvider,
3728
+ model: config.gateway.defaultModel,
3729
+ apiKey: primaryConfig.apiKey,
3730
+ baseUrl: primaryConfig.baseUrl
3731
+ });
3732
+ const tracer = observe({
3733
+ output: config.observe?.tracing ? ["console"] : [],
3734
+ costTracking: config.observe?.costTracking ?? true
3735
+ });
3736
+ const serverConfig = config.server ?? {};
3737
+ if (serverConfig.cors) {
3738
+ app.use("*", corsMiddleware(serverConfig.cors));
3739
+ }
3740
+ if (serverConfig.auth) {
3741
+ app.use("*", authMiddleware(serverConfig.auth));
3742
+ }
3743
+ if (serverConfig.rateLimit) {
3744
+ app.use("*", rateLimitMiddleware(serverConfig.rateLimit));
3745
+ }
3746
+ const agentMap = new Map;
3747
+ if (config.agents) {
3748
+ for (const agent of config.agents) {
3749
+ agentMap.set(agent.name, agent);
3750
+ }
3751
+ }
3752
+ const defaultAgent = config.agents?.[0];
3753
+ const routes = createRoutes({
3754
+ gateway: gw,
3755
+ agents: agentMap,
3756
+ defaultAgent,
3757
+ tracer,
3758
+ startTime: Date.now(),
3759
+ version: "0.1.0",
3760
+ providers: providerNames
3761
+ });
3762
+ app.route("/", routes);
3763
+ return {
3764
+ hono: app,
3765
+ gateway: gw,
3766
+ tracer,
3767
+ listen(port) {
3768
+ const listenPort = port ?? serverConfig.port ?? 3000;
3769
+ const hostname = serverConfig.hostname ?? "0.0.0.0";
3770
+ const server = Bun.serve({
3771
+ port: listenPort,
3772
+ hostname,
3773
+ fetch: app.fetch
3774
+ });
3775
+ log4.info("ElsiumAI server started", {
3776
+ url: `http://${hostname}:${listenPort}`,
3777
+ routes: ["POST /chat", "POST /complete", "GET /health", "GET /metrics", "GET /agents"]
3778
+ });
3779
+ return {
3780
+ port: server.port,
3781
+ stop: () => {
3782
+ server.stop();
3783
+ }
3784
+ };
3785
+ }
3786
+ };
3787
+ }
3788
+ // src/rbac.ts
3789
+ var log5 = createLogger();
3790
+ var BUILT_IN_ROLES = [
3791
+ {
3792
+ name: "admin",
3793
+ permissions: [
3794
+ "model:use:*",
3795
+ "agent:execute:*",
3796
+ "tool:call:*",
3797
+ "config:read",
3798
+ "config:write",
3799
+ "audit:read",
3800
+ "audit:write"
3801
+ ]
3802
+ },
3803
+ {
3804
+ name: "operator",
3805
+ permissions: ["model:use:*", "agent:execute:*", "tool:call:*", "config:read", "audit:read"]
3806
+ },
3807
+ {
3808
+ name: "user",
3809
+ permissions: ["model:use", "agent:execute", "tool:call"]
3810
+ },
3811
+ {
3812
+ name: "viewer",
3813
+ permissions: ["config:read", "audit:read"]
3814
+ }
3815
+ ];
3816
+ function matchPermission(granted, required) {
3817
+ if (granted === required)
3818
+ return true;
3819
+ if (granted.endsWith(":*")) {
3820
+ const prefix = granted.slice(0, -1);
3821
+ return required.startsWith(prefix) || required === granted.slice(0, -2);
3822
+ }
3823
+ return false;
3824
+ }
3825
+ function createRBAC(config) {
3826
+ if (config.trustRoleHeader === true) {
3827
+ log5.warn("RBAC: trustRoleHeader is enabled \u2014 any client can self-assign roles via the X-Role header. Only use this in development or behind a trusted reverse proxy.");
3828
+ }
3829
+ const roleMap = new Map;
3830
+ for (const role of BUILT_IN_ROLES) {
3831
+ roleMap.set(role.name, role);
3832
+ }
3833
+ for (const role of config.roles) {
3834
+ roleMap.set(role.name, role);
3835
+ }
3836
+ function flattenPermissions(roleName, visited = new Set) {
3837
+ if (visited.has(roleName))
3838
+ return [];
3839
+ visited.add(roleName);
3840
+ const role = roleMap.get(roleName);
3841
+ if (!role)
3842
+ return [];
3843
+ const permissions = [...role.permissions];
3844
+ if (role.inherits) {
3845
+ for (const parent of role.inherits) {
3846
+ permissions.push(...flattenPermissions(parent, visited));
3847
+ }
3848
+ }
3849
+ return permissions;
3850
+ }
3851
+ return {
3852
+ hasPermission(roleName, permission) {
3853
+ const permissions = flattenPermissions(roleName);
3854
+ return permissions.some((p) => matchPermission(p, permission));
3855
+ },
3856
+ getRolePermissions(roleName) {
3857
+ return [...new Set(flattenPermissions(roleName))];
3858
+ },
3859
+ middleware(required) {
3860
+ return async (c, next) => {
3861
+ const extractor = config.roleExtractor ?? ((ctx) => {
3862
+ if (config.trustRoleHeader) {
3863
+ return ctx.req.header("X-Role") ?? config.defaultRole ?? "viewer";
3864
+ }
3865
+ return config.defaultRole ?? "viewer";
3866
+ });
3867
+ const roleName = extractor(c);
3868
+ if (!roleName) {
3869
+ return c.json({ error: "No role assigned" }, 403);
3870
+ }
3871
+ if (!roleMap.has(roleName)) {
3872
+ return c.json({ error: `Unknown role: ${roleName}` }, 403);
3873
+ }
3874
+ const hasAccess = flattenPermissions(roleName).some((p) => matchPermission(p, required));
3875
+ if (!hasAccess) {
3876
+ return c.json({ error: `Insufficient permissions. Required: ${required}` }, 403);
3877
+ }
3878
+ await next();
3879
+ };
3880
+ }
3881
+ };
3882
+ }
3883
+ export {
3884
+ rateLimitMiddleware,
3885
+ createRoutes,
3886
+ createRBAC,
3887
+ createApp,
3888
+ corsMiddleware,
3889
+ authMiddleware
3890
+ };