From bb0a30e639b61eba4bce884efa7b72e3ee8dd689 Mon Sep 17 00:00:00 2001 From: Karl Seguin Date: Tue, 25 Mar 2025 10:46:53 +0800 Subject: [PATCH] Expose InspectorClient valueSubtype and descriptionForValueSubtype When the inspector returns a RemoteObject, the proper subType must be returned in order for the driver (i.e. puppeteer) to know what methods are available. For example, on any page.$eval, the first thing puppeteer does is request the document object via a Runtime.callFunctionOn which simply does return document; If the description of the document that we return (a "RemoteObject") doesn't include the "node" subtype, the puppeteer will fail. This PR provides the hooks for an implementation to provide its own valueSubtype implementation. However, in order for v8 to include the `node` field, we must always also include a "description" field, which is why this PR also allows implementations to provide its own `descriptionForValueSubtype`. --- build.zig | 18 +++++++++++++----- src/binding.cpp | 12 ++++++++++++ src/binding.h | 4 ++++ src/inspector.h | 2 ++ src/v8.zig | 23 ++++++++++++++++++++++- 5 files changed, 53 insertions(+), 6 deletions(-) diff --git a/build.zig b/build.zig index 1b46445..a05cbcf 100644 --- a/build.zig +++ b/build.zig @@ -15,16 +15,23 @@ pub fn build(b: *std.Build) !void { const mode = b.standardOptimizeOption(.{}); const target = b.standardTargetOptions(.{}); + var build_opts = b.addOptions(); + build_opts.addOption( + bool, + "inspector_subtype", + b.option(bool, "inspector_subtype", "Export default valueSubtype and descriptionForValueSubtype") orelse true, + ); + _ = createGetTools(b); _ = createGetV8(b, icu); const v8 = try createV8_Build(b, target, mode, use_zig_tc, icu); - const create_test = createTest(b, target, mode, use_zig_tc); + const create_test = createTest(b, target, mode, use_zig_tc, build_opts); const run_test = b.addRunArtifact(create_test); b.step("test", "Run tests.").dependOn(&run_test.step); - const build_exe = createCompileStep(b, path, target, mode, use_zig_tc); + const build_exe = createCompileStep(b, path, target, mode, use_zig_tc, build_opts); b.step("exe", "Build exe with main file at -Dpath").dependOn(&build_exe.step); const run_exe = b.addRunArtifact(build_exe); @@ -510,13 +517,14 @@ fn linkV8(b: *std.Build, step: *std.Build.Step.Compile, use_zig_tc: bool) void { } } -fn createTest(b: *std.Build, target: std.Build.ResolvedTarget, mode: std.builtin.Mode, use_zig_tc: bool) *std.Build.Step.Compile { +fn createTest(b: *std.Build, target: std.Build.ResolvedTarget, mode: std.builtin.Mode, use_zig_tc: bool, build_opts: *std.Build.Step.Options) *std.Build.Step.Compile { const step = b.addTest(.{ .root_source_file = b.path("./src/test.zig"), .target = target, .optimize = mode, .link_libc = true, }); + step.root_module.addImport("default_exports", build_opts.createModule()); step.addIncludePath(b.path("./src")); linkV8(b, step, use_zig_tc); return step; @@ -733,7 +741,7 @@ pub const GetV8SourceStep = struct { } }; -fn createCompileStep(b: *std.Build, path: []const u8, target: std.Build.ResolvedTarget, mode: std.builtin.Mode, use_zig_tc: bool) *std.Build.Step.Compile { +fn createCompileStep(b: *std.Build, path: []const u8, target: std.Build.ResolvedTarget, mode: std.builtin.Mode, use_zig_tc: bool, build_opts: *std.Build.Step.Options) *std.Build.Step.Compile { const basename = std.fs.path.basename(path); const i = std.mem.indexOf(u8, basename, ".zig") orelse basename.len; const name = basename[0..i]; @@ -746,7 +754,7 @@ fn createCompileStep(b: *std.Build, path: []const u8, target: std.Build.Resolved .link_libc = true, }); step.addIncludePath(b.path("src")); - + step.root_module.addImport("default_exports", build_opts.createModule()); if (mode == .ReleaseSafe) { step.root_module.strip = true; } diff --git a/src/binding.cpp b/src/binding.cpp index a2f9933..14877c2 100644 --- a/src/binding.cpp +++ b/src/binding.cpp @@ -1715,6 +1715,10 @@ void v8_inspector__Client__IMPL__consoleAPIMessage( unsigned columnNumber, v8_inspector::V8StackTrace *stackTrace); const v8::Context* v8_inspector__Client__IMPL__ensureDefaultContextInGroup( v8_inspector__Client__IMPL* self, void* data, int contextGroupId); +char* v8_inspector__Client__IMPL__valueSubtype( + v8_inspector__Client__IMPL* self, v8::Local value); +char* v8_inspector__Client__IMPL__descriptionForValueSubtype( + v8_inspector__Client__IMPL* self, v8::Local context, v8::Local value); // c++ implementation (just wrappers around the c/zig functions) } // extern "C" @@ -1742,6 +1746,14 @@ void v8_inspector__Client__IMPL::consoleAPIMessage( v8::Local v8_inspector__Client__IMPL::ensureDefaultContextInGroup(int contextGroupId) { return ptr_to_local(v8_inspector__Client__IMPL__ensureDefaultContextInGroup(this, this->data, contextGroupId)); } +std::unique_ptr v8_inspector__Client__IMPL::valueSubtype(v8::Local value) { + auto subType = v8_inspector__Client__IMPL__valueSubtype(this, value); + return v8_inspector::StringBuffer::create(toStringView(subType)); +} +std::unique_ptr v8_inspector__Client__IMPL::descriptionForValueSubtype(v8::Local context, v8::Local value) { + auto descriptions = v8_inspector__Client__IMPL__descriptionForValueSubtype(this, context, value); + return v8_inspector::StringBuffer::create(toStringView(descriptions)); +} extern "C" { diff --git a/src/binding.h b/src/binding.h index 867c273..d4aa86a 100644 --- a/src/binding.h +++ b/src/binding.h @@ -988,6 +988,10 @@ void v8_inspector__Client__IMPL__consoleAPIMessage( unsigned columnNumber, StackTrace *StackTrace); const Context* v8_inspector__Client__IMPL__ensureDefaultContextInGroup( InspectorClientImpl* self, void* data, int contextGroupId); +const Context* v8_inspector__Client__IMPL__valueSubtype( + InspectorClientImpl* self, Value value); +const Context* v8_inspector__Client__IMPL__descriptionForValueSubtype( + InspectorClientImpl* self, Context context, Value value); // InspectorSession diff --git a/src/inspector.h b/src/inspector.h index 452a1cf..8c710ef 100644 --- a/src/inspector.h +++ b/src/inspector.h @@ -39,6 +39,8 @@ class v8_inspector__Client__IMPL unsigned lineNumber, unsigned columnNumber, v8_inspector::V8StackTrace* stackTrace) override; v8::Local ensureDefaultContextInGroup(int contextGroupId) override; + std::unique_ptr valueSubtype(v8::Local) override; + std::unique_ptr descriptionForValueSubtype(v8::Local, v8::Local) override; }; #endif // V8INSPECTORIMPL_H diff --git a/src/v8.zig b/src/v8.zig index 8369bec..e8b8c45 100644 --- a/src/v8.zig +++ b/src/v8.zig @@ -1,7 +1,7 @@ const std = @import("std"); const t = std.testing; -const c = @cImport({ +pub const c = @cImport({ @cInclude("binding.h"); }); @@ -2551,6 +2551,27 @@ pub export fn v8_inspector__Client__IMPL__ensureDefaultContextInGroup( return inspector.ctx_handle; } + +usingnamespace if (@import("default_exports").inspector_subtype) struct { + pub export fn v8_inspector__Client__IMPL__valueSubtype( + _: *c.InspectorClientImpl, + value: *const c.Value, + ) callconv(.C) [*c]const u8 { + _ = value; + return null; + } + + pub export fn v8_inspector__Client__IMPL__descriptionForValueSubtype( + _: *c.InspectorClientImpl, + context: *const c.Context, + value: *const c.Value, + ) callconv(.C) [*c]const u8 { + _ = value; + _ = context; + return null; + } +} else struct {}; + // InspectorChannel pub const InspectorChannel = struct {