@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.
@@ -287,6 +287,100 @@ function createInputEventCoalescer(sink, options = {}) {
287
287
  };
288
288
  }
289
289
 
290
+ // src/bridge/mcp-error.ts
291
+ var MCP_ERROR_CODES = [
292
+ "unauthorized",
293
+ "forbidden",
294
+ "not_found",
295
+ "invalid_request",
296
+ "conflict",
297
+ "rate_limited",
298
+ "timeout",
299
+ "unavailable",
300
+ "internal"
301
+ ];
302
+ function isMcpErrorCode(value) {
303
+ return typeof value === "string" && MCP_ERROR_CODES.includes(value);
304
+ }
305
+ var RETRYABLE = ["rate_limited", "timeout", "unavailable"];
306
+ function isRetryableMcpErrorCode(code) {
307
+ return RETRYABLE.includes(code);
308
+ }
309
+ var McpToolError = class extends Error {
310
+ /** Machine-readable classification. `internal` when the host sent none. */
311
+ code;
312
+ /**
313
+ * Marks the instance for {@link isMcpToolError}. A structural marker rather than a prototype
314
+ * check because the error can be constructed in one bundle and inspected in another, where
315
+ * `instanceof` compares two different class objects and answers false.
316
+ */
317
+ isMcpToolError = true;
318
+ constructor(message, code = "internal") {
319
+ super(message);
320
+ this.name = "McpHostError";
321
+ this.code = code;
322
+ }
323
+ /** True when this failure is worth retrying unchanged. */
324
+ get retryable() {
325
+ return isRetryableMcpErrorCode(this.code);
326
+ }
327
+ };
328
+ function isMcpToolError(value) {
329
+ return value instanceof McpToolError || value !== null && typeof value === "object" && value.isMcpToolError === true && isMcpErrorCode(value.code);
330
+ }
331
+ function mcpErrorCodeFromHttpStatus(status) {
332
+ switch (status) {
333
+ case 401:
334
+ return "unauthorized";
335
+ case 403:
336
+ return "forbidden";
337
+ case 404:
338
+ return "not_found";
339
+ case 400:
340
+ case 422:
341
+ return "invalid_request";
342
+ case 409:
343
+ case 412:
344
+ return "conflict";
345
+ case 429:
346
+ return "rate_limited";
347
+ case 408:
348
+ case 504:
349
+ return "timeout";
350
+ case 502:
351
+ case 503:
352
+ return "unavailable";
353
+ default:
354
+ return "internal";
355
+ }
356
+ }
357
+ function classifyHostResponse(response) {
358
+ if (response.ok) {
359
+ return void 0;
360
+ }
361
+ if (isMcpErrorCode(response.mcpErrorCode)) {
362
+ return response.mcpErrorCode;
363
+ }
364
+ return typeof response.status === "number" ? mcpErrorCodeFromHttpStatus(response.status) : "internal";
365
+ }
366
+ function classifyHostError(err) {
367
+ if (err === null || typeof err !== "object") {
368
+ return "internal";
369
+ }
370
+ const candidate = err;
371
+ if (isMcpErrorCode(candidate.mcpErrorCode)) {
372
+ return candidate.mcpErrorCode;
373
+ }
374
+ const status = typeof candidate.status === "number" ? candidate.status : typeof candidate.statusCode === "number" ? candidate.statusCode : void 0;
375
+ if (status !== void 0) {
376
+ return mcpErrorCodeFromHttpStatus(status);
377
+ }
378
+ if (candidate.name === "AbortError" || candidate.name === "TimeoutError") {
379
+ return "timeout";
380
+ }
381
+ return "internal";
382
+ }
383
+
290
384
  // src/host/version-skew.ts
291
385
  var EXTENSION_VERSION_HEADER = "x-extension-version";
292
386
  var EXTENSION_ACTIVE_VERSION_HEADER = "x-extension-active-version";
@@ -713,7 +807,11 @@ var WorkerRemoteDomTransport = class {
713
807
  type: "ethisys:mcp:invokeTool:result",
714
808
  ok: result.ok,
715
809
  data: result.data,
716
- error: result.error
810
+ error: result.error,
811
+ // A client that REPORTS failure rather than throwing lands here, which is the common
812
+ // shape for anything wrapping HTTP. Classifying only the thrown path left these
813
+ // arriving as `internal`.
814
+ code: classifyHostResponse(result)
717
815
  });
718
816
  } catch (err) {
719
817
  this.replyError(message.id, "ethisys:mcp:invokeTool:result", err);
@@ -743,7 +841,11 @@ var WorkerRemoteDomTransport = class {
743
841
  type: "ethisys:mcp:getResource:result",
744
842
  ok: result.ok,
745
843
  data: result.data,
746
- error: result.error
844
+ error: result.error,
845
+ // A client that REPORTS failure rather than throwing lands here, which is the common
846
+ // shape for anything wrapping HTTP. Classifying only the thrown path left these
847
+ // arriving as `internal`.
848
+ code: classifyHostResponse(result)
747
849
  });
