You've already forked pocketbase
mirror of
https://github.com/pocketbase/pocketbase.git
synced 2025-11-25 07:34:10 +02:00
[#6102] fixed JSVM exception -> Go error unwrapping
This commit is contained in:
@@ -81,14 +81,14 @@ func hooksBinds(app core.App, loader *goja.Runtime, executors *vmsPool) {
|
||||
res, err := executor.RunProgram(pr)
|
||||
executor.Set("__args", goja.Undefined())
|
||||
|
||||
// check for returned error value
|
||||
// (legacy) check for returned Go error value
|
||||
if res != nil {
|
||||
if resErr, ok := res.Export().(error); ok {
|
||||
return resErr
|
||||
}
|
||||
}
|
||||
|
||||
return err
|
||||
return normalizeException(err)
|
||||
})
|
||||
|
||||
return []reflect.Value{reflect.ValueOf(&err).Elem()}
|
||||
@@ -197,14 +197,14 @@ func wrapHandlerFunc(executors *vmsPool, handler goja.Value) (func(*core.Request
|
||||
res, err := executor.RunProgram(pr)
|
||||
executor.Set("__args", goja.Undefined())
|
||||
|
||||
// check for returned error
|
||||
// (legacy) check for returned Go error value
|
||||
if res != nil {
|
||||
if v, ok := res.Export().(error); ok {
|
||||
return v
|
||||
}
|
||||
}
|
||||
|
||||
return err
|
||||
return normalizeException(err)
|
||||
})
|
||||
}
|
||||
|
||||
@@ -215,9 +215,9 @@ func wrapHandlerFunc(executors *vmsPool, handler goja.Value) (func(*core.Request
|
||||
}
|
||||
|
||||
type gojaHookHandler struct {
|
||||
priority int
|
||||
id string
|
||||
serializedFunc string
|
||||
priority int
|
||||
}
|
||||
|
||||
func wrapMiddlewares(executors *vmsPool, rawMiddlewares ...goja.Value) ([]*hook.Handler[*core.RequestEvent], error) {
|
||||
@@ -254,14 +254,14 @@ func wrapMiddlewares(executors *vmsPool, rawMiddlewares ...goja.Value) ([]*hook.
|
||||
res, err := executor.RunProgram(pr)
|
||||
executor.Set("__args", goja.Undefined())
|
||||
|
||||
// check for returned error
|
||||
// (legacy) check for returned Go error value
|
||||
if res != nil {
|
||||
if v, ok := res.Export().(error); ok {
|
||||
return v
|
||||
}
|
||||
}
|
||||
|
||||
return err
|
||||
return normalizeException(err)
|
||||
})
|
||||
},
|
||||
}
|
||||
@@ -276,14 +276,14 @@ func wrapMiddlewares(executors *vmsPool, rawMiddlewares ...goja.Value) ([]*hook.
|
||||
res, err := executor.RunProgram(pr)
|
||||
executor.Set("__args", goja.Undefined())
|
||||
|
||||
// check for returned error
|
||||
// (legacy) check for returned Go error value
|
||||
if res != nil {
|
||||
if v, ok := res.Export().(error); ok {
|
||||
return v
|
||||
}
|
||||
}
|
||||
|
||||
return err
|
||||
return normalizeException(err)
|
||||
})
|
||||
},
|
||||
}
|
||||
@@ -1019,3 +1019,29 @@ func newDynamicModel(shape map[string]any) any {
|
||||
|
||||
return elem.Addr().Interface()
|
||||
}
|
||||
|
||||
// normalizeException checks if the provided error is a goja.Exception
|
||||
// and attempts to return its underlying Go error.
|
||||
//
|
||||
// note: using just goja.Exception.Unwrap() is insufficient and may falsely result in nil.
|
||||
func normalizeException(err error) error {
|
||||
if err == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
jsException, ok := err.(*goja.Exception)
|
||||
if !ok {
|
||||
return err // no exception
|
||||
}
|
||||
|
||||
switch v := jsException.Value().Export().(type) {
|
||||
case error:
|
||||
err = v
|
||||
case map[string]any: // goja.GoError
|
||||
if vErr, ok := v["value"].(error); ok {
|
||||
err = vErr
|
||||
}
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ package jsvm
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"mime/multipart"
|
||||
@@ -1456,6 +1457,47 @@ func TestHooksBinds(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestHooksExceptionUnwrapping(t *testing.T) {
|
||||
app, _ := tests.NewTestApp()
|
||||
defer app.Cleanup()
|
||||
|
||||
goErr := errors.New("test")
|
||||
|
||||
vmFactory := func() *goja.Runtime {
|
||||
vm := goja.New()
|
||||
baseBinds(vm)
|
||||
vm.Set("$app", app)
|
||||
vm.Set("goErr", goErr)
|
||||
return vm
|
||||
}
|
||||
|
||||
pool := newPool(1, vmFactory)
|
||||
|
||||
vm := vmFactory()
|
||||
hooksBinds(app, vm, pool)
|
||||
|
||||
_, err := vm.RunString(`
|
||||
onModelUpdate((e) => {
|
||||
throw goErr
|
||||
}, "demo1")
|
||||
`)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
record, err := app.FindFirstRecordByFilter("demo1", "1=1")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
record.Set("text", "update")
|
||||
|
||||
err = app.Save(record)
|
||||
if !errors.Is(err, goErr) {
|
||||
t.Fatalf("Expected goError, got %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestRouterBindsCount(t *testing.T) {
|
||||
app, _ := tests.NewTestApp()
|
||||
defer app.Cleanup()
|
||||
|
||||
@@ -326,21 +326,7 @@ func (p *plugin) normalizeServeExceptions(e *core.RequestEvent) error {
|
||||
return err // no error or already committed
|
||||
}
|
||||
|
||||
jsException, ok := err.(*goja.Exception)
|
||||
if !ok {
|
||||
return err // no exception
|
||||
}
|
||||
|
||||
switch v := jsException.Value().Export().(type) {
|
||||
case error:
|
||||
err = v
|
||||
case map[string]any: // goja.GoError
|
||||
if vErr, ok := v["value"].(error); ok {
|
||||
err = vErr
|
||||
}
|
||||
}
|
||||
|
||||
return err
|
||||
return normalizeException(err)
|
||||
}
|
||||
|
||||
// watchHooks initializes a hooks file watcher that will restart the
|
||||
|
||||
Reference in New Issue
Block a user