@@ -346,7 +346,7 @@ pub fn Env(comptime State: type, comptime WebApis: type) type {
346346 // when the handle_scope is freed.
347347 // We also maintain our own "context_arena" which allows us to have
348348 // all page related memory easily managed.
349- pub fn createJsContext (self : * ExecutionWorld , global : anytype , state : State , module_loader : anytype , enter : bool ) ! * JsContext {
349+ pub fn createJsContext (self : * ExecutionWorld , global : anytype , state : State , module_loader : anytype , enter : bool , global_callback : ? GlobalMissingCallback ) ! * JsContext {
350350 std .debug .assert (self .js_context == null );
351351
352352 const ModuleLoader = switch (@typeInfo (@TypeOf (module_loader ))) {
@@ -375,6 +375,30 @@ pub fn Env(comptime State: type, comptime WebApis: type) type {
375375 const global_template = js_global .getInstanceTemplate ();
376376 global_template .setInternalFieldCount (1 );
377377
378+ // Configure the missing property callback on the global
379+ // object.
380+ if (global_callback != null ) {
381+ const configuration = v8.NamedPropertyHandlerConfiguration {
382+ .getter = struct {
383+ fn callback (c_name : ? * const v8.C_Name , raw_info : ? * const v8.C_PropertyCallbackInfo ) callconv (.c ) u8 {
384+ const info = v8 .PropertyCallbackInfo .initFromV8 (raw_info );
385+ const _isolate = info .getIsolate ();
386+ const v8_context = _isolate .getCurrentContext ();
387+
388+ const js_context : * JsContext = @ptrFromInt (v8_context .getEmbedderData (1 ).castTo (v8 .BigInt ).getUint64 ());
389+
390+ const property = valueToString (js_context .call_arena , .{ .handle = c_name .? }, _isolate , v8_context ) catch "???" ;
391+ if (js_context .global_callback .? .missing (property , js_context )) {
392+ return v8 .Intercepted .Yes ;
393+ }
394+ return v8 .Intercepted .No ;
395+ }
396+ }.callback ,
397+ .flags = v8 .PropertyHandlerFlags .NonMasking | v8 .PropertyHandlerFlags .OnlyInterceptStrings ,
398+ };
399+ global_template .setNamedProperty (configuration , null );
400+ }
401+
378402 // All the FunctionTemplates that we created and setup in Env.init
379403 // are now going to get associated with our global instance.
380404 inline for (Types , 0.. ) | s , i | {
@@ -456,6 +480,7 @@ pub fn Env(comptime State: type, comptime WebApis: type) type {
456480 .ptr = safe_module_loader ,
457481 .func = ModuleLoader .fetchModuleSource ,
458482 },
483+ .global_callback = global_callback ,
459484 };
460485
461486 var js_context = & self .js_context .? ;
@@ -608,6 +633,9 @@ pub fn Env(comptime State: type, comptime WebApis: type) type {
608633 // necessary to lookup/store the dependent module in the module_cache.
609634 module_identifier : std .AutoHashMapUnmanaged (u32 , []const u8 ) = .empty ,
610635
636+ // Global callback is called on missing property.
637+ global_callback : ? GlobalMissingCallback = null ,
638+
611639 const ModuleLoader = struct {
612640 ptr : * anyopaque ,
613641 func : * const fn (ptr : * anyopaque , specifier : []const u8 ) anyerror ! ? []const u8 ,
@@ -2546,6 +2574,35 @@ pub fn Env(comptime State: type, comptime WebApis: type) type {
25462574 self .callScopeEndFn (self .ptr );
25472575 }
25482576 };
2577+
2578+ // Callback called on global's property mssing.
2579+ // Return true to intercept the exectution or false to let the call
2580+ // continue the chain.
2581+ pub const GlobalMissingCallback = struct {
2582+ ptr : * anyopaque ,
2583+ missingFn : * const fn (ptr : * anyopaque , name : []const u8 , ctx : * JsContext ) bool ,
2584+
2585+ pub fn init (ptr : anytype ) GlobalMissingCallback {
2586+ const T = @TypeOf (ptr );
2587+ const ptr_info = @typeInfo (T );
2588+
2589+ const gen = struct {
2590+ pub fn missing (pointer : * anyopaque , name : []const u8 , ctx : * JsContext ) bool {
2591+ const self : T = @ptrCast (@alignCast (pointer ));
2592+ return ptr_info .pointer .child .missing (self , name , ctx );
2593+ }
2594+ };
2595+
2596+ return .{
2597+ .ptr = ptr ,
2598+ .missingFn = gen .missing ,
2599+ };
2600+ }
2601+
2602+ pub fn missing (self : GlobalMissingCallback , name : []const u8 , ctx : * JsContext ) bool {
2603+ return self .missingFn (self .ptr , name , ctx );
2604+ }
2605+ };
25492606 };
25502607}
25512608
@@ -3431,7 +3488,7 @@ fn valueToDetailString(arena: Allocator, value: v8.Value, isolate: v8.Isolate, v
34313488 if (debugValueToString (arena , value .castTo (v8 .Object ), isolate , v8_context )) | ds | {
34323489 return ds ;
34333490 } else | err | {
3434- log .err (.js , "debug serialize value" , .{.err = err });
3491+ log .err (.js , "debug serialize value" , .{ .err = err });
34353492 }
34363493 }
34373494 }
0 commit comments