[feat] SUI $backend function call supports custom Guard

This commit is contained in:
Max 2024-08-05 08:32:59 +08:00
parent 1ce87a1eb3
commit 9977b62a09
8 changed files with 448 additions and 333 deletions

File diff suppressed because one or more lines are too long

View file

@ -30,231 +30,236 @@ var dsl = []byte(`
"in": [":context", "$param.route", ":payload"],
"out": { "status": 200, "type": "application/json" }
},
{
"path": "/:id/setting",
"method": "GET",
"process": "sui.Setting",
"in": ["$param.id"],
"out": { "status": 200, "type": "application/json" }
},
//
//
// Remove the following code
// Developer can create the API by using the process of sui.* directly
//
// {
// "path": "/:id/setting",
// "method": "GET",
// "process": "sui.Setting",
// "in": ["$param.id"],
// "out": { "status": 200, "type": "application/json" }
// },
{
"path": "/:id/template",
"method": "GET",
"process": "sui.Template.Get",
"in": ["$param.id"],
"out": { "status": 200, "type": "application/json" }
},{
"path": "/:id/template/:template_id",
"method": "GET",
"process": "sui.Template.Find",
"in": ["$param.id", "$param.template_id"],
"out": { "status": 200, "type": "application/json" }
},
// {
// "path": "/:id/template",
// "method": "GET",
// "process": "sui.Template.Get",
// "in": ["$param.id"],
// "out": { "status": 200, "type": "application/json" }
// },{
// "path": "/:id/template/:template_id",
// "method": "GET",
// "process": "sui.Template.Find",
// "in": ["$param.id", "$param.template_id"],
// "out": { "status": 200, "type": "application/json" }
// },
{
"path": "/:id/locale/:template_id",
"method": "GET",
"process": "sui.Locale.Get",
"in": ["$param.id", "$param.template_id"],
"out": { "status": 200, "type": "application/json" }
},{
"path": "/:id/theme/:template_id",
"method": "GET",
"process": "sui.Theme.Get",
"in": ["$param.id", "$param.template_id"],
"out": { "status": 200, "type": "application/json" }
},
// {
// "path": "/:id/locale/:template_id",
// "method": "GET",
// "process": "sui.Locale.Get",
// "in": ["$param.id", "$param.template_id"],
// "out": { "status": 200, "type": "application/json" }
// },{
// "path": "/:id/theme/:template_id",
// "method": "GET",
// "process": "sui.Theme.Get",
// "in": ["$param.id", "$param.template_id"],
// "out": { "status": 200, "type": "application/json" }
// },
{
"path": "/:id/block/:template_id",
"method": "GET",
"process": "sui.Block.Get",
"in": ["$param.id", "$param.template_id"],
"out": { "status": 200, "type": "application/json" }
},{
"path": "/:id/block/export/:template_id",
"method": "GET",
"process": "sui.Block.Export",
"in": ["$param.id", "$param.template_id"],
"out": { "status": 200, "type": "application/json" }
},{
"path": "/:id/block/:template_id/:block_id",
"guard": "query-jwt",
"method": "GET",
"process": "sui.Block.Find",
"in": ["$param.id", "$param.template_id", "$param.block_id"],
"out": { "status": 200, "type": "text/javascript" }
},{
"path": "/:id/block/:template_id/:block_id/media",
"guard": "query-jwt",
"method": "GET",
"process": "sui.Block.Media",
"in": ["$param.id", "$param.template_id", "$param.block_id"],
"out": {
"status": 200,
"body": "?:content",
"headers": { "Content-Type": "?:type"}
}
},
// {
// "path": "/:id/block/:template_id",
// "method": "GET",
// "process": "sui.Block.Get",
// "in": ["$param.id", "$param.template_id"],
// "out": { "status": 200, "type": "application/json" }
// },{
// "path": "/:id/block/export/:template_id",
// "method": "GET",
// "process": "sui.Block.Export",
// "in": ["$param.id", "$param.template_id"],
// "out": { "status": 200, "type": "application/json" }
// },{
// "path": "/:id/block/:template_id/:block_id",
// "guard": "query-jwt",
// "method": "GET",
// "process": "sui.Block.Find",
// "in": ["$param.id", "$param.template_id", "$param.block_id"],
// "out": { "status": 200, "type": "text/javascript" }
// },{
// "path": "/:id/block/:template_id/:block_id/media",
// "guard": "query-jwt",
// "method": "GET",
// "process": "sui.Block.Media",
// "in": ["$param.id", "$param.template_id", "$param.block_id"],
// "out": {
// "status": 200,
// "body": "?:content",
// "headers": { "Content-Type": "?:type"}
// }
// },
{
"path": "/:id/component/:template_id",
"method": "GET",
"process": "sui.Component.Get",
"in": ["$param.id", "$param.template_id"],
"out": { "status": 200, "type": "application/json" }
},{
"path": "/:id/component/:template_id/:component_id",
"guard": "query-jwt",
"method": "GET",
"process": "sui.Component.Find",
"in": ["$param.id", "$param.template_id", "$param.component_id"],
"out": { "status": 200, "type": "text/javascript" }
},
// {
// "path": "/:id/component/:template_id",
// "method": "GET",
// "process": "sui.Component.Get",
// "in": ["$param.id", "$param.template_id"],
// "out": { "status": 200, "type": "application/json" }
// },{
// "path": "/:id/component/:template_id/:component_id",
// "guard": "query-jwt",
// "method": "GET",
// "process": "sui.Component.Find",
// "in": ["$param.id", "$param.template_id", "$param.component_id"],
// "out": { "status": 200, "type": "text/javascript" }
// },
{
"path": "/:id/page/:template_id/*route",
"method": "GET",
"process": "sui.Page.Get",
"in": ["$param.id", "$param.template_id", "$param.route"],
"out": { "status": 200, "type": "application/json" }
},{
"path": "/:id/page/tree/:template_id/*route",
"method": "GET",
"process": "sui.Page.Tree",
"in": ["$param.id", "$param.template_id", "$param.route"],
"out": { "status": 200, "type": "application/json" }
},{
"path": "/:id/page/save/:template_id/*route",
"method": "POST",
"process": "sui.Page.Save",
"in": ["$param.id", "$param.template_id", "$param.route", ":context"],
"out": { "status": 200, "type": "application/json" }
},{
"path": "/:id/page/temp/:template_id/*route",
"method": "POST",
"process": "sui.Page.SaveTemp",
"in": ["$param.id", "$param.template_id", "$param.route", ":context"],
"out": { "status": 200, "type": "application/json" }
},{
"path": "/:id/page/create/:template_id/*route",
"method": "POST",
"process": "sui.Page.Create",
"in": ["$param.id", "$param.template_id", "$param.route", ":context", ":payload"],
"out": { "status": 200, "type": "application/json" }
},{
"path": "/:id/page/duplicate/:template_id/*route",
"method": "POST",
"process": "sui.Page.Duplicate",
"in": ["$param.id", "$param.template_id", "$param.route", ":payload"],
"out": { "status": 200, "type": "application/json" }
},{
"path": "/:id/page/rename/:template_id/*route",
"method": "POST",
"process": "sui.Page.Rename",
"in": ["$param.id", "$param.template_id", "$param.route", ":payload"],
"out": { "status": 200, "type": "application/json" }
},{
"path": "/:id/page/exist/:template_id/*route",
"method": "GET",
"process": "sui.Page.Exist",
"in": ["$param.id", "$param.template_id", "$param.route"],
"out": { "status": 200, "type": "application/json" }
},{
"path": "/:id/page/remove/:template_id/*route",
"method": "POST",
"process": "sui.Page.Remove",
"in": ["$param.id", "$param.template_id", "$param.route"],
"out": { "status": 200, "type": "application/json" }
},
// {
// "path": "/:id/page/:template_id/*route",
// "method": "GET",
// "process": "sui.Page.Get",
// "in": ["$param.id", "$param.template_id", "$param.route"],
// "out": { "status": 200, "type": "application/json" }
// },{
// "path": "/:id/page/tree/:template_id/*route",
// "method": "GET",
// "process": "sui.Page.Tree",
// "in": ["$param.id", "$param.template_id", "$param.route"],
// "out": { "status": 200, "type": "application/json" }
// },{
// "path": "/:id/page/save/:template_id/*route",
// "method": "POST",
// "process": "sui.Page.Save",
// "in": ["$param.id", "$param.template_id", "$param.route", ":context"],
// "out": { "status": 200, "type": "application/json" }
// },{
// "path": "/:id/page/temp/:template_id/*route",
// "method": "POST",
// "process": "sui.Page.SaveTemp",
// "in": ["$param.id", "$param.template_id", "$param.route", ":context"],
// "out": { "status": 200, "type": "application/json" }
// },{
// "path": "/:id/page/create/:template_id/*route",
// "method": "POST",
// "process": "sui.Page.Create",
// "in": ["$param.id", "$param.template_id", "$param.route", ":context", ":payload"],
// "out": { "status": 200, "type": "application/json" }
// },{
// "path": "/:id/page/duplicate/:template_id/*route",
// "method": "POST",
// "process": "sui.Page.Duplicate",
// "in": ["$param.id", "$param.template_id", "$param.route", ":payload"],
// "out": { "status": 200, "type": "application/json" }
// },{
// "path": "/:id/page/rename/:template_id/*route",
// "method": "POST",
// "process": "sui.Page.Rename",
// "in": ["$param.id", "$param.template_id", "$param.route", ":payload"],
// "out": { "status": 200, "type": "application/json" }
// },{
// "path": "/:id/page/exist/:template_id/*route",
// "method": "GET",
// "process": "sui.Page.Exist",
// "in": ["$param.id", "$param.template_id", "$param.route"],
// "out": { "status": 200, "type": "application/json" }
// },{
// "path": "/:id/page/remove/:template_id/*route",
// "method": "POST",
// "process": "sui.Page.Remove",
// "in": ["$param.id", "$param.template_id", "$param.route"],
// "out": { "status": 200, "type": "application/json" }
// },
{
"path": "/:id/editor/render/:template_id/*route",
"method": "GET",
"process": "sui.Editor.Render",
"in": ["$param.id", "$param.template_id", "$param.route", ":query"],
"out": { "status": 200, "type": "application/json" }
},{
"path": "/:id/editor/render/:template_id/*route",
"method": "POST",
"process": "sui.Editor.RenderAfterSaveTemp",
"in": ["$param.id", "$param.template_id", "$param.route", ":context", ":query"],
"out": { "status": 200, "type": "application/json" }
},{
"path": "/:id/editor/:kind/source/:template_id/*route",
"method": "GET",
"process": "sui.Editor.Source",
"in": ["$param.id", "$param.template_id", "$param.route", "$param.kind", ":query"],
"out": { "status": 200, "type": "application/json" }
},{
"path": "/:id/editor/:kind/source/:template_id/*route",
"method": "POST",
"process": "sui.Editor.SourceAfterSaveTemp",
"in": ["$param.id", "$param.template_id", "$param.route", ":context", "$param.kind", ":query"],
"out": { "status": 200, "type": "application/json" }
},
// {
// "path": "/:id/editor/render/:template_id/*route",
// "method": "GET",
// "process": "sui.Editor.Render",
// "in": ["$param.id", "$param.template_id", "$param.route", ":query"],
// "out": { "status": 200, "type": "application/json" }
// },{
// "path": "/:id/editor/render/:template_id/*route",
// "method": "POST",
// "process": "sui.Editor.RenderAfterSaveTemp",
// "in": ["$param.id", "$param.template_id", "$param.route", ":context", ":query"],
// "out": { "status": 200, "type": "application/json" }
// },{
// "path": "/:id/editor/:kind/source/:template_id/*route",
// "method": "GET",
// "process": "sui.Editor.Source",
// "in": ["$param.id", "$param.template_id", "$param.route", "$param.kind", ":query"],
// "out": { "status": 200, "type": "application/json" }
// },{
// "path": "/:id/editor/:kind/source/:template_id/*route",
// "method": "POST",
// "process": "sui.Editor.SourceAfterSaveTemp",
// "in": ["$param.id", "$param.template_id", "$param.route", ":context", "$param.kind", ":query"],
// "out": { "status": 200, "type": "application/json" }
// },
{
"path": "/:id/asset/:template_id/@assets/*path",
"method": "GET",
"guard": "-",
"process": "sui.Template.Asset",
"in": ["$param.id", "$param.template_id", "$param.path", "$query.w", "$query.h"],
"out": {
"status": 200,
"body": "?:content",
"headers": { "Content-Type": "?:type"}
}
},{
"path": "/:id/asset/:template_id/upload",
"method": "POST",
"process": "sui.Template.AssetUpload",
"in": ["$param.id", "$param.template_id", ":context"],
"out": { "status": 200, "type": "application/json" }
},{
"path": "/:id/asset/:template_id/@pages/*path",
"guard": "query-jwt",
"method": "GET",
"process": "sui.Page.Asset",
"in": ["$param.id", "$param.template_id", "$param.path", "$query.w", "$query.h"],
"out": {
"status": 200,
"body": "?:content",
"headers": { "Content-Type": "?:type"}
}
},
// {
// "path": "/:id/asset/:template_id/@assets/*path",
// "method": "GET",
// "guard": "-",
// "process": "sui.Template.Asset",
// "in": ["$param.id", "$param.template_id", "$param.path", "$query.w", "$query.h"],
// "out": {
// "status": 200,
// "body": "?:content",
// "headers": { "Content-Type": "?:type"}
// }
// },{
// "path": "/:id/asset/:template_id/upload",
// "method": "POST",
// "process": "sui.Template.AssetUpload",
// "in": ["$param.id", "$param.template_id", ":context"],
// "out": { "status": 200, "type": "application/json" }
// },{
// "path": "/:id/asset/:template_id/@pages/*path",
// "guard": "query-jwt",
// "method": "GET",
// "process": "sui.Page.Asset",
// "in": ["$param.id", "$param.template_id", "$param.path", "$query.w", "$query.h"],
// "out": {
// "status": 200,
// "body": "?:content",
// "headers": { "Content-Type": "?:type"}
// }
// },
{
"path": "/:id/media/:driver/search",
"method": "GET",
"process": "sui.Media.Search",
"in": ["$param.id", "$param.driver", ":query"],
"out": { "status": 200, "type": "application/json" }
},
// {
// "path": "/:id/media/:driver/search",
// "method": "GET",
// "process": "sui.Media.Search",
// "in": ["$param.id", "$param.driver", ":query"],
// "out": { "status": 200, "type": "application/json" }
// },
{
"path": "/:id/preview/:template_id/*route",
"guard": "query-jwt",
"method": "GET",
"process": "sui.Preview.Render",
"in": ["$param.id", "$param.template_id", "$param.route", "$header.Referer"],
"out": {"status": 200, "type": "text/html; charset=utf-8"}
},
// {
// "path": "/:id/preview/:template_id/*route",
// "guard": "query-jwt",
// "method": "GET",
// "process": "sui.Preview.Render",
// "in": ["$param.id", "$param.template_id", "$param.route", "$header.Referer"],
// "out": {"status": 200, "type": "text/html; charset=utf-8"}
// },
{
"path": "/:id/build/:template_id",
"method": "POST",
"process": "sui.Build.All",
"in": ["$param.id", "$param.template_id", ":payload"],
"out": {"status": 200}
},{
"path": "/:id/build/:template_id/*route",
"method": "POST",
"process": "sui.Build.Page",
"in": ["$param.id", "$param.template_id", "$param.route", ":payload"],
"out": {"status": 200}
}
// {
// "path": "/:id/build/:template_id",
// "method": "POST",
// "process": "sui.Build.All",
// "in": ["$param.id", "$param.template_id", ":payload"],
// "out": {"status": 200}
// },{
// "path": "/:id/build/:template_id/*route",
// "method": "POST",
// "process": "sui.Build.Page",
// "in": ["$param.id", "$param.template_id", "$param.route", ":payload"],
// "out": {"status": 200}
// }
],
}
`)

