|
7 | 7 | #include "ser.h" |
8 | 8 | #include "setup.h" |
9 | 9 |
|
| 10 | +#include <workerd/jsg/exception-metadata.capnp.h> |
| 11 | + |
10 | 12 | #include <openssl/rand.h> |
11 | 13 |
|
| 14 | +#include <capnp/message.h> |
| 15 | +#include <capnp/serialize.h> |
12 | 16 | #include <kj/debug.h> |
13 | 17 |
|
14 | 18 | #include <cstdlib> |
@@ -454,6 +458,48 @@ void addExceptionDetail(Lock& js, kj::Exception& exception, v8::Local<v8::Value> |
454 | 458 | } |
455 | 459 | } |
456 | 460 |
|
| 461 | +void addJsExceptionMetadata(Lock& js, kj::Exception& exception, v8::Local<v8::Value> handle) { |
| 462 | + // Extract JavaScript error type and stack trace |
| 463 | + if (!handle->IsObject()) { |
| 464 | + return; // Not an error object, nothing to extract |
| 465 | + } |
| 466 | + |
| 467 | + auto errorObj = jsg::JsObject(handle.As<v8::Object>()); |
| 468 | + |
| 469 | + // Build Cap'n Proto message |
| 470 | + capnp::MallocMessageBuilder message; |
| 471 | + auto metadata = message.initRoot<JsExceptionMetadata>(); |
| 472 | + |
| 473 | + // Limit for user-controlled fields (4KB) |
| 474 | + constexpr size_t MAX_FIELD_SIZE = 4096; |
| 475 | + |
| 476 | + // Extract error name (e.g., "Error", "TypeError", "RangeError") |
| 477 | + auto nameProp = errorObj.get(js, "name"_kj); |
| 478 | + if (nameProp.isString()) { |
| 479 | + auto errorType = nameProp.toString(js); |
| 480 | + // Truncate to 4KB if needed |
| 481 | + if (errorType.size() > MAX_FIELD_SIZE) { |
| 482 | + errorType = kj::str(errorType.slice(0, MAX_FIELD_SIZE)); |
| 483 | + } |
| 484 | + metadata.setErrorType(errorType); |
| 485 | + } |
| 486 | + |
| 487 | + // Extract stack trace string |
| 488 | + auto stackProp = errorObj.get(js, "stack"_kj); |
| 489 | + if (stackProp.isString()) { |
| 490 | + auto stackTrace = stackProp.toString(js); |
| 491 | + // Truncate to 4KB if needed |
| 492 | + if (stackTrace.size() > MAX_FIELD_SIZE) { |
| 493 | + stackTrace = kj::str(stackTrace.slice(0, MAX_FIELD_SIZE)); |
| 494 | + } |
| 495 | + metadata.setStackTrace(stackTrace); |
| 496 | + } |
| 497 | + |
| 498 | + // Serialize to bytes using Cap'n Proto |
| 499 | + auto words = capnp::messageToFlatArray(message); |
| 500 | + exception.setDetail(JS_EXCEPTION_METADATA_DETAIL_ID, kj::heapArray(words.asBytes())); |
| 501 | +} |
| 502 | + |
457 | 503 | static kj::String typeErrorMessage(TypeErrorContext c, const char* expectedType) { |
458 | 504 | kj::String type; |
459 | 505 |
|
|
0 commit comments