@burdenoff/be-sdk 2026.1015.2 → 2026.1017.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,694 +0,0 @@
1
- import { logger } from './chunk-RU266375.js';
2
- import { __export, __name } from './chunk-XE4OXN2W.js';
3
-
4
- // src/platform/index.ts
5
- var platform_exports = {};
6
- __export(platform_exports, {
7
- CircuitBreakerOpenError: () => CircuitBreakerOpenError,
8
- DEFAULT_GRAPHQL_PAGE_LIMIT: () => DEFAULT_GRAPHQL_PAGE_LIMIT,
9
- LLMRouter: () => LLMRouter,
10
- MAX_GRAPHQL_PAGE_LIMIT: () => MAX_GRAPHQL_PAGE_LIMIT,
11
- __resetHttpClientBreakers: () => __resetHttpClientBreakers,
12
- buildCacheKey: () => buildCacheKey,
13
- buildConnection: () => buildConnection,
14
- buildLoaders: () => buildLoaders,
15
- buildOffsetPage: () => buildOffsetPage,
16
- clampGraphqlLimit: () => clampGraphqlLimit,
17
- clampLimit: () => clampLimit,
18
- clampOffset: () => clampOffset,
19
- createHttpClient: () => createHttpClient,
20
- createLeaderLease: () => createLeaderLease,
21
- decodeCursor: () => decodeCursor,
22
- dropOldPartitions: () => dropOldPartitions,
23
- encodeCursor: () => encodeCursor,
24
- ensureMonthlyPartitions: () => ensureMonthlyPartitions,
25
- getNamespaceVersion: () => getNamespaceVersion,
26
- httpClient: () => httpClient,
27
- invalidateNamespace: () => invalidateNamespace,
28
- monthlyPartitionName: () => monthlyPartitionName,
29
- normalizeCursorPagination: () => normalizeCursorPagination,
30
- normalizeOffsetPagination: () => normalizeOffsetPagination,
31
- normalizeRedisUrl: () => normalizeRedisUrl,
32
- paginate: () => paginate,
33
- rateLimitIncr: () => rateLimitIncr,
34
- resolveReferenceLoader: () => resolveReferenceLoader,
35
- toPrismaPage: () => toPrismaPage,
36
- withLeaderLock: () => withLeaderLock
37
- });
38
-
39
- // src/platform/httpClient.ts
40
- var breakers = /* @__PURE__ */ new Map();
41
- function hostOf(url) {
42
- try {
43
- return new URL(url).host;
44
- } catch {
45
- return url;
46
- }
47
- }
48
- __name(hostOf, "hostOf");
49
- function getBreaker(host) {
50
- let b = breakers.get(host);
51
- if (!b) {
52
- b = {
53
- failures: 0,
54
- openedAt: null,
55
- state: "CLOSED"
56
- };
57
- breakers.set(host, b);
58
- }
59
- return b;
60
- }
61
- __name(getBreaker, "getBreaker");
62
- function defaultRetryOn(status) {
63
- return status === 408 || status === 425 || status === 429 || status >= 500 && status <= 599;
64
- }
65
- __name(defaultRetryOn, "defaultRetryOn");
66
- function jitter(delay) {
67
- return Math.floor(Math.random() * delay);
68
- }
69
- __name(jitter, "jitter");
70
- function sleep(ms) {
71
- return new Promise((r) => setTimeout(r, ms));
72
- }
73
- __name(sleep, "sleep");
74
- var CircuitBreakerOpenError = class extends Error {
75
- static {
76
- __name(this, "CircuitBreakerOpenError");
77
- }
78
- constructor(host) {
79
- super(`circuit breaker OPEN for host=${host}`);
80
- this.name = "CircuitBreakerOpenError";
81
- }
82
- };
83
- function __resetHttpClientBreakers() {
84
- breakers.clear();
85
- }
86
- __name(__resetHttpClientBreakers, "__resetHttpClientBreakers");
87
- async function executeOnce(url, init, timeoutMs) {
88
- const signal = init.signal ?? AbortSignal.timeout(timeoutMs);
89
- return fetch(url, {
90
- ...init,
91
- signal
92
- });
93
- }
94
- __name(executeOnce, "executeOnce");
95
- async function httpClient(url, init = {}, config = {}) {
96
- const fullUrl = config.baseUrl && !/^https?:\/\//i.test(url) ? `${config.baseUrl.replace(/\/$/, "")}/${url.replace(/^\//, "")}` : url;
97
- const host = hostOf(fullUrl);
98
- const breaker = getBreaker(host);
99
- const breakerThreshold = config.breaker?.threshold ?? 5;
100
- const cooldownMs = config.breaker?.cooldownMs ?? 3e4;
101
- if (breaker.state === "OPEN") {
102
- if (breaker.openedAt && Date.now() - breaker.openedAt >= cooldownMs) {
103
- breaker.state = "HALF_OPEN";
104
- logger.info("httpClient.breaker.halfOpen", {
105
- host
106
- });
107
- } else {
108
- throw new CircuitBreakerOpenError(host);
109
- }
110
- }
111
- const attempts = init.retry?.attempts ?? config.retry?.attempts ?? 3;
112
- const initialDelay = init.retry?.initialDelayMs ?? config.retry?.initialDelayMs ?? 100;
113
- const maxDelay = init.retry?.maxDelayMs ?? config.retry?.maxDelayMs ?? 2e3;
114
- const retryOn = init.retry?.retryOn ?? config.retry?.retryOn ?? defaultRetryOn;
115
- const timeoutMs = init.timeoutMs ?? config.defaultTimeoutMs ?? 5e3;
116
- const headers = {
117
- ...config.defaultHeaders ?? {},
118
- ...init.headers ?? {}
119
- };
120
- let lastErr;
121
- for (let attempt = 1; attempt <= attempts; attempt++) {
122
- try {
123
- const response = await executeOnce(fullUrl, {
124
- ...init,
125
- headers
126
- }, timeoutMs);
127
- if (response.status >= 500) {
128
- breaker.failures += 1;
129
- if (breaker.failures >= breakerThreshold) {
130
- breaker.state = "OPEN";
131
- breaker.openedAt = Date.now();
132
- logger.warn("httpClient.breaker.open", {
133
- host,
134
- failures: breaker.failures
135
- });
136
- }
137
- if (attempt < attempts && retryOn(response.status)) {
138
- const delay = Math.min(initialDelay * 2 ** (attempt - 1), maxDelay);
139
- await sleep(jitter(delay));
140
- continue;
141
- }
142
- return response;
143
- }
144
- breaker.failures = 0;
145
- if (breaker.state === "HALF_OPEN") {
146
- breaker.state = "CLOSED";
147
- breaker.openedAt = null;
148
- logger.info("httpClient.breaker.closed", {
149
- host
150
- });
151
- }
152
- if (attempt < attempts && retryOn(response.status)) {
153
- const delay = Math.min(initialDelay * 2 ** (attempt - 1), maxDelay);
154
- await sleep(jitter(delay));
155
- continue;
156
- }
157
- return response;
158
- } catch (err) {
159
- lastErr = err;
160
- breaker.failures += 1;
161
- if (breaker.failures >= breakerThreshold) {
162
- breaker.state = "OPEN";
163
- breaker.openedAt = Date.now();
164
- logger.warn("httpClient.breaker.open", {
165
- host,
166
- failures: breaker.failures
167
- });
168
- }
169
- if (attempt >= attempts) break;
170
- const delay = Math.min(initialDelay * 2 ** (attempt - 1), maxDelay);
171
- await sleep(jitter(delay));
172
- }
173
- }
174
- logger.error("httpClient.exhausted", {
175
- url: fullUrl,
176
- attempts,
177
- host
178
- });
179
- throw lastErr instanceof Error ? lastErr : new Error(`httpClient failed: ${String(lastErr)}`);
180
- }
181
- __name(httpClient, "httpClient");
182
- function createHttpClient(config = {}) {
183
- return (url, init = {}) => httpClient(url, init, config);
184
- }
185
- __name(createHttpClient, "createHttpClient");
186
-
187
- // src/platform/leaderLock.ts
188
- var RELEASE_LUA = `
189
- if redis.call("get", KEYS[1]) == ARGV[1] then
190
- return redis.call("del", KEYS[1])
191
- else
192
- return 0
193
- end
194
- `;
195
- var RENEW_LUA = `
196
- if redis.call("get", KEYS[1]) == ARGV[1] then
197
- return redis.call("pexpire", KEYS[1], ARGV[2])
198
- else
199
- return 0
200
- end
201
- `;
202
- function leaderKey(name) {
203
- return `besdk:leader:${name}`;
204
- }
205
- __name(leaderKey, "leaderKey");
206
- function generateToken() {
207
- return `${Date.now()}-${Math.random().toString(36).slice(2)}-${process.pid}`;
208
- }
209
- __name(generateToken, "generateToken");
210
- function defaultRenewMs(ttlMs) {
211
- return Math.max(1e3, Math.floor(ttlMs / 3));
212
- }
213
- __name(defaultRenewMs, "defaultRenewMs");
214
- async function acquireLease(redis, key, token, ttlMs) {
215
- const ttlSeconds = Math.max(1, Math.ceil(ttlMs / 1e3));
216
- return await redis.set(key, token, "EX", ttlSeconds, "NX") === "OK";
217
- }
218
- __name(acquireLease, "acquireLease");
219
- async function renewLease(redis, key, token, ttlMs) {
220
- return await redis.eval(RENEW_LUA, 1, key, token, String(ttlMs)) === 1;
221
- }
222
- __name(renewLease, "renewLease");
223
- async function releaseLease(redis, key, token) {
224
- await redis.eval(RELEASE_LUA, 1, key, token);
225
- }
226
- __name(releaseLease, "releaseLease");
227
- function normalizeRedisUrl(url) {
228
- if (url.startsWith("valkeys://")) return url.replace(/^valkeys:\/\//, "rediss://");
229
- if (url.startsWith("valkey://")) return url.replace(/^valkey:\/\//, "redis://");
230
- return url;
231
- }
232
- __name(normalizeRedisUrl, "normalizeRedisUrl");
233
- async function withLeaderLock(redis, name, fn, options) {
234
- const key = leaderKey(name);
235
- const token = generateToken();
236
- const ttlMs = options.ttlMs;
237
- const renewMs = options.renewMs ?? defaultRenewMs(ttlMs);
238
- const acquired = await acquireLease(redis, key, token, ttlMs);
239
- if (!acquired) {
240
- return {
241
- acquired: false
242
- };
243
- }
244
- logger.info("leaderLock.acquired", {
245
- name,
246
- token,
247
- ttlMs
248
- });
249
- let stopped = false;
250
- const renewTimer = setInterval(() => {
251
- if (stopped) return;
252
- renewLease(redis, key, token, ttlMs).catch((err) => {
253
- logger.warn("leaderLock.renew.failed", {
254
- name,
255
- err: String(err)
256
- });
257
- });
258
- }, renewMs);
259
- if (typeof renewTimer.unref === "function") {
260
- renewTimer.unref();
261
- }
262
- try {
263
- const result = await fn();
264
- return {
265
- acquired: true,
266
- result
267
- };
268
- } finally {
269
- stopped = true;
270
- clearInterval(renewTimer);
271
- try {
272
- await releaseLease(redis, key, token);
273
- logger.info("leaderLock.released", {
274
- name,
275
- token
276
- });
277
- } catch (err) {
278
- logger.warn("leaderLock.release.failed", {
279
- name,
280
- err: String(err)
281
- });
282
- }
283
- }
284
- }
285
- __name(withLeaderLock, "withLeaderLock");
286
- function createLeaderLease(options) {
287
- const { name, ttlMs, redis } = options;
288
- const key = leaderKey(name);
289
- const token = generateToken();
290
- const renewMs = options.renewMs ?? defaultRenewMs(ttlMs);
291
- let held = false;
292
- let released = false;
293
- let inFlight = null;
294
- const acquireOrRenew = /* @__PURE__ */ __name(async () => {
295
- if (released) return false;
296
- try {
297
- if (held) {
298
- if (await renewLease(redis, key, token, ttlMs)) {
299
- return true;
300
- }
301
- held = false;
302
- }
303
- const acquired = await acquireLease(redis, key, token, ttlMs);
304
- if (acquired && !held) {
305
- logger.info("leaderLease.acquired", {
306
- name,
307
- token,
308
- ttlMs
309
- });
310
- }
311
- held = acquired;
312
- return held;
313
- } catch (err) {
314
- logger.warn("leaderLease.renew.failed", {
315
- name,
316
- err: String(err)
317
- });
318
- return held;
319
- }
320
- }, "acquireOrRenew");
321
- const runAttempt = /* @__PURE__ */ __name(() => {
322
- if (inFlight) return inFlight;
323
- const attempt = acquireOrRenew().finally(() => {
324
- if (inFlight === attempt) inFlight = null;
325
- });
326
- inFlight = attempt;
327
- return attempt;
328
- }, "runAttempt");
329
- const timer = setInterval(() => {
330
- if (released) return;
331
- void runAttempt();
332
- }, renewMs);
333
- if (typeof timer.unref === "function") {
334
- timer.unref();
335
- }
336
- return {
337
- renew() {
338
- return runAttempt();
339
- },
340
- async release() {
341
- if (released) return;
342
- released = true;
343
- clearInterval(timer);
344
- if (inFlight) {
345
- try {
346
- await inFlight;
347
- } catch {
348
- }
349
- }
350
- if (!held) return;
351
- held = false;
352
- try {
353
- await releaseLease(redis, key, token);
354
- logger.info("leaderLease.released", {
355
- name,
356
- token
357
- });
358
- } catch (err) {
359
- logger.warn("leaderLease.release.failed", {
360
- name,
361
- err: String(err)
362
- });
363
- }
364
- },
365
- isHeld() {
366
- return held && !released;
367
- }
368
- };
369
- }
370
- __name(createLeaderLease, "createLeaderLease");
371
-
372
- // src/platform/rateLimit.ts
373
- async function rateLimitIncr(redis, input) {
374
- const fullKey = `besdk:rl:${input.key}`;
375
- const count = await redis.incr(fullKey);
376
- if (count === 1) {
377
- await redis.pexpire(fullKey, input.windowMs);
378
- }
379
- let ttl = -1;
380
- try {
381
- ttl = await redis.pttl(fullKey);
382
- } catch {
383
- ttl = input.windowMs;
384
- }
385
- const resetAt = Date.now() + (ttl > 0 ? ttl : input.windowMs);
386
- const remaining = Math.max(0, input.limit - count);
387
- return {
388
- allowed: count <= input.limit,
389
- count,
390
- remaining,
391
- resetAt
392
- };
393
- }
394
- __name(rateLimitIncr, "rateLimitIncr");
395
-
396
- // src/platform/paginator.ts
397
- var DEFAULT_GRAPHQL_PAGE_LIMIT = 50;
398
- var MAX_GRAPHQL_PAGE_LIMIT = 100;
399
- function clampLimit(input, opts = {}) {
400
- const def = opts.defaultLimit ?? 50;
401
- const max = opts.maxLimit ?? 200;
402
- const min = opts.minLimit ?? 1;
403
- if (input == null || Number.isNaN(input)) return def;
404
- return Math.min(Math.max(Math.floor(input), min), max);
405
- }
406
- __name(clampLimit, "clampLimit");
407
- function clampOffset(input) {
408
- if (input == null || Number.isNaN(input)) return 0;
409
- return Math.max(0, Math.floor(input));
410
- }
411
- __name(clampOffset, "clampOffset");
412
- function clampGraphqlLimit(input, opts = {}) {
413
- return clampLimit(input, {
414
- defaultLimit: opts.defaultLimit ?? DEFAULT_GRAPHQL_PAGE_LIMIT,
415
- maxLimit: opts.maxLimit ?? MAX_GRAPHQL_PAGE_LIMIT,
416
- minLimit: opts.minLimit ?? 1
417
- });
418
- }
419
- __name(clampGraphqlLimit, "clampGraphqlLimit");
420
- function normalizeOffsetPagination(input, opts = {}) {
421
- return {
422
- limit: clampGraphqlLimit(input?.limit, opts),
423
- offset: clampOffset(input?.offset)
424
- };
425
- }
426
- __name(normalizeOffsetPagination, "normalizeOffsetPagination");
427
- function normalizeCursorPagination(input, opts = {}) {
428
- const first = clampGraphqlLimit(input?.first, opts);
429
- const after = typeof input?.after === "string" && input.after.trim().length > 0 ? input.after : null;
430
- return {
431
- first,
432
- after,
433
- take: first + 1
434
- };
435
- }
436
- __name(normalizeCursorPagination, "normalizeCursorPagination");
437
- function encodeCursor(payload) {
438
- return Buffer.from(JSON.stringify(payload), "utf8").toString("base64url");
439
- }
440
- __name(encodeCursor, "encodeCursor");
441
- function decodeCursor(cursor) {
442
- if (typeof cursor !== "string" || cursor.trim().length === 0) return null;
443
- try {
444
- const decoded = JSON.parse(Buffer.from(cursor, "base64url").toString("utf8"));
445
- if (decoded == null || typeof decoded !== "object" || Array.isArray(decoded)) return null;
446
- const payload = {};
447
- for (const [key, value] of Object.entries(decoded)) {
448
- if (typeof value === "string" || typeof value === "number" || typeof value === "boolean" || value == null) {
449
- payload[key] = value;
450
- }
451
- }
452
- return Object.keys(payload).length > 0 ? payload : null;
453
- } catch {
454
- return null;
455
- }
456
- }
457
- __name(decodeCursor, "decodeCursor");
458
- function buildConnection(items, opts) {
459
- const nodes = items.length > opts.limit ? items.slice(0, opts.limit) : items;
460
- const edges = nodes.map((node) => ({
461
- node,
462
- cursor: opts.cursorForNode(node)
463
- }));
464
- const firstEdge = edges[0];
465
- const lastEdge = edges.at(-1);
466
- return {
467
- edges,
468
- nodes,
469
- pageInfo: {
470
- hasNextPage: items.length > opts.limit,
471
- hasPreviousPage: opts.hasPreviousPage ?? false,
472
- startCursor: firstEdge?.cursor ?? null,
473
- endCursor: lastEdge?.cursor ?? null
474
- },
475
- totalCount: opts.totalCount
476
- };
477
- }
478
- __name(buildConnection, "buildConnection");
479
- function buildOffsetPage(items, total, pagination) {
480
- const nextOffset = pagination.offset + items.length;
481
- const hasMore = nextOffset < total;
482
- return {
483
- items,
484
- total,
485
- limit: pagination.limit,
486
- offset: pagination.offset,
487
- hasMore,
488
- nextOffset: hasMore ? nextOffset : null
489
- };
490
- }
491
- __name(buildOffsetPage, "buildOffsetPage");
492
- function toPrismaPage(pagination) {
493
- return {
494
- take: pagination.limit,
495
- skip: pagination.offset
496
- };
497
- }
498
- __name(toPrismaPage, "toPrismaPage");
499
- async function paginate(model, input, opts = {}) {
500
- const take = clampGraphqlLimit(input.take ?? void 0, opts);
501
- const items = await model.findMany({
502
- take: take + 1,
503
- skip: input.cursor ? 1 : 0,
504
- cursor: input.cursor ? {
505
- id: input.cursor
506
- } : void 0,
507
- where: input.where,
508
- orderBy: input.orderBy
509
- });
510
- const hasMore = items.length > take;
511
- const trimmed = hasMore ? items.slice(0, take) : items;
512
- const nextCursor = hasMore && trimmed.length > 0 ? trimmed[trimmed.length - 1].id : null;
513
- return {
514
- items: trimmed,
515
- hasMore,
516
- nextCursor
517
- };
518
- }
519
- __name(paginate, "paginate");
520
-
521
- // src/platform/dataLoaderFactory.ts
522
- function buildLoaders(ctx, builder) {
523
- return builder(ctx);
524
- }
525
- __name(buildLoaders, "buildLoaders");
526
- function resolveReferenceLoader(loaderName, keyField = "id") {
527
- return async (reference, ctx) => {
528
- const loader = ctx.loaders[loaderName];
529
- if (!loader) {
530
- throw new Error(`resolveReferenceLoader: loader "${loaderName}" not found on ctx.loaders`);
531
- }
532
- const key = reference[keyField];
533
- if (typeof key !== "string") {
534
- return null;
535
- }
536
- return loader.load(key);
537
- };
538
- }
539
- __name(resolveReferenceLoader, "resolveReferenceLoader");
540
-
541
- // src/platform/cacheInvalidation.ts
542
- var VERSION_PREFIX = "besdk:cv:";
543
- async function getNamespaceVersion(redis, namespace) {
544
- const v = await redis.get(`${VERSION_PREFIX}${namespace}`);
545
- if (!v) return 1;
546
- const n = Number.parseInt(v, 10);
547
- return Number.isFinite(n) && n > 0 ? n : 1;
548
- }
549
- __name(getNamespaceVersion, "getNamespaceVersion");
550
- async function buildCacheKey(redis, namespace, ...parts) {
551
- const ver = await getNamespaceVersion(redis, namespace);
552
- return `${namespace}:v${ver}:${parts.join(":")}`;
553
- }
554
- __name(buildCacheKey, "buildCacheKey");
555
- async function invalidateNamespace(redis, namespace) {
556
- return redis.incr(`${VERSION_PREFIX}${namespace}`);
557
- }
558
- __name(invalidateNamespace, "invalidateNamespace");
559
-
560
- // src/platform/pgPartition.ts
561
- function pad2(n) {
562
- return n < 10 ? `0${n}` : `${n}`;
563
- }
564
- __name(pad2, "pad2");
565
- function monthlyPartitionName(table, year, month) {
566
- return `${table}_y${year}m${pad2(month)}`;
567
- }
568
- __name(monthlyPartitionName, "monthlyPartitionName");
569
- async function ensureMonthlyPartitions(prisma, opts) {
570
- const created = [];
571
- const cur = new Date(Date.UTC(opts.from.getUTCFullYear(), opts.from.getUTCMonth(), 1));
572
- const end = new Date(Date.UTC(opts.to.getUTCFullYear(), opts.to.getUTCMonth(), 1));
573
- while (cur <= end) {
574
- const y = cur.getUTCFullYear();
575
- const m = cur.getUTCMonth() + 1;
576
- const next = new Date(Date.UTC(y, m, 1));
577
- const partition = monthlyPartitionName(opts.table, y, m);
578
- const lower = `${y}-${pad2(m)}-01`;
579
- const upper = `${next.getUTCFullYear()}-${pad2(next.getUTCMonth() + 1)}-01`;
580
- await prisma.$executeRawUnsafe(`CREATE TABLE IF NOT EXISTS "${partition}" PARTITION OF "${opts.table}" FOR VALUES FROM ('${lower}') TO ('${upper}');`);
581
- created.push(partition);
582
- cur.setUTCMonth(cur.getUTCMonth() + 1);
583
- }
584
- return created;
585
- }
586
- __name(ensureMonthlyPartitions, "ensureMonthlyPartitions");
587
- async function dropOldPartitions(prisma, opts) {
588
- const rows = await prisma.$queryRawUnsafe(`SELECT child.relname AS partition_name
589
- FROM pg_inherits
590
- JOIN pg_class parent ON pg_inherits.inhparent = parent.oid
591
- JOIN pg_class child ON pg_inherits.inhrelid = child.oid
592
- WHERE parent.relname = $1`, opts.table);
593
- const dropped = [];
594
- const cutoffYear = opts.beforeDate.getUTCFullYear();
595
- const cutoffMonth = opts.beforeDate.getUTCMonth() + 1;
596
- for (const row of rows) {
597
- const partitionRe = /_y(\d{4})m(\d{2})$/;
598
- const m = partitionRe.exec(row.partition_name);
599
- if (!m) continue;
600
- const y = Number(m[1]);
601
- const mo = Number(m[2]);
602
- if (y < cutoffYear || y === cutoffYear && mo < cutoffMonth) {
603
- await prisma.$executeRawUnsafe(`DROP TABLE IF EXISTS "${row.partition_name}";`);
604
- dropped.push(row.partition_name);
605
- }
606
- }
607
- return dropped;
608
- }
609
- __name(dropOldPartitions, "dropOldPartitions");
610
-
611
- // src/platform/llmClient.ts
612
- var DEFAULTS = {
613
- timeoutMs: 3e4,
614
- maxAttempts: 3,
615
- initialDelayMs: 500,
616
- maxOutputTokensCap: 4096
617
- };
618
- function jitter2(n) {
619
- return Math.floor(Math.random() * n);
620
- }
621
- __name(jitter2, "jitter");
622
- function sleep2(ms) {
623
- return new Promise((r) => setTimeout(r, ms));
624
- }
625
- __name(sleep2, "sleep");
626
- var LLMRouter = class {
627
- static {
628
- __name(this, "LLMRouter");
629
- }
630
- adapters = /* @__PURE__ */ new Map();
631
- opts;
632
- constructor(opts = {}) {
633
- this.opts = {
634
- ...DEFAULTS,
635
- ...opts
636
- };
637
- }
638
- register(adapter) {
639
- this.adapters.set(adapter.name, adapter);
640
- }
641
- resolveChain() {
642
- const envChain = process.env["LLM_PROVIDER_CHAIN"]?.trim();
643
- if (envChain) {
644
- return envChain.split(",").map((s) => s.trim()).filter(Boolean);
645
- }
646
- return Array.from(this.adapters.keys());
647
- }
648
- async complete(req) {
649
- const cappedReq = {
650
- ...req,
651
- maxTokens: Math.min(req.maxTokens ?? this.opts.maxOutputTokensCap, this.opts.maxOutputTokensCap)
652
- };
653
- const chain = this.resolveChain();
654
- if (chain.length === 0) {
655
- throw new Error("LLMRouter: no providers registered");
656
- }
657
- let lastErr = null;
658
- for (let attempt = 0; attempt < this.opts.maxAttempts; attempt++) {
659
- const providerName = chain[attempt % chain.length];
660
- const adapter = providerName ? this.adapters.get(providerName) : void 0;
661
- if (!adapter) {
662
- logger.warn("llmRouter.provider.notRegistered", {
663
- providerName
664
- });
665
- continue;
666
- }
667
- const timeoutMs = req.timeoutMs ?? this.opts.timeoutMs;
668
- const ctrl = new AbortController();
669
- const t = setTimeout(() => ctrl.abort(), timeoutMs);
670
- try {
671
- const response = await adapter.complete(cappedReq, ctrl.signal);
672
- return response;
673
- } catch (err) {
674
- lastErr = err;
675
- logger.warn("llmRouter.attempt.failed", {
676
- provider: adapter.name,
677
- attempt,
678
- err: String(err)
679
- });
680
- if (attempt < this.opts.maxAttempts - 1) {
681
- const delay = this.opts.initialDelayMs * 2 ** attempt;
682
- await sleep2(jitter2(delay));
683
- }
684
- } finally {
685
- clearTimeout(t);
686
- }
687
- }
688
- throw lastErr instanceof Error ? lastErr : new Error(`LLMRouter exhausted ${this.opts.maxAttempts} attempts`);
689
- }
690
- };
691
-
692
- export { CircuitBreakerOpenError, DEFAULT_GRAPHQL_PAGE_LIMIT, LLMRouter, MAX_GRAPHQL_PAGE_LIMIT, __resetHttpClientBreakers, buildCacheKey, buildConnection, buildLoaders, buildOffsetPage, clampGraphqlLimit, clampLimit, clampOffset, createHttpClient, createLeaderLease, decodeCursor, dropOldPartitions, encodeCursor, ensureMonthlyPartitions, getNamespaceVersion, httpClient, invalidateNamespace, monthlyPartitionName, normalizeCursorPagination, normalizeOffsetPagination, normalizeRedisUrl, paginate, platform_exports, rateLimitIncr, resolveReferenceLoader, toPrismaPage, withLeaderLock };
693
- //# sourceMappingURL=chunk-Z5BURBFZ.js.map
694
- //# sourceMappingURL=chunk-Z5BURBFZ.js.map