caplets 0.17.0 → 0.17.2

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.
Files changed (3) hide show
  1. package/README.md +7 -5
  2. package/dist/index.js +600 -149
  3. package/package.json +6 -6
package/README.md CHANGED
@@ -77,16 +77,18 @@ You can also invoke configured Caplets directly from the CLI for agent-friendly
77
77
  ```sh
78
78
  caplets get-caplet context7
79
79
  caplets list-tools context7
80
- caplets get-tool context7.resolve-library-id
81
- caplets call-tool context7.resolve-library-id --args '{"libraryName":"react"}'
82
- caplets call-tool context7.resolve-library-id --args '{"libraryName":"react"}' --field result.id --format json
80
+ caplets get-tool context7 resolve-library-id
81
+ caplets call-tool context7 resolve-library-id --args '{"libraryName":"react"}'
82
+ caplets call-tool context7 resolve-library-id --args '{"libraryName":"react"}' --field result.id --format json
83
83
  caplets list-resources docs
84
84
  caplets read-resource docs file:///repo/README.md
85
85
  caplets list-prompts linear
86
- caplets get-prompt linear.review_issue --args '{"issueId":"CAP-123"}'
86
+ caplets get-prompt linear review_issue --args '{"issueId":"CAP-123"}'
87
87
  caplets complete docs --resource-template 'file:///repo/{path}' --argument path --value src/
88
88
  ```
89
89
 
90
+ The older qualified form, such as `caplets call-tool context7.resolve-library-id` or `caplets get-prompt linear.review_issue`, remains supported for scripts and existing usage.
91
+
90
92
  Direct CLI operation commands print Markdown summaries by default. Add `--format plain` for plain text or `--format json` for machine-readable JSON (`md` is accepted as an alias for `markdown`). If a downstream tool returns `isError: true`, Caplets still exits with status code 1.
91
93
 
92
94
  ### Shell completions
@@ -117,7 +119,7 @@ caplets completion cmd > %USERPROFILE%\caplets-completion.cmd
117
119
  %USERPROFILE%\caplets-completion.cmd
118
120
  ```
119
121
 
120
- Completions include command names, options, common enum values, configured Caplet IDs, and cache-backed downstream names for qualified targets such as `caplets call-tool repo.<TAB>`. Downstream discovery is bounded by the `completion` config timeouts and a platform-native cache directory. Generated shell scripts suppress completion stderr; run the underlying CLI command directly when debugging completion behavior.
122
+ Completions include command names, options, common enum values, configured Caplet IDs, and cache-backed downstream names for split targets such as `caplets call-tool repo <TAB>` and qualified targets such as `caplets call-tool repo.<TAB>`. Downstream discovery is bounded by the `completion` config timeouts and a platform-native cache directory. Generated shell scripts suppress completion stderr; run the underlying CLI command directly when debugging completion behavior.
121
123
 
122
124
  Backends that require OAuth or token auth may need `caplets auth login <server>` before live downstream completions can return richer results. Completion never starts interactive login flows.
123
125
 
package/dist/index.js CHANGED
@@ -6,15 +6,12 @@ import { execFileSync, spawn } from "node:child_process";
6
6
  import process$1, { stdin, stdout } from "node:process";
7
7
  import { fileURLToPath } from "node:url";
8
8
  import { homedir, tmpdir } from "node:os";
9
- import { PassThrough } from "node:stream";
10
- import { createServer } from "node:http";
9
+ import { PassThrough, Readable } from "node:stream";
10
+ import { STATUS_CODES, createServer } from "node:http";
11
11
  import { createHash, randomBytes, randomUUID, timingSafeEqual } from "node:crypto";
12
12
  import { Buffer as Buffer$1 } from "node:buffer";
13
13
  import { createInterface } from "node:readline/promises";
14
- import { createServer as createServer$1 } from "http";
15
- import { Http2ServerRequest, constants as constants$1 } from "http2";
16
- import { Readable } from "stream";
17
- import crypto$1 from "crypto";
14
+ import { Http2ServerRequest, constants as constants$1 } from "node:http2";
18
15
  //#region \0rolldown/runtime.js
19
16
  var __defProp$1 = Object.defineProperty;
20
17
  var __exportAll$1 = (all, no_symbols) => {
@@ -27,7 +24,7 @@ var __exportAll$1 = (all, no_symbols) => {
27
24
  return target;
28
25
  };
29
26
  //#endregion
30
- //#region ../core/dist/generated-tool-input-schema-B6rce396.js
27
+ //#region ../core/dist/generated-tool-input-schema-BYoyY-l-.js
31
28
  var _a$1;
32
29
  /** A special constant with type `never` */
33
30
  const NEVER = /* @__PURE__ */ Object.freeze({ status: "aborted" });
@@ -4712,7 +4709,7 @@ function generatedToolInputJsonSchema() {
4712
4709
  return generatedToolInputJsonSchemaForCaplet({ backend: "tool" });
4713
4710
  }
4714
4711
  //#endregion
4715
- //#region ../core/dist/options-DM1cMRcp.js
4712
+ //#region ../core/dist/options-bnsSREid.js
4716
4713
  var __create = Object.create;
4717
4714
  var __defProp = Object.defineProperty;
4718
4715
  var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
@@ -28835,15 +28832,15 @@ function createFetchWithInit(baseFetch = fetch, baseInit) {
28835
28832
  });
28836
28833
  };
28837
28834
  }
28838
- let crypto$2;
28839
- crypto$2 = globalThis.crypto?.webcrypto ?? globalThis.crypto ?? import("node:crypto").then((m) => m.webcrypto);
28835
+ let crypto$1;
28836
+ crypto$1 = globalThis.crypto?.webcrypto ?? globalThis.crypto ?? import("node:crypto").then((m) => m.webcrypto);
28840
28837
  /**
28841
28838
  * Creates an array of length `size` of random bytes
28842
28839
  * @param size
28843
28840
  * @returns Array of random ints (0 to 255)
28844
28841
  */
28845
28842
  async function getRandomValues(size) {
28846
- return (await crypto$2).getRandomValues(new Uint8Array(size));
28843
+ return (await crypto$1).getRandomValues(new Uint8Array(size));
28847
28844
  }
28848
28845
  /** Generate cryptographically strong random string
28849
28846
  * @param size The desired length of the string
@@ -28871,7 +28868,7 @@ async function generateVerifier(length) {
28871
28868
  * @returns The base64 url encoded code challenge
28872
28869
  */
28873
28870
  async function generateChallenge(code_verifier) {
28874
- const buffer = await (await crypto$2).subtle.digest("SHA-256", new TextEncoder().encode(code_verifier));
28871
+ const buffer = await (await crypto$1).subtle.digest("SHA-256", new TextEncoder().encode(code_verifier));
28875
28872
  return btoa(String.fromCharCode(...new Uint8Array(buffer))).replace(/\//g, "_").replace(/\+/g, "-").replace(/=/g, "");
28876
28873
  }
28877
28874
  /** Generate a PKCE challenge pair
@@ -57628,7 +57625,7 @@ var CapletsEngine = class {
57628
57625
  }
57629
57626
  }
57630
57627
  async completeCliWords(words) {
57631
- const { completeCliWords } = await Promise.resolve().then(() => completion_CxGG6ae3_exports).then((n) => n.r);
57628
+ const { completeCliWords } = await Promise.resolve().then(() => completion_L23s2FGB_exports).then((n) => n.r);
57632
57629
  return await completeCliWords(words, {
57633
57630
  config: this.registry.config,
57634
57631
  managers: {
@@ -57966,8 +57963,8 @@ function hasEnv$1(value) {
57966
57963
  return value !== void 0 && value.trim() !== "";
57967
57964
  }
57968
57965
  //#endregion
57969
- //#region ../core/dist/completion-CxGG6ae3.js
57970
- var completion_CxGG6ae3_exports = /* @__PURE__ */ __exportAll$1({
57966
+ //#region ../core/dist/completion-L23s2FGB.js
57967
+ var completion_L23s2FGB_exports = /* @__PURE__ */ __exportAll$1({
57971
57968
  a: () => formatCapletList,
57972
57969
  c: () => resolveCliConfigPaths,
57973
57970
  i: () => trailingSpaceCompletionToken,
@@ -58437,9 +58434,17 @@ async function completeCliWords(words, options = {}) {
58437
58434
  if (normalized.length === 1) return prefixFilter([...topLevelCommandNames], current);
58438
58435
  if (normalized.length === 2 && command in cliSubcommands) return prefixFilter(cliSubcommands[command], current);
58439
58436
  if (normalized.length === 2 && capletIdCommands.has(command)) return prefixFilter(promptResourceCommands.has(command) ? configuredCapletIds(options, { backend: "mcp" }) : configuredCapletIds(options), current);
58440
- if (normalized.length === 2 && (qualifiedToolCommands.has(command) || qualifiedPromptCommands.has(command))) {
58441
- if (current.includes(".")) return prefixFilter((await discoverCompletionCandidates(current.slice(0, current.indexOf(".")), qualifiedToolCommands.has(command) ? "tools" : "prompts", discoveryOptions(options))).map((candidate) => candidate.value), current);
58442
- return prefixFilter(configuredCapletIds(options, qualifiedPromptCommands.has(command) ? { backend: "mcp" } : void 0).map((id) => `${id}.`), current);
58437
+ if (qualifiedToolCommands.has(command) || qualifiedPromptCommands.has(command)) {
58438
+ const kind = qualifiedToolCommands.has(command) ? "tools" : "prompts";
58439
+ const idFilter = qualifiedPromptCommands.has(command) ? { backend: "mcp" } : void 0;
58440
+ if (normalized.length === 2) {
58441
+ if (current.includes(".")) return prefixFilter((await discoverCompletionCandidates(current.slice(0, current.indexOf(".")), kind, discoveryOptions(options))).map((candidate) => candidate.value), current);
58442
+ return prefixFilter(configuredCapletIds(options, idFilter), current);
58443
+ }
58444
+ if (normalized.length === 3 && subcommand && !subcommand.includes(".")) {
58445
+ if (current.startsWith("-")) return [];
58446
+ return prefixFilter((await discoverCompletionCandidates(subcommand, kind, discoveryOptions(options))).map((candidate) => candidate.value.replace(`${subcommand}.`, "")), current);
58447
+ }
58443
58448
  }
58444
58449
  if (command === cliCommands.readResource && normalized.length === 3) return prefixFilter((await discoverCompletionCandidates(subcommand, "resources", discoveryOptions(options))).map((candidate) => candidate.value), current);
58445
58450
  if (command === cliCommands.auth && ["login", "logout"].includes(subcommand) && normalized.length === 3) return prefixFilter(configuredCapletIds(options), current);
@@ -59822,7 +59827,7 @@ const EMPTY_COMPLETION_RESULT = { completion: {
59822
59827
  values: [],
59823
59828
  hasMore: false
59824
59829
  } };
59825
- var version$1 = "0.18.0";
59830
+ var version$1 = "0.18.2";
59826
59831
  var CapletsMcpSession = class {
59827
59832
  engine;
59828
59833
  server;
@@ -64827,7 +64832,7 @@ var Hono$1 = class _Hono {
64827
64832
  handler = async (c, next) => (await compose([], app.errorHandler)(c, () => r.handler(c, next))).res;
64828
64833
  handler[COMPOSED_HANDLER] = r.handler;
64829
64834
  }
64830
- subApp.#addRoute(r.method, r.path, handler);
64835
+ subApp.#addRoute(r.method, r.path, handler, r.basePath);
64831
64836
  });
64832
64837
  return this;
64833
64838
  }
@@ -64944,7 +64949,7 @@ var Hono$1 = class _Hono {
64944
64949
  const pathPrefixLength = mergedPath === "/" ? 0 : mergedPath.length;
64945
64950
  return (request) => {
64946
64951
  const url = new URL(request.url);
64947
- url.pathname = url.pathname.slice(pathPrefixLength) || "/";
64952
+ url.pathname = this.getPath(request).slice(pathPrefixLength) || "/";
64948
64953
  return new Request(url, request);
64949
64954
  };
64950
64955
  })();
@@ -64956,11 +64961,11 @@ var Hono$1 = class _Hono {
64956
64961
  this.#addRoute("ALL", mergePath(path, "*"), handler);
64957
64962
  return this;
64958
64963
  }
64959
- #addRoute(method, path, handler) {
64964
+ #addRoute(method, path, handler, baseRoutePath) {
64960
64965
  method = method.toUpperCase();
64961
64966
  path = mergePath(this._basePath, path);
64962
64967
  const r = {
64963
- basePath: this._basePath,
64968
+ basePath: baseRoutePath !== void 0 ? mergePath(this._basePath, baseRoutePath) : this._basePath,
64964
64969
  path,
64965
64970
  method,
64966
64971
  handler
@@ -66127,29 +66132,49 @@ var RequestError = class extends Error {
66127
66132
  this.name = "RequestError";
66128
66133
  }
66129
66134
  };
66130
- var toRequestError = (e) => {
66135
+ const reValidRequestUrl = /^\/[!#$&-;=?-\[\]_a-z~]*$/;
66136
+ const reDotSegment = /\/\.\.?(?:[/?#]|$)/;
66137
+ const reValidHost = /^[a-z0-9._-]+(?::(?:[1-5]\d{3,4}|[6-9]\d{3}))?$/;
66138
+ const buildUrl = (scheme, host, incomingUrl) => {
66139
+ const url = `${scheme}://${host}${incomingUrl}`;
66140
+ if (!reValidHost.test(host)) {
66141
+ const urlObj = new URL(url);
66142
+ if (urlObj.hostname.length !== host.length && urlObj.hostname !== (host.includes(":") ? host.replace(/:\d+$/, "") : host).toLowerCase()) throw new RequestError("Invalid host header");
66143
+ return urlObj.href;
66144
+ } else if (incomingUrl.length === 0) return url + "/";
66145
+ else {
66146
+ if (incomingUrl.charCodeAt(0) !== 47) throw new RequestError("Invalid URL");
66147
+ if (!reValidRequestUrl.test(incomingUrl) || reDotSegment.test(incomingUrl)) return new URL(url).href;
66148
+ return url;
66149
+ }
66150
+ };
66151
+ const toRequestError = (e) => {
66131
66152
  if (e instanceof RequestError) return e;
66132
66153
  return new RequestError(e.message, { cause: e });
66133
66154
  };
