@ethisyscore/extension-runtime 1.70.0 → 1.71.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -468,6 +468,100 @@ function defaultConnectionFactory(port) {
468
468
  };
469
469
  }
470
470
 
471
+ // src/bridge/mcp-error.ts
472
+ var MCP_ERROR_CODES = [
473
+ "unauthorized",
474
+ "forbidden",
475
+ "not_found",
476
+ "invalid_request",
477
+ "conflict",
478
+ "rate_limited",
479
+ "timeout",
480
+ "unavailable",
481
+ "internal"
482
+ ];
483
+ function isMcpErrorCode(value) {
484
+ return typeof value === "string" && MCP_ERROR_CODES.includes(value);
485
+ }
486
+ var RETRYABLE = ["rate_limited", "timeout", "unavailable"];
487
+ function isRetryableMcpErrorCode(code) {
488
+ return RETRYABLE.includes(code);
489
+ }
490
+ var McpToolError = class extends Error {
491
+ /** Machine-readable classification. `internal` when the host sent none. */
492
+ code;
493
+ /**
494
+ * Marks the instance for {@link isMcpToolError}. A structural marker rather than a prototype
495
+ * check because the error can be constructed in one bundle and inspected in another, where
496
+ * `instanceof` compares two different class objects and answers false.
497
+ */
498
+ isMcpToolError = true;
499
+ constructor(message, code = "internal") {
500
+ super(message);
501
+ this.name = "McpHostError";
502
+ this.code = code;
503
+ }
504
+ /** True when this failure is worth retrying unchanged. */
505
+ get retryable() {
506
+ return isRetryableMcpErrorCode(this.code);
507
+ }
508
+ };
509
+ function isMcpToolError(value) {
510
+ return value instanceof McpToolError || value !== null && typeof value === "object" && value.isMcpToolError === true && isMcpErrorCode(value.code);
511
+ }
512
+ function mcpErrorCodeFromHttpStatus(status) {
513
+ switch (status) {
514
+ case 401:
515
+ return "unauthorized";
516
+ case 403:
517
+ return "forbidden";
518
+ case 404:
519
+ return "not_found";
520
+ case 400:
521
+ case 422:
522
+ return "invalid_request";
523
+ case 409:
524
+ case 412:
525
+ return "conflict";
526
+ case 429:
527
+ return "rate_limited";
528
+ case 408:
529
+ case 504:
530
+ return "timeout";
531
+ case 502:
532
+ case 503:
533
+ return "unavailable";
534
+ default:
535
+ return "internal";
536
+ }
537
+ }
538
+ function classifyHostResponse(response) {
539
+ if (response.ok) {
540
+ return void 0;
541
+ }
542
+ if (isMcpErrorCode(response.mcpErrorCode)) {
543
+ return response.mcpErrorCode;
544
+ }
545
+ return typeof response.status === "number" ? mcpErrorCodeFromHttpStatus(response.status) : "internal";
546
+ }
547
+ function classifyHostError(err) {
548
+ if (err === null || typeof err !== "object") {
549
+ return "internal";
550
+ }
551
+ const candidate = err;
552
+ if (isMcpErrorCode(candidate.mcpErrorCode)) {
553
+ return candidate.mcpErrorCode;
554
+ }
555
+ const status = typeof candidate.status === "number" ? candidate.status : typeof candidate.statusCode === "number" ? candidate.statusCode : void 0;
556
+ if (status !== void 0) {
557
+ return mcpErrorCodeFromHttpStatus(status);
558
+ }
559
+ if (candidate.name === "AbortError" || candidate.name === "TimeoutError") {
560
+ return "timeout";
561
+ }
562
+ return "internal";
563
+ }
564
+
471
565
  // src/plugin/createPortMcpTransport.ts
472
566
  var WIRE_INVOKE_TOOL_REQUEST = "ethisys:mcp:invokeTool";
473
567
  var WIRE_INVOKE_TOOL_RESULT = "ethisys:mcp:invokeTool:result";
@@ -505,11 +599,10 @@ function createPortMcpTransport(port, options = {}) {
505
599
  if (reply.ok === true) {
506
600
  resolver.resolve(reply.data);
507
601
  } else {
508
- const error = new Error(
509
- typeof reply.error === "string" ? reply.error : "Unknown host error"
510
- );
511
- error.name = "McpHostError";
512
- resolver.reject(error);
602
+ resolver.reject(new McpToolError(
603
+ typeof reply.error === "string" ? reply.error : "Unknown host error",
604
+ isMcpErrorCode(reply.code) ? reply.code : "internal"
605
+ ));
513
606
  }
514
607
  }
515
608
  shim.addEventListener("message", onMessage);
@@ -812,13 +905,21 @@ exports.BridgeClientContext = BridgeClientContext;
812
905
  exports.ClientPushContext = ClientPushContext;
813
906
  exports.ExtensionRuntimeProvider = ExtensionRuntimeProvider;
814
907
  exports.HostIdentityContext = HostIdentityContext;
908
+ exports.MCP_ERROR_CODES = MCP_ERROR_CODES;
909
+ exports.McpToolError = McpToolError;
815
910
  exports.PluginRealtimeContext = PluginRealtimeContext;
911
+ exports.classifyHostError = classifyHostError;
912
+ exports.classifyHostResponse = classifyHostResponse;
816
913
  exports.createPortBridgeClient = createPortBridgeClient;
817
914
  exports.createPortMcpTransport = createPortMcpTransport;
818
915
  exports.createRemoteRoot = createRemoteRoot;
819
916
  exports.decodeJwtPayload = decodeJwtPayload;
820
917
  exports.defineDeclarativePlugin = defineDeclarativePlugin;
821
918
  exports.defineEthisysPlugin = defineEthisysPlugin;
919
+ exports.isMcpErrorCode = isMcpErrorCode;
920
+ exports.isMcpToolError = isMcpToolError;
921
+ exports.isRetryableMcpErrorCode = isRetryableMcpErrorCode;
922
+ exports.mcpErrorCodeFromHttpStatus = mcpErrorCodeFromHttpStatus;
822
923
  exports.unwrapItems = unwrapItems;
823
924
  exports.useAuth = useAuth;
824
925
  exports.useBridgeClient = useBridgeClient;