748
850
  } catch (err) {
749
851
  this.replyError(message.id, "ethisys:mcp:getResource:result", err);
@@ -774,7 +876,11 @@ var WorkerRemoteDomTransport = class {
774
876
  type: "ethisys:mcp:uploadDocument:result",
775
877
  ok: result.ok,
776
878
  data: result.data,
777
- error: result.error
879
+ error: result.error,
880
+ // A client that REPORTS failure rather than throwing lands here, which is the common
881
+ // shape for anything wrapping HTTP. Classifying only the thrown path left these
882
+ // arriving as `internal`.
883
+ code: classifyHostResponse(result)
778
884
  });
779
885
  } catch (err) {
780
886
  this.replyError(message.id, "ethisys:mcp:uploadDocument:result", err);
@@ -782,7 +888,7 @@ var WorkerRemoteDomTransport = class {
782
888
  }
783
889
  replyError(id, type, err) {
784
890
  const message = err instanceof Error ? err.message : "MCP request failed";
785
- this.safePostMessage({ id, type, ok: false, error: message });
891
+ this.safePostMessage({ id, type, ok: false, error: message, code: classifyHostError(err) });
786
892
  }
787
893
  };
788
894
  var IFRAME_BRIDGE_PROTOCOL = "ethisys.iframe.bridge.v1";
@@ -988,7 +1094,11 @@ var IframeBridgeTransport = class {
988
1094
  type: "ethisys:mcp:invokeTool:result",
989
1095
  ok: result.ok,
990
1096
  data: result.data,
991
- error: result.error
1097
+ error: result.error,
1098
+ // A client that REPORTS failure rather than throwing lands here, which is the common shape
1099
+ // for anything wrapping HTTP. Classifying only the thrown path left these arriving as
1100
+ // `internal`.
1101
+ code: classifyHostResponse(result)
992
1102
  });
993
1103
  } catch (err) {
994
1104
  this.replyError(message.id, "ethisys:mcp:invokeTool:result", err);
@@ -1042,7 +1152,11 @@ var IframeBridgeTransport = class {
1042
1152
  type: "ethisys:mcp:getResource:result",
1043
1153
  ok: result.ok,
1044
1154
  data: result.data,
1045
- error: result.error
1155
+ error: result.error,
1156
+ // A client that REPORTS failure rather than throwing lands here, which is the common shape
1157
+ // for anything wrapping HTTP. Classifying only the thrown path left these arriving as
1158
+ // `internal`.
1159
+ code: classifyHostResponse(result)
1046
1160
  });
1047
1161
  } catch (err) {
1048
1162
  this.replyError(message.id, "ethisys:mcp:getResource:result", err);
@@ -1050,7 +1164,7 @@ var IframeBridgeTransport = class {
1050
1164
  }
1051
1165
  replyError(id, type, err) {
1052
1166
  const message = err instanceof Error ? err.message : "MCP request failed";
1053
- this.safePostMessage({ id, type, ok: false, error: message });
1167
+ this.safePostMessage({ id, type, ok: false, error: message, code: classifyHostError(err) });
1054
1168
  }
1055
1169
  /** Best-effort reply over the host port; tolerates post-dispose races. */
1056
1170
  safePostMessage(message) {
@@ -1084,14 +1198,22 @@ exports.EXTENSION_ACTIVE_VERSION_HEADER = EXTENSION_ACTIVE_VERSION_HEADER;
1084
1198
  exports.EXTENSION_VERSION_HEADER = EXTENSION_VERSION_HEADER;
1085
1199
  exports.IFRAME_BRIDGE_PROTOCOL = IFRAME_BRIDGE_PROTOCOL;
1086
1200
  exports.IframeBridgeTransport = IframeBridgeTransport;
1201
+ exports.MCP_ERROR_CODES = MCP_ERROR_CODES;
1202
+ exports.McpToolError = McpToolError;
1087
1203
  exports.SemanticComponentRegistry = SemanticComponentRegistry;
1088
1204
  exports.VERSION_MISMATCH_REASON = VERSION_MISMATCH_REASON;
1089
1205
  exports.WORKER_TRANSPORT_PROTOCOL = WORKER_TRANSPORT_PROTOCOL;
1090
1206
  exports.WorkerRemoteDomTransport = WorkerRemoteDomTransport;
1207
+ exports.classifyHostError = classifyHostError;
1208
+ exports.classifyHostResponse = classifyHostResponse;
1091
1209
  exports.createInputEventCoalescer = createInputEventCoalescer;
1092
1210
  exports.createOffscreenCanvasTransfer = createOffscreenCanvasTransfer;
1093
1211
  exports.detectVersionSkew = detectVersionSkew;
1094
1212
  exports.evaluate = evaluate;
1095
1213
  exports.interpret = interpret;
1214
+ exports.isMcpErrorCode = isMcpErrorCode;
1215
+ exports.isMcpToolError = isMcpToolError;
1216
+ exports.isRetryableMcpErrorCode = isRetryableMcpErrorCode;
1217
+ exports.mcpErrorCodeFromHttpStatus = mcpErrorCodeFromHttpStatus;
1096
1218
  //# sourceMappingURL=index.cjs.map
1097
1219
  //# sourceMappingURL=index.cjs.map