diff --git a/src/bun.js/api/server.zig b/src/bun.js/api/server.zig index a5b531022b..1aa556d9d6 100644 --- a/src/bun.js/api/server.zig +++ b/src/bun.js/api/server.zig @@ -1403,16 +1403,42 @@ fn NewRequestContext(comptime ssl_enabled: bool, comptime debug_mode: bool, comp return JSValue.jsUndefined(); } + fn renderMissingInvalidResponse(ctx: *RequestContext, value: JSC.JSValue) void { + var class_name = value.getClassInfoName() orelse bun.String.empty; + defer class_name.deref(); + const globalThis: *JSC.JSGlobalObject = ctx.server.globalThis; + + Output.enableBuffering(); + var writer = Output.errorWriter(); + + if (class_name.eqlComptime("Response")) { + Output.errGeneric("Expected a native Response object, but received a polyfilled Response object. Bun.serve() only supports native Response objects.", .{}); + } else if (!value.isEmpty() and !globalThis.hasException()) { + var formatter = JSC.ConsoleObject.Formatter{ + .globalThis = globalThis, + .quote_strings = true, + }; + Output.errGeneric("Expected a Response object, but received '{}'", .{value.toFmt(formatter.globalThis, &formatter)}); + } else { + Output.errGeneric("Expected a Response object", .{}); + } + + Output.flush(); + if (!globalThis.hasException()) { + JSC.ConsoleObject.writeTrace(@TypeOf(&writer), &writer, globalThis); + } + Output.flush(); + ctx.renderMissing(); + } + fn handleResolve(ctx: *RequestContext, value: JSC.JSValue) void { if (value.isEmptyOrUndefinedOrNull() or !value.isCell()) { - ctx.renderMissing(); + ctx.renderMissingInvalidResponse(value); return; } const response = value.as(JSC.WebCore.Response) orelse { - Output.prettyErrorln("Expected a Response object", .{}); - Output.flush(); - ctx.renderMissing(); + ctx.renderMissingInvalidResponse(value); return; }; ctx.response_jsvalue = value; @@ -2558,7 +2584,7 @@ fn NewRequestContext(comptime ssl_enabled: bool, comptime debug_mode: bool, comp } if (response_value.isEmptyOrUndefinedOrNull()) { - ctx.renderMissing(); + ctx.renderMissingInvalidResponse(response_value); return; } @@ -2611,11 +2637,11 @@ fn NewRequestContext(comptime ssl_enabled: bool, comptime debug_mode: bool, comp } if (fulfilled_value.isEmptyOrUndefinedOrNull()) { - ctx.renderMissing(); + ctx.renderMissingInvalidResponse(fulfilled_value); return; } var response = fulfilled_value.as(JSC.WebCore.Response) orelse { - ctx.renderMissing(); + ctx.renderMissingInvalidResponse(fulfilled_value); return; }; diff --git a/src/bun.js/bindings/bindings.zig b/src/bun.js/bindings/bindings.zig index 648789dd92..19a6a28150 100644 --- a/src/bun.js/bindings/bindings.zig +++ b/src/bun.js/bindings/bindings.zig @@ -5600,16 +5600,12 @@ pub const JSValue = enum(JSValueReprInt) { extern fn JSC__JSValue__getClassInfoName(value: JSValue, out: *bun.String) bool; - /// Returned memory is read-only memory of the s_info assigned to a JSCell - pub fn getClassInfoName(this: JSValue) ?[]const u8 { - var out: bun.String = undefined; + /// For native C++ classes extending JSCell, this retrieves s_info's name + pub fn getClassInfoName(this: JSValue) ?bun.String { + if (!this.isObject()) return null; + var out: bun.String = bun.String.empty; if (!JSC__JSValue__getClassInfoName(this, &out)) return null; - // we assume the class name is ASCII text - const data = out.latin1(); - if (bun.Environment.allow_assert) { - bun.assert(bun.strings.isAllASCII(data)); - } - return data; + return out; } }; diff --git a/src/js_ast.zig b/src/js_ast.zig index 5623b04435..974fd5084b 100644 --- a/src/js_ast.zig +++ b/src/js_ast.zig @@ -7422,12 +7422,15 @@ pub const Macro = struct { .String => this.coerce(value, .String), .Promise => this.coerce(value, .Promise), else => brk: { + var name = value.getClassInfoName() orelse bun.String.init("unknown"); + defer name.deref(); + this.log.addErrorFmt( this.source, this.caller.loc, this.allocator, - "cannot coerce {s} ({s}) to Bun's AST. Please return a simpler type", - .{ value.getClassInfoName() orelse "unknown", @tagName(value.jsType()) }, + "cannot coerce {} ({s}) to Bun's AST. Please return a simpler type", + .{ name, @tagName(value.jsType()) }, ) catch unreachable; break :brk error.MacroFailed; },