diff --git a/CHANGELOG.md b/CHANGELOG.md index a4b9abec..885d9f9f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,8 @@ +## v0.25.5 (WIP) + +- Specified a default goja script name when executing plain JS strings to allow traversing parent `node_modules` directories. + + ## v0.25.4 - Downgraded `aws-sdk-go-v2` to the version before the default data integrity checks because there have been reports for non-AWS S3 providers in addition to Backblaze (IDrive, R2) that no longer or partially work with the latest AWS SDK changes. diff --git a/plugins/jsvm/binds.go b/plugins/jsvm/binds.go index ae8184ee..23a90211 100644 --- a/plugins/jsvm/binds.go +++ b/plugins/jsvm/binds.go @@ -58,7 +58,7 @@ func hooksBinds(app core.App, loader *goja.Runtime, executors *vmsPool) { loader.Set(jsName, func(callback string, tags ...string) { // overwrite the global $app with the hook scoped instance callback = `function(e) { $app = e.app; return (` + callback + `).call(undefined, e) }` - pr := goja.MustCompile("", "{("+callback+").apply(undefined, __args)}", true) + pr := goja.MustCompile(defaultScriptPath, "{("+callback+").apply(undefined, __args)}", true) tagsAsValues := make([]reflect.Value, len(tags)) for i, tag := range tags { @@ -103,7 +103,7 @@ func hooksBinds(app core.App, loader *goja.Runtime, executors *vmsPool) { func cronBinds(app core.App, loader *goja.Runtime, executors *vmsPool) { loader.Set("cronAdd", func(jobId, cronExpr, handler string) { - pr := goja.MustCompile("", "{("+handler+").apply(undefined)}", true) + pr := goja.MustCompile(defaultScriptPath, "{("+handler+").apply(undefined)}", true) err := app.Cron().Add(jobId, cronExpr, func() { err := executors.run(func(executor *goja.Runtime) error { @@ -189,7 +189,7 @@ func wrapHandlerFunc(executors *vmsPool, handler goja.Value) (func(*core.Request // "native" handler func - no need to wrap return h, nil case func(goja.FunctionCall) goja.Value, string: - pr := goja.MustCompile("", "{("+handler.String()+").apply(undefined, __args)}", true) + pr := goja.MustCompile(defaultScriptPath, "{("+handler.String()+").apply(undefined, __args)}", true) wrappedHandler := func(e *core.RequestEvent) error { return executors.run(func(executor *goja.Runtime) error { @@ -243,7 +243,7 @@ func wrapMiddlewares(executors *vmsPool, rawMiddlewares ...goja.Value) ([]*hook. return nil, errors.New("missing or invalid Middleware function") } - pr := goja.MustCompile("", "{("+v.serializedFunc+").apply(undefined, __args)}", true) + pr := goja.MustCompile(defaultScriptPath, "{("+v.serializedFunc+").apply(undefined, __args)}", true) wrappedMiddlewares[i] = &hook.Handler[*core.RequestEvent]{ Id: v.id, @@ -267,7 +267,7 @@ func wrapMiddlewares(executors *vmsPool, rawMiddlewares ...goja.Value) ([]*hook. }, } case func(goja.FunctionCall) goja.Value, string: - pr := goja.MustCompile("", "{("+m.String()+").apply(undefined, __args)}", true) + pr := goja.MustCompile(defaultScriptPath, "{("+m.String()+").apply(undefined, __args)}", true) wrappedMiddlewares[i] = &hook.Handler[*core.RequestEvent]{ Func: func(e *core.RequestEvent) error { diff --git a/plugins/jsvm/jsvm.go b/plugins/jsvm/jsvm.go index ba5385b6..5ef610e8 100644 --- a/plugins/jsvm/jsvm.go +++ b/plugins/jsvm/jsvm.go @@ -35,6 +35,24 @@ import ( const typesFileName = "types.d.ts" +var defaultScriptPath = "pb.js" + +func init() { + // For backward compatibility and consistency with the Go exposed + // methods that accepts relative paths (e.g. `$os.writeFile`), + // we define the "current JS module" as if it is a file in the current working directory + // (the filename itself doesn't really matter and in our case the hook handlers are executed as separate "programs"). + // + // This is necessary for `require(module)` to properly traverse parents node_modules (goja_nodejs#95). + cwd, err := os.Getwd() + if err != nil { + // truly rare case, log just for debug purposes + color.Yellow("Failed to retrieve the current working directory: %v", err) + } else { + defaultScriptPath = filepath.Join(cwd, defaultScriptPath) + } +} + // Config defines the config options of the jsvm plugin. type Config struct { // OnInit is an optional function that will be called @@ -191,7 +209,7 @@ func (p *plugin) registerMigrations() error { p.config.OnInit(vm) } - _, err := vm.RunString(string(content)) + _, err := vm.RunScript(defaultScriptPath, string(content)) if err != nil { return fmt.Errorf("failed to run migration %s: %w", file, err) } @@ -306,7 +324,7 @@ func (p *plugin) registerHooks() error { } }() - _, err := loader.RunString(string(content)) + _, err := loader.RunScript(defaultScriptPath, string(content)) if err != nil { panic(err) }