added log warning for async marked JSVM handlers and resolve when possible the returned Promise as fallback
This commit is contained in:
parent
4a7a639df1
commit
4e148f7224
|
@ -11,10 +11,13 @@
|
||||||
|
|
||||||
- Added `$os.stat(file)` JSVM helper ([#6407](https://github.com/pocketbase/pocketbase/discussions/6407)).
|
- Added `$os.stat(file)` JSVM helper ([#6407](https://github.com/pocketbase/pocketbase/discussions/6407)).
|
||||||
|
|
||||||
|
- Added log warning for `async` marked JSVM handlers and resolve when possible the returned `Promise` as fallback ([#6476](https://github.com/pocketbase/pocketbase/issues/6476)).
|
||||||
|
|
||||||
- Added `store.Store.SetFunc(key, func(old T) new T)` to set/update a store value with the return result of the callback in a concurrent safe manner.
|
- Added `store.Store.SetFunc(key, func(old T) new T)` to set/update a store value with the return result of the callback in a concurrent safe manner.
|
||||||
|
|
||||||
- Added `subscription.Message.WriteSSE(w, id)` for writing an SSE formatted message into the provided writer interface (_used mostly to assist with the unit testing_).
|
- Added `subscription.Message.WriteSSE(w, id)` for writing an SSE formatted message into the provided writer interface (_used mostly to assist with the unit testing_).
|
||||||
|
|
||||||
|
|
||||||
- Bumped the default request read and write timeouts to 5mins (_old 3mins_) to accommodate slower internet connections and larger file uploads/downloads.
|
- Bumped the default request read and write timeouts to 5mins (_old 3mins_) to accommodate slower internet connections and larger file uploads/downloads.
|
||||||
_If you want to change them you can modify the `OnServe` hook's `ServeEvent.ReadTimeout/WriteTimeout` fields as shown in [#6550](https://github.com/pocketbase/pocketbase/discussions/6550#discussioncomment-12364515)._
|
_If you want to change them you can modify the `OnServe` hook's `ServeEvent.ReadTimeout/WriteTimeout` fields as shown in [#6550](https://github.com/pocketbase/pocketbase/discussions/6550#discussioncomment-12364515)._
|
||||||
|
|
||||||
|
|
|
@ -83,12 +83,10 @@ func hooksBinds(app core.App, loader *goja.Runtime, executors *vmsPool) {
|
||||||
res, err := executor.RunProgram(pr)
|
res, err := executor.RunProgram(pr)
|
||||||
executor.Set("__args", goja.Undefined())
|
executor.Set("__args", goja.Undefined())
|
||||||
|
|
||||||
// (legacy) check for returned Go error value
|
// check for returned Go error value
|
||||||
if res != nil {
|
if resErr := checkGojaValueForError(app, res); resErr != nil {
|
||||||
if resErr, ok := res.Export().(error); ok {
|
|
||||||
return resErr
|
return resErr
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
return normalizeException(err)
|
return normalizeException(err)
|
||||||
})
|
})
|
||||||
|
@ -199,11 +197,9 @@ func wrapHandlerFunc(executors *vmsPool, handler goja.Value) (func(*core.Request
|
||||||
res, err := executor.RunProgram(pr)
|
res, err := executor.RunProgram(pr)
|
||||||
executor.Set("__args", goja.Undefined())
|
executor.Set("__args", goja.Undefined())
|
||||||
|
|
||||||
// (legacy) check for returned Go error value
|
// check for returned Go error value
|
||||||
if res != nil {
|
if resErr := checkGojaValueForError(e.App, res); resErr != nil {
|
||||||
if v, ok := res.Export().(error); ok {
|
return resErr
|
||||||
return v
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return normalizeException(err)
|
return normalizeException(err)
|
||||||
|
@ -256,11 +252,9 @@ func wrapMiddlewares(executors *vmsPool, rawMiddlewares ...goja.Value) ([]*hook.
|
||||||
res, err := executor.RunProgram(pr)
|
res, err := executor.RunProgram(pr)
|
||||||
executor.Set("__args", goja.Undefined())
|
executor.Set("__args", goja.Undefined())
|
||||||
|
|
||||||
// (legacy) check for returned Go error value
|
// check for returned Go error value
|
||||||
if res != nil {
|
if resErr := checkGojaValueForError(e.App, res); resErr != nil {
|
||||||
if v, ok := res.Export().(error); ok {
|
return resErr
|
||||||
return v
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return normalizeException(err)
|
return normalizeException(err)
|
||||||
|
@ -278,11 +272,9 @@ func wrapMiddlewares(executors *vmsPool, rawMiddlewares ...goja.Value) ([]*hook.
|
||||||
res, err := executor.RunProgram(pr)
|
res, err := executor.RunProgram(pr)
|
||||||
executor.Set("__args", goja.Undefined())
|
executor.Set("__args", goja.Undefined())
|
||||||
|
|
||||||
// (legacy) check for returned Go error value
|
// check for returned Go error value
|
||||||
if res != nil {
|
if resErr := checkGojaValueForError(e.App, res); resErr != nil {
|
||||||
if v, ok := res.Export().(error); ok {
|
return resErr
|
||||||
return v
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return normalizeException(err)
|
return normalizeException(err)
|
||||||
|
@ -920,6 +912,29 @@ func httpClientBinds(vm *goja.Runtime) {
|
||||||
|
|
||||||
// -------------------------------------------------------------------
|
// -------------------------------------------------------------------
|
||||||
|
|
||||||
|
// checkGojaValueForError resolves the provided goja.Value and tries
|
||||||
|
// to extract its underlying error value (if any).
|
||||||
|
func checkGojaValueForError(app core.App, value goja.Value) error {
|
||||||
|
if value == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
exported := value.Export()
|
||||||
|
switch v := exported.(type) {
|
||||||
|
case error:
|
||||||
|
return v
|
||||||
|
case *goja.Promise:
|
||||||
|
// Promise as return result is not officially supported but try to
|
||||||
|
// resolve any thrown exception to avoid silently ignoring it
|
||||||
|
app.Logger().Warn("the handler must a non-async function and not return a Promise")
|
||||||
|
if promiseErr, ok := v.Result().Export().(error); ok {
|
||||||
|
return normalizeException(promiseErr)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// normalizeException checks if the provided error is a goja.Exception
|
// normalizeException checks if the provided error is a goja.Exception
|
||||||
// and attempts to return its underlying Go error.
|
// and attempts to return its underlying Go error.
|
||||||
//
|
//
|
||||||
|
|
|
@ -83,7 +83,7 @@ func TestBaseBindsReaderToString(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestBaseBindsToString(t *testing.T) {
|
func TestBaseBindsToStringAndToBytes(t *testing.T) {
|
||||||
vm := goja.New()
|
vm := goja.New()
|
||||||
baseBinds(vm)
|
baseBinds(vm)
|
||||||
vm.Set("scenarios", []struct {
|
vm.Set("scenarios", []struct {
|
||||||
|
@ -1597,13 +1597,14 @@ func TestRouterBinds(t *testing.T) {
|
||||||
defer app.Cleanup()
|
defer app.Cleanup()
|
||||||
|
|
||||||
result := &struct {
|
result := &struct {
|
||||||
AddCount int
|
RouteMiddlewareCalls int
|
||||||
WithCount int
|
GlobalMiddlewareCalls int
|
||||||
}{}
|
}{}
|
||||||
|
|
||||||
vmFactory := func() *goja.Runtime {
|
vmFactory := func() *goja.Runtime {
|
||||||
vm := goja.New()
|
vm := goja.New()
|
||||||
baseBinds(vm)
|
baseBinds(vm)
|
||||||
|
apisBinds(vm)
|
||||||
vm.Set("$app", app)
|
vm.Set("$app", app)
|
||||||
vm.Set("result", result)
|
vm.Set("result", result)
|
||||||
return vm
|
return vm
|
||||||
|
@ -1616,14 +1617,20 @@ func TestRouterBinds(t *testing.T) {
|
||||||
|
|
||||||
_, err := vm.RunString(`
|
_, err := vm.RunString(`
|
||||||
routerAdd("GET", "/test", (e) => {
|
routerAdd("GET", "/test", (e) => {
|
||||||
result.addCount++;
|
result.routeMiddlewareCalls++;
|
||||||
}, (e) => {
|
}, (e) => {
|
||||||
result.addCount++;
|
result.routeMiddlewareCalls++;
|
||||||
return e.next();
|
return e.next();
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// Promise is not technically supported as return result
|
||||||
|
// but we try to resolve it at least for thrown errors
|
||||||
|
routerAdd("GET", "/error", async (e) => {
|
||||||
|
throw new ApiError(456, 'test', null)
|
||||||
|
})
|
||||||
|
|
||||||
routerUse((e) => {
|
routerUse((e) => {
|
||||||
result.withCount++;
|
result.globalMiddlewareCalls++;
|
||||||
|
|
||||||
return e.next();
|
return e.next();
|
||||||
})
|
})
|
||||||
|
@ -1644,21 +1651,44 @@ func TestRouterBinds(t *testing.T) {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
rec := httptest.NewRecorder()
|
|
||||||
req := httptest.NewRequest("GET", "/test", nil)
|
|
||||||
|
|
||||||
mux, err := serveEvent.Router.BuildMux()
|
mux, err := serveEvent.Router.BuildMux()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Failed to build router mux: %v", err)
|
t.Fatalf("Failed to build router mux: %v", err)
|
||||||
}
|
}
|
||||||
mux.ServeHTTP(rec, req)
|
|
||||||
|
|
||||||
if result.AddCount != 2 {
|
scenarios := []struct {
|
||||||
t.Fatalf("Expected AddCount %d, got %d", 2, result.AddCount)
|
method string
|
||||||
|
path string
|
||||||
|
expectedRouteMiddlewareCalls int
|
||||||
|
expectedGlobalMiddlewareCalls int
|
||||||
|
expectedCode int
|
||||||
|
}{
|
||||||
|
{"GET", "/test", 2, 1, 200},
|
||||||
|
{"GET", "/error", 0, 1, 456},
|
||||||
}
|
}
|
||||||
|
|
||||||
if result.WithCount != 1 {
|
for _, s := range scenarios {
|
||||||
t.Fatalf("Expected WithCount %d, got %d", 1, result.WithCount)
|
t.Run(s.method+" "+s.path, func(t *testing.T) {
|
||||||
|
// reset
|
||||||
|
result.RouteMiddlewareCalls = 0
|
||||||
|
result.GlobalMiddlewareCalls = 0
|
||||||
|
|
||||||
|
rec := httptest.NewRecorder()
|
||||||
|
req := httptest.NewRequest(s.method, s.path, nil)
|
||||||
|
mux.ServeHTTP(rec, req)
|
||||||
|
|
||||||
|
if result.RouteMiddlewareCalls != s.expectedRouteMiddlewareCalls {
|
||||||
|
t.Fatalf("Expected RouteMiddlewareCalls %d, got %d", s.expectedRouteMiddlewareCalls, result.RouteMiddlewareCalls)
|
||||||
|
}
|
||||||
|
|
||||||
|
if result.GlobalMiddlewareCalls != s.expectedGlobalMiddlewareCalls {
|
||||||
|
t.Fatalf("Expected GlobalMiddlewareCalls %d, got %d", s.expectedGlobalMiddlewareCalls, result.GlobalMiddlewareCalls)
|
||||||
|
}
|
||||||
|
|
||||||
|
if rec.Code != s.expectedCode {
|
||||||
|
t.Fatalf("Expected status code %d, got %d", s.expectedCode, rec.Code)
|
||||||
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue