package jsmod import ( "context" "sync" ) type contextKey string const internalContextKey contextKey = "__GoJSContext__" // Get retrieves an injected value from the context using the unified context map. func Get(ctx context.Context, key string) any { if ctx == nil { return nil } if m, ok := ctx.Value(internalContextKey).(map[string]any); ok { return m[key] } return nil } // NewContext returns a new context with the provided injection map. func NewContext(parent context.Context, injects map[string]any) context.Context { if parent == nil { parent = context.Background() } return context.WithValue(parent, internalContextKey, injects) } // IsSafeMode checks if the provided context indicates that the execution is in safe mode. func IsSafeMode(ctx context.Context) bool { if sm, ok := Get(ctx, "SafeMode").(bool); ok { return sm } return false // Default to false if not specified (internal trusted caller) } type Module struct { Exports map[string]any UnsafeList map[string]bool } var ( modules = make(map[string]*Module) mu sync.RWMutex ) // Register registers a Go module with its exported functions and properties. // These modules will be accessible within the JS environment. // unsafeList identifies methods that require elevated permissions (e.g., file writing, shell execution). func Register(name string, exports map[string]any, unsafeList ...string) { mu.Lock() defer mu.Unlock() if modules[name] == nil { modules[name] = &Module{ Exports: make(map[string]any, len(exports)), UnsafeList: make(map[string]bool), } } for k, v := range exports { modules[name].Exports[k] = v } for _, method := range unsafeList { modules[name].UnsafeList[method] = true } } // GetModules returns all registered modules and their unsafe status. func GetModules() map[string]*Module { mu.RLock() defer mu.RUnlock() res := make(map[string]*Module, len(modules)) for name, mod := range modules { res[name] = mod } return res }