Merge pull request #1495 from lightpanda-io/fast_getter
Some checks failed
e2e-test / zig build release (push) Has been cancelled
e2e-test / demo-scripts (push) Has been cancelled
e2e-test / cdp-and-hyperfine-bench (push) Has been cancelled
e2e-test / perf-fmt (push) Has been cancelled
e2e-test / browser fetch (push) Has been cancelled
zig-test / zig test using v8 in debug mode (push) Has been cancelled
zig-test / zig test (push) Has been cancelled
zig-test / perf-fmt (push) Has been cancelled
nightly build / build-linux-x86_64 (push) Has been cancelled
nightly build / build-linux-aarch64 (push) Has been cancelled
nightly build / build-macos-aarch64 (push) Has been cancelled
nightly build / build-macos-x86_64 (push) Has been cancelled
wpt / web platform tests json output (push) Has been cancelled
wpt / perf-fmt (push) Has been cancelled
e2e-integration-test / zig build release (push) Has been cancelled
e2e-integration-test / demo-integration-scripts (push) Has been cancelled

Adds Document.prerendering
This commit is contained in:
Karl Seguin
2026-02-08 21:45:06 +08:00
committed by GitHub
11 changed files with 132 additions and 76 deletions

View File

@@ -280,6 +280,7 @@ fn countExternalReferences() comptime_int {
// +1 for the illegal constructor callback // +1 for the illegal constructor callback
var count: comptime_int = 1; var count: comptime_int = 1;
var has_non_template_property: bool = false;
inline for (JsApis) |JsApi| { inline for (JsApis) |JsApi| {
// Constructor (only if explicit) // Constructor (only if explicit)
@@ -302,6 +303,10 @@ fn countExternalReferences() comptime_int {
if (value.setter != null) count += 1; // setter if (value.setter != null) count += 1; // setter
} else if (T == bridge.Function) { } else if (T == bridge.Function) {
count += 1; count += 1;
} else if (T == bridge.Property) {
if (value.template == false) {
has_non_template_property = true;
}
} else if (T == bridge.Iterator) { } else if (T == bridge.Iterator) {
count += 1; count += 1;
} else if (T == bridge.Indexed) { } else if (T == bridge.Indexed) {
@@ -314,6 +319,10 @@ fn countExternalReferences() comptime_int {
} }
} }
if (has_non_template_property) {
count += 1;
}
// In debug mode, add unknown property callbacks for types without NamedIndexed // In debug mode, add unknown property callbacks for types without NamedIndexed
if (comptime IS_DEBUG) { if (comptime IS_DEBUG) {
inline for (JsApis) |JsApi| { inline for (JsApis) |JsApi| {
@@ -333,6 +342,8 @@ fn collectExternalReferences() [countExternalReferences()]isize {
references[idx] = @bitCast(@intFromPtr(&illegalConstructorCallback)); references[idx] = @bitCast(@intFromPtr(&illegalConstructorCallback));
idx += 1; idx += 1;
var has_non_template_property = false;
inline for (JsApis) |JsApi| { inline for (JsApis) |JsApi| {
if (@hasDecl(JsApi, "constructor")) { if (@hasDecl(JsApi, "constructor")) {
references[idx] = @bitCast(@intFromPtr(JsApi.constructor.func)); references[idx] = @bitCast(@intFromPtr(JsApi.constructor.func));
@@ -358,6 +369,10 @@ fn collectExternalReferences() [countExternalReferences()]isize {
} else if (T == bridge.Function) { } else if (T == bridge.Function) {
references[idx] = @bitCast(@intFromPtr(value.func)); references[idx] = @bitCast(@intFromPtr(value.func));
idx += 1; idx += 1;
} else if (T == bridge.Property) {
if (value.template == false) {
has_non_template_property = true;
}
} else if (T == bridge.Iterator) { } else if (T == bridge.Iterator) {
references[idx] = @bitCast(@intFromPtr(value.func)); references[idx] = @bitCast(@intFromPtr(value.func));
idx += 1; idx += 1;
@@ -379,6 +394,11 @@ fn collectExternalReferences() [countExternalReferences()]isize {
} }
} }
if (has_non_template_property) {
references[idx] = @bitCast(@intFromPtr(&bridge.Property.getter));
idx += 1;
}
// In debug mode, collect unknown property callbacks for types without NamedIndexed // In debug mode, collect unknown property callbacks for types without NamedIndexed
if (comptime IS_DEBUG) { if (comptime IS_DEBUG) {
inline for (JsApis) |JsApi| { inline for (JsApis) |JsApi| {
@@ -497,17 +517,24 @@ fn attachClass(comptime JsApi: type, isolate: *v8.Isolate, template: *v8.Functio
v8.v8__Template__Set(@ptrCast(target), js_name, @ptrCast(function_template), v8.None); v8.v8__Template__Set(@ptrCast(target), js_name, @ptrCast(function_template), v8.None);
}, },
bridge.Property => { bridge.Property => {
// simpleZigValueToJs now returns raw handle directly const js_value = switch (value.value) {
const js_value = switch (value) { inline .bool, .int => |v| js.simpleZigValueToJs(.{ .handle = isolate }, v, true, false),
.int => |v| js.simpleZigValueToJs(.{ .handle = isolate }, v, true, false),
}; };
const js_name = v8.v8__String__NewFromUtf8(isolate, name.ptr, v8.kNormal, @intCast(name.len)); const js_name = v8.v8__String__NewFromUtf8(isolate, name.ptr, v8.kNormal, @intCast(name.len));
// apply it both to the type itself
v8.v8__Template__Set(@ptrCast(template), js_name, js_value, v8.ReadOnly + v8.DontDelete);
// and to instances of the type if (value.template == false) {
v8.v8__Template__Set(@ptrCast(target), js_name, js_value, v8.ReadOnly + v8.DontDelete); // not defined on the template, only on the instance. This
// is like an Accessor, but because the value is known at
// compile time, we skip _a lot_ of code and quickly return
// the hard-coded value
const getter_callback = @constCast(v8.v8__FunctionTemplate__New__DEFAULT3(isolate, bridge.Property.getter, js_value));
v8.v8__ObjectTemplate__SetAccessorProperty__DEFAULT(target, js_name, getter_callback);
} else {
// apply it both to the type itself
v8.v8__Template__Set(@ptrCast(template), js_name, js_value, v8.ReadOnly + v8.DontDelete);
// and to instances of the type
v8.v8__Template__Set(@ptrCast(target), js_name, js_value, v8.ReadOnly + v8.DontDelete);
}
}, },
bridge.Constructor => {}, // already handled in generateConstructor bridge.Constructor => {}, // already handled in generateConstructor
else => {}, else => {},

View File

@@ -62,12 +62,13 @@ pub fn Builder(comptime T: type) type {
return Callable.init(T, func, opts); return Callable.init(T, func, opts);
} }
pub fn property(value: anytype) Property { pub fn property(value: anytype, opts: Property.Opts) Property {
switch (@typeInfo(@TypeOf(value))) { // If you add strings to this, they might need to be internalized!
.comptime_int, .int => return .{ .int = value }, return switch (@typeInfo(@TypeOf(value))) {
else => {}, .bool => Property.init(.{ .bool = value }, opts),
} .comptime_int, .int => Property.init(.{ .int = value }, opts),
@compileError("Property for " ++ @typeName(@TypeOf(value)) ++ " hasn't been defined yet"); else => @compileError("Property for " ++ @typeName(@TypeOf(value)) ++ " hasn't been defined yet"),
};
} }
const PrototypeChainEntry = @import("TaggedOpaque.zig").PrototypeChainEntry; const PrototypeChainEntry = @import("TaggedOpaque.zig").PrototypeChainEntry;
@@ -398,8 +399,33 @@ pub const Callable = struct {
} }
}; };
pub const Property = union(enum) { pub const Property = struct {
int: i64, value: Value,
template: bool,
// If you add strings to this, they might need to be internalized!
const Value = union(enum) {
int: i64,
bool: bool,
};
const Opts = struct {
template: bool,
};
fn init(value: Value, opts: Opts) Property {
return .{
.value = value,
.template = opts.template,
};
}
pub fn getter(handle: ?*const v8.FunctionCallbackInfo) callconv(.c) void {
const value = v8.v8__FunctionCallbackInfo__Data(handle.?);
var rv: v8.ReturnValue = undefined;
v8.v8__FunctionCallbackInfo__GetReturnValue(handle.?, &rv);
v8.v8__ReturnValue__Set(rv, value);
}
}; };
const Finalizer = struct { const Finalizer = struct {

View File

@@ -15,6 +15,8 @@
testing.expectEqual(window, document.defaultView); testing.expectEqual(window, document.defaultView);
testing.expectEqual(false, document.hidden); testing.expectEqual(false, document.hidden);
testing.expectEqual("visible", document.visibilityState); testing.expectEqual("visible", document.visibilityState);
testing.expectEqual(false, document.prerendering);
testing.expectEqual(undefined, Document.prerendering);
</script> </script>
<script id=headAndbody> <script id=headAndbody>

View File

@@ -1004,6 +1004,7 @@ pub const JsApi = struct {
pub const adoptedStyleSheets = bridge.accessor(Document.getAdoptedStyleSheets, Document.setAdoptedStyleSheets, .{}); pub const adoptedStyleSheets = bridge.accessor(Document.getAdoptedStyleSheets, Document.setAdoptedStyleSheets, .{});
pub const hidden = bridge.accessor(Document.getHidden, null, .{}); pub const hidden = bridge.accessor(Document.getHidden, null, .{});
pub const visibilityState = bridge.accessor(Document.getVisibilityState, null, .{}); pub const visibilityState = bridge.accessor(Document.getVisibilityState, null, .{});
pub const prerendering = bridge.property(false, .{ .template = false });
pub const defaultView = bridge.accessor(struct { pub const defaultView = bridge.accessor(struct {
fn defaultView(_: *const Document, page: *Page) *@import("Window.zig") { fn defaultView(_: *const Document, page: *Page) *@import("Window.zig") {

View File

@@ -410,10 +410,10 @@ pub const JsApi = struct {
pub const cancelBubble = bridge.accessor(Event.getCancelBubble, Event.setCancelBubble, .{}); pub const cancelBubble = bridge.accessor(Event.getCancelBubble, Event.setCancelBubble, .{});
// Event phase constants // Event phase constants
pub const NONE = bridge.property(@intFromEnum(EventPhase.none)); pub const NONE = bridge.property(@intFromEnum(EventPhase.none), .{ .template = true });
pub const CAPTURING_PHASE = bridge.property(@intFromEnum(EventPhase.capturing_phase)); pub const CAPTURING_PHASE = bridge.property(@intFromEnum(EventPhase.capturing_phase), .{ .template = true });
pub const AT_TARGET = bridge.property(@intFromEnum(EventPhase.at_target)); pub const AT_TARGET = bridge.property(@intFromEnum(EventPhase.at_target), .{ .template = true });
pub const BUBBLING_PHASE = bridge.property(@intFromEnum(EventPhase.bubbling_phase)); pub const BUBBLING_PHASE = bridge.property(@intFromEnum(EventPhase.bubbling_phase), .{ .template = true });
}; };
// tested in event_target // tested in event_target

View File

@@ -874,25 +874,25 @@ pub const JsApi = struct {
pub var class_id: bridge.ClassId = undefined; pub var class_id: bridge.ClassId = undefined;
}; };
pub const ELEMENT_NODE = bridge.property(1); pub const ELEMENT_NODE = bridge.property(1, .{ .template = true });
pub const ATTRIBUTE_NODE = bridge.property(2); pub const ATTRIBUTE_NODE = bridge.property(2, .{ .template = true });
pub const TEXT_NODE = bridge.property(3); pub const TEXT_NODE = bridge.property(3, .{ .template = true });
pub const CDATA_SECTION_NODE = bridge.property(4); pub const CDATA_SECTION_NODE = bridge.property(4, .{ .template = true });
pub const ENTITY_REFERENCE_NODE = bridge.property(5); pub const ENTITY_REFERENCE_NODE = bridge.property(5, .{ .template = true });
pub const ENTITY_NODE = bridge.property(6); pub const ENTITY_NODE = bridge.property(6, .{ .template = true });
pub const PROCESSING_INSTRUCTION_NODE = bridge.property(7); pub const PROCESSING_INSTRUCTION_NODE = bridge.property(7, .{ .template = true });
pub const COMMENT_NODE = bridge.property(8); pub const COMMENT_NODE = bridge.property(8, .{ .template = true });
pub const DOCUMENT_NODE = bridge.property(9); pub const DOCUMENT_NODE = bridge.property(9, .{ .template = true });
pub const DOCUMENT_TYPE_NODE = bridge.property(10); pub const DOCUMENT_TYPE_NODE = bridge.property(10, .{ .template = true });
pub const DOCUMENT_FRAGMENT_NODE = bridge.property(11); pub const DOCUMENT_FRAGMENT_NODE = bridge.property(11, .{ .template = true });
pub const NOTATION_NODE = bridge.property(12); pub const NOTATION_NODE = bridge.property(12, .{ .template = true });
pub const DOCUMENT_POSITION_DISCONNECTED = bridge.property(0x01); pub const DOCUMENT_POSITION_DISCONNECTED = bridge.property(0x01, .{ .template = true });
pub const DOCUMENT_POSITION_PRECEDING = bridge.property(0x02); pub const DOCUMENT_POSITION_PRECEDING = bridge.property(0x02, .{ .template = true });
pub const DOCUMENT_POSITION_FOLLOWING = bridge.property(0x04); pub const DOCUMENT_POSITION_FOLLOWING = bridge.property(0x04, .{ .template = true });
pub const DOCUMENT_POSITION_CONTAINS = bridge.property(0x08); pub const DOCUMENT_POSITION_CONTAINS = bridge.property(0x08, .{ .template = true });
pub const DOCUMENT_POSITION_CONTAINED_BY = bridge.property(0x10); pub const DOCUMENT_POSITION_CONTAINED_BY = bridge.property(0x10, .{ .template = true });
pub const DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC = bridge.property(0x20); pub const DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC = bridge.property(0x20, .{ .template = true });
pub const nodeName = bridge.accessor(struct { pub const nodeName = bridge.accessor(struct {
fn wrap(self: *const Node, page: *Page) []const u8 { fn wrap(self: *const Node, page: *Page) []const u8 {

View File

@@ -90,21 +90,21 @@ pub const JsApi = struct {
pub const empty_with_no_proto = true; pub const empty_with_no_proto = true;
}; };
pub const FILTER_ACCEPT = bridge.property(NodeFilter.FILTER_ACCEPT); pub const FILTER_ACCEPT = bridge.property(NodeFilter.FILTER_ACCEPT, .{ .template = true });
pub const FILTER_REJECT = bridge.property(NodeFilter.FILTER_REJECT); pub const FILTER_REJECT = bridge.property(NodeFilter.FILTER_REJECT, .{ .template = true });
pub const FILTER_SKIP = bridge.property(NodeFilter.FILTER_SKIP); pub const FILTER_SKIP = bridge.property(NodeFilter.FILTER_SKIP, .{ .template = true });
pub const SHOW_ALL = bridge.property(NodeFilter.SHOW_ALL); pub const SHOW_ALL = bridge.property(NodeFilter.SHOW_ALL, .{ .template = true });
pub const SHOW_ELEMENT = bridge.property(NodeFilter.SHOW_ELEMENT); pub const SHOW_ELEMENT = bridge.property(NodeFilter.SHOW_ELEMENT, .{ .template = true });
pub const SHOW_ATTRIBUTE = bridge.property(NodeFilter.SHOW_ATTRIBUTE); pub const SHOW_ATTRIBUTE = bridge.property(NodeFilter.SHOW_ATTRIBUTE, .{ .template = true });
pub const SHOW_TEXT = bridge.property(NodeFilter.SHOW_TEXT); pub const SHOW_TEXT = bridge.property(NodeFilter.SHOW_TEXT, .{ .template = true });
pub const SHOW_CDATA_SECTION = bridge.property(NodeFilter.SHOW_CDATA_SECTION); pub const SHOW_CDATA_SECTION = bridge.property(NodeFilter.SHOW_CDATA_SECTION, .{ .template = true });
pub const SHOW_ENTITY_REFERENCE = bridge.property(NodeFilter.SHOW_ENTITY_REFERENCE); pub const SHOW_ENTITY_REFERENCE = bridge.property(NodeFilter.SHOW_ENTITY_REFERENCE, .{ .template = true });
pub const SHOW_ENTITY = bridge.property(NodeFilter.SHOW_ENTITY); pub const SHOW_ENTITY = bridge.property(NodeFilter.SHOW_ENTITY, .{ .template = true });
pub const SHOW_PROCESSING_INSTRUCTION = bridge.property(NodeFilter.SHOW_PROCESSING_INSTRUCTION); pub const SHOW_PROCESSING_INSTRUCTION = bridge.property(NodeFilter.SHOW_PROCESSING_INSTRUCTION, .{ .template = true });
pub const SHOW_COMMENT = bridge.property(NodeFilter.SHOW_COMMENT); pub const SHOW_COMMENT = bridge.property(NodeFilter.SHOW_COMMENT, .{ .template = true });
pub const SHOW_DOCUMENT = bridge.property(NodeFilter.SHOW_DOCUMENT); pub const SHOW_DOCUMENT = bridge.property(NodeFilter.SHOW_DOCUMENT, .{ .template = true });
pub const SHOW_DOCUMENT_TYPE = bridge.property(NodeFilter.SHOW_DOCUMENT_TYPE); pub const SHOW_DOCUMENT_TYPE = bridge.property(NodeFilter.SHOW_DOCUMENT_TYPE, .{ .template = true });
pub const SHOW_DOCUMENT_FRAGMENT = bridge.property(NodeFilter.SHOW_DOCUMENT_FRAGMENT); pub const SHOW_DOCUMENT_FRAGMENT = bridge.property(NodeFilter.SHOW_DOCUMENT_FRAGMENT, .{ .template = true });
pub const SHOW_NOTATION = bridge.property(NodeFilter.SHOW_NOTATION); pub const SHOW_NOTATION = bridge.property(NodeFilter.SHOW_NOTATION, .{ .template = true });
}; };

View File

@@ -565,10 +565,10 @@ pub const JsApi = struct {
}; };
// Constants for compareBoundaryPoints // Constants for compareBoundaryPoints
pub const START_TO_START = bridge.property(0); pub const START_TO_START = bridge.property(0, .{ .template = true });
pub const START_TO_END = bridge.property(1); pub const START_TO_END = bridge.property(1, .{ .template = true });
pub const END_TO_END = bridge.property(2); pub const END_TO_END = bridge.property(2, .{ .template = true });
pub const END_TO_START = bridge.property(3); pub const END_TO_START = bridge.property(3, .{ .template = true });
pub const constructor = bridge.constructor(Range.init, .{}); pub const constructor = bridge.constructor(Range.init, .{});
pub const setStart = bridge.function(Range.setStart, .{ .dom_exception = true }); pub const setStart = bridge.function(Range.setStart, .{ .dom_exception = true });

View File

@@ -284,16 +284,16 @@ pub const JsApi = struct {
pub var class_id: bridge.ClassId = undefined; pub var class_id: bridge.ClassId = undefined;
}; };
pub const NETWORK_EMPTY = bridge.property(@intFromEnum(NetworkState.NETWORK_EMPTY)); pub const NETWORK_EMPTY = bridge.property(@intFromEnum(NetworkState.NETWORK_EMPTY), .{ .template = true });
pub const NETWORK_IDLE = bridge.property(@intFromEnum(NetworkState.NETWORK_IDLE)); pub const NETWORK_IDLE = bridge.property(@intFromEnum(NetworkState.NETWORK_IDLE), .{ .template = true });
pub const NETWORK_LOADING = bridge.property(@intFromEnum(NetworkState.NETWORK_LOADING)); pub const NETWORK_LOADING = bridge.property(@intFromEnum(NetworkState.NETWORK_LOADING), .{ .template = true });
pub const NETWORK_NO_SOURCE = bridge.property(@intFromEnum(NetworkState.NETWORK_NO_SOURCE)); pub const NETWORK_NO_SOURCE = bridge.property(@intFromEnum(NetworkState.NETWORK_NO_SOURCE), .{ .template = true });
pub const HAVE_NOTHING = bridge.property(@intFromEnum(ReadyState.HAVE_NOTHING)); pub const HAVE_NOTHING = bridge.property(@intFromEnum(ReadyState.HAVE_NOTHING), .{ .template = true });
pub const HAVE_METADATA = bridge.property(@intFromEnum(ReadyState.HAVE_METADATA)); pub const HAVE_METADATA = bridge.property(@intFromEnum(ReadyState.HAVE_METADATA), .{ .template = true });
pub const HAVE_CURRENT_DATA = bridge.property(@intFromEnum(ReadyState.HAVE_CURRENT_DATA)); pub const HAVE_CURRENT_DATA = bridge.property(@intFromEnum(ReadyState.HAVE_CURRENT_DATA), .{ .template = true });
pub const HAVE_FUTURE_DATA = bridge.property(@intFromEnum(ReadyState.HAVE_FUTURE_DATA)); pub const HAVE_FUTURE_DATA = bridge.property(@intFromEnum(ReadyState.HAVE_FUTURE_DATA), .{ .template = true });
pub const HAVE_ENOUGH_DATA = bridge.property(@intFromEnum(ReadyState.HAVE_ENOUGH_DATA)); pub const HAVE_ENOUGH_DATA = bridge.property(@intFromEnum(ReadyState.HAVE_ENOUGH_DATA), .{ .template = true });
pub const src = bridge.accessor(Media.getSrc, Media.setSrc, .{}); pub const src = bridge.accessor(Media.getSrc, Media.setSrc, .{});
pub const autoplay = bridge.accessor(Media.getAutoplay, Media.setAutoplay, .{}); pub const autoplay = bridge.accessor(Media.getAutoplay, Media.setAutoplay, .{});

View File

@@ -49,10 +49,10 @@ pub const JsApi = struct {
}; };
// Error code constants // Error code constants
pub const MEDIA_ERR_ABORTED = bridge.property(1); pub const MEDIA_ERR_ABORTED = bridge.property(1, .{ .template = true });
pub const MEDIA_ERR_NETWORK = bridge.property(2); pub const MEDIA_ERR_NETWORK = bridge.property(2, .{ .template = true });
pub const MEDIA_ERR_DECODE = bridge.property(3); pub const MEDIA_ERR_DECODE = bridge.property(3, .{ .template = true });
pub const MEDIA_ERR_SRC_NOT_SUPPORTED = bridge.property(4); pub const MEDIA_ERR_SRC_NOT_SUPPORTED = bridge.property(4, .{ .template = true });
pub const code = bridge.accessor(MediaError.getCode, null, .{}); pub const code = bridge.accessor(MediaError.getCode, null, .{});
pub const message = bridge.accessor(MediaError.getMessage, null, .{}); pub const message = bridge.accessor(MediaError.getMessage, null, .{});

View File

@@ -552,11 +552,11 @@ pub const JsApi = struct {
}; };
pub const constructor = bridge.constructor(XMLHttpRequest.init, .{}); pub const constructor = bridge.constructor(XMLHttpRequest.init, .{});
pub const UNSENT = bridge.property(@intFromEnum(XMLHttpRequest.ReadyState.unsent)); pub const UNSENT = bridge.property(@intFromEnum(XMLHttpRequest.ReadyState.unsent), .{ .template = true });
pub const OPENED = bridge.property(@intFromEnum(XMLHttpRequest.ReadyState.opened)); pub const OPENED = bridge.property(@intFromEnum(XMLHttpRequest.ReadyState.opened), .{ .template = true });
pub const HEADERS_RECEIVED = bridge.property(@intFromEnum(XMLHttpRequest.ReadyState.headers_received)); pub const HEADERS_RECEIVED = bridge.property(@intFromEnum(XMLHttpRequest.ReadyState.headers_received), .{ .template = true });
pub const LOADING = bridge.property(@intFromEnum(XMLHttpRequest.ReadyState.loading)); pub const LOADING = bridge.property(@intFromEnum(XMLHttpRequest.ReadyState.loading), .{ .template = true });
pub const DONE = bridge.property(@intFromEnum(XMLHttpRequest.ReadyState.done)); pub const DONE = bridge.property(@intFromEnum(XMLHttpRequest.ReadyState.done), .{ .template = true });
pub const onreadystatechange = bridge.accessor(XMLHttpRequest.getOnReadyStateChange, XMLHttpRequest.setOnReadyStateChange, .{}); pub const onreadystatechange = bridge.accessor(XMLHttpRequest.getOnReadyStateChange, XMLHttpRequest.setOnReadyStateChange, .{});
pub const withCredentials = bridge.accessor(XMLHttpRequest.getWithCredentials, XMLHttpRequest.setWithCredentials, .{ .dom_exception = true }); pub const withCredentials = bridge.accessor(XMLHttpRequest.getWithCredentials, XMLHttpRequest.setWithCredentials, .{ .dom_exception = true });