@eidentic/server 0.1.0

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.cjs ADDED
@@ -0,0 +1,2669 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __esm = (fn, res) => function __init() {
7
+ return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
8
+ };
9
+ var __export = (target, all) => {
10
+ for (var name in all)
11
+ __defProp(target, name, { get: all[name], enumerable: true });
12
+ };
13
+ var __copyProps = (to, from, except, desc) => {
14
+ if (from && typeof from === "object" || typeof from === "function") {
15
+ for (let key of __getOwnPropNames(from))
16
+ if (!__hasOwnProp.call(to, key) && key !== except)
17
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
18
+ }
19
+ return to;
20
+ };
21
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
22
+
23
+ // ../../node_modules/.pnpm/@hono+node-server@2.0.4_hono@4.12.23/node_modules/@hono/node-server/dist/constants-BLSFu_RU.mjs
24
+ var X_ALREADY_SENT;
25
+ var init_constants_BLSFu_RU = __esm({
26
+ "../../node_modules/.pnpm/@hono+node-server@2.0.4_hono@4.12.23/node_modules/@hono/node-server/dist/constants-BLSFu_RU.mjs"() {
27
+ "use strict";
28
+ X_ALREADY_SENT = "x-hono-already-sent";
29
+ }
30
+ });
31
+
32
+ // ../../node_modules/.pnpm/@hono+node-server@2.0.4_hono@4.12.23/node_modules/@hono/node-server/dist/index.mjs
33
+ var dist_exports = {};
34
+ __export(dist_exports, {
35
+ RequestError: () => RequestError,
36
+ createAdaptorServer: () => createAdaptorServer,
37
+ getRequestListener: () => getRequestListener,
38
+ serve: () => serve,
39
+ upgradeWebSocket: () => upgradeWebSocket
40
+ });
41
+ async function readWithoutBlocking(readPromise) {
42
+ return Promise.race([readPromise, Promise.resolve().then(() => Promise.resolve(void 0))]);
43
+ }
44
+ function writeFromReadableStreamDefaultReader(reader, writable, currentReadPromise) {
45
+ const cancel = (error) => {
46
+ reader.cancel(error).catch(() => {
47
+ });
48
+ };
49
+ writable.on("close", cancel);
50
+ writable.on("error", cancel);
51
+ (currentReadPromise ?? reader.read()).then(flow, handleStreamError);
52
+ return reader.closed.finally(() => {
53
+ writable.off("close", cancel);
54
+ writable.off("error", cancel);
55
+ });
56
+ function handleStreamError(error) {
57
+ if (error) writable.destroy(error);
58
+ }
59
+ function onDrain() {
60
+ reader.read().then(flow, handleStreamError);
61
+ }
62
+ function flow({ done, value }) {
63
+ try {
64
+ if (done) writable.end();
65
+ else if (!writable.write(value)) writable.once("drain", onDrain);
66
+ else return reader.read().then(flow, handleStreamError);
67
+ } catch (e) {
68
+ handleStreamError(e);
69
+ }
70
+ }
71
+ }
72
+ function writeFromReadableStream(stream, writable) {
73
+ if (stream.locked) throw new TypeError("ReadableStream is locked.");
74
+ else if (writable.destroyed) return;
75
+ return writeFromReadableStreamDefaultReader(stream.getReader(), writable);
76
+ }
77
+ var import_node_http, import_node_http2, import_node_stream, import_ws, RequestError, reValidRequestUrl, reDotSegment, reValidHost, buildUrl, toRequestError, GlobalRequest, Request$1, newHeadersFromIncoming, wrapBodyStream, newRequestFromIncoming, getRequestCache, requestCache, incomingKey, urlKey, methodKey, headersKey, abortControllerKey, getAbortController, abortRequest, bodyBufferKey, bodyReadPromiseKey, bodyConsumedDirectlyKey, bodyLockReaderKey, abortReasonKey, newBodyUnusableError, rejectBodyUnusable, textDecoder, consumeBodyDirectOnce, toArrayBuffer, contentType, methodTokenRegExp, normalizeIncomingMethod, validateDirectReadMethod, readBodyWithFastPath, readRawBodyIfAvailable, readBodyDirect, requestPrototype, newRequest, defaultContentType, responseCache, getResponseCache, cacheKey, GlobalResponse, Response$1, validRedirectUrl, parseRedirectUrl, validRedirectStatuses, buildOutgoingHttpHeaders, outgoingEnded, incomingDraining, DRAIN_TIMEOUT_MS, MAX_DRAIN_BYTES, drainIncoming, makeCloseHandler, isImmediateCacheableResponse, handleRequestError, handleFetchError, handleResponseError, flushHeaders, responseViaCache, isPromise, responseViaResponseObject, getRequestListener, CloseEvent, generateConnectionSymbol, CONNECTION_SYMBOL_KEY, WAIT_FOR_WEBSOCKET_SYMBOL, responseHeadersToSkip, appendResponseHeaders, rejectUpgradeRequest, createUpgradeRequest, setupWebSocket, upgradeWebSocket, createAdaptorServer, serve;
78
+ var init_dist = __esm({
79
+ "../../node_modules/.pnpm/@hono+node-server@2.0.4_hono@4.12.23/node_modules/@hono/node-server/dist/index.mjs"() {
80
+ "use strict";
81
+ init_constants_BLSFu_RU();
82
+ import_node_http = require("node:http");
83
+ import_node_http2 = require("node:http2");
84
+ import_node_stream = require("node:stream");
85
+ import_ws = require("hono/ws");
86
+ RequestError = class extends Error {
87
+ constructor(message, options) {
88
+ super(message, options);
89
+ this.name = "RequestError";
90
+ }
91
+ };
92
+ reValidRequestUrl = /^\/[!#$&-;=?-\[\]_a-z~]*$/;
93
+ reDotSegment = /\/\.\.?(?:[/?#]|$)/;
94
+ reValidHost = /^[a-z0-9._-]+(?::(?:[1-5]\d{3,4}|[6-9]\d{3}))?$/;
95
+ buildUrl = (scheme, host, incomingUrl) => {
96
+ const url = `${scheme}://${host}${incomingUrl}`;
97
+ if (!reValidHost.test(host)) {
98
+ const urlObj = new URL(url);
99
+ if (urlObj.hostname.length !== host.length && urlObj.hostname !== (host.includes(":") ? host.replace(/:\d+$/, "") : host).toLowerCase()) throw new RequestError("Invalid host header");
100
+ return urlObj.href;
101
+ } else if (incomingUrl.length === 0) return url + "/";
102
+ else {
103
+ if (incomingUrl.charCodeAt(0) !== 47) throw new RequestError("Invalid URL");
104
+ if (!reValidRequestUrl.test(incomingUrl) || reDotSegment.test(incomingUrl)) return new URL(url).href;
105
+ return url;
106
+ }
107
+ };
108
+ toRequestError = (e) => {
109
+ if (e instanceof RequestError) return e;
110
+ return new RequestError(e.message, { cause: e });
111
+ };
112
+ GlobalRequest = global.Request;
113
+ Request$1 = class extends GlobalRequest {
114
+ constructor(input, options) {
115
+ if (typeof input === "object" && getRequestCache in input) {
116
+ const hasReplacementBody = options !== void 0 && "body" in options && options.body != null;
117
+ if (input[bodyConsumedDirectlyKey] && !hasReplacementBody) throw new TypeError("Cannot construct a Request with a Request object that has already been used.");
118
+ input = input[getRequestCache]();
119
+ }
120
+ if (typeof options?.body?.getReader !== "undefined") options.duplex ??= "half";
121
+ super(input, options);
122
+ }
123
+ };
124
+ newHeadersFromIncoming = (incoming) => {
125
+ const headerRecord = [];
126
+ const rawHeaders = incoming.rawHeaders;
127
+ for (let i = 0, len = rawHeaders.length; i < len; i += 2) {
128
+ const key = rawHeaders[i];
129
+ if (key.charCodeAt(0) !== 58) headerRecord.push([key, rawHeaders[i + 1]]);
130
+ }
131
+ return new Headers(headerRecord);
132
+ };
133
+ wrapBodyStream = /* @__PURE__ */ Symbol("wrapBodyStream");
134
+ newRequestFromIncoming = (method, url, headers, incoming, abortController) => {
135
+ const init = {
136
+ method,
137
+ headers,
138
+ signal: abortController.signal
139
+ };
140
+ if (method === "TRACE") {
141
+ init.method = "GET";
142
+ const req = new Request$1(url, init);
143
+ Object.defineProperty(req, "method", { get() {
144
+ return "TRACE";
145
+ } });
146
+ return req;
147
+ }
148
+ if (!(method === "GET" || method === "HEAD")) if ("rawBody" in incoming && incoming.rawBody instanceof Buffer) init.body = new ReadableStream({ start(controller) {
149
+ controller.enqueue(incoming.rawBody);
150
+ controller.close();
151
+ } });
152
+ else if (incoming[wrapBodyStream]) {
153
+ let reader;
154
+ init.body = new ReadableStream({ async pull(controller) {
155
+ try {
156
+ reader ||= import_node_stream.Readable.toWeb(incoming).getReader();
157
+ const { done, value } = await reader.read();
158
+ if (done) controller.close();
159
+ else controller.enqueue(value);
160
+ } catch (error) {
161
+ controller.error(error);
162
+ }
163
+ } });
164
+ } else init.body = import_node_stream.Readable.toWeb(incoming);
165
+ return new Request$1(url, init);
166
+ };
167
+ getRequestCache = /* @__PURE__ */ Symbol("getRequestCache");
168
+ requestCache = /* @__PURE__ */ Symbol("requestCache");
169
+ incomingKey = /* @__PURE__ */ Symbol("incomingKey");
170
+ urlKey = /* @__PURE__ */ Symbol("urlKey");
171
+ methodKey = /* @__PURE__ */ Symbol("methodKey");
172
+ headersKey = /* @__PURE__ */ Symbol("headersKey");
173
+ abortControllerKey = /* @__PURE__ */ Symbol("abortControllerKey");
174
+ getAbortController = /* @__PURE__ */ Symbol("getAbortController");
175
+ abortRequest = /* @__PURE__ */ Symbol("abortRequest");
176
+ bodyBufferKey = /* @__PURE__ */ Symbol("bodyBuffer");
177
+ bodyReadPromiseKey = /* @__PURE__ */ Symbol("bodyReadPromise");
178
+ bodyConsumedDirectlyKey = /* @__PURE__ */ Symbol("bodyConsumedDirectly");
179
+ bodyLockReaderKey = /* @__PURE__ */ Symbol("bodyLockReader");
180
+ abortReasonKey = /* @__PURE__ */ Symbol("abortReason");
181
+ newBodyUnusableError = () => {
182
+ return /* @__PURE__ */ new TypeError("Body is unusable");
183
+ };
184
+ rejectBodyUnusable = () => {
185
+ return Promise.reject(newBodyUnusableError());
186
+ };
187
+ textDecoder = new TextDecoder();
188
+ consumeBodyDirectOnce = (request) => {
189
+ if (request[bodyConsumedDirectlyKey]) return rejectBodyUnusable();
190
+ request[bodyConsumedDirectlyKey] = true;
191
+ };
192
+ toArrayBuffer = (buf) => {
193
+ return buf.buffer.slice(buf.byteOffset, buf.byteOffset + buf.byteLength);
194
+ };
195
+ contentType = (request) => {
196
+ return (request[headersKey] ||= newHeadersFromIncoming(request[incomingKey])).get("content-type") || "";
197
+ };
198
+ methodTokenRegExp = /^[!#$%&'*+\-.^_`|~0-9A-Za-z]+$/;
199
+ normalizeIncomingMethod = (method) => {
200
+ if (typeof method !== "string" || method.length === 0) return "GET";
201
+ switch (method) {
202
+ case "DELETE":
203
+ case "GET":
204
+ case "HEAD":
205
+ case "OPTIONS":
206
+ case "POST":
207
+ case "PUT":
208
+ return method;
209
+ }
210
+ const upper = method.toUpperCase();
211
+ switch (upper) {
212
+ case "DELETE":
213
+ case "GET":
214
+ case "HEAD":
215
+ case "OPTIONS":
216
+ case "POST":
217
+ case "PUT":
218
+ return upper;
219
+ default:
220
+ return method;
221
+ }
222
+ };
223
+ validateDirectReadMethod = (method) => {
224
+ if (!methodTokenRegExp.test(method)) return /* @__PURE__ */ new TypeError(`'${method}' is not a valid HTTP method.`);
225
+ const normalized = method.toUpperCase();
226
+ if (normalized === "CONNECT" || normalized === "TRACK" || normalized === "TRACE" && method !== "TRACE") return /* @__PURE__ */ new TypeError(`'${method}' HTTP method is unsupported.`);
227
+ };
228
+ readBodyWithFastPath = (request, method, fromBuffer) => {
229
+ if (request[bodyConsumedDirectlyKey]) return rejectBodyUnusable();
230
+ const methodName = request.method;
231
+ if (methodName === "GET" || methodName === "HEAD") return request[getRequestCache]()[method]();
232
+ const methodValidationError = validateDirectReadMethod(methodName);
233
+ if (methodValidationError) return Promise.reject(methodValidationError);
234
+ if (request[requestCache]) {
235
+ if (methodName !== "TRACE") return request[requestCache][method]();
236
+ }
237
+ const alreadyUsedError = consumeBodyDirectOnce(request);
238
+ if (alreadyUsedError) return alreadyUsedError;
239
+ const raw = readRawBodyIfAvailable(request);
240
+ if (raw) {
241
+ const result = Promise.resolve(fromBuffer(raw, request));
242
+ request[bodyBufferKey] = void 0;
243
+ return result;
244
+ }
245
+ return readBodyDirect(request).then((buf) => {
246
+ const result = fromBuffer(buf, request);
247
+ request[bodyBufferKey] = void 0;
248
+ return result;
249
+ });
250
+ };
251
+ readRawBodyIfAvailable = (request) => {
252
+ const incoming = request[incomingKey];
253
+ if ("rawBody" in incoming && incoming.rawBody instanceof Buffer) return incoming.rawBody;
254
+ };
255
+ readBodyDirect = (request) => {
256
+ if (request[bodyBufferKey]) return Promise.resolve(request[bodyBufferKey]);
257
+ if (request[bodyReadPromiseKey]) return request[bodyReadPromiseKey];
258
+ const incoming = request[incomingKey];
259
+ if (import_node_stream.Readable.isDisturbed(incoming)) return rejectBodyUnusable();
260
+ const promise = new Promise((resolve, reject) => {
261
+ const chunks = [];
262
+ let settled = false;
263
+ const finish = (callback) => {
264
+ if (settled) return;
265
+ settled = true;
266
+ cleanup();
267
+ callback();
268
+ };
269
+ const onData = (chunk) => {
270
+ chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk));
271
+ };
272
+ const onEnd = () => {
273
+ finish(() => {
274
+ const buffer = chunks.length === 1 ? chunks[0] : Buffer.concat(chunks);
275
+ request[bodyBufferKey] = buffer;
276
+ resolve(buffer);
277
+ });
278
+ };
279
+ const onError = (error) => {
280
+ finish(() => {
281
+ reject(error);
282
+ });
283
+ };
284
+ const onClose = () => {
285
+ if (incoming.readableEnded) {
286
+ onEnd();
287
+ return;
288
+ }
289
+ finish(() => {
290
+ if (incoming.errored) {
291
+ reject(incoming.errored);
292
+ return;
293
+ }
294
+ const reason = request[abortReasonKey];
295
+ if (reason !== void 0) {
296
+ reject(reason instanceof Error ? reason : new Error(String(reason)));
297
+ return;
298
+ }
299
+ reject(/* @__PURE__ */ new Error("Client connection prematurely closed."));
300
+ });
301
+ };
302
+ const cleanup = () => {
303
+ incoming.off("data", onData);
304
+ incoming.off("end", onEnd);
305
+ incoming.off("error", onError);
306
+ incoming.off("close", onClose);
307
+ request[bodyReadPromiseKey] = void 0;
308
+ };
309
+ incoming.on("data", onData);
310
+ incoming.on("end", onEnd);
311
+ incoming.on("error", onError);
312
+ incoming.on("close", onClose);
313
+ queueMicrotask(() => {
314
+ if (settled) return;
315
+ if (incoming.readableEnded) onEnd();
316
+ else if (incoming.errored) onError(incoming.errored);
317
+ else if (incoming.destroyed) onClose();
318
+ });
319
+ });
320
+ request[bodyReadPromiseKey] = promise;
321
+ return promise;
322
+ };
323
+ requestPrototype = {
324
+ get method() {
325
+ return this[methodKey];
326
+ },
327
+ get url() {
328
+ return this[urlKey];
329
+ },
330
+ get headers() {
331
+ return this[headersKey] ||= newHeadersFromIncoming(this[incomingKey]);
332
+ },
333
+ [abortRequest](reason) {
334
+ if (this[abortReasonKey] === void 0) this[abortReasonKey] = reason;
335
+ const abortController = this[abortControllerKey];
336
+ if (abortController && !abortController.signal.aborted) abortController.abort(reason);
337
+ },
338
+ [getAbortController]() {
339
+ this[abortControllerKey] ||= new AbortController();
340
+ if (this[abortReasonKey] !== void 0 && !this[abortControllerKey].signal.aborted) this[abortControllerKey].abort(this[abortReasonKey]);
341
+ return this[abortControllerKey];
342
+ },
343
+ [getRequestCache]() {
344
+ const abortController = this[getAbortController]();
345
+ if (this[requestCache]) return this[requestCache];
346
+ const method = this.method;
347
+ if (this[bodyConsumedDirectlyKey] && !(method === "GET" || method === "HEAD")) {
348
+ this[bodyBufferKey] = void 0;
349
+ const init = {
350
+ method: method === "TRACE" ? "GET" : method,
351
+ headers: this.headers,
352
+ signal: abortController.signal
353
+ };
354
+ if (method !== "TRACE") {
355
+ init.body = new ReadableStream({ start(c) {
356
+ c.close();
357
+ } });
358
+ init.duplex = "half";
359
+ }
360
+ const req = new Request$1(this[urlKey], init);
361
+ if (method === "TRACE") Object.defineProperty(req, "method", { get() {
362
+ return "TRACE";
363
+ } });
364
+ return this[requestCache] = req;
365
+ }
366
+ return this[requestCache] = newRequestFromIncoming(this.method, this[urlKey], this.headers, this[incomingKey], abortController);
367
+ },
368
+ get body() {
369
+ if (!this[bodyConsumedDirectlyKey]) return this[getRequestCache]().body;
370
+ const request = this[getRequestCache]();
371
+ if (!this[bodyLockReaderKey] && request.body) this[bodyLockReaderKey] = request.body.getReader();
372
+ return request.body;
373
+ },
374
+ get bodyUsed() {
375
+ if (this[bodyConsumedDirectlyKey]) return true;
376
+ if (this[requestCache]) return this[requestCache].bodyUsed;
377
+ return false;
378
+ }
379
+ };
380
+ Object.defineProperty(requestPrototype, "signal", { get() {
381
+ return this[getAbortController]().signal;
382
+ } });
383
+ [
384
+ "cache",
385
+ "credentials",
386
+ "destination",
387
+ "integrity",
388
+ "mode",
389
+ "redirect",
390
+ "referrer",
391
+ "referrerPolicy",
392
+ "keepalive"
393
+ ].forEach((k) => {
394
+ Object.defineProperty(requestPrototype, k, { get() {
395
+ return this[getRequestCache]()[k];
396
+ } });
397
+ });
398
+ ["clone", "formData"].forEach((k) => {
399
+ Object.defineProperty(requestPrototype, k, { value: function() {
400
+ if (this[bodyConsumedDirectlyKey]) {
401
+ if (k === "clone") throw newBodyUnusableError();
402
+ return rejectBodyUnusable();
403
+ }
404
+ return this[getRequestCache]()[k]();
405
+ } });
406
+ });
407
+ Object.defineProperty(requestPrototype, "text", { value: function() {
408
+ return readBodyWithFastPath(this, "text", (buf) => textDecoder.decode(buf));
409
+ } });
410
+ Object.defineProperty(requestPrototype, "arrayBuffer", { value: function() {
411
+ return readBodyWithFastPath(this, "arrayBuffer", (buf) => toArrayBuffer(buf));
412
+ } });
413
+ Object.defineProperty(requestPrototype, "blob", { value: function() {
414
+ return readBodyWithFastPath(this, "blob", (buf, request) => {
415
+ const type = contentType(request);
416
+ const init = type ? { headers: { "content-type": type } } : void 0;
417
+ return new Response(buf, init).blob();
418
+ });
419
+ } });
420
+ Object.defineProperty(requestPrototype, "json", { value: function() {
421
+ if (this[bodyConsumedDirectlyKey]) return rejectBodyUnusable();
422
+ return this.text().then(JSON.parse);
423
+ } });
424
+ Object.defineProperty(requestPrototype, /* @__PURE__ */ Symbol.for("nodejs.util.inspect.custom"), { value: function(depth, options, inspectFn) {
425
+ return `Request (lightweight) ${inspectFn({
426
+ method: this.method,
427
+ url: this.url,
428
+ headers: this.headers,
429
+ nativeRequest: this[requestCache]
430
+ }, {
431
+ ...options,
432
+ depth: depth == null ? null : depth - 1
433
+ })}`;
434
+ } });
435
+ Object.setPrototypeOf(requestPrototype, Request$1.prototype);
436
+ newRequest = (incoming, defaultHostname) => {
437
+ const req = Object.create(requestPrototype);
438
+ req[incomingKey] = incoming;
439
+ req[methodKey] = normalizeIncomingMethod(incoming.method);
440
+ const incomingUrl = incoming.url || "";
441
+ if (incomingUrl[0] !== "/" && (incomingUrl.startsWith("http://") || incomingUrl.startsWith("https://"))) {
442
+ if (incoming instanceof import_node_http2.Http2ServerRequest) throw new RequestError("Absolute URL for :path is not allowed in HTTP/2");
443
+ try {
444
+ req[urlKey] = new URL(incomingUrl).href;
445
+ } catch (e) {
446
+ throw new RequestError("Invalid absolute URL", { cause: e });
447
+ }
448
+ return req;
449
+ }
450
+ const host = (incoming instanceof import_node_http2.Http2ServerRequest ? incoming.authority : incoming.headers.host) || defaultHostname;
451
+ if (!host) throw new RequestError("Missing host header");
452
+ let scheme;
453
+ if (incoming instanceof import_node_http2.Http2ServerRequest) {
454
+ scheme = incoming.scheme;
455
+ if (!(scheme === "http" || scheme === "https")) throw new RequestError("Unsupported scheme");
456
+ } else scheme = incoming.socket && incoming.socket.encrypted ? "https" : "http";
457
+ try {
458
+ req[urlKey] = buildUrl(scheme, host, incomingUrl);
459
+ } catch (e) {
460
+ if (e instanceof RequestError) throw e;
461
+ else throw new RequestError("Invalid URL", { cause: e });
462
+ }
463
+ return req;
464
+ };
465
+ defaultContentType = "text/plain; charset=UTF-8";
466
+ responseCache = /* @__PURE__ */ Symbol("responseCache");
467
+ getResponseCache = /* @__PURE__ */ Symbol("getResponseCache");
468
+ cacheKey = /* @__PURE__ */ Symbol("cache");
469
+ GlobalResponse = global.Response;
470
+ Response$1 = class Response$12 {
471
+ #body;
472
+ #init;
473
+ [getResponseCache]() {
474
+ const cache = this[cacheKey];
475
+ const liveHeaders = cache && cache[2] instanceof Headers ? cache[2] : void 0;
476
+ delete this[cacheKey];
477
+ return this[responseCache] ||= new GlobalResponse(this.#body, liveHeaders ? {
478
+ ...this.#init,
479
+ headers: liveHeaders
480
+ } : this.#init);
481
+ }
482
+ constructor(body, init) {
483
+ let headers;
484
+ this.#body = body;
485
+ if (init instanceof Response$12) {
486
+ const cachedGlobalResponse = init[responseCache];
487
+ if (cachedGlobalResponse) {
488
+ this.#init = cachedGlobalResponse;
489
+ this[getResponseCache]();
490
+ return;
491
+ } else {
492
+ this.#init = init.#init;
493
+ headers = new Headers(init.headers);
494
+ }
495
+ } else this.#init = init;
496
+ if (body == null || typeof body === "string" || typeof body?.getReader !== "undefined" || body instanceof Blob || body instanceof Uint8Array) this[cacheKey] = [
497
+ init?.status || 200,
498
+ body ?? null,
499
+ headers || init?.headers
500
+ ];
501
+ }
502
+ get headers() {
503
+ const cache = this[cacheKey];
504
+ if (cache) {
505
+ if (!(cache[2] instanceof Headers)) cache[2] = new Headers(cache[2] || (cache[1] === null ? void 0 : { "content-type": defaultContentType }));
506
+ return cache[2];
507
+ }
508
+ return this[getResponseCache]().headers;
509
+ }
510
+ get status() {
511
+ return this[cacheKey]?.[0] ?? this[getResponseCache]().status;
512
+ }
513
+ get ok() {
514
+ const status = this.status;
515
+ return status >= 200 && status < 300;
516
+ }
517
+ };
518
+ [
519
+ "body",
520
+ "bodyUsed",
521
+ "redirected",
522
+ "statusText",
523
+ "trailers",
524
+ "type",
525
+ "url"
526
+ ].forEach((k) => {
527
+ Object.defineProperty(Response$1.prototype, k, { get() {
528
+ return this[getResponseCache]()[k];
529
+ } });
530
+ });
531
+ [
532
+ "arrayBuffer",
533
+ "blob",
534
+ "clone",
535
+ "formData",
536
+ "json",
537
+ "text"
538
+ ].forEach((k) => {
539
+ Object.defineProperty(Response$1.prototype, k, { value: function() {
540
+ return this[getResponseCache]()[k]();
541
+ } });
542
+ });
543
+ Object.defineProperty(Response$1.prototype, /* @__PURE__ */ Symbol.for("nodejs.util.inspect.custom"), { value: function(depth, options, inspectFn) {
544
+ return `Response (lightweight) ${inspectFn({
545
+ status: this.status,
546
+ headers: this.headers,
547
+ ok: this.ok,
548
+ nativeResponse: this[responseCache]
549
+ }, {
550
+ ...options,
551
+ depth: depth == null ? null : depth - 1
552
+ })}`;
553
+ } });
554
+ Object.setPrototypeOf(Response$1, GlobalResponse);
555
+ Object.setPrototypeOf(Response$1.prototype, GlobalResponse.prototype);
556
+ validRedirectUrl = /^https?:\/\/[!#-;=?-[\]_a-z~A-Z]+$/;
557
+ parseRedirectUrl = (url) => {
558
+ if (url instanceof URL) return url.href;
559
+ if (validRedirectUrl.test(url)) return url;
560
+ return new URL(url).href;
561
+ };
562
+ validRedirectStatuses = /* @__PURE__ */ new Set([
563
+ 301,
564
+ 302,
565
+ 303,
566
+ 307,
567
+ 308
568
+ ]);
569
+ Object.defineProperty(Response$1, "redirect", {
570
+ value: function redirect(url, status = 302) {
571
+ if (!validRedirectStatuses.has(status)) throw new RangeError("Invalid status code");
572
+ return new Response$1(null, {
573
+ status,
574
+ headers: { location: parseRedirectUrl(url) }
575
+ });
576
+ },
577
+ writable: true,
578
+ configurable: true
579
+ });
580
+ Object.defineProperty(Response$1, "json", {
581
+ value: function json(data, init) {
582
+ const body = JSON.stringify(data);
583
+ if (body === void 0) throw new TypeError("The data is not JSON serializable");
584
+ const initHeaders = init?.headers;
585
+ let headers;
586
+ if (initHeaders) {
587
+ headers = new Headers(initHeaders);
588
+ if (!headers.has("content-type")) headers.set("content-type", "application/json");
589
+ } else headers = { "content-type": "application/json" };
590
+ return new Response$1(body, {
591
+ status: init?.status ?? 200,
592
+ statusText: init?.statusText,
593
+ headers
594
+ });
595
+ },
596
+ writable: true,
597
+ configurable: true
598
+ });
599
+ buildOutgoingHttpHeaders = (headers, defaultContentType2) => {
600
+ const res = {};
601
+ if (!(headers instanceof Headers)) headers = new Headers(headers ?? void 0);
602
+ if (headers.has("set-cookie")) {
603
+ const cookies = [];
604
+ for (const [k, v] of headers) if (k === "set-cookie") cookies.push(v);
605
+ else res[k] = v;
606
+ if (cookies.length > 0) res["set-cookie"] = cookies;
607
+ } else for (const [k, v] of headers) res[k] = v;
608
+ if (defaultContentType2) res["content-type"] ??= defaultContentType2;
609
+ return res;
610
+ };
611
+ outgoingEnded = /* @__PURE__ */ Symbol("outgoingEnded");
612
+ incomingDraining = /* @__PURE__ */ Symbol("incomingDraining");
613
+ DRAIN_TIMEOUT_MS = 500;
614
+ MAX_DRAIN_BYTES = 64 * 1024 * 1024;
615
+ drainIncoming = (incoming) => {
616
+ const incomingWithDrainState = incoming;
617
+ if (incoming.destroyed || incomingWithDrainState[incomingDraining]) return;
618
+ incomingWithDrainState[incomingDraining] = true;
619
+ if (incoming instanceof import_node_http2.Http2ServerRequest) {
620
+ try {
621
+ incoming.stream?.close?.(import_node_http2.constants.NGHTTP2_NO_ERROR);
622
+ } catch {
623
+ }
624
+ return;
625
+ }
626
+ let bytesRead = 0;
627
+ const cleanup = () => {
628
+ clearTimeout(timer);
629
+ incoming.off("data", onData);
630
+ incoming.off("end", cleanup);
631
+ incoming.off("error", cleanup);
632
+ };
633
+ const forceClose = () => {
634
+ cleanup();
635
+ const socket = incoming.socket;
636
+ if (socket && !socket.destroyed) socket.destroySoon();
637
+ };
638
+ const timer = setTimeout(forceClose, DRAIN_TIMEOUT_MS);
639
+ timer.unref?.();
640
+ const onData = (chunk) => {
641
+ bytesRead += chunk.length;
642
+ if (bytesRead > MAX_DRAIN_BYTES) forceClose();
643
+ };
644
+ incoming.on("data", onData);
645
+ incoming.on("end", cleanup);
646
+ incoming.on("error", cleanup);
647
+ incoming.resume();
648
+ };
649
+ makeCloseHandler = (req, incoming, outgoing, needsBodyCleanup) => () => {
650
+ if (incoming.errored) req[abortRequest](incoming.errored.toString());
651
+ else if (!outgoing.writableFinished) req[abortRequest]("Client connection prematurely closed.");
652
+ if (needsBodyCleanup && !incoming.readableEnded) setTimeout(() => {
653
+ if (!incoming.readableEnded) setTimeout(() => {
654
+ drainIncoming(incoming);
655
+ });
656
+ });
657
+ };
658
+ isImmediateCacheableResponse = (res) => {
659
+ if (!(cacheKey in res)) return false;
660
+ const body = res[cacheKey][1];
661
+ return body === null || typeof body === "string" || body instanceof Uint8Array;
662
+ };
663
+ handleRequestError = () => new Response(null, { status: 400 });
664
+ handleFetchError = (e) => new Response(null, { status: e instanceof Error && (e.name === "TimeoutError" || e.constructor.name === "TimeoutError") ? 504 : 500 });
665
+ handleResponseError = (e, outgoing) => {
666
+ const err = e instanceof Error ? e : new Error("unknown error", { cause: e });
667
+ if (err.code === "ERR_STREAM_PREMATURE_CLOSE") console.info("The user aborted a request.");
668
+ else {
669
+ console.error(e);
670
+ if (!outgoing.headersSent) outgoing.writeHead(500, { "Content-Type": "text/plain" });
671
+ outgoing.end(`Error: ${err.message}`);
672
+ outgoing.destroy(err);
673
+ }
674
+ };
675
+ flushHeaders = (outgoing) => {
676
+ if ("flushHeaders" in outgoing && outgoing.writable) outgoing.flushHeaders();
677
+ };
678
+ responseViaCache = async (res, outgoing) => {
679
+ let [status, body, header] = res[cacheKey];
680
+ if (!header) {
681
+ if (body === null) {
682
+ outgoing.writeHead(status);
683
+ outgoing.end();
684
+ } else if (typeof body === "string") {
685
+ outgoing.writeHead(status, {
686
+ "Content-Type": defaultContentType,
687
+ "Content-Length": Buffer.byteLength(body)
688
+ });
689
+ outgoing.end(body);
690
+ } else if (body instanceof Uint8Array) {
691
+ outgoing.writeHead(status, {
692
+ "Content-Type": defaultContentType,
693
+ "Content-Length": body.byteLength
694
+ });
695
+ outgoing.end(body);
696
+ } else if (body instanceof Blob) {
697
+ outgoing.writeHead(status, {
698
+ "Content-Type": defaultContentType,
699
+ "Content-Length": body.size
700
+ });
701
+ outgoing.end(new Uint8Array(await body.arrayBuffer()));
702
+ } else {
703
+ outgoing.writeHead(status, { "Content-Type": defaultContentType });
704
+ flushHeaders(outgoing);
705
+ await writeFromReadableStream(body, outgoing)?.catch((e) => handleResponseError(e, outgoing));
706
+ }
707
+ outgoing[outgoingEnded]?.();
708
+ return;
709
+ }
710
+ let hasContentLength = false;
711
+ if (header instanceof Headers) {
712
+ hasContentLength = header.has("content-length");
713
+ header = buildOutgoingHttpHeaders(header, body === null ? void 0 : defaultContentType);
714
+ } else if (Array.isArray(header)) {
715
+ const headerObj = new Headers(header);
716
+ hasContentLength = headerObj.has("content-length");
717
+ header = buildOutgoingHttpHeaders(headerObj, body === null ? void 0 : defaultContentType);
718
+ } else for (const key in header) if (key.length === 14 && key.toLowerCase() === "content-length") {
719
+ hasContentLength = true;
720
+ break;
721
+ }
722
+ if (!hasContentLength) {
723
+ if (typeof body === "string") header["Content-Length"] = Buffer.byteLength(body);
724
+ else if (body instanceof Uint8Array) header["Content-Length"] = body.byteLength;
725
+ else if (body instanceof Blob) header["Content-Length"] = body.size;
726
+ }
727
+ outgoing.writeHead(status, header);
728
+ if (body == null) outgoing.end();
729
+ else if (typeof body === "string" || body instanceof Uint8Array) outgoing.end(body);
730
+ else if (body instanceof Blob) outgoing.end(new Uint8Array(await body.arrayBuffer()));
731
+ else {
732
+ flushHeaders(outgoing);
733
+ await writeFromReadableStream(body, outgoing)?.catch((e) => handleResponseError(e, outgoing));
734
+ }
735
+ outgoing[outgoingEnded]?.();
736
+ };
737
+ isPromise = (res) => typeof res.then === "function";
738
+ responseViaResponseObject = async (res, outgoing, options = {}) => {
739
+ if (isPromise(res)) if (options.errorHandler) try {
740
+ res = await res;
741
+ } catch (err) {
742
+ const errRes = await options.errorHandler(err);
743
+ if (!errRes) return;
744
+ res = errRes;
745
+ }
746
+ else res = await res.catch(handleFetchError);
747
+ if (cacheKey in res) return responseViaCache(res, outgoing);
748
+ const resHeaderRecord = buildOutgoingHttpHeaders(res.headers, res.body === null ? void 0 : defaultContentType);
749
+ if (res.body) {
750
+ const reader = res.body.getReader();
751
+ const values = [];
752
+ let done = false;
753
+ let currentReadPromise = void 0;
754
+ if (resHeaderRecord["transfer-encoding"] !== "chunked") {
755
+ let maxReadCount = 2;
756
+ for (let i = 0; i < maxReadCount; i++) {
757
+ currentReadPromise ||= reader.read();
758
+ const chunk = await readWithoutBlocking(currentReadPromise).catch((e) => {
759
+ console.error(e);
760
+ done = true;
761
+ });
762
+ if (!chunk) {
763
+ if (i === 1) {
764
+ await new Promise((resolve) => setTimeout(resolve));
765
+ maxReadCount = 3;
766
+ continue;
767
+ }
768
+ break;
769
+ }
770
+ currentReadPromise = void 0;
771
+ if (chunk.value) values.push(chunk.value);
772
+ if (chunk.done) {
773
+ done = true;
774
+ break;
775
+ }
776
+ }
777
+ if (done && !("content-length" in resHeaderRecord)) resHeaderRecord["content-length"] = values.reduce((acc, value) => acc + value.length, 0);
778
+ }
779
+ outgoing.writeHead(res.status, resHeaderRecord);
780
+ values.forEach((value) => {
781
+ outgoing.write(value);
782
+ });
783
+ if (done) outgoing.end();
784
+ else {
785
+ if (values.length === 0) flushHeaders(outgoing);
786
+ await writeFromReadableStreamDefaultReader(reader, outgoing, currentReadPromise);
787
+ }
788
+ } else if (resHeaderRecord[X_ALREADY_SENT]) {
789
+ } else {
790
+ outgoing.writeHead(res.status, resHeaderRecord);
791
+ outgoing.end();
792
+ }
793
+ outgoing[outgoingEnded]?.();
794
+ };
795
+ getRequestListener = (fetchCallback, options = {}) => {
796
+ const autoCleanupIncoming = options.autoCleanupIncoming ?? true;
797
+ if (options.overrideGlobalObjects !== false && global.Request !== Request$1) {
798
+ Object.defineProperty(global, "Request", { value: Request$1 });
799
+ Object.defineProperty(global, "Response", { value: Response$1 });
800
+ }
801
+ return async (incoming, outgoing) => {
802
+ let res, req;
803
+ let needsBodyCleanup = false;
804
+ let closeHandlerAttached = false;
805
+ const ensureCloseHandler = () => {
806
+ if (!req || closeHandlerAttached) return;
807
+ closeHandlerAttached = true;
808
+ outgoing.on("close", makeCloseHandler(req, incoming, outgoing, needsBodyCleanup));
809
+ };
810
+ try {
811
+ req = newRequest(incoming, options.hostname);
812
+ needsBodyCleanup = autoCleanupIncoming && !(incoming.method === "GET" || incoming.method === "HEAD");
813
+ if (needsBodyCleanup) {
814
+ incoming[wrapBodyStream] = true;
815
+ if (incoming instanceof import_node_http2.Http2ServerRequest) outgoing[outgoingEnded] = () => {
816
+ if (!incoming.readableEnded) setTimeout(() => {
817
+ if (!incoming.readableEnded) setTimeout(() => {
818
+ incoming.destroy();
819
+ outgoing.destroy();
820
+ });
821
+ });
822
+ };
823
+ }
824
+ res = fetchCallback(req, {
825
+ incoming,
826
+ outgoing
827
+ });
828
+ if (!isPromise(res) && isImmediateCacheableResponse(res)) {
829
+ if (needsBodyCleanup && !incoming.readableEnded) outgoing.once("finish", () => {
830
+ if (!incoming.readableEnded) drainIncoming(incoming);
831
+ });
832
+ return responseViaCache(res, outgoing);
833
+ }
834
+ ensureCloseHandler();
835
+ } catch (e) {
836
+ if (!res) if (options.errorHandler) {
837
+ ensureCloseHandler();
838
+ res = await options.errorHandler(req ? e : toRequestError(e));
839
+ if (!res) return;
840
+ } else if (!req) res = handleRequestError();
841
+ else res = handleFetchError(e);
842
+ else return handleResponseError(e, outgoing);
843
+ }
844
+ try {
845
+ return await responseViaResponseObject(res, outgoing, options);
846
+ } catch (e) {
847
+ return handleResponseError(e, outgoing);
848
+ }
849
+ };
850
+ };
851
+ CloseEvent = globalThis.CloseEvent ?? class extends Event {
852
+ #eventInitDict;
853
+ constructor(type, eventInitDict = {}) {
854
+ super(type, eventInitDict);
855
+ this.#eventInitDict = eventInitDict;
856
+ }
857
+ get wasClean() {
858
+ return this.#eventInitDict.wasClean ?? false;
859
+ }
860
+ get code() {
861
+ return this.#eventInitDict.code ?? 0;
862
+ }
863
+ get reason() {
864
+ return this.#eventInitDict.reason ?? "";
865
+ }
866
+ };
867
+ generateConnectionSymbol = () => /* @__PURE__ */ Symbol("connection");
868
+ CONNECTION_SYMBOL_KEY = /* @__PURE__ */ Symbol("CONNECTION_SYMBOL_KEY");
869
+ WAIT_FOR_WEBSOCKET_SYMBOL = /* @__PURE__ */ Symbol("WAIT_FOR_WEBSOCKET_SYMBOL");
870
+ responseHeadersToSkip = /* @__PURE__ */ new Set([
871
+ "connection",
872
+ "content-length",
873
+ "keep-alive",
874
+ "proxy-authenticate",
875
+ "proxy-authorization",
876
+ "te",
877
+ "trailer",
878
+ "transfer-encoding",
879
+ "upgrade",
880
+ "sec-websocket-accept",
881
+ "sec-websocket-extensions",
882
+ "sec-websocket-protocol"
883
+ ]);
884
+ appendResponseHeaders = (headers, responseHeaders) => {
885
+ if (!responseHeaders) return;
886
+ responseHeaders.forEach((value, key) => {
887
+ if (responseHeadersToSkip.has(key.toLowerCase())) return;
888
+ headers.push(`${key}: ${value}`);
889
+ });
890
+ };
891
+ rejectUpgradeRequest = (socket, status, responseHeaders) => {
892
+ const responseLines = ["Connection: close", "Content-Length: 0"];
893
+ appendResponseHeaders(responseLines, responseHeaders);
894
+ socket.end(`HTTP/1.1 ${status.toString()} ${import_node_http.STATUS_CODES[status] ?? ""}\r
895
+ ${responseLines.join("\r\n")}\r
896
+ \r
897
+ `);
898
+ };
899
+ createUpgradeRequest = (request) => {
900
+ const protocol = request.socket.encrypted ? "https" : "http";
901
+ const url = new URL(request.url ?? "/", `${protocol}://${request.headers.host ?? "localhost"}`);
902
+ const headers = new Headers();
903
+ for (const key in request.headers) {
904
+ const value = request.headers[key];
905
+ if (!value) continue;
906
+ headers.append(key, Array.isArray(value) ? value[0] : value);
907
+ }
908
+ return new Request(url, { headers });
909
+ };
910
+ setupWebSocket = (options) => {
911
+ const { server, fetchCallback, wss } = options;
912
+ const waiterMap = /* @__PURE__ */ new Map();
913
+ wss.on("connection", (ws, request) => {
914
+ const waiter = waiterMap.get(request);
915
+ if (waiter) {
916
+ waiter.resolve(ws);
917
+ waiterMap.delete(request);
918
+ }
919
+ });
920
+ const waitForWebSocket = (request, connectionSymbol) => {
921
+ return new Promise((resolve) => {
922
+ waiterMap.set(request, {
923
+ resolve,
924
+ connectionSymbol
925
+ });
926
+ });
927
+ };
928
+ server.on("upgrade", async (request, socket, head) => {
929
+ if (request.headers.upgrade?.toLowerCase() !== "websocket") return;
930
+ const env = {
931
+ incoming: request,
932
+ outgoing: void 0,
933
+ wss,
934
+ [WAIT_FOR_WEBSOCKET_SYMBOL]: waitForWebSocket
935
+ };
936
+ let status = 400;
937
+ let responseHeaders;
938
+ try {
939
+ const response = await fetchCallback(createUpgradeRequest(request), env);
940
+ if (response instanceof Response) {
941
+ status = response.status;
942
+ responseHeaders = response.headers;
943
+ }
944
+ } catch {
945
+ if (server.listenerCount("upgrade") === 1) rejectUpgradeRequest(socket, 500);
946
+ return;
947
+ }
948
+ const waiter = waiterMap.get(request);
949
+ if (!waiter || waiter.connectionSymbol !== env[CONNECTION_SYMBOL_KEY]) {
950
+ waiterMap.delete(request);
951
+ if (server.listenerCount("upgrade") === 1) rejectUpgradeRequest(socket, status, responseHeaders);
952
+ return;
953
+ }
954
+ const addResponseHeaders = (headers) => {
955
+ appendResponseHeaders(headers, responseHeaders);
956
+ };
957
+ wss.on("headers", addResponseHeaders);
958
+ try {
959
+ wss.handleUpgrade(request, socket, head, (ws) => {
960
+ wss.emit("connection", ws, request);
961
+ });
962
+ } finally {
963
+ wss.off("headers", addResponseHeaders);
964
+ }
965
+ });
966
+ server.on("close", () => {
967
+ wss.close();
968
+ });
969
+ };
970
+ upgradeWebSocket = (0, import_ws.defineWebSocketHelper)(async (c, events, options) => {
971
+ if (c.req.header("upgrade")?.toLowerCase() !== "websocket") return;
972
+ const env = c.env;
973
+ const waitForWebSocket = env[WAIT_FOR_WEBSOCKET_SYMBOL];
974
+ if (!waitForWebSocket || !env.incoming) return new Response(null, { status: 500 });
975
+ const connectionSymbol = generateConnectionSymbol();
976
+ env[CONNECTION_SYMBOL_KEY] = connectionSymbol;
977
+ (async () => {
978
+ const ws = await waitForWebSocket(env.incoming, connectionSymbol);
979
+ const messagesReceivedInStarting = [];
980
+ const bufferMessage = (data, isBinary) => {
981
+ messagesReceivedInStarting.push([data, isBinary]);
982
+ };
983
+ ws.on("message", bufferMessage);
984
+ const ctx = {
985
+ binaryType: "arraybuffer",
986
+ close(code, reason) {
987
+ ws.close(code, reason);
988
+ },
989
+ protocol: ws.protocol,
990
+ raw: ws,
991
+ get readyState() {
992
+ return ws.readyState;
993
+ },
994
+ send(source, opts) {
995
+ ws.send(source, { compress: opts?.compress });
996
+ },
997
+ url: new URL(c.req.url)
998
+ };
999
+ try {
1000
+ events?.onOpen?.(new Event("open"), ctx);
1001
+ } catch (e) {
1002
+ (options?.onError ?? console.error)(e);
1003
+ }
1004
+ const handleMessage = (data, isBinary) => {
1005
+ const datas = Array.isArray(data) ? data : [data];
1006
+ for (const data2 of datas) try {
1007
+ events?.onMessage?.(new MessageEvent("message", { data: isBinary ? data2 instanceof ArrayBuffer ? data2 : data2.buffer.slice(data2.byteOffset, data2.byteOffset + data2.byteLength) : typeof data2 === "string" ? data2 : Buffer.from(data2).toString("utf-8") }), ctx);
1008
+ } catch (e) {
1009
+ (options?.onError ?? console.error)(e);
1010
+ }
1011
+ };
1012
+ ws.off("message", bufferMessage);
1013
+ for (const message of messagesReceivedInStarting) handleMessage(...message);
1014
+ ws.on("message", (data, isBinary) => {
1015
+ handleMessage(data, isBinary);
1016
+ });
1017
+ ws.on("close", (code, reason) => {
1018
+ try {
1019
+ events?.onClose?.(new CloseEvent("close", {
1020
+ code,
1021
+ reason: reason.toString()
1022
+ }), ctx);
1023
+ } catch (e) {
1024
+ (options?.onError ?? console.error)(e);
1025
+ }
1026
+ });
1027
+ ws.on("error", (error) => {
1028
+ try {
1029
+ events?.onError?.(new ErrorEvent("error", { error }), ctx);
1030
+ } catch (e) {
1031
+ (options?.onError ?? console.error)(e);
1032
+ }
1033
+ });
1034
+ })();
1035
+ return new Response();
1036
+ });
1037
+ createAdaptorServer = (options) => {
1038
+ const fetchCallback = options.fetch;
1039
+ const requestListener = getRequestListener(fetchCallback, {
1040
+ hostname: options.hostname,
1041
+ overrideGlobalObjects: options.overrideGlobalObjects,
1042
+ autoCleanupIncoming: options.autoCleanupIncoming
1043
+ });
1044
+ const server = (options.createServer || import_node_http.createServer)(options.serverOptions || {}, requestListener);
1045
+ if (options.websocket && options.websocket.server) {
1046
+ if (options.websocket.server.options.noServer !== true) throw new Error("WebSocket server must be created with { noServer: true } option");
1047
+ setupWebSocket({
1048
+ server,
1049
+ fetchCallback,
1050
+ wss: options.websocket.server
1051
+ });
1052
+ }
1053
+ return server;
1054
+ };
1055
+ serve = (options, listeningListener) => {
1056
+ const server = createAdaptorServer(options);
1057
+ server.listen(options?.port ?? 3e3, options.hostname, () => {
1058
+ const serverInfo = server.address();
1059
+ listeningListener && listeningListener(serverInfo);
1060
+ });
1061
+ return server;
1062
+ };
1063
+ }
1064
+ });
1065
+
1066
+ // src/index.ts
1067
+ var index_exports = {};
1068
+ __export(index_exports, {
1069
+ ApiKeyAuth: () => ApiKeyAuth,
1070
+ AsyncRunRegistry: () => AsyncRunRegistry,
1071
+ BatchRunner: () => BatchRunner,
1072
+ InMemoryQuota: () => InMemoryQuota,
1073
+ InMemoryTokenBucketLimiter: () => InMemoryTokenBucketLimiter,
1074
+ NoAuth: () => NoAuth,
1075
+ Scheduler: () => Scheduler,
1076
+ WorkflowRunError: () => import_workflow2.WorkflowRunError,
1077
+ createServer: () => createServer2,
1078
+ serveNode: () => serveNode,
1079
+ toUIMessageStream: () => toUIMessageStream,
1080
+ toUIMessageStreamResponse: () => toUIMessageStreamResponse
1081
+ });
1082
+ module.exports = __toCommonJS(index_exports);
1083
+ var import_hono = require("hono");
1084
+ var import_streaming = require("hono/streaming");
1085
+ var import_body_limit = require("hono/body-limit");
1086
+ var import_cors = require("hono/cors");
1087
+ var import_workflow = require("@eidentic/workflow");
1088
+
1089
+ // src/rate-limit.ts
1090
+ var InMemoryTokenBucketLimiter = class {
1091
+ capacity;
1092
+ refillPerSec;
1093
+ now;
1094
+ buckets = /* @__PURE__ */ new Map();
1095
+ /**
1096
+ * The eviction threshold in ms: entries older than this are guaranteed to be
1097
+ * at full capacity, so removing them is lossless.
1098
+ * = (capacity / refillPerSec) * 1000 * 2
1099
+ * For zero-refill configs a fixed 24-hour window bounds growth.
1100
+ */
1101
+ evictThresholdMs;
1102
+ /**
1103
+ * Sweep runs at most once per this interval. Set to half the eviction
1104
+ * threshold so that stale entries are caught within at most one extra window.
1105
+ */
1106
+ sweepIntervalMs;
1107
+ lastSweepMs = 0;
1108
+ constructor(opts) {
1109
+ this.capacity = opts.capacity;
1110
+ this.refillPerSec = opts.refillPerSec;
1111
+ this.now = opts.now ?? (() => Date.now());
1112
+ if (opts.refillPerSec > 0) {
1113
+ const fullRefillMs = opts.capacity / opts.refillPerSec * 1e3;
1114
+ this.evictThresholdMs = fullRefillMs * 2;
1115
+ this.sweepIntervalMs = fullRefillMs;
1116
+ } else {
1117
+ this.evictThresholdMs = 864e5;
1118
+ this.sweepIntervalMs = 36e5;
1119
+ }
1120
+ }
1121
+ /**
1122
+ * Test-only accessor: number of entries currently held in the buckets map.
1123
+ * Not part of the `RateLimiterPort` contract.
1124
+ */
1125
+ get bucketCount() {
1126
+ return this.buckets.size;
1127
+ }
1128
+ acquire(key, cost = 1) {
1129
+ const nowMs = this.now();
1130
+ if (nowMs - this.lastSweepMs >= this.sweepIntervalMs) {
1131
+ this._sweep(nowMs);
1132
+ this.lastSweepMs = nowMs;
1133
+ }
1134
+ let bucket = this.buckets.get(key);
1135
+ if (!bucket) {
1136
+ bucket = { tokens: this.capacity, lastRefillMs: nowMs };
1137
+ this.buckets.set(key, bucket);
1138
+ }
1139
+ const elapsedSec = (nowMs - bucket.lastRefillMs) / 1e3;
1140
+ bucket.tokens = Math.min(this.capacity, bucket.tokens + elapsedSec * this.refillPerSec);
1141
+ bucket.lastRefillMs = nowMs;
1142
+ if (bucket.tokens >= cost) {
1143
+ bucket.tokens -= cost;
1144
+ return { ok: true, remaining: Math.floor(bucket.tokens) };
1145
+ }
1146
+ const retryAfterMs = this.refillPerSec > 0 ? Math.ceil((cost - bucket.tokens) / this.refillPerSec * 1e3) : void 0;
1147
+ return { ok: false, retryAfterMs, remaining: Math.floor(bucket.tokens) };
1148
+ }
1149
+ /**
1150
+ * Evict bucket entries older than `evictThresholdMs`. Called opportunistically
1151
+ * from `acquire` — no timer involved.
1152
+ */
1153
+ _sweep(nowMs) {
1154
+ for (const [k, state] of this.buckets) {
1155
+ if (nowMs - state.lastRefillMs > this.evictThresholdMs) {
1156
+ this.buckets.delete(k);
1157
+ }
1158
+ }
1159
+ }
1160
+ };
1161
+
1162
+ // src/quota.ts
1163
+ var InMemoryQuota = class {
1164
+ resolve;
1165
+ ledger = /* @__PURE__ */ new Map();
1166
+ /** In-flight run count per key: incremented on check, decremented on record/release. */
1167
+ reserved = /* @__PURE__ */ new Map();
1168
+ /** Per-key monotonic generation counter, bumped on reset() to invalidate outstanding tokens. */
1169
+ generations = /* @__PURE__ */ new Map();
1170
+ /** All live reservation tokens, used by the max-age sweep. */
1171
+ activeReservations = /* @__PURE__ */ new Set();
1172
+ /** Max-age sweep interval handle — cleared on destroy(). */
1173
+ sweepInterval;
1174
+ /** How old a reservation must be (ms) before the sweep discards it. Default 5 minutes. */
1175
+ reservationMaxAgeMs;
1176
+ constructor(limits, options) {
1177
+ this.resolve = typeof limits === "function" ? limits : () => limits;
1178
+ this.reservationMaxAgeMs = options?.reservationMaxAgeMs ?? 3e5;
1179
+ if (this.reservationMaxAgeMs > 0 && isFinite(this.reservationMaxAgeMs)) {
1180
+ this.sweepInterval = setInterval(() => {
1181
+ this.sweepStaleReservations();
1182
+ }, this.reservationMaxAgeMs);
1183
+ if (typeof this.sweepInterval === "object" && this.sweepInterval !== null && typeof this.sweepInterval.unref === "function") {
1184
+ this.sweepInterval.unref();
1185
+ }
1186
+ }
1187
+ }
1188
+ /**
1189
+ * Release all stale reservations (older than `reservationMaxAgeMs`).
1190
+ * Called automatically by the background sweep, but also available for testing.
1191
+ */
1192
+ sweepStaleReservations() {
1193
+ const now = Date.now();
1194
+ for (const reservation of this.activeReservations) {
1195
+ if (now - reservation.createdAt >= this.reservationMaxAgeMs) {
1196
+ this.activeReservations.delete(reservation);
1197
+ if (reservation.generation === this.getGeneration(reservation.key)) {
1198
+ const cur = this.getReserved(reservation.key);
1199
+ if (cur > 0) this.reserved.set(reservation.key, cur - 1);
1200
+ }
1201
+ }
1202
+ }
1203
+ }
1204
+ /**
1205
+ * Stop the background sweep interval. Call this when shutting down to prevent
1206
+ * open handle warnings in tests and to release resources cleanly.
1207
+ */
1208
+ destroy() {
1209
+ if (this.sweepInterval !== void 0) {
1210
+ clearInterval(this.sweepInterval);
1211
+ }
1212
+ }
1213
+ getUsage(key) {
1214
+ let u = this.ledger.get(key);
1215
+ if (!u) {
1216
+ u = { usd: 0, tokens: 0, runs: 0 };
1217
+ this.ledger.set(key, u);
1218
+ }
1219
+ return u;
1220
+ }
1221
+ getGeneration(key) {
1222
+ return this.generations.get(key) ?? 0;
1223
+ }
1224
+ getReserved(key) {
1225
+ return this.reserved.get(key) ?? 0;
1226
+ }
1227
+ /**
1228
+ * Check whether `key` may start another run. On success, reserves 1 run in the in-flight
1229
+ * counter and returns a `reservation` token. Hard ceilings are checked against
1230
+ * `committed + reserved` so concurrent callers see each other's pending runs.
1231
+ *
1232
+ * Always call `record(key, spend, reservation)` or `release(reservation)` after `check`
1233
+ * to free the reservation and prevent in-flight count leakage.
1234
+ */
1235
+ check(key) {
1236
+ const limits = this.resolve(key);
1237
+ const usage = this.getUsage(key);
1238
+ const inFlight = this.getReserved(key);
1239
+ if (limits.hardUsd !== void 0 && usage.usd >= limits.hardUsd) {
1240
+ return { ok: false, reason: `hard USD ceiling reached (${usage.usd} >= ${limits.hardUsd})`, usage };
1241
+ }
1242
+ if (limits.hardTokens !== void 0 && usage.tokens >= limits.hardTokens) {
1243
+ return { ok: false, reason: `hard token ceiling reached (${usage.tokens} >= ${limits.hardTokens})`, usage };
1244
+ }
1245
+ if (limits.hardRuns !== void 0 && usage.runs + inFlight >= limits.hardRuns) {
1246
+ return { ok: false, reason: `hard run ceiling reached (${usage.runs + inFlight} >= ${limits.hardRuns})`, usage };
1247
+ }
1248
+ this.reserved.set(key, inFlight + 1);
1249
+ const generation = this.getGeneration(key);
1250
+ const reservation = { key, generation, createdAt: Date.now() };
1251
+ this.activeReservations.add(reservation);
1252
+ const warn = limits.softUsd !== void 0 && usage.usd >= limits.softUsd;
1253
+ return { ok: true, warn: warn || void 0, usage, reservation };
1254
+ }
1255
+ /**
1256
+ * Settle a reservation by recording actual spend. The 1-run reservation is consumed and the
1257
+ * committed counter is updated with the real spend. If `reservation` is provided and stale
1258
+ * (reset() was called between check and record), the settle is a no-op — no double-counting.
1259
+ *
1260
+ * Legacy callers that omit `reservation` still have their spend committed (backward-compatible),
1261
+ * but the in-flight counter is not decremented (they weren't reserving).
1262
+ */
1263
+ record(key, spend, reservation) {
1264
+ if (reservation !== void 0) {
1265
+ this.activeReservations.delete(reservation);
1266
+ if (reservation.generation === this.getGeneration(key)) {
1267
+ const cur = this.getReserved(key);
1268
+ if (cur > 0) this.reserved.set(key, cur - 1);
1269
+ }
1270
+ }
1271
+ const usage = this.getUsage(key);
1272
+ usage.usd += spend.usd;
1273
+ usage.tokens += spend.tokens;
1274
+ usage.runs += 1;
1275
+ }
1276
+ /**
1277
+ * Release a reservation WITHOUT recording spend (error / abort path).
1278
+ * If the token is stale (reset() was called), this is a no-op.
1279
+ */
1280
+ release(reservation) {
1281
+ this.activeReservations.delete(reservation);
1282
+ if (reservation.generation !== this.getGeneration(reservation.key)) return;
1283
+ const cur = this.getReserved(reservation.key);
1284
+ if (cur > 0) this.reserved.set(reservation.key, cur - 1);
1285
+ }
1286
+ /**
1287
+ * Reset usage counters for a specific key, or ALL keys when called with no argument.
1288
+ * Increments the generation counter for affected keys so outstanding reservation tokens
1289
+ * become stale and cannot settle against the fresh state.
1290
+ * Useful for tests and dev tooling.
1291
+ */
1292
+ reset(key) {
1293
+ if (key !== void 0) {
1294
+ this.ledger.delete(key);
1295
+ this.reserved.delete(key);
1296
+ this.generations.set(key, (this.generations.get(key) ?? 0) + 1);
1297
+ for (const r of this.activeReservations) {
1298
+ if (r.key === key) this.activeReservations.delete(r);
1299
+ }
1300
+ } else {
1301
+ this.ledger.clear();
1302
+ this.reserved.clear();
1303
+ for (const k of [...this.generations.keys()]) {
1304
+ this.generations.set(k, (this.generations.get(k) ?? 0) + 1);
1305
+ }
1306
+ this.activeReservations.clear();
1307
+ }
1308
+ }
1309
+ };
1310
+
1311
+ // src/ui-message-stream.ts
1312
+ var import_ai = require("ai");
1313
+ function toUIMessageStream(events) {
1314
+ return (0, import_ai.createUIMessageStream)({
1315
+ execute: async ({ writer }) => {
1316
+ writer.write({ type: "start" });
1317
+ writer.write({ type: "start-step" });
1318
+ let textBlockOpen = false;
1319
+ let textBlockId = "text-0";
1320
+ function openTextBlock(id) {
1321
+ if (!textBlockOpen) {
1322
+ textBlockId = id;
1323
+ writer.write({ type: "text-start", id: textBlockId });
1324
+ textBlockOpen = true;
1325
+ }
1326
+ }
1327
+ function closeTextBlock() {
1328
+ if (textBlockOpen) {
1329
+ writer.write({ type: "text-end", id: textBlockId });
1330
+ textBlockOpen = false;
1331
+ }
1332
+ }
1333
+ for await (const ev of events) {
1334
+ switch (ev.type) {
1335
+ // ------------------------------------------------------------------
1336
+ // Streaming token delta — primary hot path for live text streaming
1337
+ // ------------------------------------------------------------------
1338
+ case "stream.delta": {
1339
+ openTextBlock("streaming-text");
1340
+ writer.write({ type: "text-delta", delta: ev.delta.text, id: textBlockId });
1341
+ break;
1342
+ }
1343
+ // ------------------------------------------------------------------
1344
+ // Assistant turn — complete content blocks (text + tool_use)
1345
+ // ------------------------------------------------------------------
1346
+ case "assistant": {
1347
+ closeTextBlock();
1348
+ for (const block of ev.content) {
1349
+ if (block.type === "text") {
1350
+ const id = `text-${crypto.randomUUID()}`;
1351
+ writer.write({ type: "text-start", id });
1352
+ writer.write({ type: "text-delta", delta: block.text, id });
1353
+ writer.write({ type: "text-end", id });
1354
+ } else if (block.type === "tool_use") {
1355
+ writer.write({
1356
+ type: "tool-input-available",
1357
+ toolCallId: block.callId,
1358
+ toolName: block.name,
1359
+ input: block.input
1360
+ });
1361
+ }
1362
+ }
1363
+ break;
1364
+ }
1365
+ // ------------------------------------------------------------------
1366
+ // Tool result
1367
+ // ------------------------------------------------------------------
1368
+ case "tool.result": {
1369
+ if (ev.isError) {
1370
+ writer.write({
1371
+ type: "tool-output-error",
1372
+ toolCallId: ev.callId,
1373
+ errorText: typeof ev.output === "string" ? ev.output : JSON.stringify(ev.output)
1374
+ });
1375
+ } else {
1376
+ writer.write({
1377
+ type: "tool-output-available",
1378
+ toolCallId: ev.callId,
1379
+ output: ev.output
1380
+ });
1381
+ }
1382
+ break;
1383
+ }
1384
+ // ------------------------------------------------------------------
1385
+ // Terminal result — stream is done
1386
+ // ------------------------------------------------------------------
1387
+ case "result": {
1388
+ closeTextBlock();
1389
+ const finishReason = (() => {
1390
+ switch (ev.subtype) {
1391
+ case "success":
1392
+ return "stop";
1393
+ case "max_tokens":
1394
+ return "length";
1395
+ case "error":
1396
+ return "error";
1397
+ case "max_turns":
1398
+ case "max_cost":
1399
+ case "max_wall_clock":
1400
+ case "aborted":
1401
+ case "suspended":
1402
+ default:
1403
+ return "other";
1404
+ }
1405
+ })();
1406
+ writer.write({ type: "finish-step" });
1407
+ writer.write({ type: "finish", finishReason });
1408
+ break;
1409
+ }
1410
+ // ------------------------------------------------------------------
1411
+ // Ignored events — metadata / audit signals not meaningful to UI
1412
+ // ------------------------------------------------------------------
1413
+ case "session.init":
1414
+ case "compaction":
1415
+ break;
1416
+ }
1417
+ }
1418
+ },
1419
+ onError: (err) => {
1420
+ const msg = err instanceof Error ? err.message : String(err);
1421
+ return `Stream error: ${msg}`;
1422
+ }
1423
+ });
1424
+ }
1425
+ function toUIMessageStreamResponse(events, opts = {}) {
1426
+ return (0, import_ai.createUIMessageStreamResponse)({
1427
+ stream: toUIMessageStream(events),
1428
+ status: opts.status,
1429
+ headers: opts.headers
1430
+ });
1431
+ }
1432
+
1433
+ // src/scheduler.ts
1434
+ var import_cron_parser = require("cron-parser");
1435
+ var realClock = {
1436
+ now: () => Date.now()
1437
+ };
1438
+ var realTimer = {
1439
+ setInterval: (fn, ms) => globalThis.setInterval(fn, ms),
1440
+ clearInterval: (handle) => globalThis.clearInterval(handle)
1441
+ };
1442
+ function defaultLogger() {
1443
+ return {
1444
+ log(level, namespace, message, fields) {
1445
+ if (level === "error" || level === "warn") {
1446
+ console.error(`[${level.toUpperCase()}] ${namespace}: ${message}`, fields ?? "");
1447
+ }
1448
+ }
1449
+ };
1450
+ }
1451
+ var Scheduler = class {
1452
+ tickIntervalMs;
1453
+ clock;
1454
+ timer;
1455
+ logger;
1456
+ tasks = /* @__PURE__ */ new Map();
1457
+ timerHandle = null;
1458
+ running = false;
1459
+ constructor(opts = {}) {
1460
+ this.tickIntervalMs = opts.tickIntervalMs ?? 1e3;
1461
+ this.clock = opts.clock ?? realClock;
1462
+ this.timer = opts.timer ?? realTimer;
1463
+ this.logger = opts.logger ?? defaultLogger();
1464
+ }
1465
+ // ---------------------------------------------------------------------------
1466
+ // Lifecycle
1467
+ // ---------------------------------------------------------------------------
1468
+ /**
1469
+ * Start the scheduler's internal tick loop.
1470
+ * Calling `start()` while already running is a no-op.
1471
+ */
1472
+ start() {
1473
+ if (this.running) return;
1474
+ this.running = true;
1475
+ this.timerHandle = this.timer.setInterval(() => {
1476
+ this.tick(this.clock.now());
1477
+ }, this.tickIntervalMs);
1478
+ }
1479
+ /**
1480
+ * Stop the scheduler. All in-flight callbacks are allowed to complete
1481
+ * (they are not aborted), but no new runs will be triggered.
1482
+ * Calling `stop()` while not running is a no-op.
1483
+ */
1484
+ stop() {
1485
+ if (!this.running) return;
1486
+ this.running = false;
1487
+ if (this.timerHandle !== null) {
1488
+ this.timer.clearInterval(this.timerHandle);
1489
+ this.timerHandle = null;
1490
+ }
1491
+ }
1492
+ // ---------------------------------------------------------------------------
1493
+ // Task management
1494
+ // ---------------------------------------------------------------------------
1495
+ /**
1496
+ * Register a scheduled task. If a task with the same `id` already exists,
1497
+ * it is replaced (the old state is discarded).
1498
+ *
1499
+ * For cron tasks, the first next-fire time is computed immediately from the
1500
+ * current clock value.
1501
+ */
1502
+ add(task) {
1503
+ const now = this.clock.now();
1504
+ let nextFireAt = null;
1505
+ if (task.schedule.kind === "cron") {
1506
+ validateCronExpression(task.schedule.expression);
1507
+ nextFireAt = computeNextCron(task.schedule, now, this.logger);
1508
+ }
1509
+ this.tasks.set(task.id, {
1510
+ task,
1511
+ lastFiredAt: now,
1512
+ nextFireAt,
1513
+ inFlight: false
1514
+ });
1515
+ }
1516
+ /**
1517
+ * Remove a registered task by id.
1518
+ * Any in-flight callback for this task will be allowed to complete, but no
1519
+ * further fires will occur.
1520
+ * Returns `true` if the task was found and removed, `false` otherwise.
1521
+ */
1522
+ remove(id) {
1523
+ return this.tasks.delete(id);
1524
+ }
1525
+ /** Returns the ids of all currently registered tasks. */
1526
+ taskIds() {
1527
+ return [...this.tasks.keys()];
1528
+ }
1529
+ // ---------------------------------------------------------------------------
1530
+ // Tick — can be called manually in tests
1531
+ // ---------------------------------------------------------------------------
1532
+ /**
1533
+ * Evaluate all registered tasks against the given timestamp and fire any
1534
+ * that are due.
1535
+ *
1536
+ * This is the core scheduling method. The `start()` loop calls it
1537
+ * automatically at `tickIntervalMs` granularity, but tests can call it
1538
+ * directly to drive time without real timers.
1539
+ */
1540
+ tick(now) {
1541
+ for (const state of this.tasks.values()) {
1542
+ if (isDue(state, now)) {
1543
+ this._fire(state, now);
1544
+ }
1545
+ }
1546
+ }
1547
+ // ---------------------------------------------------------------------------
1548
+ // Internal fire
1549
+ // ---------------------------------------------------------------------------
1550
+ _fire(state, now) {
1551
+ if (state.inFlight) {
1552
+ this.logger.log("debug", "scheduler", "task skipped (overlap)", {
1553
+ taskId: state.task.id,
1554
+ now
1555
+ });
1556
+ return;
1557
+ }
1558
+ state.inFlight = true;
1559
+ state.lastFiredAt = now;
1560
+ if (state.task.schedule.kind === "cron") {
1561
+ state.nextFireAt = computeNextCron(state.task.schedule, now, this.logger);
1562
+ }
1563
+ const ctx = { taskId: state.task.id, triggeredAt: now };
1564
+ Promise.resolve().then(() => state.task.run(ctx)).catch((err) => {
1565
+ const msg = err instanceof Error ? err.message : String(err);
1566
+ this.logger.log("error", "scheduler", "task run failed", {
1567
+ taskId: state.task.id,
1568
+ error: msg,
1569
+ stack: err instanceof Error ? err.stack : void 0
1570
+ });
1571
+ }).finally(() => {
1572
+ state.inFlight = false;
1573
+ });
1574
+ }
1575
+ };
1576
+ function isDue(state, now) {
1577
+ const { task } = state;
1578
+ if (task.schedule.kind === "interval") {
1579
+ return now >= state.lastFiredAt + task.schedule.everyMs;
1580
+ }
1581
+ if (state.nextFireAt === null) return false;
1582
+ return now >= state.nextFireAt;
1583
+ }
1584
+ function validateCronExpression(expression) {
1585
+ try {
1586
+ import_cron_parser.CronExpressionParser.parse(expression, { tz: "UTC" });
1587
+ } catch (err) {
1588
+ const detail = err instanceof Error ? err.message : String(err);
1589
+ throw new Error(
1590
+ `Invalid cron expression "${expression}": ${detail}`
1591
+ );
1592
+ }
1593
+ }
1594
+ function computeNextCron(schedule, afterMs, logger) {
1595
+ try {
1596
+ const expr = import_cron_parser.CronExpressionParser.parse(schedule.expression, {
1597
+ currentDate: new Date(afterMs),
1598
+ tz: schedule.tz ?? "UTC"
1599
+ });
1600
+ return expr.next().getTime();
1601
+ } catch (err) {
1602
+ logger.log("error", "scheduler", "failed to compute next cron time", {
1603
+ expression: schedule.expression,
1604
+ error: err instanceof Error ? err.message : String(err)
1605
+ });
1606
+ return null;
1607
+ }
1608
+ }
1609
+
1610
+ // src/batch-runner.ts
1611
+ var ConcurrentAgentBackend = class {
1612
+ constructor(agent) {
1613
+ this.agent = agent;
1614
+ }
1615
+ agent;
1616
+ async run(item, signal) {
1617
+ try {
1618
+ let finalOutput = "";
1619
+ let finalUsage = { inputTokens: 0, outputTokens: 0 };
1620
+ let finalCost;
1621
+ for await (const ev of this.agent.query(item.input, {
1622
+ sessionId: item.sessionId,
1623
+ ...item.userId ? { userId: item.userId } : {},
1624
+ ...item.orgId ? { orgId: item.orgId } : {},
1625
+ signal
1626
+ })) {
1627
+ if (ev.type === "result") {
1628
+ finalOutput = typeof ev.output === "string" ? ev.output : ev.output == null ? "" : String(ev.output);
1629
+ finalUsage = ev.usage;
1630
+ finalCost = ev.cost;
1631
+ }
1632
+ }
1633
+ return {
1634
+ status: "success",
1635
+ id: item.id,
1636
+ output: finalOutput,
1637
+ usage: finalUsage,
1638
+ cost: finalCost,
1639
+ sessionId: item.sessionId
1640
+ };
1641
+ } catch (err) {
1642
+ return {
1643
+ status: "error",
1644
+ id: item.id,
1645
+ error: err instanceof Error ? err.message : String(err),
1646
+ sessionId: item.sessionId
1647
+ };
1648
+ }
1649
+ }
1650
+ };
1651
+ var BatchRunner = class {
1652
+ concurrency;
1653
+ backend;
1654
+ constructor(agent, options = {}) {
1655
+ this.concurrency = Math.max(1, options.concurrency ?? 4);
1656
+ this.backend = options.backend ?? new ConcurrentAgentBackend(agent);
1657
+ }
1658
+ /**
1659
+ * Process a list of inputs with bounded concurrency.
1660
+ *
1661
+ * @param items - Items to process. Each must have at least `input` set.
1662
+ * @param opts - Run-level options (signal, progress callback, collectResults).
1663
+ * @returns `BatchResult` containing per-item outcomes and aggregate totals.
1664
+ *
1665
+ * ### Large-batch tip
1666
+ * For very large batches (thousands of items), holding all results in memory may
1667
+ * be impractical. Pass `collectResults: false` to skip in-memory accumulation:
1668
+ * `BatchResult.results` will be empty while `aggregate` totals remain accurate.
1669
+ * Drain results incrementally via `onProgress` instead.
1670
+ */
1671
+ async run(items, opts = {}) {
1672
+ const { signal, onProgress, collectResults = true } = opts;
1673
+ const resolved = items.map((item, idx) => ({
1674
+ id: item.id ?? String(idx),
1675
+ input: item.input,
1676
+ userId: item.userId ?? "",
1677
+ orgId: item.orgId ?? "",
1678
+ sessionId: item.sessionId ?? crypto.randomUUID()
1679
+ }));
1680
+ const results = [];
1681
+ let cancelled = false;
1682
+ let inlineTotalInputTokens = 0;
1683
+ let inlineTotalOutputTokens = 0;
1684
+ let inlineTotalUsd;
1685
+ let inlineSuccessCount = 0;
1686
+ let inlineErrorCount = 0;
1687
+ if (resolved.length === 0) {
1688
+ return { results, aggregate: computeAggregate(results, cancelled) };
1689
+ }
1690
+ let nextIndex = 0;
1691
+ const processOne = async () => {
1692
+ while (true) {
1693
+ if (signal?.aborted) {
1694
+ cancelled = true;
1695
+ return;
1696
+ }
1697
+ const idx = nextIndex;
1698
+ if (idx >= resolved.length) return;
1699
+ nextIndex++;
1700
+ const item = resolved[idx];
1701
+ const itemSignal = signal ?? new AbortController().signal;
1702
+ let result;
1703
+ try {
1704
+ result = await this.backend.run(item, itemSignal);
1705
+ } catch (err) {
1706
+ result = {
1707
+ status: "error",
1708
+ id: item.id,
1709
+ error: err instanceof Error ? err.message : String(err),
1710
+ sessionId: item.sessionId
1711
+ };
1712
+ }
1713
+ if (collectResults) {
1714
+ results.push(result);
1715
+ } else {
1716
+ if (result.status === "success") {
1717
+ inlineSuccessCount++;
1718
+ inlineTotalInputTokens += result.usage.inputTokens;
1719
+ inlineTotalOutputTokens += result.usage.outputTokens;
1720
+ if (result.cost?.usd !== void 0) {
1721
+ inlineTotalUsd = (inlineTotalUsd ?? 0) + result.cost.usd;
1722
+ }
1723
+ } else {
1724
+ inlineErrorCount++;
1725
+ }
1726
+ }
1727
+ onProgress?.(result);
1728
+ }
1729
+ };
1730
+ const lanes = Array.from(
1731
+ { length: Math.min(this.concurrency, resolved.length) },
1732
+ () => processOne()
1733
+ );
1734
+ await Promise.all(lanes);
1735
+ if (signal?.aborted) cancelled = true;
1736
+ if (collectResults) {
1737
+ return { results, aggregate: computeAggregate(results, cancelled) };
1738
+ }
1739
+ return {
1740
+ results,
1741
+ aggregate: {
1742
+ totalUsage: { inputTokens: inlineTotalInputTokens, outputTokens: inlineTotalOutputTokens },
1743
+ ...inlineTotalUsd !== void 0 ? { totalUsd: inlineTotalUsd } : {},
1744
+ successCount: inlineSuccessCount,
1745
+ errorCount: inlineErrorCount,
1746
+ cancelled
1747
+ }
1748
+ };
1749
+ }
1750
+ };
1751
+ function computeAggregate(results, cancelled) {
1752
+ let totalInputTokens = 0;
1753
+ let totalOutputTokens = 0;
1754
+ let totalUsd;
1755
+ let successCount = 0;
1756
+ let errorCount = 0;
1757
+ for (const r of results) {
1758
+ if (r.status === "success") {
1759
+ successCount++;
1760
+ totalInputTokens += r.usage.inputTokens;
1761
+ totalOutputTokens += r.usage.outputTokens;
1762
+ if (r.cost?.usd !== void 0) {
1763
+ totalUsd = (totalUsd ?? 0) + r.cost.usd;
1764
+ }
1765
+ } else {
1766
+ errorCount++;
1767
+ }
1768
+ }
1769
+ return {
1770
+ totalUsage: { inputTokens: totalInputTokens, outputTokens: totalOutputTokens },
1771
+ ...totalUsd !== void 0 ? { totalUsd } : {},
1772
+ successCount,
1773
+ errorCount,
1774
+ cancelled
1775
+ };
1776
+ }
1777
+
1778
+ // src/index.ts
1779
+ var import_workflow2 = require("@eidentic/workflow");
1780
+ var AsyncRunRegistry = class {
1781
+ runs = /* @__PURE__ */ new Map();
1782
+ maxRuns;
1783
+ constructor(options) {
1784
+ this.maxRuns = options?.maxRuns ?? 1e3;
1785
+ }
1786
+ set(entry) {
1787
+ if (this.runs.size >= this.maxRuns) {
1788
+ this._evictOldestSettled();
1789
+ }
1790
+ this.runs.set(entry.runId, entry);
1791
+ }
1792
+ get(runId) {
1793
+ return this.runs.get(runId);
1794
+ }
1795
+ settle(runId, patch) {
1796
+ const entry = this.runs.get(runId);
1797
+ if (entry) {
1798
+ Object.assign(entry, patch, { settledAt: Date.now() });
1799
+ }
1800
+ }
1801
+ /** Evict the single oldest settled (non-in-flight) entry to make room. */
1802
+ _evictOldestSettled() {
1803
+ let oldestId;
1804
+ let oldestAt = Infinity;
1805
+ for (const [id, e] of this.runs) {
1806
+ if (e.status !== "running" && e.createdAt < oldestAt) {
1807
+ oldestAt = e.createdAt;
1808
+ oldestId = id;
1809
+ }
1810
+ }
1811
+ if (oldestId !== void 0) {
1812
+ this.runs.delete(oldestId);
1813
+ }
1814
+ }
1815
+ /** Return all entries (copy of values). Used by graceful drain to check in-flight count. */
1816
+ values() {
1817
+ return [...this.runs.values()];
1818
+ }
1819
+ };
1820
+ var NoAuth = {
1821
+ authenticate(_req) {
1822
+ return {};
1823
+ }
1824
+ };
1825
+ function ApiKeyAuth(keys) {
1826
+ return {
1827
+ authenticate(req) {
1828
+ const authHeader = req.headers["authorization"];
1829
+ const xApiKey = req.headers["x-api-key"];
1830
+ let key;
1831
+ if (authHeader?.startsWith("Bearer ")) {
1832
+ key = authHeader.slice(7);
1833
+ } else if (xApiKey) {
1834
+ key = xApiKey;
1835
+ }
1836
+ if (!key) return null;
1837
+ if (!Object.hasOwn(keys, key)) return null;
1838
+ return keys[key] ?? null;
1839
+ }
1840
+ };
1841
+ }
1842
+ function makeResolver(agents) {
1843
+ if (typeof agents === "function") return agents;
1844
+ return (id) => agents[id];
1845
+ }
1846
+ async function runAuth(auth, req) {
1847
+ const headers = {};
1848
+ req.headers.forEach((value, key) => {
1849
+ headers[key.toLowerCase()] = value;
1850
+ });
1851
+ const url = new URL(req.url);
1852
+ const authReq = {
1853
+ method: req.method,
1854
+ path: url.pathname,
1855
+ headers
1856
+ };
1857
+ return auth.authenticate(authReq);
1858
+ }
1859
+ var BODY_LIMIT = 512 * 1024;
1860
+ var STREAM_EVENT_TYPES_THAT_PERSIST = /* @__PURE__ */ new Set([
1861
+ "assistant",
1862
+ "tool.result",
1863
+ "compaction"
1864
+ ]);
1865
+ function makeSseIdTracker(baseSeq) {
1866
+ let next = baseSeq;
1867
+ return {
1868
+ idForSessionInit() {
1869
+ return String(next);
1870
+ },
1871
+ idForPersistedEvent() {
1872
+ next += 1;
1873
+ return String(next);
1874
+ },
1875
+ currentId() {
1876
+ return String(next);
1877
+ }
1878
+ };
1879
+ }
1880
+ function synthesizeResultFromStore(storedEvents, sessionId) {
1881
+ for (let i = storedEvents.length - 1; i >= 0; i--) {
1882
+ const ev = storedEvents[i];
1883
+ if (ev.kind === "assistant") {
1884
+ const payload = ev.payload;
1885
+ const content = payload.content ?? [];
1886
+ const hasToolUse = content.some((b) => b.type === "tool_use");
1887
+ if (hasToolUse) {
1888
+ return null;
1889
+ }
1890
+ const text = content.filter((b) => b.type === "text").map((b) => b.text).join("");
1891
+ const usage = ev.meta?.usage ?? {
1892
+ inputTokens: 0,
1893
+ outputTokens: 0
1894
+ };
1895
+ return {
1896
+ type: "result",
1897
+ subtype: "success",
1898
+ output: text,
1899
+ usage,
1900
+ numTurns: storedEvents.filter((e) => e.kind === "assistant").length,
1901
+ sessionId
1902
+ };
1903
+ }
1904
+ if (ev.kind === "suspension") {
1905
+ return null;
1906
+ }
1907
+ }
1908
+ return null;
1909
+ }
1910
+ function storedEventToStreamPayload(ev) {
1911
+ switch (ev.kind) {
1912
+ case "assistant": {
1913
+ const payload = ev.payload;
1914
+ return { type: "assistant", content: payload.content ?? [] };
1915
+ }
1916
+ case "tool_result": {
1917
+ const payload = ev.payload;
1918
+ return {
1919
+ type: "tool.result",
1920
+ callId: payload.callId,
1921
+ toolName: payload.toolName,
1922
+ output: payload.output,
1923
+ isError: false
1924
+ };
1925
+ }
1926
+ case "compaction": {
1927
+ const payload = ev.payload;
1928
+ return {
1929
+ type: "compaction",
1930
+ sessionId: ev.sessionId,
1931
+ before: payload.before,
1932
+ after: payload.after,
1933
+ stages: payload.stages
1934
+ };
1935
+ }
1936
+ // "user", "checkpoint", "tool_call", "suspension" — not replayed
1937
+ default:
1938
+ return null;
1939
+ }
1940
+ }
1941
+ function assertCallbackUrl(rawUrl, allowPrivateHosts) {
1942
+ let parsed;
1943
+ try {
1944
+ parsed = new URL(rawUrl);
1945
+ } catch {
1946
+ throw new Error("Invalid callbackUrl");
1947
+ }
1948
+ if (parsed.protocol !== "http:" && parsed.protocol !== "https:") {
1949
+ throw new Error("callbackUrl must use http or https");
1950
+ }
1951
+ if (!allowPrivateHosts && isCallbackHostBlocked(parsed.hostname)) {
1952
+ throw new Error("callbackUrl resolves to a blocked private/loopback/metadata host");
1953
+ }
1954
+ return parsed;
1955
+ }
1956
+ function isCallbackHostBlocked(host) {
1957
+ const h = host.startsWith("[") && host.endsWith("]") ? host.slice(1, -1) : host;
1958
+ if (h.toLowerCase() === "localhost") return true;
1959
+ const v4 = /^(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})$/.exec(h);
1960
+ if (v4) {
1961
+ const a = Number(v4[1]), b = Number(v4[2]);
1962
+ if (a === 0 || a === 127 || a === 10) return true;
1963
+ if (a === 172 && b >= 16 && b <= 31) return true;
1964
+ if (a === 192 && b === 168) return true;
1965
+ if (a === 169 && b === 254) return true;
1966
+ return false;
1967
+ }
1968
+ let ndInt;
1969
+ if (/^0x[0-9a-fA-F]+$/.test(h)) ndInt = parseInt(h, 16) >>> 0;
1970
+ else if (/^\d+$/.test(h)) {
1971
+ const n = Number(h);
1972
+ if (!isNaN(n) && n >= 0 && n <= 4294967295) ndInt = n >>> 0;
1973
+ } else if (/^0[0-7]+$/.test(h)) ndInt = parseInt(h, 8) >>> 0;
1974
+ if (ndInt !== void 0) {
1975
+ const a = ndInt >>> 24 & 255, b = ndInt >>> 16 & 255;
1976
+ if (a === 0 || a === 127 || a === 10) return true;
1977
+ if (a === 172 && b >= 16 && b <= 31) return true;
1978
+ if (a === 192 && b === 168) return true;
1979
+ if (a === 169 && b === 254) return true;
1980
+ return false;
1981
+ }
1982
+ let v6 = h.toLowerCase();
1983
+ const pct = v6.indexOf("%");
1984
+ if (pct !== -1) v6 = v6.slice(0, pct);
1985
+ const mapD = /^::(?:ffff:)?(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})$/.exec(v6);
1986
+ if (mapD) {
1987
+ const a = Number(mapD[1]), b = Number(mapD[2]);
1988
+ const n = (Number(mapD[1]) << 24 | Number(mapD[2]) << 16 | Number(mapD[3]) << 8 | Number(mapD[4])) >>> 0;
1989
+ const aa = n >>> 24 & 255, bb = n >>> 16 & 255;
1990
+ if (aa === 0 || aa === 127 || aa === 10) return true;
1991
+ if (aa === 172 && bb >= 16 && bb <= 31) return true;
1992
+ if (aa === 192 && bb === 168) return true;
1993
+ if (aa === 169 && bb === 254) return true;
1994
+ void a;
1995
+ void b;
1996
+ return false;
1997
+ }
1998
+ const mapH = /^::ffff:([0-9a-f]{1,4}):([0-9a-f]{1,4})$/.exec(v6);
1999
+ if (mapH) {
2000
+ const n = (parseInt(mapH[1] ?? "0", 16) << 16 | parseInt(mapH[2] ?? "0", 16)) >>> 0;
2001
+ const a = n >>> 24 & 255, b = n >>> 16 & 255;
2002
+ if (a === 0 || a === 127 || a === 10) return true;
2003
+ if (a === 172 && b >= 16 && b <= 31) return true;
2004
+ if (a === 192 && b === 168) return true;
2005
+ if (a === 169 && b === 254) return true;
2006
+ return false;
2007
+ }
2008
+ if (v6 === "::" || v6 === "::1") return true;
2009
+ if (/^f[cd][0-9a-f]{0,2}(:|$)/.test(v6)) return true;
2010
+ if (/^fe[89ab][0-9a-f]?(:|$)/.test(v6)) return true;
2011
+ return false;
2012
+ }
2013
+ async function deliverWebhook(callbackUrl, payload, signingSecret, logger) {
2014
+ const body = JSON.stringify(payload);
2015
+ const timestamp = String(Date.now());
2016
+ const message = timestamp + "." + body;
2017
+ const enc = new TextEncoder();
2018
+ const key = await crypto.subtle.importKey(
2019
+ "raw",
2020
+ enc.encode(signingSecret),
2021
+ { name: "HMAC", hash: "SHA-256" },
2022
+ false,
2023
+ ["sign"]
2024
+ );
2025
+ const sig = await crypto.subtle.sign("HMAC", key, enc.encode(message));
2026
+ const hexSig = Array.from(new Uint8Array(sig)).map((b) => b.toString(16).padStart(2, "0")).join("");
2027
+ const signature = `sha256=${hexSig}`;
2028
+ const delays = [0, 1e3, 2e3];
2029
+ for (let attempt = 0; attempt < delays.length; attempt++) {
2030
+ if (attempt > 0) {
2031
+ await new Promise((r) => setTimeout(r, delays[attempt]));
2032
+ }
2033
+ try {
2034
+ const controller = new AbortController();
2035
+ const timer = setTimeout(() => controller.abort(), 1e4);
2036
+ try {
2037
+ const res = await fetch(callbackUrl, {
2038
+ method: "POST",
2039
+ headers: {
2040
+ "content-type": "application/json",
2041
+ "X-Eidentic-Signature": signature,
2042
+ "X-Eidentic-Timestamp": timestamp
2043
+ },
2044
+ body,
2045
+ signal: controller.signal,
2046
+ // Never follow redirects
2047
+ redirect: "manual"
2048
+ });
2049
+ clearTimeout(timer);
2050
+ if (res.status >= 200 && res.status < 300) return;
2051
+ logger.error(`[eidentic/server] webhook delivery attempt ${attempt + 1} failed: HTTP ${res.status} for ${callbackUrl}`);
2052
+ } finally {
2053
+ clearTimeout(timer);
2054
+ }
2055
+ } catch (err) {
2056
+ logger.error(`[eidentic/server] webhook delivery attempt ${attempt + 1} error:`, err);
2057
+ }
2058
+ }
2059
+ logger.error(`[eidentic/server] webhook delivery exhausted retries for ${callbackUrl}`);
2060
+ }
2061
+ var DEFAULT_PRE_AUTH_CAPACITY = 60;
2062
+ var DEFAULT_PRE_AUTH_REFILL_PER_SEC = 1;
2063
+ function defaultGetClientKey(c, trustProxy) {
2064
+ if (trustProxy) {
2065
+ const xff = c.req.header("x-forwarded-for");
2066
+ if (xff) {
2067
+ const first = xff.split(",")[0]?.trim();
2068
+ if (first) return first;
2069
+ }
2070
+ }
2071
+ const incoming = c.env?.["incoming"];
2072
+ return incoming?.socket?.remoteAddress ?? "unknown";
2073
+ }
2074
+ function createServer2(opts) {
2075
+ const resolve = makeResolver(opts.agents);
2076
+ const auth = opts.auth ?? NoAuth;
2077
+ const defaultKey = (p, _agentId) => p.apiKey ?? p.userId ?? p.orgId ?? "anonymous";
2078
+ const getRateLimitKey = opts.rateLimitKey ?? defaultKey;
2079
+ const getQuotaKey = opts.quotaKey ?? defaultKey;
2080
+ const maxInputChars = opts.maxInputChars ?? 32e3;
2081
+ const quota = opts.quota;
2082
+ const preAuthLimiter = opts.preAuthRateLimiter === null ? null : opts.preAuthRateLimiter ?? new InMemoryTokenBucketLimiter({
2083
+ capacity: DEFAULT_PRE_AUTH_CAPACITY,
2084
+ refillPerSec: DEFAULT_PRE_AUTH_REFILL_PER_SEC
2085
+ });
2086
+ const trustProxy = opts.trustProxy ?? false;
2087
+ const getClientKey = opts.getClientKey ? opts.getClientKey : (c) => defaultGetClientKey(c, trustProxy);
2088
+ let _draining = false;
2089
+ const app = new import_hono.Hono({ strict: true });
2090
+ const base = opts.basePath ?? "";
2091
+ const r = base ? app.basePath(base) : app;
2092
+ if (opts.cors !== void 0) {
2093
+ r.use("*", (0, import_cors.cors)(opts.cors));
2094
+ }
2095
+ r.use("*", async (c, next) => {
2096
+ await next();
2097
+ c.header("X-Content-Type-Options", "nosniff");
2098
+ });
2099
+ r.use("/v1/*", async (c, next) => {
2100
+ if (_draining) {
2101
+ c.header("Retry-After", "5");
2102
+ return c.json({ error: "service_draining" }, 503);
2103
+ }
2104
+ await next();
2105
+ });
2106
+ if (preAuthLimiter !== null) {
2107
+ r.use("/v1/*", async (c, next) => {
2108
+ const clientKey = getClientKey(c);
2109
+ const rl = await preAuthLimiter.acquire(clientKey);
2110
+ if (!rl.ok) {
2111
+ c.header("X-Content-Type-Options", "nosniff");
2112
+ const retryAfterSec = rl.retryAfterMs !== void 0 ? Math.ceil(rl.retryAfterMs / 1e3) : void 0;
2113
+ if (retryAfterSec !== void 0) {
2114
+ c.header("Retry-After", String(retryAfterSec));
2115
+ }
2116
+ return c.json({ error: "rate_limited", retryAfterMs: rl.retryAfterMs }, 429);
2117
+ }
2118
+ await next();
2119
+ });
2120
+ }
2121
+ const asyncRuns = new AsyncRunRegistry({ maxRuns: opts.maxAsyncRuns });
2122
+ const workflowRuns = opts.workflowRuns ?? (0, import_workflow.createWorkflowRunRegistry)();
2123
+ const _setDraining = (v) => {
2124
+ _draining = v;
2125
+ };
2126
+ const _getAsyncRuns = () => asyncRuns;
2127
+ r.get("/health", (c) => c.json({ ok: true }));
2128
+ function checkOwnership(session, principal) {
2129
+ const sessionOwned = session.userId !== void 0 || session.orgId !== void 0 || session.apiKey !== void 0;
2130
+ if (!sessionOwned) return true;
2131
+ if (session.userId !== void 0 && principal.userId === session.userId) return true;
2132
+ if (session.orgId !== void 0 && principal.orgId === session.orgId) return true;
2133
+ if (session.apiKey !== void 0 && principal.apiKey === session.apiKey) return true;
2134
+ return false;
2135
+ }
2136
+ async function runAgentStream(c, agent, agentId, principal, sessionId, getIterable, logTag, emitSessionComment) {
2137
+ const rawLastEventId = c.req.header("last-event-id");
2138
+ let lastEventId;
2139
+ if (rawLastEventId !== void 0) {
2140
+ const parsed = parseInt(rawLastEventId, 10);
2141
+ if (isNaN(parsed) || parsed < 0 || !Number.isSafeInteger(parsed)) {
2142
+ return c.json({ error: "Invalid Last-Event-ID: must be a non-negative integer" }, 400);
2143
+ }
2144
+ lastEventId = parsed;
2145
+ }
2146
+ const hasLastEventId = lastEventId !== void 0;
2147
+ let streamQuotaKey;
2148
+ let streamQuotaReservation;
2149
+ if (quota) {
2150
+ streamQuotaKey = getQuotaKey(principal, agentId);
2151
+ const qc = await quota.check(streamQuotaKey);
2152
+ if (!qc.ok) {
2153
+ return c.json({ error: "quota_exceeded", reason: qc.reason, usage: qc.usage }, 402);
2154
+ }
2155
+ if (qc.warn) c.header("X-Eidentic-Quota-Warning", "soft-limit");
2156
+ streamQuotaReservation = qc.reservation;
2157
+ }
2158
+ const signal = c.req.raw.signal ?? new AbortController().signal;
2159
+ return (0, import_streaming.streamSSE)(c, async (stream) => {
2160
+ if (emitSessionComment) {
2161
+ await stream.writeln(`: session=${sessionId.replace(/[\r\n]/g, "")}`);
2162
+ }
2163
+ let storedEventsCache = null;
2164
+ if (hasLastEventId) {
2165
+ const storedEvents = await agent.store.readEvents(sessionId);
2166
+ storedEventsCache = storedEvents;
2167
+ const toReplay = storedEvents.filter((e) => e.seq > lastEventId);
2168
+ for (const ev of toReplay) {
2169
+ if (signal.aborted) break;
2170
+ const payload = storedEventToStreamPayload(ev);
2171
+ if (payload !== null) {
2172
+ await stream.writeSSE({
2173
+ event: payload["type"],
2174
+ data: JSON.stringify(payload),
2175
+ id: String(ev.seq)
2176
+ });
2177
+ }
2178
+ }
2179
+ const syntheticResult = synthesizeResultFromStore(storedEvents, sessionId);
2180
+ if (syntheticResult !== null) {
2181
+ await stream.writeSSE({
2182
+ event: "result",
2183
+ data: JSON.stringify(syntheticResult)
2184
+ });
2185
+ if (quota && streamQuotaReservation !== void 0) {
2186
+ quota.release?.(streamQuotaReservation);
2187
+ }
2188
+ return;
2189
+ }
2190
+ }
2191
+ const existingEvents = storedEventsCache ?? await agent.store.readEvents(sessionId);
2192
+ const baseSeq = existingEvents.length === 0 ? 0 : existingEvents[existingEvents.length - 1].seq + 1;
2193
+ const idTracker = makeSseIdTracker(baseSeq);
2194
+ let terminalResult;
2195
+ try {
2196
+ for await (const ev of getIterable()) {
2197
+ if (signal.aborted) break;
2198
+ if (ev.type === "session.init") {
2199
+ await stream.writeSSE({
2200
+ event: ev.type,
2201
+ data: JSON.stringify(ev),
2202
+ id: idTracker.idForSessionInit()
2203
+ });
2204
+ } else if (STREAM_EVENT_TYPES_THAT_PERSIST.has(ev.type)) {
2205
+ await stream.writeSSE({
2206
+ event: ev.type,
2207
+ data: JSON.stringify(ev),
2208
+ id: idTracker.idForPersistedEvent()
2209
+ });
2210
+ } else {
2211
+ let payload = ev;
2212
+ if (ev.type === "result" && ev.subtype === "error") {
2213
+ console.error(`[eidentic/server] ${logTag} run error:`, ev.output);
2214
+ payload = { ...ev, output: "Agent run failed" };
2215
+ }
2216
+ await stream.writeSSE({ event: ev.type, data: JSON.stringify(payload) });
2217
+ }
2218
+ if (ev.type === "result") {
2219
+ terminalResult = { usage: ev.usage, cost: ev.cost };
2220
+ }
2221
+ }
2222
+ } catch (err) {
2223
+ if (quota && streamQuotaReservation !== void 0) {
2224
+ quota.release?.(streamQuotaReservation);
2225
+ streamQuotaReservation = void 0;
2226
+ }
2227
+ if (!signal.aborted) {
2228
+ console.error(`[eidentic/server] ${logTag} error:`, err);
2229
+ await stream.writeSSE({
2230
+ event: "result",
2231
+ data: JSON.stringify({
2232
+ type: "result",
2233
+ subtype: "error",
2234
+ output: "Agent run failed",
2235
+ usage: { inputTokens: 0, outputTokens: 0 },
2236
+ numTurns: 0,
2237
+ sessionId
2238
+ })
2239
+ });
2240
+ }
2241
+ }
2242
+ if (quota && streamQuotaKey !== void 0 && terminalResult) {
2243
+ const tokens = terminalResult.usage.inputTokens + terminalResult.usage.outputTokens;
2244
+ const usd = terminalResult.cost?.usd ?? 0;
2245
+ await quota.record(streamQuotaKey, { usd, tokens }, streamQuotaReservation);
2246
+ } else if (quota && streamQuotaReservation !== void 0 && !terminalResult) {
2247
+ quota.release?.(streamQuotaReservation);
2248
+ }
2249
+ });
2250
+ }
2251
+ async function checkPostAuthRateLimit(c, principal, agentId) {
2252
+ if (!opts.rateLimiter) return null;
2253
+ const baseKey = getRateLimitKey(principal, agentId);
2254
+ const rlKey = baseKey === "anonymous" ? `anon:${getClientKey(c)}` : baseKey;
2255
+ const rl = await opts.rateLimiter.acquire(rlKey);
2256
+ if (!rl.ok) {
2257
+ const retryAfterSec = rl.retryAfterMs !== void 0 ? Math.ceil(rl.retryAfterMs / 1e3) : void 0;
2258
+ if (retryAfterSec !== void 0) c.header("Retry-After", String(retryAfterSec));
2259
+ return c.json({ error: "rate_limited", retryAfterMs: rl.retryAfterMs }, 429);
2260
+ }
2261
+ return null;
2262
+ }
2263
+ r.post(
2264
+ "/v1/agents/:agentId/query",
2265
+ (0, import_body_limit.bodyLimit)({ maxSize: BODY_LIMIT }),
2266
+ async (c) => {
2267
+ const principal = await runAuth(auth, c.req.raw);
2268
+ if (principal === null) return c.json({ error: "Unauthorized" }, 401);
2269
+ const agentId = c.req.param("agentId");
2270
+ const rlErr = await checkPostAuthRateLimit(c, principal, agentId);
2271
+ if (rlErr) return rlErr;
2272
+ let body;
2273
+ try {
2274
+ body = await c.req.json();
2275
+ } catch {
2276
+ return c.json({ error: "Invalid JSON body" }, 400);
2277
+ }
2278
+ if (typeof body !== "object" || body === null || typeof body["input"] !== "string" || body["input"] === "") {
2279
+ return c.json({ error: "Missing or invalid 'input' field" }, 400);
2280
+ }
2281
+ const { input, sessionId: bodySessionId } = body;
2282
+ if (input.length > maxInputChars) {
2283
+ return c.json({ error: `Input exceeds maximum length of ${maxInputChars} characters` }, 400);
2284
+ }
2285
+ const agent = resolve(agentId);
2286
+ if (!agent) {
2287
+ return c.json({ error: "Not found" }, 404);
2288
+ }
2289
+ const sessionId = typeof bodySessionId === "string" && bodySessionId.length > 0 ? bodySessionId : crypto.randomUUID();
2290
+ if (typeof bodySessionId === "string" && bodySessionId.length > 0) {
2291
+ const sessionRecord = await agent.store.getSession(bodySessionId);
2292
+ if (sessionRecord && !checkOwnership(sessionRecord, principal)) {
2293
+ return c.json({ error: "Forbidden" }, 403);
2294
+ }
2295
+ }
2296
+ return runAgentStream(
2297
+ c,
2298
+ agent,
2299
+ agentId,
2300
+ principal,
2301
+ sessionId,
2302
+ () => agent.query(input, {
2303
+ sessionId,
2304
+ userId: principal.userId,
2305
+ orgId: principal.orgId,
2306
+ // H1 fix: pass apiKey so apiKey-only principals own their sessions.
2307
+ apiKey: principal.apiKey,
2308
+ signal: c.req.raw.signal ?? new AbortController().signal
2309
+ }),
2310
+ "agent.query",
2311
+ /* emitSessionComment */
2312
+ true
2313
+ );
2314
+ }
2315
+ );
2316
+ r.post(
2317
+ "/v1/agents/:agentId/resume",
2318
+ (0, import_body_limit.bodyLimit)({ maxSize: BODY_LIMIT }),
2319
+ async (c) => {
2320
+ const principal = await runAuth(auth, c.req.raw);
2321
+ if (principal === null) return c.json({ error: "Unauthorized" }, 401);
2322
+ const agentId = c.req.param("agentId");
2323
+ const rlErr = await checkPostAuthRateLimit(c, principal, agentId);
2324
+ if (rlErr) return rlErr;
2325
+ let body;
2326
+ try {
2327
+ body = await c.req.json();
2328
+ } catch {
2329
+ return c.json({ error: "Invalid JSON body" }, 400);
2330
+ }
2331
+ if (typeof body !== "object" || body === null || typeof body["sessionId"] !== "string" || body["sessionId"] === "") {
2332
+ return c.json({ error: "Missing or invalid 'sessionId' field" }, 400);
2333
+ }
2334
+ const rawDecision = body["decision"];
2335
+ if (typeof rawDecision === "string" && rawDecision.length > maxInputChars) {
2336
+ return c.json({ error: `Decision input exceeds maximum length of ${maxInputChars} characters` }, 400);
2337
+ }
2338
+ const { sessionId, decision } = body;
2339
+ const agent = resolve(agentId);
2340
+ if (!agent) {
2341
+ return c.json({ error: "Not found" }, 404);
2342
+ }
2343
+ const sessionRecord = await agent.store.getSession(sessionId);
2344
+ if (sessionRecord && !checkOwnership(sessionRecord, principal)) {
2345
+ return c.json({ error: "Forbidden" }, 403);
2346
+ }
2347
+ return runAgentStream(
2348
+ c,
2349
+ agent,
2350
+ agentId,
2351
+ principal,
2352
+ sessionId,
2353
+ () => agent.resume(sessionId, {
2354
+ userId: principal.userId,
2355
+ orgId: principal.orgId,
2356
+ decision,
2357
+ signal: c.req.raw.signal ?? new AbortController().signal
2358
+ }),
2359
+ "agent.resume",
2360
+ /* emitSessionComment */
2361
+ false
2362
+ );
2363
+ }
2364
+ );
2365
+ r.post(
2366
+ "/v1/agents/:agentId/runs",
2367
+ (0, import_body_limit.bodyLimit)({ maxSize: BODY_LIMIT }),
2368
+ async (c) => {
2369
+ const principal = await runAuth(auth, c.req.raw);
2370
+ if (principal === null) return c.json({ error: "Unauthorized" }, 401);
2371
+ const agentId = c.req.param("agentId");
2372
+ const rlErr = await checkPostAuthRateLimit(c, principal, agentId);
2373
+ if (rlErr) return rlErr;
2374
+ let body;
2375
+ try {
2376
+ body = await c.req.json();
2377
+ } catch {
2378
+ return c.json({ error: "Invalid JSON body" }, 400);
2379
+ }
2380
+ if (typeof body !== "object" || body === null || typeof body["input"] !== "string" || body["input"] === "") {
2381
+ return c.json({ error: "Missing or invalid 'input' field" }, 400);
2382
+ }
2383
+ const { input, sessionId: bodySessionId, callbackUrl: rawCallbackUrl } = body;
2384
+ if (input.length > maxInputChars) {
2385
+ return c.json({ error: `Input exceeds maximum length of ${maxInputChars} characters` }, 400);
2386
+ }
2387
+ let validatedCallbackUrl;
2388
+ if (rawCallbackUrl !== void 0) {
2389
+ if (!opts.webhooks) {
2390
+ return c.json({ error: "Webhook callbacks are not configured on this server" }, 400);
2391
+ }
2392
+ if (typeof rawCallbackUrl !== "string" || rawCallbackUrl.length === 0) {
2393
+ return c.json({ error: "callbackUrl must be a non-empty string" }, 400);
2394
+ }
2395
+ try {
2396
+ const u = assertCallbackUrl(rawCallbackUrl, opts.webhooks.allowPrivateHosts ?? false);
2397
+ validatedCallbackUrl = u.href;
2398
+ } catch (err) {
2399
+ return c.json({ error: err instanceof Error ? err.message : "Invalid callbackUrl" }, 400);
2400
+ }
2401
+ }
2402
+ const agent = resolve(agentId);
2403
+ if (!agent) {
2404
+ return c.json({ error: "Not found" }, 404);
2405
+ }
2406
+ const sessionId = typeof bodySessionId === "string" && bodySessionId.length > 0 ? bodySessionId : crypto.randomUUID();
2407
+ if (typeof bodySessionId === "string" && bodySessionId.length > 0) {
2408
+ const sessionRecord = await agent.store.getSession(bodySessionId);
2409
+ if (sessionRecord && !checkOwnership(sessionRecord, principal)) {
2410
+ return c.json({ error: "Forbidden" }, 403);
2411
+ }
2412
+ }
2413
+ let asyncQuotaKey;
2414
+ let asyncQuotaReservation;
2415
+ if (quota) {
2416
+ asyncQuotaKey = getQuotaKey(principal, agentId);
2417
+ const qc = await quota.check(asyncQuotaKey);
2418
+ if (!qc.ok) {
2419
+ return c.json({ error: "quota_exceeded", reason: qc.reason, usage: qc.usage }, 402);
2420
+ }
2421
+ asyncQuotaReservation = qc.reservation;
2422
+ }
2423
+ const runId = crypto.randomUUID();
2424
+ asyncRuns.set({
2425
+ runId,
2426
+ sessionId,
2427
+ agentId,
2428
+ status: "running",
2429
+ owner: {
2430
+ userId: principal.userId,
2431
+ orgId: principal.orgId,
2432
+ apiKey: principal.apiKey
2433
+ },
2434
+ createdAt: Date.now()
2435
+ });
2436
+ (async () => {
2437
+ let terminalOutput;
2438
+ let terminalError;
2439
+ let terminalUsage;
2440
+ let terminalResult;
2441
+ let localReservation = asyncQuotaReservation;
2442
+ try {
2443
+ for await (const ev of agent.query(input, {
2444
+ sessionId,
2445
+ userId: principal.userId,
2446
+ orgId: principal.orgId
2447
+ })) {
2448
+ if (ev.type === "result") {
2449
+ terminalResult = { usage: ev.usage, cost: ev.cost };
2450
+ terminalUsage = ev.usage;
2451
+ if (ev.subtype === "success") {
2452
+ terminalOutput = typeof ev.output === "string" ? ev.output : ev.output !== void 0 ? String(ev.output) : void 0;
2453
+ } else if (ev.subtype === "error") {
2454
+ terminalError = typeof ev.output === "string" ? ev.output : ev.output !== void 0 ? String(ev.output) : void 0;
2455
+ }
2456
+ }
2457
+ }
2458
+ if (quota && asyncQuotaKey !== void 0 && terminalResult) {
2459
+ const tokens = terminalResult.usage.inputTokens + terminalResult.usage.outputTokens;
2460
+ const usd = terminalResult.cost?.usd ?? 0;
2461
+ await quota.record(asyncQuotaKey, { usd, tokens }, localReservation);
2462
+ localReservation = void 0;
2463
+ }
2464
+ const finalStatus = terminalError ? "failed" : "completed";
2465
+ asyncRuns.settle(runId, {
2466
+ status: finalStatus,
2467
+ output: terminalOutput,
2468
+ error: terminalError
2469
+ });
2470
+ if (validatedCallbackUrl && opts.webhooks) {
2471
+ const webhookPayload = {
2472
+ runId,
2473
+ agentId,
2474
+ status: finalStatus,
2475
+ ...terminalOutput !== void 0 ? { output: terminalOutput } : {},
2476
+ ...terminalError !== void 0 ? { error: terminalError } : {},
2477
+ ...terminalUsage !== void 0 ? { usage: terminalUsage } : {}
2478
+ };
2479
+ void deliverWebhook(validatedCallbackUrl, webhookPayload, opts.webhooks.signingSecret, console);
2480
+ }
2481
+ } catch (err) {
2482
+ if (quota && localReservation !== void 0) {
2483
+ quota.release?.(localReservation);
2484
+ localReservation = void 0;
2485
+ }
2486
+ const msg = err instanceof Error ? err.message : String(err);
2487
+ asyncRuns.settle(runId, { status: "failed", error: msg });
2488
+ if (validatedCallbackUrl && opts.webhooks) {
2489
+ const webhookPayload = {
2490
+ runId,
2491
+ agentId,
2492
+ status: "failed",
2493
+ error: msg,
2494
+ ...terminalUsage !== void 0 ? { usage: terminalUsage } : {}
2495
+ };
2496
+ void deliverWebhook(validatedCallbackUrl, webhookPayload, opts.webhooks.signingSecret, console);
2497
+ }
2498
+ } finally {
2499
+ if (quota && localReservation !== void 0 && !terminalResult) {
2500
+ quota.release?.(localReservation);
2501
+ }
2502
+ }
2503
+ })();
2504
+ return c.json({ runId, sessionId, status: "running" }, 202);
2505
+ }
2506
+ );
2507
+ r.get("/v1/agents/:agentId/runs/:runId/status", async (c) => {
2508
+ const principal = await runAuth(auth, c.req.raw);
2509
+ if (principal === null) {
2510
+ return c.json({ error: "Unauthorized" }, 401);
2511
+ }
2512
+ const agentId = c.req.param("agentId");
2513
+ const agent = resolve(agentId);
2514
+ if (!agent) {
2515
+ return c.json({ error: "Not found" }, 404);
2516
+ }
2517
+ const runId = c.req.param("runId");
2518
+ const entry = asyncRuns.get(runId);
2519
+ if (!entry) {
2520
+ return c.json({ error: "Not found" }, 404);
2521
+ }
2522
+ const ownerMatches = entry.owner.userId !== void 0 && entry.owner.userId === principal.userId || entry.owner.orgId !== void 0 && entry.owner.orgId === principal.orgId || entry.owner.apiKey !== void 0 && entry.owner.apiKey === principal.apiKey || // NoAuth / anonymous: allow if owner has no identifying fields set
2523
+ entry.owner.userId === void 0 && entry.owner.orgId === void 0 && entry.owner.apiKey === void 0;
2524
+ if (!ownerMatches) {
2525
+ return c.json({ error: "Forbidden" }, 403);
2526
+ }
2527
+ const response = {
2528
+ runId: entry.runId,
2529
+ sessionId: entry.sessionId,
2530
+ status: entry.status
2531
+ };
2532
+ if (entry.output !== void 0) response["output"] = entry.output;
2533
+ if (entry.error !== void 0) response["error"] = entry.error;
2534
+ if (entry.settledAt !== void 0) response["settledAt"] = entry.settledAt;
2535
+ return c.json(response, 200);
2536
+ });
2537
+ if (opts.exposeEvents === true) {
2538
+ r.get("/v1/agents/:agentId/sessions/:sessionId/events", async (c) => {
2539
+ const principal = await runAuth(auth, c.req.raw);
2540
+ if (principal === null) {
2541
+ return c.json({ error: "Unauthorized" }, 401);
2542
+ }
2543
+ const agentId = c.req.param("agentId");
2544
+ const agent = resolve(agentId);
2545
+ if (!agent) {
2546
+ return c.json({ error: "Not found" }, 404);
2547
+ }
2548
+ const sessionId = c.req.param("sessionId");
2549
+ const sessionRecord = await agent.store.getSession(sessionId);
2550
+ if (sessionRecord && !checkOwnership(sessionRecord, principal)) {
2551
+ return c.json({ error: "Forbidden" }, 403);
2552
+ }
2553
+ const events = await agent.store.readEvents(sessionId);
2554
+ return c.json({ events });
2555
+ });
2556
+ }
2557
+ function checkWorkflowOwnership(rec, principal) {
2558
+ const owner = rec.owner;
2559
+ if (owner === void 0) return true;
2560
+ const hasAnyOwner = owner.userId !== void 0 || owner.orgId !== void 0 || owner.apiKey !== void 0;
2561
+ if (!hasAnyOwner) return true;
2562
+ if (owner.userId !== void 0 && principal.userId === owner.userId) return true;
2563
+ if (owner.orgId !== void 0 && principal.orgId === owner.orgId) return true;
2564
+ if (owner.apiKey !== void 0 && principal.apiKey === owner.apiKey) return true;
2565
+ return false;
2566
+ }
2567
+ r.get("/v1/workflows", async (c) => {
2568
+ const principal = await runAuth(auth, c.req.raw);
2569
+ if (principal === null) {
2570
+ return c.json({ error: "Unauthorized" }, 401);
2571
+ }
2572
+ const summaries = workflowRuns.list().filter((rec) => checkWorkflowOwnership(rec, principal)).map((rec) => ({
2573
+ id: rec.id,
2574
+ name: rec.name,
2575
+ status: rec.status,
2576
+ startedAt: rec.startedAt,
2577
+ durationMs: rec.durationMs,
2578
+ stepCount: rec.stepCount
2579
+ }));
2580
+ return c.json(summaries, 200);
2581
+ });
2582
+ r.get("/v1/workflows/:id", async (c) => {
2583
+ const principal = await runAuth(auth, c.req.raw);
2584
+ if (principal === null) {
2585
+ return c.json({ error: "Unauthorized" }, 401);
2586
+ }
2587
+ const id = c.req.param("id");
2588
+ const rec = workflowRuns.get(id);
2589
+ if (!rec || !checkWorkflowOwnership(rec, principal)) {
2590
+ return c.json({ error: "Not found" }, 404);
2591
+ }
2592
+ const detail = {
2593
+ id: rec.id,
2594
+ name: rec.name,
2595
+ status: rec.status,
2596
+ startedAt: rec.startedAt,
2597
+ durationMs: rec.durationMs,
2598
+ stepCount: rec.stepCount,
2599
+ trace: rec.trace,
2600
+ ...rec.output !== void 0 ? { output: rec.output } : {},
2601
+ ...rec.error !== void 0 ? { error: rec.error } : {}
2602
+ };
2603
+ return c.json(detail, 200);
2604
+ });
2605
+ const handle = {
2606
+ recordWorkflow(name, result, owner, opts2) {
2607
+ const rec = workflowRuns.record(name, result, owner, opts2);
2608
+ return rec.id;
2609
+ },
2610
+ recordWorkflowError(err, owner, opts2) {
2611
+ const msg = err.cause instanceof Error ? err.cause.message : String(err.cause ?? err.message);
2612
+ const rec = workflowRuns.recordError(err.workflowName, err.trace, msg, owner, opts2);
2613
+ return rec.id;
2614
+ }
2615
+ };
2616
+ Object.defineProperties(app, {
2617
+ _setDraining: { value: _setDraining, enumerable: false, writable: false },
2618
+ _getAsyncRuns: { value: _getAsyncRuns, enumerable: false, writable: false }
2619
+ });
2620
+ return Object.assign(app, { handle });
2621
+ }
2622
+ async function serveNode(app, opts) {
2623
+ let nodeServer;
2624
+ try {
2625
+ nodeServer = await Promise.resolve().then(() => (init_dist(), dist_exports));
2626
+ } catch {
2627
+ throw new Error(
2628
+ "@hono/node-server is not installed. Run `pnpm add @hono/node-server` (or npm/yarn) in your project to use serveNode()."
2629
+ );
2630
+ }
2631
+ const port = opts?.port ?? 3e3;
2632
+ const server = nodeServer.serve({ fetch: app.fetch, port });
2633
+ const _setDraining = app._setDraining;
2634
+ const _getAsyncRuns = app._getAsyncRuns;
2635
+ return {
2636
+ close() {
2637
+ server.close();
2638
+ },
2639
+ async drain(timeoutMs = 3e4) {
2640
+ if (_setDraining) _setDraining(true);
2641
+ await new Promise((resolve) => server.close(() => resolve()));
2642
+ const deadline = Date.now() + timeoutMs;
2643
+ while (Date.now() < deadline) {
2644
+ if (_getAsyncRuns) {
2645
+ const running = _getAsyncRuns().values().filter((e) => e.status === "running");
2646
+ if (running.length === 0) break;
2647
+ } else {
2648
+ break;
2649
+ }
2650
+ await new Promise((r) => setTimeout(r, 100));
2651
+ }
2652
+ }
2653
+ };
2654
+ }
2655
+ // Annotate the CommonJS export names for ESM import in node:
2656
+ 0 && (module.exports = {
2657
+ ApiKeyAuth,
2658
+ AsyncRunRegistry,
2659
+ BatchRunner,
2660
+ InMemoryQuota,
2661
+ InMemoryTokenBucketLimiter,
2662
+ NoAuth,
2663
+ Scheduler,
2664
+ WorkflowRunError,
2665
+ createServer,
2666
+ serveNode,
2667
+ toUIMessageStream,
2668
+ toUIMessageStreamResponse
2669
+ });