View file

@ -4,6 +4,7 @@ import (
"bytes"
"fmt"
"io"
"strconv"
"strings"
"github.com/gin-gonic/gin"
@ -157,7 +158,7 @@ func (r *Request) scriptGuardExec(c *gin.Context, name string, args []interface{
script, err := v8.Select(id)
if err != nil {
c.JSON(403, gin.H{"code": 403, "message": fmt.Sprintf("Guard: %s %s", name, err.Error())})
c.JSON(403, gin.H{"code": 403, "message": err.Error()})
c.Abort()
return err
}
@ -394,7 +395,29 @@ func (r *Request) scriptGuardExec(c *gin.Context, name string, args []interface{
_, err = ctx.Call(method, args...)
if err != nil {
c.JSON(403, gin.H{"code": 403, "message": fmt.Sprintf("Guard: %s %s", name, err.Error())})
message := err.Error()
if strings.HasPrefix(message, "Exception|") {
parts := strings.Split(message, ": ")
fmt.Println(parts)
if len(parts) > 1 {
codestr := strings.TrimPrefix(parts[0], "Exception|")
message := parts[1]
code := 403
if codestr != "" {
if v, err := strconv.Atoi(codestr); err == nil {
code = v
}
}
c.JSON(code, gin.H{"code": code, "message": message})
c.Abort()
return err
}
}
c.JSON(403, gin.H{"code": 403, "message": message})
c.Abort()
return err
}

View file

@ -2,14 +2,24 @@ package api
import (
"path/filepath"
"strings"
"github.com/gin-gonic/gin"
jsoniter "github.com/json-iterator/go"
"github.com/yaoapp/gou/application"
"github.com/yaoapp/gou/process"
"github.com/yaoapp/kun/exception"
"github.com/yaoapp/kun/log"
"github.com/yaoapp/yao/sui/core"
)
var configs = map[string]*core.PageConfig{}
var chConfig = make(chan *core.PageConfig, 1)
func init() {
go configWriter()
}
// Run the backend script, with Api prefix method
func Run(process *process.Process) interface{} {
process.ValidateArgNums(3)
@ -38,17 +48,6 @@ func Run(process *process.Process) interface{} {
return nil
}
if payload["page"] == nil {
exception.New("The page is required", 400).Throw()
return nil
}
page, ok := payload["page"].(string)
if !ok {
exception.New("The page must be a string", 400).Throw()
return nil
}
args := []interface{}{}
if payload["args"] != nil {
args, ok = payload["args"].([]interface{})
@ -58,41 +57,39 @@ func Run(process *process.Process) interface{} {
}
}
ctx.Request.URL.Path = page
r, _, err := NewRequestContext(ctx)
if err != nil {
exception.Err(err, 500).Throw()
return nil
}
var c *core.Cache = nil
if !r.Request.DisableCache() {
c = core.GetCache(r.File)
// Load the script
file := filepath.Join("/public", route)
// Get the page config
cfg, err := getPageConfig(file, r.Request.DisableCache())
if err != nil {
log.Error("Can't load the page config (%s), %s", route, err.Error())
exception.New("Can't load the page config (%s), get more information from the log.", 500, route).Throw()
return nil
}
if c == nil {
c, _, err = r.MakeCache()
// Config and guard
prefix := "Api"
if cfg != nil {
_, err := r.apiGuard(method, cfg.API)
if err != nil {
log.Error("[SUI] Can't make cache, %s %s error: %s", route, method, err.Error())
exception.New("Can't make cache, the route and method is correct, get more information from the log.", 500).Throw()
log.Error("Guard error: %s", err.Error())
r.context.Done()
return nil
}
// Custom prefix
if cfg.API != nil && cfg.API.Prefix != "" {
prefix = cfg.API.Prefix
}
}
// Guard the page
code, err := r.Guard(c)
if err != nil {
exception.Err(err, code).Throw()
return nil
}
if c == nil {
exception.New("Cache not found", 500).Throw()
return nil
}
// Load the script
file := filepath.Join("/public", route)
script, err := core.LoadScript(file, r.Request.DisableCache())
if err != nil {
exception.New("Can't load the script (%s), get more information from the log.", 500, route).Throw()
@ -106,18 +103,17 @@ func Run(process *process.Process) interface{} {
scriptCtx, err := script.NewContext(process.Sid, nil)
if err != nil {
exception.Err(err, 500).Throw()
return nil
}
defer scriptCtx.Close()
global := scriptCtx.Global()
if !global.Has("Api" + method) {
if !global.Has(prefix + method) {
exception.New("Method %s not found", 500, method).Throw()
return nil
}
res, err := scriptCtx.Call("Api"+method, args...)
res, err := scriptCtx.Call(prefix+method, args...)
if err != nil {
exception.Err(err, 500).Throw()
return nil
@ -125,3 +121,78 @@ func Run(process *process.Process) interface{} {
return res
}
// getPageConfig get the page config
func getPageConfig(file string, disableCache ...bool) (*core.PageConfig, error) {
// LOAD FROM CACHE
base := strings.TrimSuffix(strings.TrimSuffix(file, ".sui"), ".jit")
if disableCache == nil || !disableCache[0] {
if cfg, has := configs[base]; has {
return cfg, nil
}
}
file = base + ".cfg"
if exist, _ := application.App.Exists(file); !exist {
return nil, nil
}
source, err := application.App.Read(file)
if err != nil {
return nil, err
}
cfg := core.PageConfig{}
err = jsoniter.Unmarshal(source, &cfg)
if err != nil {
return nil, err
}
// Save to cache
go func() { chConfig <- &cfg }()
return &cfg, nil
}
func (r *Request) apiGuard(method string, api *core.PageAPI) (int, error) {
if api == nil {
return 200, nil
}
guard := api.DefaultGuard
if api.Guards != nil {
if g, has := api.Guards[method]; has {
guard = g
}
}
if guard == "" || guard == "-" {
return 200, nil
}
// Build in guard
if guard, has := Guards[guard]; has {
err := guard(r)
if err != nil {
return 403, err
}
return 200, nil
}
// Developer custom guard
err := r.processGuard(guard)
if err != nil {
return 403, err
}
return 200, nil
}
func configWriter() {
for {
select {
case config := <-chConfig:
configs[config.Root] = config
}
}
}

View file

@ -61,16 +61,17 @@ func (page *Page) GetConfig() *PageConfig {
// ExportConfig export the config
func (page *Page) ExportConfig() string {
if page.Config == nil {
return fmt.Sprintf(`{"cache_store": "%s"}`, page.CacheStore)
return fmt.Sprintf(`{"cacheStore": "%s"}`, page.CacheStore)
}
config, err := jsoniter.MarshalToString(map[string]interface{}{
"title": page.Config.Title,
"guard": page.Config.Guard,
"cache_store": page.CacheStore,
"cache": page.Config.Cache,
"data_cache": page.Config.DataCache,
"root": page.Root,
"title": page.Config.Title,
"guard": page.Config.Guard,
"cacheStore": page.CacheStore,
"cache": page.Config.Cache,
"dataCache": page.Config.DataCache,
"api": page.Config.API,
"root": page.Root,
})
if err != nil {

View file

@ -378,9 +378,10 @@ type PageSetting struct {
CacheStore string `json:"cache_store,omitempty"`
Cache int `json:"cache,omitempty"`
Root string `json:"root,omitempty"`
DataCache int `json:"data_cache,omitempty"`
DataCache int `json:"dataCache,omitempty"`
Description string `json:"description,omitempty"`
SEO *PageSEO `json:"seo,omitempty"`
API *PageAPI `json:"api,omitempty"`
}
// PageConfigRendered is the struct for the page config rendered
@ -389,6 +390,13 @@ type PageConfigRendered struct {
Link string `json:"link,omitempty"`
}
// PageAPI is the struct for the page api
type PageAPI struct {
Prefix string `json:"prefix,omitempty"`
DefaultGuard string `json:"defaultGuard,omitempty"`
Guards map[string]string `json:"guards,omitempty"`
}
// PageSEO is the struct for the page seo
type PageSEO struct {
Title string `json:"title,omitempty"`

View file

@ -221,16 +221,18 @@ function __sui_store(elm) {
async function __sui_backend_call(
route: string,
page: string,
headers: [string, string][] | Record<string, string> | Headers,
method: string,
...args: any
): Promise<any> {
const url = `/api/__yao/sui/v1/run${route}`;
const headers = {
headers = {
"Content-Type": "application/json",
Referer: window.location.href,
Cookie: document.cookie,
...headers,
};
const payload = { method, args, page };
const payload = { method, args };
try {
const body = JSON.stringify(payload);
const response = await fetch(url, { method: "POST", headers, body: body });

View file

@ -176,25 +176,30 @@ class __Render {
}
}
function $Backend(route?: string) {
const page = window.location.pathname;
function $Backend(
route?: string,
headers?: [string, string][] | Record<string, string> | Headers
) {
const root = document.body.getAttribute("s:public") || "/";
route = route || page;
route = route || window.location.pathname;
const re = new RegExp("^" + root);
route = root + route.replace(re, "");
return new __Backend(route, page);
return new __Backend(route, headers);
}
class __Backend {
route = "";
page = "";
constructor(route: string, page: string) {
headers: [string, string][] | Record<string, string> | Headers = {};
constructor(
route: string,
headers: [string, string][] | Record<string, string> | Headers = {}
) {
this.route = route;
this.page = page;
this.headers = headers;
}
async Call(method: string, ...args: any): Promise<any> {
// @ts-ignore
return await __sui_backend_call(this.route, this.page, method, ...args);
return await __sui_backend_call(this.route, this.headers, method, ...args);
}
}