66134
- var GlobalRequest = global.Request;
66155
+ const GlobalRequest = global.Request;
66135
66156
  var Request$1 = class extends GlobalRequest {
66136
66157
  constructor(input, options) {
66137
- if (typeof input === "object" && getRequestCache in input) input = input[getRequestCache]();
66138
- if (typeof options?.body?.getReader !== "undefined") options.duplex ??= "half";
66158
+ if (typeof input === "object" && getRequestCache in input) {
66159
+ const hasReplacementBody = options !== void 0 && "body" in options && options.body != null;
66160
+ if (input[bodyConsumedDirectlyKey] && !hasReplacementBody) throw new TypeError("Cannot construct a Request with a Request object that has already been used.");
66161
+ input = input[getRequestCache]();
66162
+ }
66163
+ if (typeof (options?.body)?.getReader !== "undefined") options.duplex ??= "half";
66139
66164
  super(input, options);
66140
66165
  }
66141
66166
  };
66142
- var newHeadersFromIncoming = (incoming) => {
66167
+ const newHeadersFromIncoming = (incoming) => {
66143
66168
  const headerRecord = [];
66144
66169
  const rawHeaders = incoming.rawHeaders;
66145
- for (let i = 0; i < rawHeaders.length; i += 2) {
66146
- const { [i]: key, [i + 1]: value } = rawHeaders;
66147
- if (key.charCodeAt(0) !== 58) headerRecord.push([key, value]);
66170
+ for (let i = 0, len = rawHeaders.length; i < len; i += 2) {
66171
+ const key = rawHeaders[i];
66172
+ if (key.charCodeAt(0) !== 58) headerRecord.push([key, rawHeaders[i + 1]]);
66148
66173
  }
66149
66174
  return new Headers(headerRecord);
66150
66175
  };
66151
- var wrapBodyStream = Symbol("wrapBodyStream");
66152
- var newRequestFromIncoming = (method, url, headers, incoming, abortController) => {
66176
+ const wrapBodyStream = Symbol("wrapBodyStream");
66177
+ const newRequestFromIncoming = (method, url, headers, incoming, abortController) => {
66153
66178
  const init = {
66154
66179
  method,
66155
66180
  headers,
@@ -66182,15 +66207,162 @@ var newRequestFromIncoming = (method, url, headers, incoming, abortController) =
66182
66207
  } else init.body = Readable.toWeb(incoming);
66183
66208
  return new Request$1(url, init);
66184
66209
  };
66185
- var getRequestCache = Symbol("getRequestCache");
66186
- var requestCache = Symbol("requestCache");
66187
- var incomingKey = Symbol("incomingKey");
66188
- var urlKey = Symbol("urlKey");
66189
- var headersKey = Symbol("headersKey");
66190
- var abortControllerKey = Symbol("abortControllerKey");
66191
- var requestPrototype = {
66210
+ const getRequestCache = Symbol("getRequestCache");
66211
+ const requestCache = Symbol("requestCache");
66212
+ const incomingKey = Symbol("incomingKey");
66213
+ const urlKey = Symbol("urlKey");
66214
+ const methodKey = Symbol("methodKey");
66215
+ const headersKey = Symbol("headersKey");
66216
+ const abortControllerKey = Symbol("abortControllerKey");
66217
+ const getAbortController = Symbol("getAbortController");
66218
+ const abortRequest = Symbol("abortRequest");
66219
+ const bodyBufferKey = Symbol("bodyBuffer");
66220
+ const bodyReadPromiseKey = Symbol("bodyReadPromise");
66221
+ const bodyConsumedDirectlyKey = Symbol("bodyConsumedDirectly");
66222
+ const bodyLockReaderKey = Symbol("bodyLockReader");
66223
+ const abortReasonKey = Symbol("abortReason");
66224
+ const newBodyUnusableError = () => {
66225
+ return /* @__PURE__ */ new TypeError("Body is unusable");
66226
+ };
66227
+ const rejectBodyUnusable = () => {
66228
+ return Promise.reject(newBodyUnusableError());
66229
+ };
66230
+ const textDecoder = new TextDecoder();
66231
+ const consumeBodyDirectOnce = (request) => {
66232
+ if (request[bodyConsumedDirectlyKey]) return rejectBodyUnusable();
66233
+ request[bodyConsumedDirectlyKey] = true;
66234
+ };
66235
+ const toArrayBuffer = (buf) => {
66236
+ return buf.buffer.slice(buf.byteOffset, buf.byteOffset + buf.byteLength);
66237
+ };
66238
+ const contentType = (request) => {
66239
+ return (request[headersKey] ||= newHeadersFromIncoming(request[incomingKey])).get("content-type") || "";
66240
+ };
66241
+ const methodTokenRegExp = /^[!#$%&'*+\-.^_`|~0-9A-Za-z]+$/;
66242
+ const normalizeIncomingMethod = (method) => {
66243
+ if (typeof method !== "string" || method.length === 0) return "GET";
66244
+ switch (method) {
66245
+ case "DELETE":
66246
+ case "GET":
66247
+ case "HEAD":
66248
+ case "OPTIONS":
66249
+ case "POST":
66250
+ case "PUT": return method;
66251
+ }
66252
+ const upper = method.toUpperCase();
66253
+ switch (upper) {
66254
+ case "DELETE":
66255
+ case "GET":
66256
+ case "HEAD":
66257
+ case "OPTIONS":
66258
+ case "POST":
66259
+ case "PUT": return upper;
66260
+ default: return method;
66261
+ }
66262
+ };
66263
+ const validateDirectReadMethod = (method) => {
66264
+ if (!methodTokenRegExp.test(method)) return /* @__PURE__ */ new TypeError(`'${method}' is not a valid HTTP method.`);
66265
+ const normalized = method.toUpperCase();
66266
+ if (normalized === "CONNECT" || normalized === "TRACK" || normalized === "TRACE" && method !== "TRACE") return /* @__PURE__ */ new TypeError(`'${method}' HTTP method is unsupported.`);
66267
+ };
66268
+ const readBodyWithFastPath = (request, method, fromBuffer) => {
66269
+ if (request[bodyConsumedDirectlyKey]) return rejectBodyUnusable();
66270
+ const methodName = request.method;
66271
+ if (methodName === "GET" || methodName === "HEAD") return request[getRequestCache]()[method]();
66272
+ const methodValidationError = validateDirectReadMethod(methodName);
66273
+ if (methodValidationError) return Promise.reject(methodValidationError);
66274
+ if (request[requestCache]) {
66275
+ if (methodName !== "TRACE") return request[requestCache][method]();
66276
+ }
66277
+ const alreadyUsedError = consumeBodyDirectOnce(request);
66278
+ if (alreadyUsedError) return alreadyUsedError;
66279
+ const raw = readRawBodyIfAvailable(request);
66280
+ if (raw) {
66281
+ const result = Promise.resolve(fromBuffer(raw, request));
66282
+ request[bodyBufferKey] = void 0;
66283
+ return result;
66284
+ }
66285
+ return readBodyDirect(request).then((buf) => {
66286
+ const result = fromBuffer(buf, request);
66287
+ request[bodyBufferKey] = void 0;
66288
+ return result;
66289
+ });
66290
+ };
66291
+ const readRawBodyIfAvailable = (request) => {
66292
+ const incoming = request[incomingKey];
66293
+ if ("rawBody" in incoming && incoming.rawBody instanceof Buffer) return incoming.rawBody;
66294
+ };
66295
+ const readBodyDirect = (request) => {
66296
+ if (request[bodyBufferKey]) return Promise.resolve(request[bodyBufferKey]);
66297
+ if (request[bodyReadPromiseKey]) return request[bodyReadPromiseKey];
66298
+ const incoming = request[incomingKey];
66299
+ if (Readable.isDisturbed(incoming)) return rejectBodyUnusable();
66300
+ const promise = new Promise((resolve, reject) => {
66301
+ const chunks = [];
66302
+ let settled = false;
66303
+ const finish = (callback) => {
66304
+ if (settled) return;
66305
+ settled = true;
66306
+ cleanup();
66307
+ callback();
66308
+ };
66309
+ const onData = (chunk) => {
66310
+ chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk));
66311
+ };
66312
+ const onEnd = () => {
66313
+ finish(() => {
66314
+ const buffer = chunks.length === 1 ? chunks[0] : Buffer.concat(chunks);
66315
+ request[bodyBufferKey] = buffer;
66316
+ resolve(buffer);
66317
+ });
66318
+ };
66319
+ const onError = (error) => {
66320
+ finish(() => {
66321
+ reject(error);
66322
+ });
66323
+ };
66324
+ const onClose = () => {
66325
+ if (incoming.readableEnded) {
66326
+ onEnd();
66327
+ return;
66328
+ }
66329
+ finish(() => {
66330
+ if (incoming.errored) {
66331
+ reject(incoming.errored);
66332
+ return;
66333
+ }
66334
+ const reason = request[abortReasonKey];
66335
+ if (reason !== void 0) {
66336
+ reject(reason instanceof Error ? reason : new Error(String(reason)));
66337
+ return;
66338
+ }
66339
+ reject(/* @__PURE__ */ new Error("Client connection prematurely closed."));
66340
+ });
66341
+ };
66342
+ const cleanup = () => {
66343
+ incoming.off("data", onData);
66344
+ incoming.off("end", onEnd);
66345
+ incoming.off("error", onError);
66346
+ incoming.off("close", onClose);
66347
+ request[bodyReadPromiseKey] = void 0;
66348
+ };
66349
+ incoming.on("data", onData);
66350
+ incoming.on("end", onEnd);
66351
+ incoming.on("error", onError);
66352
+ incoming.on("close", onClose);
66353
+ queueMicrotask(() => {
66354
+ if (settled) return;
66355
+ if (incoming.readableEnded) onEnd();
66356
+ else if (incoming.errored) onError(incoming.errored);
66357
+ else if (incoming.destroyed) onClose();
66358
+ });
66359
+ });
66360
+ request[bodyReadPromiseKey] = promise;
66361
+ return promise;
66362
+ };
66363
+ const requestPrototype = {
66192
66364
  get method() {
66193
- return this[incomingKey].method || "GET";
66365
+ return this[methodKey];
66194
66366
  },
66195
66367
  get url() {
66196
66368
  return this[urlKey];
@@ -66198,18 +66370,57 @@ var requestPrototype = {
66198
66370
  get headers() {
66199
66371
  return this[headersKey] ||= newHeadersFromIncoming(this[incomingKey]);
66200
66372
  },
66201
- [Symbol("getAbortController")]() {
66202
- this[getRequestCache]();
66373
+ [abortRequest](reason) {
66374
+ if (this[abortReasonKey] === void 0) this[abortReasonKey] = reason;
66375
+ const abortController = this[abortControllerKey];
66376
+ if (abortController && !abortController.signal.aborted) abortController.abort(reason);
66377
+ },
66378
+ [getAbortController]() {
66379
+ this[abortControllerKey] ||= new AbortController();
66380
+ if (this[abortReasonKey] !== void 0 && !this[abortControllerKey].signal.aborted) this[abortControllerKey].abort(this[abortReasonKey]);
66203
66381
  return this[abortControllerKey];
66204
66382
  },
66205
66383
  [getRequestCache]() {
66206
- this[abortControllerKey] ||= new AbortController();
66207
- return this[requestCache] ||= newRequestFromIncoming(this.method, this[urlKey], this.headers, this[incomingKey], this[abortControllerKey]);
66384
+ const abortController = this[getAbortController]();
66385
+ if (this[requestCache]) return this[requestCache];
66386
+ const method = this.method;
66387
+ if (this[bodyConsumedDirectlyKey] && !(method === "GET" || method === "HEAD")) {
66388
+ this[bodyBufferKey] = void 0;
66389
+ const init = {
66390
+ method: method === "TRACE" ? "GET" : method,
66391
+ headers: this.headers,
66392
+ signal: abortController.signal
66393
+ };
66394
+ if (method !== "TRACE") {
66395
+ init.body = new ReadableStream({ start(c) {
66396
+ c.close();
66397
+ } });
66398
+ init.duplex = "half";
66399
+ }
66400
+ const req = new Request$1(this[urlKey], init);
66401
+ if (method === "TRACE") Object.defineProperty(req, "method", { get() {
66402
+ return "TRACE";
66403
+ } });
66404
+ return this[requestCache] = req;
66405
+ }
66406
+ return this[requestCache] = newRequestFromIncoming(this.method, this[urlKey], this.headers, this[incomingKey], abortController);
66407
+ },
66408
+ get body() {
66409
+ if (!this[bodyConsumedDirectlyKey]) return this[getRequestCache]().body;
66410
+ const request = this[getRequestCache]();
66411
+ if (!this[bodyLockReaderKey] && request.body) this[bodyLockReaderKey] = request.body.getReader();
66412
+ return request.body;
66413
+ },
66414
+ get bodyUsed() {
66415
+ if (this[bodyConsumedDirectlyKey]) return true;
66416
+ if (this[requestCache]) return this[requestCache].bodyUsed;
66417
+ return false;
66208
66418
  }
66209
66419
  };
66420
+ Object.defineProperty(requestPrototype, "signal", { get() {
66421
+ return this[getAbortController]().signal;
66422
+ } });
66210
66423
  [
66211
- "body",
66212
- "bodyUsed",
66213
66424
  "cache",
66214
66425
  "credentials",
66215
66426
  "destination",
@@ -66218,25 +66429,37 @@ var requestPrototype = {
66218
66429
  "redirect",
66219
66430
  "referrer",
66220
66431
  "referrerPolicy",
66221
- "signal",
66222
66432
  "keepalive"
66223
66433
  ].forEach((k) => {
66224
66434
  Object.defineProperty(requestPrototype, k, { get() {
66225
66435
  return this[getRequestCache]()[k];
66226
66436
  } });
66227
66437
  });
66228
- [
66229
- "arrayBuffer",
66230
- "blob",
66231
- "clone",
66232
- "formData",
66233
- "json",
66234
- "text"
66235
- ].forEach((k) => {
66438
+ ["clone", "formData"].forEach((k) => {
66236
66439
  Object.defineProperty(requestPrototype, k, { value: function() {
66440
+ if (this[bodyConsumedDirectlyKey]) {
66441
+ if (k === "clone") throw newBodyUnusableError();
66442
+ return rejectBodyUnusable();
66443
+ }
66237
66444
  return this[getRequestCache]()[k]();
66238
66445
  } });
66239
66446
  });
66447
+ Object.defineProperty(requestPrototype, "text", { value: function() {
66448
+ return readBodyWithFastPath(this, "text", (buf) => textDecoder.decode(buf));
66449
+ } });
66450
+ Object.defineProperty(requestPrototype, "arrayBuffer", { value: function() {
66451
+ return readBodyWithFastPath(this, "arrayBuffer", (buf) => toArrayBuffer(buf));
66452
+ } });
66453
+ Object.defineProperty(requestPrototype, "blob", { value: function() {
66454
+ return readBodyWithFastPath(this, "blob", (buf, request) => {
66455
+ const type = contentType(request);
66456
+ return new Response(buf, type ? { headers: { "content-type": type } } : void 0).blob();
66457
+ });
66458
+ } });
66459
+ Object.defineProperty(requestPrototype, "json", { value: function() {
66460
+ if (this[bodyConsumedDirectlyKey]) return rejectBodyUnusable();
66461
+ return this.text().then(JSON.parse);
66462
+ } });
66240
66463
  Object.defineProperty(requestPrototype, Symbol.for("nodejs.util.inspect.custom"), { value: function(depth, options, inspectFn) {
66241
66464
  return `Request (lightweight) ${inspectFn({
66242
66465
  method: this.method,
@@ -66249,9 +66472,10 @@ Object.defineProperty(requestPrototype, Symbol.for("nodejs.util.inspect.custom")
66249
66472
  })}`;
66250
66473
  } });
66251
66474
  Object.setPrototypeOf(requestPrototype, Request$1.prototype);
66252
- var newRequest = (incoming, defaultHostname) => {
66475
+ const newRequest = (incoming, defaultHostname) => {
66253
66476
  const req = Object.create(requestPrototype);
66254
66477
  req[incomingKey] = incoming;
66478
+ req[methodKey] = normalizeIncomingMethod(incoming.method);
66255
66479
  const incomingUrl = incoming.url || "";
66256
66480
  if (incomingUrl[0] !== "/" && (incomingUrl.startsWith("http://") || incomingUrl.startsWith("https://"))) {
66257
66481
  if (incoming instanceof Http2ServerRequest) throw new RequestError("Absolute URL for :path is not allowed in HTTP/2");
@@ -66269,26 +66493,35 @@ var newRequest = (incoming, defaultHostname) => {
66269
66493
  scheme = incoming.scheme;
66270
66494
  if (!(scheme === "http" || scheme === "https")) throw new RequestError("Unsupported scheme");
66271
66495
  } else scheme = incoming.socket && incoming.socket.encrypted ? "https" : "http";
66272
- const url = new URL(`${scheme}://${host}${incomingUrl}`);
66273
- if (url.hostname.length !== host.length && url.hostname !== host.replace(/:\d+$/, "")) throw new RequestError("Invalid host header");
66274
- req[urlKey] = url.href;
66496
+ try {
66497
+ req[urlKey] = buildUrl(scheme, host, incomingUrl);
66498
+ } catch (e) {
66499
+ if (e instanceof RequestError) throw e;
66500
+ else throw new RequestError("Invalid URL", { cause: e });
66501
+ }
66275
66502
  return req;
66276
66503
  };
66277
- var responseCache = Symbol("responseCache");
66278
- var getResponseCache = Symbol("getResponseCache");
66279
- var cacheKey = Symbol("cache");
66280
- var GlobalResponse = global.Response;
66281
- var Response2 = class _Response {
66504
+ const defaultContentType = "text/plain; charset=UTF-8";
66505
+ const responseCache = Symbol("responseCache");
66506
+ const getResponseCache = Symbol("getResponseCache");
66507
+ const cacheKey = Symbol("cache");
66508
+ const GlobalResponse = global.Response;
66509
+ var Response$1 = class Response$1 {
66282
66510
  #body;
66283
66511
  #init;
66284
66512
  [getResponseCache]() {
66513
+ const cache = this[cacheKey];
66514
+ const liveHeaders = cache && cache[2] instanceof Headers ? cache[2] : void 0;
66285
66515
  delete this[cacheKey];
66286
- return this[responseCache] ||= new GlobalResponse(this.#body, this.#init);
66516
+ return this[responseCache] ||= new GlobalResponse(this.#body, liveHeaders ? {
66517
+ ...this.#init,
66518
+ headers: liveHeaders
66519
+ } : this.#init);
66287
66520
  }
66288
66521
  constructor(body, init) {
66289
66522
  let headers;
66290
66523
  this.#body = body;
66291
- if (init instanceof _Response) {
66524
+ if (init instanceof Response$1) {
66292
66525
  const cachedGlobalResponse = init[responseCache];
66293
66526
  if (cachedGlobalResponse) {
66294
66527
  this.#init = cachedGlobalResponse;
@@ -66296,19 +66529,19 @@ var Response2 = class _Response {
66296
66529
  return;
66297
66530
  } else {
66298
66531
  this.#init = init.#init;
66299
- headers = new Headers(init.#init.headers);
66532
+ headers = new Headers(init.headers);
66300
66533
  }
66301
66534
  } else this.#init = init;
66302
- if (typeof body === "string" || typeof body?.getReader !== "undefined" || body instanceof Blob || body instanceof Uint8Array) this[cacheKey] = [
66535
+ if (body == null || typeof body === "string" || typeof body?.getReader !== "undefined" || body instanceof Blob || body instanceof Uint8Array) this[cacheKey] = [
66303
66536
  init?.status || 200,
66304
- body,
66537
+ body ?? null,
66305
66538
  headers || init?.headers
66306
66539
  ];
66307
66540
  }
66308
66541
  get headers() {
66309
66542
  const cache = this[cacheKey];
66310
66543
  if (cache) {
66311
- if (!(cache[2] instanceof Headers)) cache[2] = new Headers(cache[2] || { "content-type": "text/plain; charset=UTF-8" });
66544
+ if (!(cache[2] instanceof Headers)) cache[2] = new Headers(cache[2] || (cache[1] === null ? void 0 : { "content-type": defaultContentType }));
66312
66545
  return cache[2];
66313
66546
  }
66314
66547
  return this[getResponseCache]().headers;
@@ -66330,7 +66563,7 @@ var Response2 = class _Response {
66330
66563
  "type",
66331
66564
  "url"
66332
66565
  ].forEach((k) => {
66333
- Object.defineProperty(Response2.prototype, k, { get() {
66566
+ Object.defineProperty(Response$1.prototype, k, { get() {
66334
66567
  return this[getResponseCache]()[k];
66335
66568
  } });
66336
66569
  });
@@ -66342,11 +66575,11 @@ var Response2 = class _Response {
66342
66575
  "json",
66343
66576
  "text"
66344
66577
  ].forEach((k) => {
66345
- Object.defineProperty(Response2.prototype, k, { value: function() {
66578
+ Object.defineProperty(Response$1.prototype, k, { value: function() {
66346
66579
  return this[getResponseCache]()[k]();
66347
66580
  } });
66348
66581
  });
66349
- Object.defineProperty(Response2.prototype, Symbol.for("nodejs.util.inspect.custom"), { value: function(depth, options, inspectFn) {
66582
+ Object.defineProperty(Response$1.prototype, Symbol.for("nodejs.util.inspect.custom"), { value: function(depth, options, inspectFn) {
66350
66583
  return `Response (lightweight) ${inspectFn({
66351
66584
  status: this.status,
66352
66585
  headers: this.headers,
@@ -66357,8 +66590,51 @@ Object.defineProperty(Response2.prototype, Symbol.for("nodejs.util.inspect.custo
66357
66590
  depth: depth == null ? null : depth - 1
66358
66591
  })}`;
66359
66592
  } });
66360
- Object.setPrototypeOf(Response2, GlobalResponse);
66361
- Object.setPrototypeOf(Response2.prototype, GlobalResponse.prototype);
66593
+ Object.setPrototypeOf(Response$1, GlobalResponse);
66594
+ Object.setPrototypeOf(Response$1.prototype, GlobalResponse.prototype);
66595
+ const validRedirectUrl = /^https?:\/\/[!#-;=?-[\]_a-z~A-Z]+$/;
66596
+ const parseRedirectUrl = (url) => {
66597
+ if (url instanceof URL) return url.href;
66598
+ if (validRedirectUrl.test(url)) return url;
66599
+ return new URL(url).href;
66600
+ };
66601
+ const validRedirectStatuses = new Set([
66602
+ 301,
66603
+ 302,
66604
+ 303,
66605
+ 307,
66606
+ 308
66607
+ ]);
66608
+ Object.defineProperty(Response$1, "redirect", {
66609
+ value: function redirect(url, status = 302) {
66610
+ if (!validRedirectStatuses.has(status)) throw new RangeError("Invalid status code");
66611
+ return new Response$1(null, {
66612
+ status,
66613
+ headers: { location: parseRedirectUrl(url) }
66614
+ });
66615
+ },
66616
+ writable: true,
66617
+ configurable: true
66618
+ });
66619
+ Object.defineProperty(Response$1, "json", {
66620
+ value: function json(data, init) {
66621
+ const body = JSON.stringify(data);
66622
+ if (body === void 0) throw new TypeError("The data is not JSON serializable");
66623
+ const initHeaders = init?.headers;
66624
+ let headers;
66625
+ if (initHeaders) {
66626
+ headers = new Headers(initHeaders);
66627
+ if (!headers.has("content-type")) headers.set("content-type", "application/json");
66628
+ } else headers = { "content-type": "application/json" };
66629
+ return new Response$1(body, {
66630
+ status: init?.status ?? 200,
66631
+ statusText: init?.statusText,
66632
+ headers
66633
+ });
66634
+ },
66635
+ writable: true,
66636
+ configurable: true
66637
+ });
66362
66638
  async function readWithoutBlocking(readPromise) {
66363
66639
  return Promise.race([readPromise, Promise.resolve().then(() => Promise.resolve(void 0))]);
66364
66640
  }
@@ -66394,23 +66670,23 @@ function writeFromReadableStream(stream, writable) {
66394
66670
  else if (writable.destroyed) return;
66395
66671
  return writeFromReadableStreamDefaultReader(stream.getReader(), writable);
66396
66672
  }
66397
- var buildOutgoingHttpHeaders = (headers) => {
66673
+ const buildOutgoingHttpHeaders = (headers, defaultContentType) => {
66398
66674
  const res = {};
66399
66675
  if (!(headers instanceof Headers)) headers = new Headers(headers ?? void 0);
66400
- const cookies = [];
66401
- for (const [k, v] of headers) if (k === "set-cookie") cookies.push(v);
66402
- else res[k] = v;
66403
- if (cookies.length > 0) res["set-cookie"] = cookies;
66404
- res["content-type"] ??= "text/plain; charset=UTF-8";
66676
+ if (headers.has("set-cookie")) {
66677
+ const cookies = [];
66678
+ for (const [k, v] of headers) if (k === "set-cookie") cookies.push(v);
66679
+ else res[k] = v;
66680
+ if (cookies.length > 0) res["set-cookie"] = cookies;
66681
+ } else for (const [k, v] of headers) res[k] = v;
66682
+ if (defaultContentType) res["content-type"] ??= defaultContentType;
66405
66683
  return res;
66406
66684
  };
66407
- var X_ALREADY_SENT = "x-hono-already-sent";
66408
- if (typeof global.crypto === "undefined") global.crypto = crypto$1;
66409
- var outgoingEnded = Symbol("outgoingEnded");
66410
- var incomingDraining = Symbol("incomingDraining");
66411
- var DRAIN_TIMEOUT_MS = 500;
66412
- var MAX_DRAIN_BYTES = 64 * 1024 * 1024;
66413
- var drainIncoming = (incoming) => {
66685
+ const outgoingEnded = Symbol("outgoingEnded");
66686
+ const incomingDraining = Symbol("incomingDraining");
66687
+ const DRAIN_TIMEOUT_MS = 500;
66688
+ const MAX_DRAIN_BYTES = 64 * 1024 * 1024;
66689
+ const drainIncoming = (incoming) => {
66414
66690
  const incomingWithDrainState = incoming;
66415
66691
  if (incoming.destroyed || incomingWithDrainState[incomingDraining]) return;
66416
66692
  incomingWithDrainState[incomingDraining] = true;
@@ -66443,9 +66719,23 @@ var drainIncoming = (incoming) => {
66443
66719
  incoming.on("error", cleanup);
66444
66720
  incoming.resume();
66445
66721
  };
66446
- var handleRequestError = () => new Response(null, { status: 400 });
66447
- var handleFetchError = (e) => new Response(null, { status: e instanceof Error && (e.name === "TimeoutError" || e.constructor.name === "TimeoutError") ? 504 : 500 });
66448
- var handleResponseError = (e, outgoing) => {
66722
+ const makeCloseHandler = (req, incoming, outgoing, needsBodyCleanup) => () => {
66723
+ if (incoming.errored) req[abortRequest](incoming.errored.toString());
66724
+ else if (!outgoing.writableFinished) req[abortRequest]("Client connection prematurely closed.");
66725
+ if (needsBodyCleanup && !incoming.readableEnded) setTimeout(() => {
66726
+ if (!incoming.readableEnded) setTimeout(() => {
66727
+ drainIncoming(incoming);
66728
+ });
66729
+ });
66730
+ };
66731
+ const isImmediateCacheableResponse = (res) => {
66732
+ if (!(cacheKey in res)) return false;
66733
+ const body = res[cacheKey][1];
66734
+ return body === null || typeof body === "string" || body instanceof Uint8Array;
66735
+ };
66736
+ const handleRequestError = () => new Response(null, { status: 400 });
66737
+ const handleFetchError = (e) => new Response(null, { status: e instanceof Error && (e.name === "TimeoutError" || e.constructor.name === "TimeoutError") ? 504 : 500 });
66738
+ const handleResponseError = (e, outgoing) => {
66449
66739
  const err = e instanceof Error ? e : new Error("unknown error", { cause: e });
66450
66740
  if (err.code === "ERR_STREAM_PREMATURE_CLOSE") console.info("The user aborted a request.");
66451
66741
  else {
@@ -66455,20 +66745,49 @@ var handleResponseError = (e, outgoing) => {
66455
66745
  outgoing.destroy(err);
66456
66746
  }
66457
66747
  };
66458
- var flushHeaders = (outgoing) => {
66748
+ const flushHeaders = (outgoing) => {
66459
66749
  if ("flushHeaders" in outgoing && outgoing.writable) outgoing.flushHeaders();
66460
66750
  };
66461
- var responseViaCache = async (res, outgoing) => {
66751
+ const responseViaCache = async (res, outgoing) => {
66462
66752
  let [status, body, header] = res[cacheKey];
66753
+ if (!header) {
66754
+ if (body === null) {
66755
+ outgoing.writeHead(status);
66756
+ outgoing.end();
66757
+ } else if (typeof body === "string") {
66758
+ outgoing.writeHead(status, {
66759
+ "Content-Type": defaultContentType,
66760
+ "Content-Length": Buffer.byteLength(body)
66761
+ });
66762
+ outgoing.end(body);
66763
+ } else if (body instanceof Uint8Array) {
66764
+ outgoing.writeHead(status, {
66765
+ "Content-Type": defaultContentType,
66766
+ "Content-Length": body.byteLength
66767
+ });
66768
+ outgoing.end(body);
66769
+ } else if (body instanceof Blob) {
66770
+ outgoing.writeHead(status, {
66771
+ "Content-Type": defaultContentType,
66772
+ "Content-Length": body.size
66773
+ });
66774
+ outgoing.end(new Uint8Array(await body.arrayBuffer()));
66775
+ } else {
66776
+ outgoing.writeHead(status, { "Content-Type": defaultContentType });
66777
+ flushHeaders(outgoing);
66778
+ await writeFromReadableStream(body, outgoing)?.catch((e) => handleResponseError(e, outgoing));
66779
+ }
66780
+ outgoing[outgoingEnded]?.();
66781
+ return;
66782
+ }
66463
66783
  let hasContentLength = false;
66464
- if (!header) header = { "content-type": "text/plain; charset=UTF-8" };
66465
- else if (header instanceof Headers) {
66784
+ if (header instanceof Headers) {
66466
66785
  hasContentLength = header.has("content-length");
66467
- header = buildOutgoingHttpHeaders(header);
66786
+ header = buildOutgoingHttpHeaders(header, body === null ? void 0 : defaultContentType);
66468
66787
  } else if (Array.isArray(header)) {
66469
66788
  const headerObj = new Headers(header);
66470
66789
  hasContentLength = headerObj.has("content-length");
66471
- header = buildOutgoingHttpHeaders(headerObj);
66790
+ header = buildOutgoingHttpHeaders(headerObj, body === null ? void 0 : defaultContentType);
66472
66791
  } else for (const key in header) if (key.length === 14 && key.toLowerCase() === "content-length") {
66473
66792
  hasContentLength = true;
66474
66793
  break;
@@ -66479,7 +66798,8 @@ var responseViaCache = async (res, outgoing) => {
66479
66798
  else if (body instanceof Blob) header["Content-Length"] = body.size;
66480
66799
  }
66481
66800
  outgoing.writeHead(status, header);
66482
- if (typeof body === "string" || body instanceof Uint8Array) outgoing.end(body);
66801
+ if (body == null) outgoing.end();
66802
+ else if (typeof body === "string" || body instanceof Uint8Array) outgoing.end(body);
66483
66803
  else if (body instanceof Blob) outgoing.end(new Uint8Array(await body.arrayBuffer()));
66484
66804
  else {
66485
66805
  flushHeaders(outgoing);
@@ -66487,8 +66807,8 @@ var responseViaCache = async (res, outgoing) => {
66487
66807
  }
66488
66808
  outgoing[outgoingEnded]?.();
66489
66809
  };
66490
- var isPromise = (res) => typeof res.then === "function";
66491
- var responseViaResponseObject = async (res, outgoing, options = {}) => {
66810
+ const isPromise = (res) => typeof res.then === "function";
66811
+ const responseViaResponseObject = async (res, outgoing, options = {}) => {
66492
66812
  if (isPromise(res)) if (options.errorHandler) try {
66493
66813
  res = await res;
66494
66814
  } catch (err) {
@@ -66498,7 +66818,7 @@ var responseViaResponseObject = async (res, outgoing, options = {}) => {
66498
66818
  }
66499
66819
  else res = await res.catch(handleFetchError);
66500
66820
  if (cacheKey in res) return responseViaCache(res, outgoing);
66501
- const resHeaderRecord = buildOutgoingHttpHeaders(res.headers);
66821
+ const resHeaderRecord = buildOutgoingHttpHeaders(res.headers, res.body === null ? void 0 : defaultContentType);
66502
66822
  if (res.body) {
66503
66823
  const reader = res.body.getReader();
66504
66824
  const values = [];
@@ -66538,57 +66858,55 @@ var responseViaResponseObject = async (res, outgoing, options = {}) => {
66538
66858
  if (values.length === 0) flushHeaders(outgoing);
66539
66859
  await writeFromReadableStreamDefaultReader(reader, outgoing, currentReadPromise);
66540
66860
  }
66541
- } else if (resHeaderRecord[X_ALREADY_SENT]) {} else {
66861
+ } else if (resHeaderRecord["x-hono-already-sent"]) {} else {
66542
66862
  outgoing.writeHead(res.status, resHeaderRecord);
66543
66863
  outgoing.end();
66544
66864
  }
66545
66865
  outgoing[outgoingEnded]?.();
66546
66866
  };
66547
- var getRequestListener = (fetchCallback, options = {}) => {
66867
+ const getRequestListener = (fetchCallback, options = {}) => {
66548
66868
  const autoCleanupIncoming = options.autoCleanupIncoming ?? true;
66549
66869
  if (options.overrideGlobalObjects !== false && global.Request !== Request$1) {
66550
66870
  Object.defineProperty(global, "Request", { value: Request$1 });
66551
- Object.defineProperty(global, "Response", { value: Response2 });
66871
+ Object.defineProperty(global, "Response", { value: Response$1 });
66552
66872
  }
66553
66873
  return async (incoming, outgoing) => {
66554
66874
  let res, req;
66875
+ let needsBodyCleanup = false;
66876
+ let closeHandlerAttached = false;
66877
+ const ensureCloseHandler = () => {
66878
+ if (!req || closeHandlerAttached) return;
66879
+ closeHandlerAttached = true;
66880
+ outgoing.on("close", makeCloseHandler(req, incoming, outgoing, needsBodyCleanup));
66881
+ };
66555
66882
  try {
66556
66883
  req = newRequest(incoming, options.hostname);
66557
- let incomingEnded = !autoCleanupIncoming || incoming.method === "GET" || incoming.method === "HEAD";
66558
- if (!incomingEnded) {
66884
+ needsBodyCleanup = autoCleanupIncoming && !(incoming.method === "GET" || incoming.method === "HEAD");
66885
+ if (needsBodyCleanup) {
66559
66886
  incoming[wrapBodyStream] = true;
66560
- incoming.on("end", () => {
66561
- incomingEnded = true;
66562
- });
66563
66887
  if (incoming instanceof Http2ServerRequest) outgoing[outgoingEnded] = () => {
66564
- if (!incomingEnded) setTimeout(() => {
66565
- if (!incomingEnded) setTimeout(() => {
66566
- drainIncoming(incoming);
66888
+ if (!incoming.readableEnded) setTimeout(() => {
66889
+ if (!incoming.readableEnded) setTimeout(() => {
66890
+ incoming.destroy();
66891
+ outgoing.destroy();
66567
66892
  });
66568
66893
  });
66569
66894
  };
66570
- outgoing.on("finish", () => {
66571
- if (!incomingEnded) drainIncoming(incoming);
66572
- });
66573
66895
  }
66574
- outgoing.on("close", () => {
66575
- if (req[abortControllerKey]) {
66576
- if (incoming.errored) req[abortControllerKey].abort(incoming.errored.toString());
66577
- else if (!outgoing.writableFinished) req[abortControllerKey].abort("Client connection prematurely closed.");
66578
- }
66579
- if (!incomingEnded) setTimeout(() => {
66580
- if (!incomingEnded) setTimeout(() => {
66581
- drainIncoming(incoming);
66582
- });
66583
- });
66584
- });
66585
66896
  res = fetchCallback(req, {
66586
66897
  incoming,
66587
66898
  outgoing
66588
66899
  });
66589
- if (cacheKey in res) return responseViaCache(res, outgoing);
66900
+ if (!isPromise(res) && isImmediateCacheableResponse(res)) {
66901
+ if (needsBodyCleanup && !incoming.readableEnded) outgoing.once("finish", () => {
66902
+ if (!incoming.readableEnded) drainIncoming(incoming);
66903
+ });
66904
+ return responseViaCache(res, outgoing);
66905
+ }
66906
+ ensureCloseHandler();
66590
66907
  } catch (e) {
66591
66908
  if (!res) if (options.errorHandler) {
66909
+ ensureCloseHandler();
66592
66910
  res = await options.errorHandler(req ? e : toRequestError(e));
66593
66911
  if (!res) return;
66594
66912
  } else if (!req) res = handleRequestError();
@@ -66602,16 +66920,126 @@ var getRequestListener = (fetchCallback, options = {}) => {
66602
66920
  }
66603
66921
  };
66604
66922
  };
66605
- var createAdaptorServer = (options) => {
66923
+ globalThis.CloseEvent;
66924
+ const CONNECTION_SYMBOL_KEY = Symbol("CONNECTION_SYMBOL_KEY");
66925
+ const WAIT_FOR_WEBSOCKET_SYMBOL = Symbol("WAIT_FOR_WEBSOCKET_SYMBOL");
66926
+ const responseHeadersToSkip = new Set([
66927
+ "connection",
66928
+ "content-length",
66929
+ "keep-alive",
66930
+ "proxy-authenticate",
66931
+ "proxy-authorization",
66932
+ "te",
66933
+ "trailer",
66934
+ "transfer-encoding",
66935
+ "upgrade",
66936
+ "sec-websocket-accept",
66937
+ "sec-websocket-extensions",
66938
+ "sec-websocket-protocol"
66939
+ ]);
66940
+ const appendResponseHeaders = (headers, responseHeaders) => {
66941
+ if (!responseHeaders) return;
66942
+ responseHeaders.forEach((value, key) => {
66943
+ if (responseHeadersToSkip.has(key.toLowerCase())) return;
66944
+ headers.push(`${key}: ${value}`);
66945
+ });
66946
+ };
66947
+ const rejectUpgradeRequest = (socket, status, responseHeaders) => {
66948
+ const responseLines = ["Connection: close", "Content-Length: 0"];
66949
+ appendResponseHeaders(responseLines, responseHeaders);
66950
+ socket.end(`HTTP/1.1 ${status.toString()} ${STATUS_CODES[status] ?? ""}\r\n${responseLines.join("\r\n")}\r\n\r
66951
+ `);
66952
+ };
66953
+ const createUpgradeRequest = (request) => {
66954
+ const protocol = request.socket.encrypted ? "https" : "http";
66955
+ const url = new URL(request.url ?? "/", `${protocol}://${request.headers.host ?? "localhost"}`);
66956
+ const headers = new Headers();
66957
+ for (const key in request.headers) {
66958
+ const value = request.headers[key];
66959
+ if (!value) continue;
66960
+ headers.append(key, Array.isArray(value) ? value[0] : value);
66961
+ }
66962
+ return new Request(url, { headers });
66963
+ };
66964
+ const setupWebSocket = (options) => {
66965
+ const { server, fetchCallback, wss } = options;
66966
+ const waiterMap = /* @__PURE__ */ new Map();
66967
+ wss.on("connection", (ws, request) => {
66968
+ const waiter = waiterMap.get(request);
66969
+ if (waiter) {
66970
+ waiter.resolve(ws);
66971
+ waiterMap.delete(request);
66972
+ }
66973
+ });
66974
+ const waitForWebSocket = (request, connectionSymbol) => {
66975
+ return new Promise((resolve) => {
66976
+ waiterMap.set(request, {
66977
+ resolve,
66978
+ connectionSymbol
66979
+ });
66980
+ });
66981
+ };
66982
+ server.on("upgrade", async (request, socket, head) => {
66983
+ if (request.headers.upgrade?.toLowerCase() !== "websocket") return;
66984
+ const env = {
66985
+ incoming: request,
66986
+ outgoing: void 0,
66987
+ wss,
66988
+ [WAIT_FOR_WEBSOCKET_SYMBOL]: waitForWebSocket
66989
+ };
66990
+ let status = 400;
66991
+ let responseHeaders;
66992
+ try {
66993
+ const response = await fetchCallback(createUpgradeRequest(request), env);
66994
+ if (response instanceof Response) {
66995
+ status = response.status;
66996
+ responseHeaders = response.headers;
66997
+ }
66998
+ } catch {
66999
+ if (server.listenerCount("upgrade") === 1) rejectUpgradeRequest(socket, 500);
67000
+ return;
67001
+ }
67002
+ const waiter = waiterMap.get(request);
67003
+ if (!waiter || waiter.connectionSymbol !== env[CONNECTION_SYMBOL_KEY]) {
67004
+ waiterMap.delete(request);
67005
+ if (server.listenerCount("upgrade") === 1) rejectUpgradeRequest(socket, status, responseHeaders);
67006
+ return;
67007
+ }
67008
+ const addResponseHeaders = (headers) => {
67009
+ appendResponseHeaders(headers, responseHeaders);
67010
+ };
67011
+ wss.on("headers", addResponseHeaders);
67012
+ try {
67013
+ wss.handleUpgrade(request, socket, head, (ws) => {
67014
+ wss.emit("connection", ws, request);
67015
+ });
67016
+ } finally {
67017
+ wss.off("headers", addResponseHeaders);
67018
+ }
67019
+ });
67020
+ server.on("close", () => {
67021
+ wss.close();
67022
+ });
67023
+ };
67024
+ const createAdaptorServer = (options) => {
66606
67025
  const fetchCallback = options.fetch;
66607
67026
  const requestListener = getRequestListener(fetchCallback, {
66608
67027
  hostname: options.hostname,
66609
67028
  overrideGlobalObjects: options.overrideGlobalObjects,
66610
67029
  autoCleanupIncoming: options.autoCleanupIncoming
66611
67030
  });
66612
- return (options.createServer || createServer$1)(options.serverOptions || {}, requestListener);
67031
+ const server = (options.createServer || createServer)(options.serverOptions || {}, requestListener);
67032
+ if (options.websocket && options.websocket.server) {
67033
+ if (options.websocket.server.options.noServer !== true) throw new Error("WebSocket server must be created with { noServer: true } option");
67034
+ setupWebSocket({
67035
+ server,
67036
+ fetchCallback,
67037
+ wss: options.websocket.server
67038
+ });
67039
+ }
67040
+ return server;
66613
67041
  };
66614
- var serve = (options, listeningListener) => {
67042
+ const serve = (options, listeningListener) => {
66615
67043
  const server = createAdaptorServer(options);
66616
67044
  server.listen(options?.port ?? 3e3, options.hostname, () => {
66617
67045
  const serverInfo = server.address();
@@ -67071,7 +67499,7 @@ function createHttpServeApp(options, engine, io = {}) {
67071
67499
  }
67072
67500
  });
67073
67501
  }
67074
- return c.json(await dispatchRemoteCliRequest(request, controlContext(io, writeErr, authFlowStore, c.req.url, paths.control, options.trustProxy, (name) => c.req.header(name))));
67502
+ return c.json(await dispatchRemoteCliRequest(request, controlContext(io, writeErr, authFlowStore, c.req.url, paths.control, options.publicOrigin, options.trustProxy, (name) => c.req.header(name))));
67075
67503
  });
67076
67504
  app.get(routePath(paths.control, "auth/callback/:flowId"), async (c) => {
67077
67505
  const flowId = c.req.param("flowId");
@@ -67081,7 +67509,7 @@ function createHttpServeApp(options, engine, io = {}) {
67081
67509
  flowId,
67082
67510
  callbackUrl: c.req.url
67083
67511
  }
67084
- }, controlContext(io, writeErr, authFlowStore, c.req.url, paths.control, options.trustProxy, (name) => c.req.header(name)));
67512
+ }, controlContext(io, writeErr, authFlowStore, c.req.url, paths.control, options.publicOrigin, options.trustProxy, (name) => c.req.header(name)));
67085
67513
  if (!result.ok) writeErr(`Caplets authentication failed for flow ${flowId}: ${result.error.message}\n`);
67086
67514
  return result.ok ? c.text("Caplets authentication complete. You can return to your terminal.") : c.text("Caplets authentication failed. Check server logs for details.", 400);
67087
67515
  });
@@ -67095,12 +67523,12 @@ function createHttpServeApp(options, engine, io = {}) {
67095
67523
  if (options.warnUnauthenticatedNetwork) writeErr(`Warning: Caplets MCP HTTP server is listening on ${options.host} without authentication.\n`);
67096
67524
  return app;
67097
67525
  }
67098
- function controlContext(io, writeErr, authFlowStore, requestUrl, controlPath, trustProxy, header) {
67526
+ function controlContext(io, writeErr, authFlowStore, requestUrl, controlPath, publicOrigin, trustProxy, header) {
67099
67527
  return {
67100
67528
  ...io.control,
67101
67529
  projectCapletsRoot: io.control?.projectCapletsRoot ?? resolveProjectCapletsRoot(),
67102
67530
  authFlowStore,
67103
- controlCallbackBaseUrl: new URL(controlPath, publicRequestOrigin(requestUrl, trustProxy, header)).toString(),
67531
+ controlCallbackBaseUrl: new URL(controlPath, publicOrigin ?? publicRequestOrigin(requestUrl, trustProxy, header)).toString(),
67104
67532
  writeErr
67105
67533
  };
67106
67534
  }
@@ -67265,6 +67693,7 @@ function resolveServeOptions(raw, env = process.env) {
67265
67693
  host,
67266
67694
  port,
67267
67695
  path,
67696
+ ...serverUrl ? { publicOrigin: serverUrl.origin } : {},
67268
67697
  auth,
67269
67698
  warnUnauthenticatedNetwork: !loopback && !auth.enabled,
67270
67699
  loopback,
@@ -67454,9 +67883,12 @@ function createProgram(io = {}) {
67454
67883
  suggestions = remote ? await remote.request("complete_cli", {
67455
67884
  shell,
67456
67885
  words: completionWords
67457
- }) : await completeCliWords(completionWords, configPath ? { configPath } : {});
67886
+ }) : await completeCliWordsLocally(completionWords, {
67887
+ ...configPath ? { configPath } : {},
67888
+ ...io.authDir ? { authDir: io.authDir } : {}
67889
+ });
67458
67890
  } catch {
67459
- suggestions = [];
67891
+ suggestions = remote ? [] : await completeCliWords(completionWords, configPath ? { configPath } : {});
67460
67892
  }
67461
67893
  if (suggestions.length > 0) writeOut(`${suggestions.join("\n")}\n`);
67462
67894
  });
@@ -67650,8 +68082,8 @@ function createProgram(io = {}) {
67650
68082
  format: options.format
67651
68083
  });
67652
68084
  });
67653
- program.command(cliCommands.getTool).description("Print one downstream tool schema.").argument("<caplet.tool>", "qualified target, split on the first dot").option("--format <format>", "output format: markdown, md, plain, or json", parseOutputFormat).action(async (target, options) => {
67654
- const { caplet, tool } = parseQualifiedTarget(target);
68085
+ program.command(cliCommands.getTool).description("Print one downstream tool schema.").argument("<caplet-or-target>", "Caplet ID or qualified <caplet.tool> target").argument("[tool]", "downstream tool name when caplet is provided separately").option("--format <format>", "output format: markdown, md, plain, or json", parseOutputFormat).action(async (capletOrTarget, toolArgument, options) => {
68086
+ const { caplet, tool } = parseQualifiedTarget(capletOrTarget, toolArgument);
67655
68087
  await executeOperation(caplet, {
67656
68088
  operation: "get_tool",
67657
68089
  tool
@@ -67665,8 +68097,8 @@ function createProgram(io = {}) {
67665
68097
  format: options.format
67666
68098
  });
67667
68099
  });
67668
- program.command(cliCommands.callTool).description("Call one downstream tool.").argument("<caplet.tool>", "qualified target, split on the first dot").option("--args <json-object>", "JSON object of downstream tool arguments").option("--field <path>", "project a field from structured output", collect, []).option("--format <format>", "output format: markdown, md, plain, or json", parseOutputFormat).action(async (target, options) => {
67669
- const { caplet, tool } = parseQualifiedTarget(target);
68100
+ program.command(cliCommands.callTool).description("Call one downstream tool.").argument("<caplet-or-target>", "Caplet ID or qualified <caplet.tool> target").argument("[tool]", "downstream tool name when caplet is provided separately").option("--args <json-object>", "JSON object of downstream tool arguments").option("--field <path>", "project a field from structured output", collect, []).option("--format <format>", "output format: markdown, md, plain, or json", parseOutputFormat).action(async (capletOrTarget, toolArgument, options) => {
68101
+ const { caplet, tool } = parseQualifiedTarget(capletOrTarget, toolArgument);
67670
68102
  await executeOperation(caplet, {
67671
68103
  operation: "call_tool",
67672
68104
  tool,
@@ -67762,8 +68194,8 @@ function createProgram(io = {}) {
67762
68194
  remote: remoteClientForCli(io),
67763
68195
  format: options.format
67764
68196
  }));
67765
- program.command(cliCommands.getPrompt).description("Get one MCP prompt by name.").argument("<caplet.prompt>", "qualified target, split on the first dot").option("--args <json-object>", "JSON object of prompt arguments").option("--format <format>", "output format: markdown, md, plain, or json", parseOutputFormat).action(async (target, options) => {
67766
- const { caplet, tool: prompt } = parseQualifiedTarget(target);
68197
+ program.command(cliCommands.getPrompt).description("Get one MCP prompt by name.").argument("<caplet-or-target>", "MCP Caplet ID or qualified <caplet.prompt> target").argument("[prompt]", "prompt name when caplet is provided separately").option("--args <json-object>", "JSON object of prompt arguments").option("--format <format>", "output format: markdown, md, plain, or json", parseOutputFormat).action(async (capletOrTarget, promptArgument, options) => {
68198
+ const { caplet, tool: prompt } = parseQualifiedTarget(capletOrTarget, promptArgument);
67767
68199
  await executeOperation(caplet, {
67768
68200
  operation: "get_prompt",
67769
68201
  prompt,
@@ -67928,14 +68360,33 @@ function parseOutputFormat(value) {
67928
68360
  default: throw new CapletsError("REQUEST_INVALID", `Expected output format markdown, md, plain, or json; got ${value}`);
67929
68361
  }
67930
68362
  }
67931
- function parseQualifiedTarget(target) {
67932
- const dot = target.indexOf(".");
67933
- if (dot <= 0 || dot === target.length - 1) throw new CapletsError("REQUEST_INVALID", "Expected qualified target in the form <caplet>.<tool>");
68363
+ function parseQualifiedTarget(capletOrTarget, toolArgument) {
68364
+ if (toolArgument !== void 0) {
68365
+ if (capletOrTarget.length === 0 || toolArgument.length === 0) throw new CapletsError("REQUEST_INVALID", "Expected target in the form <caplet> <tool> or <caplet>.<tool>");
68366
+ return {
68367
+ caplet: capletOrTarget,
68368
+ tool: toolArgument
68369
+ };
68370
+ }
68371
+ const dot = capletOrTarget.indexOf(".");
68372
+ if (dot <= 0 || dot === capletOrTarget.length - 1) throw new CapletsError("REQUEST_INVALID", "Expected target in the form <caplet> <tool> or <caplet>.<tool>");
67934
68373
  return {
67935
- caplet: target.slice(0, dot),
67936
- tool: target.slice(dot + 1)
68374
+ caplet: capletOrTarget.slice(0, dot),
68375
+ tool: capletOrTarget.slice(dot + 1)
67937
68376
  };
67938
68377
  }
68378
+ async function completeCliWordsLocally(words, options) {
68379
+ const engine = new CapletsEngine({
68380
+ ...options.configPath ? { configPath: options.configPath } : {},
68381
+ ...options.authDir ? { authDir: options.authDir } : {},
68382
+ watch: false
68383
+ });
68384
+ try {
68385
+ return await engine.completeCliWords(words);
68386
+ } finally {
68387
+ await engine.close();
68388
+ }
68389
+ }
67939
68390
  function parseCallToolArgs(value) {
67940
68391
  if (value === void 0) return {};
67941
68392
  let parsed;
@@ -68360,7 +68811,7 @@ function writeAddResult(writeOut, label, result) {
68360
68811
  }
68361
68812
  //#endregion
68362
68813
  //#region package.json
68363
- var version = "0.17.0";
68814
+ var version = "0.17.2";
68364
68815
  //#endregion
68365
68816
  //#region src/index.ts
68366
68817
  async function main() {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "caplets",
3
- "version": "0.17.0",
3
+ "version": "0.17.2",
4
4
  "description": "Progressive disclosure gateway CLI for MCP servers and native Caplets adapters.",
5
5
  "keywords": [
6
6
  "caplets",
@@ -34,14 +34,14 @@
34
34
  },
35
35
  "dependencies": {
36
36
  "@modelcontextprotocol/sdk": "^1.29.0",
37
- "@caplets/core": "0.18.0"
37
+ "@caplets/core": "0.18.2"
38
38
  },
39
39
  "devDependencies": {
40
- "@types/node": "^25.9.0",
41
- "@typescript/native-preview": "7.0.0-dev.20260518.1",
42
- "rolldown": "^1.0.1",
40
+ "@types/node": "^25.9.1",
41
+ "@typescript/native-preview": "7.0.0-dev.20260519.1",
42
+ "rolldown": "^1.0.2",
43
43
  "typescript": "^6.0.3",
44
- "vitest": "^4.1.6"
44
+ "vitest": "^4.1.7"
45
45
  },
46
46
  "engines": {
47
47
  "node": ">=22"