Compare commits

...

14 Commits

51 changed files with 5741 additions and 417 deletions

2
.gitignore vendored
View File

@ -1,7 +1,7 @@
/node_modules /node_modules
/bin /bin
/pkg/sdk/client/dist
/.env /.env
/tools /tools
*.sqlite *.sqlite
/.gitea-release /.gitea-release
/.edge

View File

@ -0,0 +1,50 @@
[
{
"username": "superadmin",
"algo": "argon2id",
"password": "$argon2id$v=19$m=65536,t=3,p=2$cWOxfEyBy4EyKZR5usB2Pw$xG+Z/E2DUJP9kF0s1fhZjIuP03gFQ65dP7pHRJz7eR8",
"claims": {
"arcad_entrypoint": "edge",
"arcad_role": "superadmin",
"arcad_tenant": "dev.cli",
"preferred_username": "SuperAdmin",
"sub": "superadmin"
}
},
{
"username": "admin",
"algo": "argon2id",
"password": "$argon2id$v=19$m=65536,t=3,p=2$WXXc4ECnkej6WO7f0Xya6Q$UG2wcGltJcuW0cNTR85mAl65tI1kFWMMw7ADS2FMOvY",
"claims": {
"arcad_entrypoint": "edge",
"arcad_role": "admin",
"arcad_tenant": "dev.cli",
"preferred_username": "Admin",
"sub": "admin"
}
},
{
"username": "superuser",
"algo": "argon2id",
"password": "$argon2id$v=19$m=65536,t=3,p=2$gkDAWCzfU23+un3x0ny+YA$L/NSPrd5iKPK/UnSCKfSz4EO+v94N3LTLky4QGJOfpI",
"claims": {
"arcad_entrypoint": "edge",
"arcad_role": "superuser",
"arcad_tenant": "dev.cli",
"preferred_username": "SuperUser",
"sub": "superuser"
}
},
{
"username": "user",
"algo": "argon2id",
"password": "$argon2id$v=19$m=65536,t=3,p=2$DhUm9qXUKP35Lzp5M37eZA$2+h6yDxSTHZqFZIuI7JZfFWozwrObna8a8yCgEEPlPE",
"claims": {
"arcad_entrypoint": "edge",
"arcad_role": "user",
"arcad_tenant": "dev.cli",
"preferred_username": "User",
"sub": "user"
}
}
]

View File

@ -0,0 +1,47 @@
package app
import (
"fmt"
"forge.cadoles.com/arcad/edge/pkg/module/auth/http/passwd"
"github.com/pkg/errors"
"github.com/urfave/cli/v2"
"forge.cadoles.com/arcad/edge/pkg/module/auth/http/passwd/argon2id"
_ "forge.cadoles.com/arcad/edge/pkg/module/auth/http/passwd/plain"
)
func HashPasswordCommand() *cli.Command {
return &cli.Command{
Name: "hash-password",
Usage: "Hash the provided password with the specified algorithm",
Flags: []cli.Flag{
&cli.StringFlag{
Name: "password",
Usage: "hash `PASSWORD`",
Aliases: []string{"p"},
Value: "",
Required: true,
},
&cli.StringFlag{
Name: "algorithm",
Usage: fmt.Sprintf("use `ALGORITHM` to hash password (available: %v)", passwd.Algorithms()),
Aliases: []string{"a"},
Value: string(argon2id.Algo),
},
},
Action: func(ctx *cli.Context) error {
algo := ctx.String("algorithm")
password := ctx.String("password")
hash, err := passwd.Hash(passwd.Algo(algo), password)
if err != nil {
return errors.WithStack(err)
}
fmt.Println(hash)
return nil
},
}
}

View File

@ -47,7 +47,7 @@ func PackageCommand() *cli.Command {
bundle := bundle.NewDirectoryBundle(appDir) bundle := bundle.NewDirectoryBundle(appDir)
manifest, err := app.LoadAppManifest(bundle) manifest, err := app.LoadManifest(bundle)
if err != nil { if err != nil {
return errors.Wrap(err, "could not load app manifest") return errors.Wrap(err, "could not load app manifest")
} }

View File

@ -11,6 +11,7 @@ func Root() *cli.Command {
Subcommands: []*cli.Command{ Subcommands: []*cli.Command{
RunCommand(), RunCommand(),
PackageCommand(), PackageCommand(),
HashPasswordCommand(),
}, },
} }
} }

View File

@ -1,11 +1,12 @@
package app package app
import ( import (
"database/sql" "encoding/json"
"fmt" "io/ioutil"
"net/http" "net/http"
"os"
"path/filepath" "path/filepath"
"time" "strings"
"forge.cadoles.com/arcad/edge/pkg/app" "forge.cadoles.com/arcad/edge/pkg/app"
"forge.cadoles.com/arcad/edge/pkg/bus" "forge.cadoles.com/arcad/edge/pkg/bus"
@ -13,6 +14,7 @@ import (
appHTTP "forge.cadoles.com/arcad/edge/pkg/http" appHTTP "forge.cadoles.com/arcad/edge/pkg/http"
"forge.cadoles.com/arcad/edge/pkg/module" "forge.cadoles.com/arcad/edge/pkg/module"
"forge.cadoles.com/arcad/edge/pkg/module/auth" "forge.cadoles.com/arcad/edge/pkg/module/auth"
authHTTP "forge.cadoles.com/arcad/edge/pkg/module/auth/http"
"forge.cadoles.com/arcad/edge/pkg/module/cast" "forge.cadoles.com/arcad/edge/pkg/module/cast"
"forge.cadoles.com/arcad/edge/pkg/module/net" "forge.cadoles.com/arcad/edge/pkg/module/net"
"forge.cadoles.com/arcad/edge/pkg/storage" "forge.cadoles.com/arcad/edge/pkg/storage"
@ -23,11 +25,15 @@ import (
"github.com/dop251/goja" "github.com/dop251/goja"
"github.com/go-chi/chi/v5" "github.com/go-chi/chi/v5"
"github.com/go-chi/chi/v5/middleware" "github.com/go-chi/chi/v5/middleware"
"github.com/golang-jwt/jwt" "github.com/lestrrat-go/jwx/v2/jwa"
"github.com/lestrrat-go/jwx/v2/jwk"
"github.com/pkg/errors" "github.com/pkg/errors"
"github.com/urfave/cli/v2" "github.com/urfave/cli/v2"
_ "modernc.org/sqlite" _ "embed"
_ "forge.cadoles.com/arcad/edge/pkg/module/auth/http/passwd/argon2id"
_ "forge.cadoles.com/arcad/edge/pkg/module/auth/http/passwd/plain"
) )
func RunCommand() *cli.Command { func RunCommand() *cli.Command {
@ -60,22 +66,12 @@ func RunCommand() *cli.Command {
&cli.StringFlag{ &cli.StringFlag{
Name: "storage-file", Name: "storage-file",
Usage: "use `FILE` for SQLite storage database", Usage: "use `FILE` for SQLite storage database",
Value: "data.sqlite", Value: ".edge/%APPID%/data.sqlite",
}, },
&cli.StringFlag{ &cli.StringFlag{
Name: "auth-subject", Name: "accounts-file",
Usage: "set the `SUBJECT` associated with the simulated connected user", Usage: "use `FILE` as local accounts",
Value: "jdoe", Value: ".edge/%APPID%/accounts.json",
},
&cli.StringFlag{
Name: "auth-role",
Usage: "set the `ROLE` associated with the simulated connected user",
Value: "user",
},
&cli.StringFlag{
Name: "auth-preferred-username",
Usage: "set the `PREFERRED_USERNAME` associated with the simulated connected user",
Value: "Jane Doe",
}, },
}, },
Action: func(ctx *cli.Context) error { Action: func(ctx *cli.Context) error {
@ -85,12 +81,6 @@ func RunCommand() *cli.Command {
logFormat := ctx.String("log-format") logFormat := ctx.String("log-format")
logLevel := ctx.Int("log-level") logLevel := ctx.Int("log-level")
storageFile := ctx.String("storage-file")
authSubject := ctx.String("auth-subject")
authRole := ctx.String("auth-role")
authPreferredUsername := ctx.String("auth-preferred-username")
logger.SetFormat(logger.Format(logFormat)) logger.SetFormat(logger.Format(logFormat))
logger.SetLevel(logger.Level(logLevel)) logger.SetLevel(logger.Level(logLevel))
@ -108,20 +98,21 @@ func RunCommand() *cli.Command {
return errors.Wrapf(err, "could not open path '%s' as an app bundle", path) return errors.Wrapf(err, "could not open path '%s' as an app bundle", path)
} }
mux := chi.NewMux() manifest, err := app.LoadManifest(bundle)
mux.Use(middleware.Logger)
mux.Use(dummyAuthMiddleware(authSubject, authRole, authPreferredUsername))
bus := memory.NewBus()
db, err := sql.Open("sqlite", storageFile)
if err != nil { if err != nil {
return errors.Wrapf(err, "could not open database with path '%s'", storageFile) return errors.Wrap(err, "could not load manifest from app bundle")
}
storageFile := injectAppID(ctx.String("storage-file"), manifest.ID)
db, err := sqlite.Open(storageFile)
if err != nil {
return errors.WithStack(err)
} }
ds := sqlite.NewDocumentStoreWithDB(db) ds := sqlite.NewDocumentStoreWithDB(db)
bs := sqlite.NewBlobStoreWithDB(db) bs := sqlite.NewBlobStoreWithDB(db)
bus := memory.NewBus()
handler := appHTTP.NewHandler( handler := appHTTP.NewHandler(
appHTTP.WithBus(bus), appHTTP.WithBus(bus),
@ -131,11 +122,33 @@ func RunCommand() *cli.Command {
return errors.Wrap(err, "could not load app bundle") return errors.Wrap(err, "could not load app bundle")
} }
mux.Handle("/*", handler) router := chi.NewRouter()
router.Use(middleware.Logger)
accountsFile := injectAppID(ctx.String("accounts-file"), manifest.ID)
accounts, err := loadLocalAccounts(accountsFile)
if err != nil {
return errors.Wrap(err, "could not load local accounts")
}
// Add auth handler
key, err := dummyKey()
if err != nil {
return errors.WithStack(err)
}
router.Handle("/auth/*", authHTTP.NewLocalHandler(
jwa.HS256, key,
authHTTP.WithRoutePrefix("/auth"),
authHTTP.WithAccounts(accounts...),
))
// Add app handler
router.Handle("/*", handler)
logger.Info(cmdCtx, "listening", logger.F("address", address)) logger.Info(cmdCtx, "listening", logger.F("address", address))
if err := http.ListenAndServe(address, mux); err != nil { if err := http.ListenAndServe(address, router); err != nil {
return errors.WithStack(err) return errors.WithStack(err)
} }
@ -156,10 +169,18 @@ func getServerModules(bus bus.Bus, ds storage.DocumentStore, bs storage.BlobStor
module.BlobModuleFactory(bus, bs), module.BlobModuleFactory(bus, bs),
module.Extends( module.Extends(
auth.ModuleFactory( auth.ModuleFactory(
auth.WithJWT(dummyKeyFunc), auth.WithJWT(dummyKeySet),
), ),
func(o *goja.Object) { func(o *goja.Object) {
if err := o.Set("CLAIM_ROLE", "role"); err != nil { if err := o.Set("CLAIM_TENANT", "arcad_tenant"); err != nil {
panic(errors.New("could not set 'CLAIM_TENANT' property"))
}
if err := o.Set("CLAIM_ENTRYPOINT", "arcad_entrypoint"); err != nil {
panic(errors.New("could not set 'CLAIM_ENTRYPOINT' property"))
}
if err := o.Set("CLAIM_ROLE", "arcad_role"); err != nil {
panic(errors.New("could not set 'CLAIM_ROLE' property")) panic(errors.New("could not set 'CLAIM_ROLE' property"))
} }
@ -173,59 +194,72 @@ func getServerModules(bus bus.Bus, ds storage.DocumentStore, bs storage.BlobStor
var dummySecret = []byte("not_so_secret") var dummySecret = []byte("not_so_secret")
func dummyKeyFunc(t *jwt.Token) (interface{}, error) { func dummyKey() (jwk.Key, error) {
if _, ok := t.Method.(*jwt.SigningMethodHMAC); !ok { key, err := jwk.FromRaw(dummySecret)
return nil, fmt.Errorf("Unexpected signing method: %v", t.Header["alg"]) if err != nil {
return nil, errors.WithStack(err)
} }
return dummySecret, nil return key, nil
} }
func dummyAuthMiddleware(subject, role, username string) func(http.Handler) http.Handler { func dummyKeySet() (jwk.Set, error) {
return func(h http.Handler) http.Handler { key, err := dummyKey()
fn := func(w http.ResponseWriter, r *http.Request) { if err != nil {
unauthenticated := subject == "" && role == "" && username == "" return nil, errors.WithStack(err)
}
if unauthenticated { if err := key.Set(jwk.AlgorithmKey, jwa.HS256); err != nil {
h.ServeHTTP(w, r) return nil, errors.WithStack(err)
}
return set := jwk.NewSet()
if err := set.AddKey(key); err != nil {
return nil, errors.WithStack(err)
}
return set, nil
}
func ensureDir(path string) error {
if err := os.MkdirAll(filepath.Dir(path), os.ModePerm); err != nil {
return errors.WithStack(err)
}
return nil
}
func injectAppID(str string, appID app.ID) string {
return strings.ReplaceAll(str, "%APPID%", string(appID))
}
//go:embed default-accounts.json
var defaultAccounts []byte
func loadLocalAccounts(path string) ([]authHTTP.LocalAccount, error) {
if err := ensureDir(path); err != nil {
return nil, errors.WithStack(err)
}
data, err := ioutil.ReadFile(path)
if err != nil {
if errors.Is(err, os.ErrNotExist) {
if err := ioutil.WriteFile(path, defaultAccounts, 0o640); err != nil {
return nil, errors.WithStack(err)
} }
claims := jwt.MapClaims{ data = defaultAccounts
"nbf": time.Now().UTC().Unix(), } else {
} return nil, errors.WithStack(err)
if subject != "" {
claims["sub"] = subject
}
if role != "" {
claims["role"] = role
}
if username != "" {
claims["preferred_username"] = username
}
token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
ctx := r.Context()
rawToken, err := token.SignedString(dummySecret)
if err != nil {
logger.Error(ctx, "could not sign token", logger.E(errors.WithStack(err)))
http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
return
}
r.Header.Add("Authorization", "Bearer "+rawToken)
h.ServeHTTP(w, r)
} }
return http.HandlerFunc(fn)
} }
var accounts []authHTTP.LocalAccount
if err := json.Unmarshal(data, &accounts); err != nil {
return nil, errors.WithStack(err)
}
return accounts, nil
} }

View File

@ -36,6 +36,6 @@ Cette propriété identifie l'utilisateur connecté. Si la valeur retournée par
Cette propriété retourne le rôle de l'utilisateur connecté au sein du "tenant" courant. Si la valeur retournée par la méthode `getClaim()` est vide, alors l'utilisateur n'est pas connecté. Cette propriété retourne le rôle de l'utilisateur connecté au sein du "tenant" courant. Si la valeur retournée par la méthode `getClaim()` est vide, alors l'utilisateur n'est pas connecté.
### `auth.PREFERRED_USERNAME` ### `auth.CLAIM_PREFERRED_USERNAME`
Cette propriété retourne le nom "préféré pour l'affichage" de l'utilisateur connecté. Si la valeur retournée par la méthode `getClaim()` est vide, alors l'utilisateur n'est pas connecté ou l'utilisateur n'a pas défini de nom d'utilisateur particulier. Cette propriété retourne le nom "préféré pour l'affichage" de l'utilisateur connecté. Si la valeur retournée par la méthode `getClaim()` est vide, alors l'utilisateur n'est pas connecté ou l'utilisateur n'a pas défini de nom d'utilisateur particulier.

View File

@ -178,6 +178,6 @@ var results = store.query(ctx, "myCollection", {
limit: 10, limit: 10,
offset: 5, offset: 5,
orderBy: "foo", orderBy: "foo",
orderDirection: store.ASC, orderDirection: store.DIRECTION_ASC,
}); });
``` ```

50
go.mod
View File

@ -2,13 +2,23 @@ module forge.cadoles.com/arcad/edge
go 1.19 go 1.19
require modernc.org/sqlite v1.20.4 require (
github.com/lestrrat-go/jwx/v2 v2.0.8
modernc.org/sqlite v1.20.4
)
require ( require (
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.1.0 // indirect
github.com/goccy/go-json v0.9.11 // indirect
github.com/gogo/protobuf v0.0.0-20161014173244-50d1bd39ce4e // indirect github.com/gogo/protobuf v0.0.0-20161014173244-50d1bd39ce4e // indirect
github.com/golang-jwt/jwt v3.2.2+incompatible // indirect github.com/golang-jwt/jwt v3.2.2+incompatible // indirect
github.com/hashicorp/go.net v0.0.0-20151006203346-104dcad90073 // indirect github.com/hashicorp/go.net v0.0.0-20151006203346-104dcad90073 // indirect
github.com/hashicorp/mdns v0.0.0-20151206042412-9d85cf22f9f8 // indirect github.com/hashicorp/mdns v0.0.0-20151206042412-9d85cf22f9f8 // indirect
github.com/lestrrat-go/blackmagic v1.0.1 // indirect
github.com/lestrrat-go/httpcc v1.0.1 // indirect
github.com/lestrrat-go/httprc v1.0.4 // indirect
github.com/lestrrat-go/iter v1.0.2 // indirect
github.com/lestrrat-go/option v1.0.0 // indirect
github.com/miekg/dns v0.0.0-20161006100029-fc4e1e2843d8 // indirect github.com/miekg/dns v0.0.0-20161006100029-fc4e1e2843d8 // indirect
) )
@ -20,40 +30,40 @@ require (
github.com/danwakefield/fnmatch v0.0.0-20160403171240-cbb64ac3d964 // indirect github.com/danwakefield/fnmatch v0.0.0-20160403171240-cbb64ac3d964 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect github.com/davecgh/go-spew v1.1.1 // indirect
github.com/dlclark/regexp2 v1.7.0 // indirect github.com/dlclark/regexp2 v1.7.0 // indirect
github.com/dop251/goja v0.0.0-20230203172422-5460598cfa32 // indirect github.com/dop251/goja v0.0.0-20230203172422-5460598cfa32
github.com/dop251/goja_nodejs v0.0.0-20230207183254-2229640ea097 // indirect github.com/dop251/goja_nodejs v0.0.0-20230207183254-2229640ea097
github.com/dustin/go-humanize v1.0.0 // indirect github.com/dustin/go-humanize v1.0.0 // indirect
github.com/fatih/color v1.7.0 // indirect github.com/fatih/color v1.7.0 // indirect
github.com/gabriel-vasile/mimetype v1.4.1 // indirect github.com/gabriel-vasile/mimetype v1.4.1
github.com/go-chi/chi/v5 v5.0.8 // indirect github.com/go-chi/chi/v5 v5.0.8
github.com/go-sourcemap/sourcemap v2.1.3+incompatible // indirect github.com/go-sourcemap/sourcemap v2.1.3+incompatible // indirect
github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e // indirect github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e // indirect
github.com/google/uuid v1.3.0 // indirect github.com/google/uuid v1.3.0 // indirect
github.com/gorilla/websocket v1.4.2 // indirect github.com/gorilla/websocket v1.4.2 // indirect
github.com/igm/sockjs-go/v3 v3.0.2 // indirect github.com/igm/sockjs-go/v3 v3.0.2
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 // indirect github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 // indirect
github.com/mattn/go-colorable v0.1.4 // indirect github.com/mattn/go-colorable v0.1.4 // indirect
github.com/mattn/go-isatty v0.0.16 // indirect github.com/mattn/go-isatty v0.0.16 // indirect
github.com/mitchellh/mapstructure v1.5.0 // indirect github.com/mitchellh/mapstructure v1.5.0
github.com/oklog/ulid/v2 v2.1.0 // indirect github.com/oklog/ulid/v2 v2.1.0
github.com/orcaman/concurrent-map v1.0.0 // indirect github.com/orcaman/concurrent-map v1.0.0
github.com/pkg/errors v0.9.1 // indirect github.com/pkg/errors v0.9.1
github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0 // indirect github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0 // indirect
github.com/russross/blackfriday/v2 v2.1.0 // indirect github.com/russross/blackfriday/v2 v2.1.0 // indirect
github.com/spf13/afero v1.9.3 // indirect github.com/spf13/afero v1.9.3 // indirect
github.com/urfave/cli/v2 v2.24.3 // indirect github.com/urfave/cli/v2 v2.24.3
github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 // indirect github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 // indirect
gitlab.com/wpetit/goweb v0.0.0-20230206085656-dec695f0e2e9 // indirect gitlab.com/wpetit/goweb v0.0.0-20230206085656-dec695f0e2e9
go.opencensus.io v0.22.5 // indirect go.opencensus.io v0.22.5 // indirect
golang.org/x/crypto v0.0.0-20211108221036-ceb1ce70b4fa // indirect golang.org/x/crypto v0.7.0 // indirect
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4 // indirect golang.org/x/mod v0.8.0 // indirect
golang.org/x/net v0.4.0 // indirect golang.org/x/net v0.8.0 // indirect
golang.org/x/sys v0.3.0 // indirect golang.org/x/sys v0.6.0 // indirect
golang.org/x/term v0.3.0 // indirect golang.org/x/term v0.6.0 // indirect
golang.org/x/text v0.5.0 // indirect golang.org/x/text v0.8.0 // indirect
golang.org/x/tools v0.1.12 // indirect golang.org/x/tools v0.6.0 // indirect
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v2 v2.4.0
lukechampine.com/uint128 v1.2.0 // indirect lukechampine.com/uint128 v1.2.0 // indirect
modernc.org/cc/v3 v3.40.0 // indirect modernc.org/cc/v3 v3.40.0 // indirect
modernc.org/ccgo/v3 v3.16.13 // indirect modernc.org/ccgo/v3 v3.16.13 // indirect

42
go.sum
View File

@ -72,6 +72,9 @@ github.com/davecgh/go-spew v1.0.1-0.20160907170601-6d212800a42e/go.mod h1:J7Y8Yc
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/decred/dcrd/crypto/blake256 v1.0.0/go.mod h1:sQl2p6Y26YV+ZOcSTP6thNdn47hh8kt6rqSlvmrXFAc=
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.1.0 h1:HbphB4TFFXpv7MNrT52FGrrgVXF1owhMVTHFZIlnvd4=
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.1.0/go.mod h1:DZGJHZMqrU4JJqFAWUS2UO1+lbSKsdiOoYi9Zzey7Fc=
github.com/dlclark/regexp2 v1.1.6/go.mod h1:2pZnwuY/m+8K6iRw6wQdMtk+rH5tNGR1i55kozfMjCc= github.com/dlclark/regexp2 v1.1.6/go.mod h1:2pZnwuY/m+8K6iRw6wQdMtk+rH5tNGR1i55kozfMjCc=
github.com/dlclark/regexp2 v1.2.0 h1:8sAhBGEM0dRWogWqWyQeIJnxjWO6oIjl8FKqREDsGfk= github.com/dlclark/regexp2 v1.2.0 h1:8sAhBGEM0dRWogWqWyQeIJnxjWO6oIjl8FKqREDsGfk=
github.com/dlclark/regexp2 v1.2.0/go.mod h1:2pZnwuY/m+8K6iRw6wQdMtk+rH5tNGR1i55kozfMjCc= github.com/dlclark/regexp2 v1.2.0/go.mod h1:2pZnwuY/m+8K6iRw6wQdMtk+rH5tNGR1i55kozfMjCc=
@ -108,6 +111,8 @@ github.com/go-playground/locales v0.12.1/go.mod h1:IUMDtCfWo/w/mtMfIE/IG2K+Ey3yg
github.com/go-playground/universal-translator v0.16.0/go.mod h1:1AnU7NaIRDWWzGEKwgtJRd2xk99HeFyHw3yid4rvQIY= github.com/go-playground/universal-translator v0.16.0/go.mod h1:1AnU7NaIRDWWzGEKwgtJRd2xk99HeFyHw3yid4rvQIY=
github.com/go-sourcemap/sourcemap v2.1.3+incompatible h1:W1iEw64niKVGogNgBN3ePyLFfuisuzeidWPMPWmECqU= github.com/go-sourcemap/sourcemap v2.1.3+incompatible h1:W1iEw64niKVGogNgBN3ePyLFfuisuzeidWPMPWmECqU=
github.com/go-sourcemap/sourcemap v2.1.3+incompatible/go.mod h1:F8jJfvm2KbVjc5NqelyYJmf/v5J0dwNLS2mL4sNA1Jg= github.com/go-sourcemap/sourcemap v2.1.3+incompatible/go.mod h1:F8jJfvm2KbVjc5NqelyYJmf/v5J0dwNLS2mL4sNA1Jg=
github.com/goccy/go-json v0.9.11 h1:/pAaQDLHEoCq/5FFmSKBswWmK6H0e8g4159Kc/X/nqk=
github.com/goccy/go-json v0.9.11/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
github.com/gogo/protobuf v0.0.0-20161014173244-50d1bd39ce4e h1:eeyMpoxANuWNQ9O2auv4wXxJsrXzLUhdHaOmNWEGkRY= github.com/gogo/protobuf v0.0.0-20161014173244-50d1bd39ce4e h1:eeyMpoxANuWNQ9O2auv4wXxJsrXzLUhdHaOmNWEGkRY=
github.com/gogo/protobuf v0.0.0-20161014173244-50d1bd39ce4e/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/gogo/protobuf v0.0.0-20161014173244-50d1bd39ce4e/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
github.com/golang-jwt/jwt v3.2.2+incompatible h1:IfV12K8xAKAnZqdXVzCZ+TOjboZ2keLg81eXfW3O+oY= github.com/golang-jwt/jwt v3.2.2+incompatible h1:IfV12K8xAKAnZqdXVzCZ+TOjboZ2keLg81eXfW3O+oY=
@ -204,6 +209,18 @@ github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/leodido/go-urn v1.1.0/go.mod h1:+cyI34gQWZcE1eQU7NVgKkkzdXDQHr1dBMtdAPozLkw= github.com/leodido/go-urn v1.1.0/go.mod h1:+cyI34gQWZcE1eQU7NVgKkkzdXDQHr1dBMtdAPozLkw=
github.com/lestrrat-go/blackmagic v1.0.1 h1:lS5Zts+5HIC/8og6cGHb0uCcNCa3OUt1ygh3Qz2Fe80=
github.com/lestrrat-go/blackmagic v1.0.1/go.mod h1:UrEqBzIR2U6CnzVyUtfM6oZNMt/7O7Vohk2J0OGSAtU=
github.com/lestrrat-go/httpcc v1.0.1 h1:ydWCStUeJLkpYyjLDHihupbn2tYmZ7m22BGkcvZZrIE=
github.com/lestrrat-go/httpcc v1.0.1/go.mod h1:qiltp3Mt56+55GPVCbTdM9MlqhvzyuL6W/NMDA8vA5E=
github.com/lestrrat-go/httprc v1.0.4 h1:bAZymwoZQb+Oq8MEbyipag7iSq6YIga8Wj6GOiJGdI8=
github.com/lestrrat-go/httprc v1.0.4/go.mod h1:mwwz3JMTPBjHUkkDv/IGJ39aALInZLrhBp0X7KGUZlo=
github.com/lestrrat-go/iter v1.0.2 h1:gMXo1q4c2pHmC3dn8LzRhJfP1ceCbgSiT9lUydIzltI=
github.com/lestrrat-go/iter v1.0.2/go.mod h1:Momfcq3AnRlRjI5b5O8/G5/BvpzrhoFTZcn06fEOPt4=
github.com/lestrrat-go/jwx/v2 v2.0.8 h1:jCFT8oc0hEDVjgUgsBy1F9cbjsjAVZSXNi7JaU9HR/Q=
github.com/lestrrat-go/jwx/v2 v2.0.8/go.mod h1:zLxnyv9rTlEvOUHbc48FAfIL8iYu2hHvIRaTFGc8mT0=
github.com/lestrrat-go/option v1.0.0 h1:WqAWL8kh8VcSoD6xjSH34/1m8yxluXQbDeKNfvFeEO4=
github.com/lestrrat-go/option v1.0.0/go.mod h1:5ZHFbivi4xwXxhxY9XHDe2FHo6/Z7WWmtT7T5nBBp3I=
github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
github.com/mattn/go-colorable v0.1.4 h1:snbPLB8fVfU9iwbbo30TPtbLRzwWu6aJS6Xh4eaaviA= github.com/mattn/go-colorable v0.1.4 h1:snbPLB8fVfU9iwbbo30TPtbLRzwWu6aJS6Xh4eaaviA=
github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
@ -243,12 +260,18 @@ github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAm
github.com/spf13/afero v1.9.3 h1:41FoI0fD7OR7mGcKE/aOiLkGreyf8ifIOQmJANWogMk= github.com/spf13/afero v1.9.3 h1:41FoI0fD7OR7mGcKE/aOiLkGreyf8ifIOQmJANWogMk=
github.com/spf13/afero v1.9.3/go.mod h1:iUV7ddyEEZPO5gA3zD4fJt6iStLlL+Lg4m2cihcDf8Y= github.com/spf13/afero v1.9.3/go.mod h1:iUV7ddyEEZPO5gA3zD4fJt6iStLlL+Lg4m2cihcDf8Y=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
github.com/stretchr/testify v1.1.5-0.20160925220609-976c720a22c8/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.1.5-0.20160925220609-976c720a22c8/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA= github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA=
github.com/urfave/cli/v2 v2.24.3 h1:7Q1w8VN8yE0MJEHP06bv89PjYsN4IHWED2s1v/Zlfm0= github.com/urfave/cli/v2 v2.24.3 h1:7Q1w8VN8yE0MJEHP06bv89PjYsN4IHWED2s1v/Zlfm0=
github.com/urfave/cli/v2 v2.24.3/go.mod h1:GHupkWPMM0M/sj1a2b4wUrWBPzazNrIjouW6fmdJLxc= github.com/urfave/cli/v2 v2.24.3/go.mod h1:GHupkWPMM0M/sj1a2b4wUrWBPzazNrIjouW6fmdJLxc=
@ -280,6 +303,10 @@ golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.0.0-20211108221036-ceb1ce70b4fa h1:idItI2DDfCokpg0N51B2VtiLdJ4vAuXC9fnCb2gACo4= golang.org/x/crypto v0.0.0-20211108221036-ceb1ce70b4fa h1:idItI2DDfCokpg0N51B2VtiLdJ4vAuXC9fnCb2gACo4=
golang.org/x/crypto v0.0.0-20211108221036-ceb1ce70b4fa/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20211108221036-ceb1ce70b4fa/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.0.0-20220427172511-eb4f295cb31f h1:OeJjE6G4dgCY4PIXvIRQbE8+RX+uXZyGhUy/ksMGJoc=
golang.org/x/crypto v0.0.0-20220427172511-eb4f295cb31f/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/crypto v0.7.0 h1:AvwMYaRytfdeVt3u6mLaxYtErKYjxA2OXjJ1HHq6t3A=
golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
@ -315,6 +342,8 @@ golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4 h1:6zppjxzCulZykYSLyVDYbneBfbaBIQPYMevg0bEwv2s= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4 h1:6zppjxzCulZykYSLyVDYbneBfbaBIQPYMevg0bEwv2s=
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
golang.org/x/mod v0.8.0 h1:LUYupSeNrTNCGzR/hVBk2NHZO4hXcVaW1k4Qx7rjPx8=
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
golang.org/x/net v0.0.0-20161013035702-8b4af36cd21a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20161013035702-8b4af36cd21a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
@ -347,10 +376,13 @@ golang.org/x/net v0.0.0-20201031054903-ff519b6c9102/go.mod h1:sp8m0HH+o8qH0wwXwY
golang.org/x/net v0.0.0-20201209123823-ac852fbbde11/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20201209123823-ac852fbbde11/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20220624214902-1bab6f366d9e/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.0.0-20220624214902-1bab6f366d9e/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
golang.org/x/net v0.4.0 h1:Q5QPcMlvfxFTAPV0+07Xz/MpK9NTXu2VDUuy0FeMfaU= golang.org/x/net v0.4.0 h1:Q5QPcMlvfxFTAPV0+07Xz/MpK9NTXu2VDUuy0FeMfaU=
golang.org/x/net v0.4.0/go.mod h1:MBQ8lrhLObU/6UmLb4fmbmk5OcyYmqtbGd/9yIeKjEE= golang.org/x/net v0.4.0/go.mod h1:MBQ8lrhLObU/6UmLb4fmbmk5OcyYmqtbGd/9yIeKjEE=
golang.org/x/net v0.8.0 h1:Zrh2ngAOFYneWTAIAPethzeaQLuHwhuBkuV6ZiRnUaQ=
golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
@ -407,6 +439,7 @@ golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210225134936-a50acf3fe073/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210225134936-a50acf3fe073/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1 h1:SrN+KX8Art/Sf4HNj6Zcz06G7VEz+7w9tdXTPOZ7+l4= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1 h1:SrN+KX8Art/Sf4HNj6Zcz06G7VEz+7w9tdXTPOZ7+l4=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
@ -415,11 +448,15 @@ golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBc
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.3.0 h1:w8ZOecv6NaNa/zC8944JTU3vz4u6Lagfk4RPQxv92NQ= golang.org/x/sys v0.3.0 h1:w8ZOecv6NaNa/zC8944JTU3vz4u6Lagfk4RPQxv92NQ=
golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0 h1:MVltZSvRTcU2ljQOhs94SXPftV6DCNnZViHeQps87pQ=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1 h1:v+OssWQX+hTHEmOBgwxdZxK4zHq3yOs8F9J7mk0PY8E= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1 h1:v+OssWQX+hTHEmOBgwxdZxK4zHq3yOs8F9J7mk0PY8E=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/term v0.3.0 h1:qoo4akIqOcDME5bhc/NgxUdovd6BSS2uMsVjB56q1xI= golang.org/x/term v0.3.0 h1:qoo4akIqOcDME5bhc/NgxUdovd6BSS2uMsVjB56q1xI=
golang.org/x/term v0.3.0/go.mod h1:q750SLmJuPmVoN1blW3UFBPREJfb1KmY3vwxfr+nFDA= golang.org/x/term v0.3.0/go.mod h1:q750SLmJuPmVoN1blW3UFBPREJfb1KmY3vwxfr+nFDA=
golang.org/x/term v0.6.0 h1:clScbb1cHjoCkyRbWwBEUZ5H/tIFu5TAXIqaZD0Gcjw=
golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U=
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
@ -432,6 +469,8 @@ golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/text v0.5.0 h1:OLmvp0KP+FVG99Ct/qFiL/Fhk4zp4QQnZ7b2U+5piUM= golang.org/x/text v0.5.0 h1:OLmvp0KP+FVG99Ct/qFiL/Fhk4zp4QQnZ7b2U+5piUM=
golang.org/x/text v0.5.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.5.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/text v0.8.0 h1:57P1ETyNKtuIjB4SRd15iJxuhj8Gc416Y78H3qgMh68=
golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
@ -484,6 +523,8 @@ golang.org/x/tools v0.0.0-20210108195828-e2f9c7f1fc8e/go.mod h1:emZCQorbCU4vsT4f
golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0=
golang.org/x/tools v0.1.12 h1:VveCTK38A2rkS8ZqFY25HIDFscX5X9OoEhJd3quQmXU= golang.org/x/tools v0.1.12 h1:VveCTK38A2rkS8ZqFY25HIDFscX5X9OoEhJd3quQmXU=
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
golang.org/x/tools v0.6.0 h1:BOw41kyTf3PuCW1pVQf8+Cyg8pMlkYB1oo9iJ6D/lKM=
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
@ -587,6 +628,7 @@ gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=

View File

@ -4,7 +4,7 @@
<meta charset="utf-8" /> <meta charset="utf-8" />
<title>Client SDK Test suite</title> <title>Client SDK Test suite</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" />
<link rel="stylesheet" href="vendor/mocha.css" /> <link rel="stylesheet" href="/vendor/mocha.css" />
<style> <style>
body { body {
background-color: white; background-color: white;
@ -13,15 +13,18 @@
</head> </head>
<body> <body>
<div id="mocha"></div> <div id="mocha"></div>
<script src="vendor/chai.js"></script> <script src="/vendor/chai.js"></script>
<script src="vendor/mocha.js"></script> <script src="/vendor/mocha.js"></script>
<script class="mocha-init"> <script class="mocha-init">
mocha.setup('bdd'); mocha.setup('bdd');
mocha.checkLeaks(); mocha.checkLeaks();
</script> </script>
<script src="/edge/sdk/client.js"></script> <script src="/edge/sdk/client.js"></script>
<script src="test/client-sdk.js"></script> <script src="/test/client-sdk.js"></script>
<script src="test/auth-module.js"></script> <script src="/test/auth-module.js"></script>
<script src="/test/net-module.js"></script>
<script src="/test/rpc-module.js"></script>
<script src="/test/file-module.js"></script>
<script class="mocha-exec"> <script class="mocha-exec">
mocha.run(); mocha.run();
</script> </script>

View File

@ -11,9 +11,10 @@ describe('Auth Module', function() {
it('should retrieve user informations', function() { it('should retrieve user informations', function() {
return Edge.rpc("getUserInfo") return Edge.rpc("getUserInfo")
.then(userInfo => { .then(userInfo => {
chai.assert.isNotNull(userInfo.subject); console.log("getUserInfo result:", userInfo);
chai.assert.isNotNull(userInfo.role); chai.assert.property(userInfo, 'subject');
chai.assert.isNotNull(userInfo.preferredUsername); chai.assert.property(userInfo, 'role');
chai.assert.property(userInfo, 'preferredUsername');
}) })
}); });

View File

@ -22,127 +22,4 @@ describe('Edge', function() {
}); });
}); });
describe('#send()', function() {
this.timeout(5000);
before(() => {
return Edge.connect();
});
after(() => {
Edge.disconnect();
});
it('should send a message to the server and echo back', function(done) {
const now = new Date();
const handler = evt => {
chai.assert.equal(evt.detail.now, now.toJSON());
Edge.removeEventListener('message', handler);
done();
}
// Server should echo back message
Edge.addEventListener('message', handler);
// Send message to server
Edge.send({ now });
});
});
});
describe('Remote Procedure Call', function() {
before(() => {
return Edge.connect();
});
after(() => {
Edge.disconnect();
});
it('should call the remote echo() method and resolve the returned value', function() {
const foo = "bar";
return Edge.rpc('echo', { foo })
.then(result => {
chai.assert.equal(result.foo, foo);
});
});
it('should call the remote throwErrorFromClient() method and reject with an error', function() {
return Edge.rpc('throwErrorFromClient')
.catch(err => {
// Assert that it's an "internal" error
// See https://www.jsonrpc.org/specification#error_object
chai.assert.equal(err.code, -32603);
});
});
it('should call an unregistered method and reject with an error', function() {
return Edge.rpc('unregisteredMethod')
.catch(err => {
// Assert that it's an "method not found" error
// See https://www.jsonrpc.org/specification#error_object
chai.assert.equal(err.code, -32601);
});
});
it('should call the add() method repetitively and keep count of the sent values', function() {
this.timeout(10000);
const values = [];
for(let i = 0; i <= 1000; i++) {
values.push((Math.random() * 1000 | 0));
}
return Edge.rpc('reset')
.then(() => {
return Promise.all(values.map(v => Edge.rpc("add", {value: v})));
})
.then(() => Edge.rpc('total'))
.then(remoteTotal => {
const localTotal = values.reduce((t, v) => t+v);
console.log("Remote total:", remoteTotal, "Local total:", localTotal);
chai.assert.equal(remoteTotal, localTotal)
})
});
});
describe('File Module', function() {
before(() => {
return Edge.connect();
});
after(() => {
Edge.disconnect();
});
it('should upload then download a blob', function() {
const content = JSON.stringify({"date": new Date()});
const blob = new Blob([content], {type: "application/json"});
return Edge.upload(blob)
.then(upload => upload.result())
.then(result => {
chai.assert.isNotEmpty(result.blobId);
chai.assert.isNotEmpty(result.bucket);
const blobUrl = Edge.blobUrl(result.bucket, result.blobId);
chai.assert.isNotEmpty(blobUrl);
return fetch(blobUrl)
.then(res => res.text())
.then(blobContent => {
chai.assert.equal(content, blobContent);
});
})
.catch(err => {
chai.assert.fail(err);
})
});
}); });

View File

@ -0,0 +1,36 @@
describe('File Module', function () {
before(() => {
return Edge.connect();
});
after(() => {
Edge.disconnect();
});
it('should upload then download a blob', function () {
const content = JSON.stringify({ "date": new Date() });
const blob = new Blob([content], { type: "application/json" });
return Edge.upload(blob)
.then(upload => upload.result())
.then(result => {
chai.assert.isNotEmpty(result.blobId);
chai.assert.isNotEmpty(result.bucket);
const blobUrl = Edge.blobUrl(result.bucket, result.blobId);
chai.assert.isNotEmpty(blobUrl);
return fetch(blobUrl)
.then(res => res.text())
.then(blobContent => {
chai.assert.equal(content, blobContent);
});
})
.catch(err => {
chai.assert.fail(err);
})
});
});

View File

@ -0,0 +1,49 @@
describe('Net Module', function () {
this.timeout(5000);
before(() => {
return Edge.connect();
});
after(() => {
Edge.disconnect();
});
it('should broadcast a message from server', function (done) {
const message = { test: 'broadcast', now: Date.now() };
const handler = (evt) => {
const receivedMessage = evt.detail;
if (receivedMessage.test !== 'broadcast') return;
chai.assert.deepEqual(message, evt.detail);
Edge.removeEventListener('message', handler);
done();
};
Edge.addEventListener("message", handler);
Edge.send(message);
});
it('should send a message to the server and echo back', function(done) {
const now = new Date();
const handler = evt => {
const receivedMessage = evt.detail;
if (receivedMessage.test !== 'echo') return;
chai.assert.equal(receivedMessage.now, now.toJSON());
Edge.removeEventListener('message', handler);
done();
}
// Server should echo back message
Edge.addEventListener('message', handler);
// Send message to server
Edge.send({ test: 'echo', now });
});
});

View File

@ -0,0 +1,59 @@
describe('Remote Procedure Call', function () {
before(() => {
return Edge.connect();
});
after(() => {
Edge.disconnect();
});
it('should call the remote echo() method and resolve the returned value', function () {
const foo = "bar";
return Edge.rpc('echo', { foo })
.then(result => {
console.log(result);
chai.assert.equal(result.foo, foo);
});
});
it('should call the remote throwErrorFromClient() method and reject with an error', function () {
return Edge.rpc('throwErrorFromClient')
.catch(err => {
// Assert that it's an "internal" error
// See https://www.jsonrpc.org/specification#error_object
chai.assert.equal(err.code, -32603);
});
});
it('should call an unregistered method and reject with an error', function () {
return Edge.rpc('unregisteredMethod')
.catch(err => {
// Assert that it's an "method not found" error
// See https://www.jsonrpc.org/specification#error_object
chai.assert.equal(err.code, -32601);
});
});
it('should call the add() method repetitively and keep count of the sent values', function () {
this.timeout(10000);
const values = [];
for (let i = 0; i <= 1000; i++) {
values.push((Math.random() * 1000 | 0));
}
return Edge.rpc('reset')
.then(() => {
return Promise.all(values.map(v => Edge.rpc("add", { value: v })));
})
.then(() => Edge.rpc('total'))
.then(remoteTotal => {
const localTotal = values.reduce((t, v) => t + v);
console.log("Remote total:", remoteTotal, "Local total:", localTotal);
chai.assert.equal(remoteTotal, localTotal)
})
});
});

View File

@ -14,9 +14,16 @@ function onInit() {
} }
// Called for each client message // Called for each client message
function onClientMessage(ctx, data) { function onClientMessage(ctx, message) {
console.log("onClientMessage", data.now); console.log("onClientMessage", message);
net.send(ctx, { now: data.now });
switch (message.test) {
case "broadcast":
net.broadcast(message);
break;
default:
net.send(ctx, message);
}
} }
// Called for each blob upload request // Called for each blob upload request

View File

@ -1,6 +1,7 @@
**/*.go **/*.go
pkg/app/sdk/client/src/**/*.js **/*.tmpl
pkg/app/sdk/client/src/**/*.ts pkg/sdk/client/src/**/*.js
pkg/sdk/client/src/**/*.ts
misc/client-sdk-testsuite/src/**/* misc/client-sdk-testsuite/src/**/*
modd.conf modd.conf
{ {
@ -8,5 +9,5 @@ modd.conf
prep: cd misc/client-sdk-testsuite && make dist prep: cd misc/client-sdk-testsuite && make dist
prep: make GOTEST_ARGS="-short" test prep: make GOTEST_ARGS="-short" test
prep: make build prep: make build
daemon: bin/cli app run -p misc/client-sdk-testsuite/dist --storage-file ./sdk-testsuite.sqlite daemon: bin/cli app run -p misc/client-sdk-testsuite/dist
} }

View File

@ -1,5 +1,11 @@
package app package app
import (
"forge.cadoles.com/arcad/edge/pkg/bundle"
"github.com/pkg/errors"
"gopkg.in/yaml.v2"
)
type ID string type ID string
type Manifest struct { type Manifest struct {
@ -10,7 +16,24 @@ type Manifest struct {
Tags []string `yaml:"tags"` Tags []string `yaml:"tags"`
} }
type App struct { func LoadManifest(b bundle.Bundle) (*Manifest, error) {
ID ID reader, _, err := b.File("manifest.yml")
Manifest *Manifest if err != nil {
return nil, errors.Wrap(err, "could not read manifest.yml")
}
defer func() {
if err := reader.Close(); err != nil {
panic(errors.WithStack(err))
}
}()
manifest := &Manifest{}
decoder := yaml.NewDecoder(reader)
if err := decoder.Decode(manifest); err != nil {
return nil, errors.Wrap(err, "could not decode manifest.yml")
}
return manifest, nil
} }

View File

@ -1,101 +0,0 @@
package app
import (
"context"
"path/filepath"
"gitlab.com/wpetit/goweb/logger"
"gopkg.in/yaml.v2"
"forge.cadoles.com/arcad/edge/pkg/bundle"
"github.com/pkg/errors"
)
type FilesystemLoader struct {
searchPatterns []string
}
type LoadedApp struct {
App *App
Bundle bundle.Bundle
}
func (l *FilesystemLoader) Load(ctx context.Context) ([]*LoadedApp, error) {
apps := make([]*LoadedApp, 0)
for _, seachPattern := range l.searchPatterns {
absSearchPattern, err := filepath.Abs(seachPattern)
if err != nil {
return nil, errors.Wrapf(err, "could not generate absolute path for '%s'", seachPattern)
}
logger.Debug(ctx, "searching apps in filesystem", logger.F("searchPattern", absSearchPattern))
files, err := filepath.Glob(absSearchPattern)
if err != nil {
return nil, errors.Wrapf(err, "could not search files with pattern '%s'", absSearchPattern)
}
for _, f := range files {
loopCtx := logger.With(ctx, logger.F("file", f))
logger.Debug(loopCtx, "found app bundle")
b, err := bundle.FromPath(f)
if err != nil {
logger.Error(loopCtx, "could not load bundle", logger.E(errors.WithStack(err)))
continue
}
logger.Debug(loopCtx, "loading app manifest")
appManifest, err := LoadAppManifest(b)
if err != nil {
logger.Error(loopCtx, "could not load app manifest", logger.E(errors.WithStack(err)))
continue
}
g := &App{
ID: appManifest.ID,
Manifest: appManifest,
}
apps = append(apps, &LoadedApp{
App: g,
Bundle: b,
})
}
}
return apps, nil
}
func NewFilesystemLoader(searchPatterns ...string) *FilesystemLoader {
return &FilesystemLoader{
searchPatterns: searchPatterns,
}
}
func LoadAppManifest(b bundle.Bundle) (*Manifest, error) {
reader, _, err := b.File("manifest.yml")
if err != nil {
return nil, errors.Wrap(err, "could not read manifest.yml")
}
defer func() {
if err := reader.Close(); err != nil {
panic(errors.WithStack(err))
}
}()
manifest := &Manifest{}
decoder := yaml.NewDecoder(reader)
if err := decoder.Decode(manifest); err != nil {
return nil, errors.Wrap(err, "could not decode manifest.yml")
}
return manifest, nil
}

View File

@ -1,15 +1,20 @@
package app package app
import ( import (
"context"
"math/rand" "math/rand"
"sync" "sync"
"github.com/dop251/goja" "github.com/dop251/goja"
"github.com/dop251/goja_nodejs/eventloop" "github.com/dop251/goja_nodejs/eventloop"
"github.com/pkg/errors" "github.com/pkg/errors"
"gitlab.com/wpetit/goweb/logger"
) )
var ErrFuncDoesNotExist = errors.New("function does not exist") var (
ErrFuncDoesNotExist = errors.New("function does not exist")
ErUnknownError = errors.New("unknown error")
)
type Server struct { type Server struct {
runtime *goja.Runtime runtime *goja.Runtime
@ -26,16 +31,18 @@ func (s *Server) Load(name string, src string) error {
return nil return nil
} }
func (s *Server) ExecFuncByName(funcName string, args ...interface{}) (goja.Value, error) { func (s *Server) ExecFuncByName(ctx context.Context, funcName string, args ...interface{}) (goja.Value, error) {
ctx = logger.With(ctx, logger.F("function", funcName), logger.F("args", args))
callable, ok := goja.AssertFunction(s.runtime.Get(funcName)) callable, ok := goja.AssertFunction(s.runtime.Get(funcName))
if !ok { if !ok {
return nil, errors.WithStack(ErrFuncDoesNotExist) return nil, errors.WithStack(ErrFuncDoesNotExist)
} }
return s.Exec(callable, args...) return s.Exec(ctx, callable, args...)
} }
func (s *Server) Exec(callable goja.Callable, args ...interface{}) (goja.Value, error) { func (s *Server) Exec(ctx context.Context, callable goja.Callable, args ...interface{}) (goja.Value, error) {
var ( var (
wg sync.WaitGroup wg sync.WaitGroup
value goja.Value value goja.Value
@ -45,6 +52,25 @@ func (s *Server) Exec(callable goja.Callable, args ...interface{}) (goja.Value,
wg.Add(1) wg.Add(1)
s.loop.RunOnLoop(func(vm *goja.Runtime) { s.loop.RunOnLoop(func(vm *goja.Runtime) {
logger.Debug(ctx, "executing callable")
defer wg.Done()
defer func() {
if recovered := recover(); recovered != nil {
revoveredErr, ok := recovered.(error)
if ok {
logger.Error(ctx, "recovered runtime error", logger.E(errors.WithStack(revoveredErr)))
err = errors.WithStack(ErUnknownError)
return
}
panic(recovered)
}
}()
jsArgs := make([]goja.Value, 0, len(args)) jsArgs := make([]goja.Value, 0, len(args))
for _, a := range args { for _, a := range args {
jsArgs = append(jsArgs, vm.ToValue(a)) jsArgs = append(jsArgs, vm.ToValue(a))
@ -54,8 +80,6 @@ func (s *Server) Exec(callable goja.Callable, args ...interface{}) (goja.Value,
if err != nil { if err != nil {
err = errors.WithStack(err) err = errors.WithStack(err)
} }
wg.Done()
}) })
wg.Wait() wg.Wait()

View File

@ -99,3 +99,5 @@ func (f *File) Readdir(count int) ([]os.FileInfo, error) {
func (f *File) Stat() (os.FileInfo, error) { func (f *File) Stat() (os.FileInfo, error) {
return f.fi, nil return f.fi, nil
} }
var _ http.FileSystem = &FileSystem{}

View File

@ -59,7 +59,7 @@ func (h *Handler) Load(bdle bundle.Bundle) error {
} }
fs := bundle.NewFileSystem("public", bdle) fs := bundle.NewFileSystem("public", bdle)
public := http.FileServer(fs) public := HTML5Fileserver(fs)
sockjs := sockjs.NewHandler(sockJSPathPrefix, h.sockjsOpts, h.handleSockJSSession) sockjs := sockjs.NewHandler(sockJSPathPrefix, h.sockjsOpts, h.handleSockJSSession)
if h.server != nil { if h.server != nil {

View File

@ -0,0 +1,54 @@
package http
import (
"net/http"
"os"
"path"
"strings"
"github.com/pkg/errors"
"gitlab.com/wpetit/goweb/logger"
)
func HTML5Fileserver(fs http.FileSystem) http.Handler {
handler := http.FileServer(fs)
fn := func(w http.ResponseWriter, r *http.Request) {
urlPath := r.URL.Path
if !strings.HasPrefix(urlPath, "/") {
urlPath = "/" + urlPath
r.URL.Path = urlPath
}
urlPath = path.Clean(urlPath)
file, err := fs.Open(urlPath)
if err != nil {
if errors.Is(err, os.ErrNotExist) {
r.URL.Path = "/"
handler.ServeHTTP(w, r)
return
}
logger.Error(r.Context(), "could not open bundle file", logger.E(err))
http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
return
}
defer func() {
if err := file.Close(); err != nil {
logger.Error(r.Context(), "could not close file", logger.E(err))
http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
return
}
}()
handler.ServeHTTP(w, r)
}
return http.HandlerFunc(fn)
}

View File

@ -0,0 +1,35 @@
package http
import (
"time"
"github.com/lestrrat-go/jwx/v2/jwa"
"github.com/lestrrat-go/jwx/v2/jwk"
"github.com/lestrrat-go/jwx/v2/jwt"
"github.com/pkg/errors"
)
func generateSignedToken(algo jwa.KeyAlgorithm, key jwk.Key, claims map[string]any) ([]byte, error) {
token := jwt.New()
if err := token.Set(jwt.NotBeforeKey, time.Now()); err != nil {
return nil, errors.WithStack(err)
}
for key, value := range claims {
if err := token.Set(key, value); err != nil {
return nil, errors.Wrapf(err, "could not set claim '%s' with value '%v'", key, value)
}
}
if err := token.Set(jwk.AlgorithmKey, jwa.HS256); err != nil {
return nil, errors.WithStack(err)
}
rawToken, err := jwt.Sign(token, jwt.WithKey(algo, key))
if err != nil {
return nil, errors.WithStack(err)
}
return rawToken, nil
}

View File

@ -0,0 +1,27 @@
package http
import "forge.cadoles.com/arcad/edge/pkg/module/auth/http/passwd"
type LocalAccount struct {
Username string `json:"username"`
Algo passwd.Algo `json:"algo"`
Password string `json:"password"`
Claims map[string]any `json:"claims"`
}
func NewLocalAccount(username, password string, algo passwd.Algo, claims map[string]any) LocalAccount {
return LocalAccount{
Username: username,
Password: password,
Algo: algo,
Claims: claims,
}
}
func toAccountsMap(accounts []LocalAccount) map[string]LocalAccount {
accountsMap := make(map[string]LocalAccount)
for _, acc := range accounts {
accountsMap[acc.Username] = acc
}
return accountsMap
}

View File

@ -0,0 +1,183 @@
package http
import (
"html/template"
"net/http"
"time"
_ "embed"
"forge.cadoles.com/arcad/edge/pkg/module/auth"
"forge.cadoles.com/arcad/edge/pkg/module/auth/http/passwd"
"github.com/go-chi/chi/v5"
"github.com/lestrrat-go/jwx/v2/jwa"
"github.com/lestrrat-go/jwx/v2/jwk"
"github.com/pkg/errors"
"gitlab.com/wpetit/goweb/logger"
)
//go:embed templates/login.html.tmpl
var rawLoginTemplate string
var loginTemplate *template.Template
var (
errNotFound = errors.New("not found")
errInvalidPassword = errors.New("invalid password")
)
func init() {
loginTemplate = template.Must(template.New("").Parse(rawLoginTemplate))
}
type LocalHandler struct {
router chi.Router
algo jwa.KeyAlgorithm
key jwk.Key
accounts map[string]LocalAccount
}
func (h *LocalHandler) initRouter(prefix string) {
router := chi.NewRouter()
router.Route(prefix, func(r chi.Router) {
r.Get("/login", h.serveForm)
r.Post("/login", h.handleForm)
r.Get("/logout", h.handleLogout)
})
h.router = router
}
type loginTemplateData struct {
URL string
Username string
Password string
Message string
}
func (h *LocalHandler) serveForm(w http.ResponseWriter, r *http.Request) {
ctx := r.Context()
data := loginTemplateData{
URL: r.URL.String(),
Username: "",
Password: "",
Message: "",
}
if err := loginTemplate.Execute(w, data); err != nil {
logger.Error(ctx, "could not execute login page template", logger.E(errors.WithStack(err)))
}
}
func (h *LocalHandler) handleForm(w http.ResponseWriter, r *http.Request) {
ctx := r.Context()
if err := r.ParseForm(); err != nil {
logger.Error(ctx, "could not parse form", logger.E(errors.WithStack(err)))
http.Error(w, http.StatusText(http.StatusBadRequest), http.StatusBadRequest)
return
}
username := r.Form.Get("username")
password := r.Form.Get("password")
data := loginTemplateData{
URL: r.URL.String(),
Username: username,
Password: password,
Message: "",
}
account, err := h.authenticate(username, password)
if err != nil {
if errors.Is(err, errNotFound) || errors.Is(err, errInvalidPassword) {
data.Message = "Invalid username or password."
if err := loginTemplate.Execute(w, data); err != nil {
logger.Error(ctx, "could not execute login page template", logger.E(errors.WithStack(err)))
}
return
}
logger.Error(ctx, "could not authenticate account", logger.E(errors.WithStack(err)))
http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
return
}
token, err := generateSignedToken(h.algo, h.key, account.Claims)
if err != nil {
logger.Error(ctx, "could not generate signed token", logger.E(errors.WithStack(err)))
http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
return
}
cookie := http.Cookie{
Name: auth.CookieName,
Value: string(token),
HttpOnly: false,
Path: "/",
}
http.SetCookie(w, &cookie)
http.Redirect(w, r, "/", http.StatusSeeOther)
}
func (h *LocalHandler) handleLogout(w http.ResponseWriter, r *http.Request) {
http.SetCookie(w, &http.Cookie{
Name: auth.CookieName,
Value: "",
HttpOnly: false,
Expires: time.Unix(0, 0),
Path: "/",
})
http.Redirect(w, r, "/", http.StatusSeeOther)
}
func (h *LocalHandler) authenticate(username, password string) (*LocalAccount, error) {
account, exists := h.accounts[username]
if !exists {
return nil, errors.WithStack(errNotFound)
}
matches, err := passwd.Match(account.Algo, password, account.Password)
if err != nil {
return nil, errors.WithStack(err)
}
if !matches {
return nil, errors.WithStack(errInvalidPassword)
}
return &account, nil
}
func NewLocalHandler(algo jwa.KeyAlgorithm, key jwk.Key, funcs ...LocalHandlerOptionFunc) *LocalHandler {
opts := defaultLocalHandlerOptions()
for _, fn := range funcs {
fn(opts)
}
handler := &LocalHandler{
algo: algo,
key: key,
accounts: toAccountsMap(opts.Accounts),
}
handler.initRouter(opts.RoutePrefix)
return handler
}
// ServeHTTP implements http.Handler.
func (h *LocalHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
h.router.ServeHTTP(w, r)
}
var _ http.Handler = &LocalHandler{}

View File

@ -0,0 +1,27 @@
package http
type LocalHandlerOptions struct {
RoutePrefix string
Accounts []LocalAccount
}
type LocalHandlerOptionFunc func(*LocalHandlerOptions)
func defaultLocalHandlerOptions() *LocalHandlerOptions {
return &LocalHandlerOptions{
RoutePrefix: "",
Accounts: make([]LocalAccount, 0),
}
}
func WithAccounts(accounts ...LocalAccount) LocalHandlerOptionFunc {
return func(opts *LocalHandlerOptions) {
opts.Accounts = accounts
}
}
func WithRoutePrefix(prefix string) LocalHandlerOptionFunc {
return func(opts *LocalHandlerOptions) {
opts.RoutePrefix = prefix
}
}

View File

@ -0,0 +1,136 @@
package argon2id
import (
"crypto/rand"
"crypto/subtle"
"encoding/base64"
"fmt"
"strings"
"forge.cadoles.com/arcad/edge/pkg/module/auth/http/passwd"
"github.com/pkg/errors"
"golang.org/x/crypto/argon2"
)
const (
Algo passwd.Algo = "argon2id"
)
func init() {
passwd.Register(Algo, &Hasher{})
}
var (
ErrInvalidHash = errors.New("invalid hash")
ErrIncompatibleVersion = errors.New("incompatible version")
)
type params struct {
memory uint32
iterations uint32
parallelism uint8
saltLength uint32
keyLength uint32
}
var defaultParams = params{
memory: 64 * 1024,
iterations: 3,
parallelism: 2,
saltLength: 16,
keyLength: 32,
}
type Hasher struct{}
// Hash implements passwd.Hasher
func (*Hasher) Hash(plaintext string) (string, error) {
salt, err := generateRandomBytes(defaultParams.saltLength)
if err != nil {
return "", errors.WithStack(err)
}
hash := argon2.IDKey([]byte(plaintext), salt, defaultParams.iterations, defaultParams.memory, defaultParams.parallelism, defaultParams.keyLength)
// Base64 encode the salt and hashed password.
b64Salt := base64.RawStdEncoding.EncodeToString(salt)
b64Hash := base64.RawStdEncoding.EncodeToString(hash)
// Return a string using the standard encoded hash representation.
encodedHash := fmt.Sprintf("$argon2id$v=%d$m=%d,t=%d,p=%d$%s$%s", argon2.Version, defaultParams.memory, defaultParams.iterations, defaultParams.parallelism, b64Salt, b64Hash)
return encodedHash, nil
}
// Match implements passwd.Hasher.
func (*Hasher) Match(plaintext string, hash string) (bool, error) {
matches, err := comparePasswordAndHash(plaintext, hash)
if err != nil {
return false, errors.WithStack(err)
}
return matches, nil
}
var _ passwd.Hasher = &Hasher{}
func generateRandomBytes(n uint32) ([]byte, error) {
buf := make([]byte, n)
if _, err := rand.Read(buf); err != nil {
return nil, errors.WithStack(err)
}
return buf, nil
}
func comparePasswordAndHash(password, encodedHash string) (match bool, err error) {
p, salt, hash, err := decodeHash(encodedHash)
if err != nil {
return false, errors.WithStack(err)
}
otherHash := argon2.IDKey([]byte(password), salt, p.iterations, p.memory, p.parallelism, p.keyLength)
if subtle.ConstantTimeCompare(hash, otherHash) == 1 {
return true, nil
}
return false, nil
}
func decodeHash(encodedHash string) (p *params, salt, hash []byte, err error) {
vals := strings.Split(encodedHash, "$")
if len(vals) != 6 {
return nil, nil, nil, ErrInvalidHash
}
var version int
_, err = fmt.Sscanf(vals[2], "v=%d", &version)
if err != nil {
return nil, nil, nil, err
}
if version != argon2.Version {
return nil, nil, nil, ErrIncompatibleVersion
}
p = &params{}
_, err = fmt.Sscanf(vals[3], "m=%d,t=%d,p=%d", &p.memory, &p.iterations, &p.parallelism)
if err != nil {
return nil, nil, nil, err
}
salt, err = base64.RawStdEncoding.Strict().DecodeString(vals[4])
if err != nil {
return nil, nil, nil, err
}
p.saltLength = uint32(len(salt))
hash, err = base64.RawStdEncoding.Strict().DecodeString(vals[5])
if err != nil {
return nil, nil, nil, err
}
p.keyLength = uint32(len(hash))
return p, salt, hash, nil
}

View File

@ -0,0 +1,8 @@
package passwd
type Algo string
type Hasher interface {
Hash(plaintext string) (string, error)
Match(plaintext string, hash string) (bool, error)
}

View File

@ -0,0 +1,31 @@
package plain
import (
"crypto/subtle"
"forge.cadoles.com/arcad/edge/pkg/module/auth/http/passwd"
)
const (
Algo passwd.Algo = "plain"
)
func init() {
passwd.Register(Algo, &Hasher{})
}
type Hasher struct{}
// Hash implements passwd.Hasher
func (*Hasher) Hash(plaintext string) (string, error) {
return plaintext, nil
}
// Match implements passwd.Hasher.
func (*Hasher) Match(plaintext string, hash string) (bool, error) {
matches := subtle.ConstantTimeCompare([]byte(plaintext), []byte(hash)) == 1
return matches, nil
}
var _ passwd.Hasher = &Hasher{}

View File

@ -0,0 +1,87 @@
package passwd
import (
"github.com/pkg/errors"
)
var ErrAlgoNotFound = errors.New("algo not found")
type Registry struct {
hashers map[Algo]Hasher
}
func (r *Registry) Register(algo Algo, hasher Hasher) {
r.hashers[algo] = hasher
}
func (r *Registry) Match(algo Algo, plaintext string, hash string) (bool, error) {
hasher, exists := r.hashers[algo]
if !exists {
return false, errors.WithStack(ErrAlgoNotFound)
}
matches, err := hasher.Match(plaintext, hash)
if err != nil {
return false, errors.WithStack(err)
}
return matches, nil
}
func (r *Registry) Hash(algo Algo, plaintext string) (string, error) {
hasher, exists := r.hashers[algo]
if !exists {
return "", errors.WithStack(ErrAlgoNotFound)
}
hash, err := hasher.Hash(plaintext)
if err != nil {
return "", errors.WithStack(err)
}
return hash, nil
}
func (r *Registry) Algorithms() []Algo {
algorithms := make([]Algo, 0, len(r.hashers))
for algo := range r.hashers {
algorithms = append(algorithms, algo)
}
return algorithms
}
func NewRegistry() *Registry {
return &Registry{
hashers: make(map[Algo]Hasher),
}
}
var defaultRegistry = NewRegistry()
func Match(algo Algo, plaintext string, hash string) (bool, error) {
matches, err := defaultRegistry.Match(algo, plaintext, hash)
if err != nil {
return false, errors.WithStack(err)
}
return matches, nil
}
func Hash(algo Algo, plaintext string) (string, error) {
hash, err := defaultRegistry.Hash(algo, plaintext)
if err != nil {
return "", errors.WithStack(err)
}
return hash, nil
}
func Algorithms() []Algo {
return defaultRegistry.Algorithms()
}
func Register(algo Algo, hasher Hasher) {
defaultRegistry.Register(algo, hasher)
}

View File

@ -0,0 +1,105 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<title>Login</title>
<style>
html {
box-sizing: border-box;
font-size: 16px;
}
*, *:before, *:after {
box-sizing: inherit;
}
body, h1, h2, h3, h4, h5, h6, p, ol, ul {
margin: 0;
padding: 0;
font-weight: normal;
}
html, body {
width: 100%;
height: 100%;
font-family: Arial, Helvetica, sans-serif;
background-color: #f7f7f7;
}
#container {
display: flex;
align-items: center;
justify-content: center;
height: 100%;
flex-direction: column;
}
.form-control {
margin-bottom: 0.5em;
}
.form-control > label {
font-weight: bold;
}
.form-control > input {
width: 100%;
line-height: 1.4em;
border: 1px solid #ccc;
border-radius: 3px;
font-size: 1.2em;
padding: 0 5px;
margin: 5px 0;
}
#submit {
float: right;
background-color: #5e77ff;
padding: 5px 10px;
border: none;
border-radius: 5px;
color: white;
font-size: 1em;
cursor: pointer;
}
#submit:hover {
background-color: hsl(231deg 100% 71%);
}
#login {
padding: 1.5em 1em;
border: 1px solid #e0e0e0;
background-color: white;
border-radius: 5px;
box-shadow: 2px 2px #cccccc1c;
color: #333333 !important;
}
#message {
margin-bottom: 10px;
color: red;
text-shadow: 1px 1px #fff0f0;
}
</style>
</head>
<body>
<div id="container">
<p id="message">{{ .Message }}</p>
<div id="login">
<form method="post" action="{{ .URL }}">
<div class="form-control">
<label for="username">Username</label>
<input type="text" id="username" name="username" value="{{ .Username }}" required />
</div>
<div class="form-control">
<label for="password">Password</label>
<input type="password" id="password" name="password" value="{{ .Password }}" required />
</div>
<input id="submit" type="submit" value="Login" />
</form>
</div>
</div>
</body>
</html>

View File

@ -5,14 +5,22 @@ import (
"net/http" "net/http"
"strings" "strings"
"github.com/golang-jwt/jwt" "github.com/lestrrat-go/jwx/v2/jwk"
"github.com/lestrrat-go/jwx/v2/jws"
"github.com/lestrrat-go/jwx/v2/jwt"
"github.com/pkg/errors" "github.com/pkg/errors"
) )
func WithJWT(keyFunc jwt.Keyfunc) OptionFunc { const (
CookieName string = "edge-auth"
)
type GetKeySetFunc func() (jwk.Set, error)
func WithJWT(getKeySet GetKeySetFunc) OptionFunc {
return func(o *Option) { return func(o *Option) {
o.GetClaim = func(ctx context.Context, r *http.Request, claimName string) (string, error) { o.GetClaim = func(ctx context.Context, r *http.Request, claimName string) (string, error) {
claim, err := getClaim[string](r, claimName, keyFunc) claim, err := getClaim[string](r, claimName, getKeySet)
if err != nil { if err != nil {
return "", errors.WithStack(err) return "", errors.WithStack(err)
} }
@ -22,28 +30,59 @@ func WithJWT(keyFunc jwt.Keyfunc) OptionFunc {
} }
} }
func getClaim[T any](r *http.Request, claimAttr string, keyFunc jwt.Keyfunc) (T, error) { func FindToken(r *http.Request, getKeySet GetKeySetFunc) (jwt.Token, error) {
rawToken := strings.TrimPrefix(r.Header.Get("Authorization"), "Bearer ") authorization := r.Header.Get("Authorization")
// Retrieve token from Authorization header
rawToken := strings.TrimPrefix(authorization, "Bearer ")
// Retrieve token from ?edge-auth=<value>
if rawToken == "" { if rawToken == "" {
rawToken = r.URL.Query().Get("token") rawToken = r.URL.Query().Get(CookieName)
} }
if rawToken == "" { if rawToken == "" {
return *new(T), errors.WithStack(ErrUnauthenticated) cookie, err := r.Cookie(CookieName)
if err != nil && !errors.Is(err, http.ErrNoCookie) {
return nil, errors.WithStack(err)
}
if cookie != nil {
rawToken = cookie.Value
}
} }
token, err := jwt.Parse(rawToken, keyFunc) if rawToken == "" {
return nil, errors.WithStack(ErrUnauthenticated)
}
keySet, err := getKeySet()
if err != nil {
return nil, errors.WithStack(err)
}
token, err := jwt.Parse([]byte(rawToken),
jwt.WithKeySet(keySet, jws.WithRequireKid(false)),
jwt.WithValidate(true),
)
if err != nil {
return nil, errors.WithStack(err)
}
return token, nil
}
func getClaim[T any](r *http.Request, claimAttr string, getKeySet GetKeySetFunc) (T, error) {
token, err := FindToken(r, getKeySet)
if err != nil { if err != nil {
return *new(T), errors.WithStack(err) return *new(T), errors.WithStack(err)
} }
if !token.Valid { ctx := r.Context()
return *new(T), errors.Errorf("invalid jwt token: '%v'", token.Raw)
}
mapClaims, ok := token.Claims.(jwt.MapClaims) mapClaims, err := token.AsMap(ctx)
if !ok { if err != nil {
return *new(T), errors.Errorf("unexpected claims type '%T'", token.Claims) return *new(T), errors.WithStack(err)
} }
rawClaim, exists := mapClaims[claimAttr] rawClaim, exists := mapClaims[claimAttr]

View File

@ -55,7 +55,7 @@ func (m *Module) getClaim(call goja.FunctionCall, rt *goja.Runtime) goja.Value {
} }
func ModuleFactory(funcs ...OptionFunc) app.ServerModuleFactory { func ModuleFactory(funcs ...OptionFunc) app.ServerModuleFactory {
opt := &Option{} opt := defaultOptions()
for _, fn := range funcs { for _, fn := range funcs {
fn(opt) fn(opt)
} }

View File

@ -2,7 +2,6 @@ package auth
import ( import (
"context" "context"
"fmt"
"io/ioutil" "io/ioutil"
"net/http" "net/http"
"testing" "testing"
@ -12,7 +11,9 @@ import (
"forge.cadoles.com/arcad/edge/pkg/app" "forge.cadoles.com/arcad/edge/pkg/app"
edgeHTTP "forge.cadoles.com/arcad/edge/pkg/http" edgeHTTP "forge.cadoles.com/arcad/edge/pkg/http"
"forge.cadoles.com/arcad/edge/pkg/module" "forge.cadoles.com/arcad/edge/pkg/module"
"github.com/golang-jwt/jwt" "github.com/lestrrat-go/jwx/v2/jwa"
"github.com/lestrrat-go/jwx/v2/jwk"
"github.com/lestrrat-go/jwx/v2/jwt"
"github.com/pkg/errors" "github.com/pkg/errors"
"gitlab.com/wpetit/goweb/logger" "gitlab.com/wpetit/goweb/logger"
) )
@ -22,12 +23,12 @@ func TestAuthModule(t *testing.T) {
logger.SetLevel(slog.LevelDebug) logger.SetLevel(slog.LevelDebug)
keyFunc, secret := getKeyFunc() key := getDummyKey()
server := app.NewServer( server := app.NewServer(
module.ConsoleModuleFactory(), module.ConsoleModuleFactory(),
ModuleFactory( ModuleFactory(
WithJWT(keyFunc), WithJWT(getDummyKeySet(key)),
), ),
) )
@ -51,21 +52,26 @@ func TestAuthModule(t *testing.T) {
t.Fatalf("%+v", errors.WithStack(err)) t.Fatalf("%+v", errors.WithStack(err))
} }
token := jwt.NewWithClaims(jwt.SigningMethodHS256, jwt.MapClaims{ token := jwt.New()
"sub": "jdoe",
"nbf": time.Now().UTC().Unix(),
})
rawToken, err := token.SignedString(secret) if err := token.Set(jwt.SubjectKey, "jdoe"); err != nil {
t.Fatalf("%+v", errors.WithStack(err))
}
if err := token.Set(jwt.NotBeforeKey, time.Now()); err != nil {
t.Fatalf("%+v", errors.WithStack(err))
}
rawToken, err := jwt.Sign(token, jwt.WithKey(jwa.HS256, key))
if err != nil { if err != nil {
t.Fatalf("%+v", errors.WithStack(err)) t.Fatalf("%+v", errors.WithStack(err))
} }
req.Header.Add("Authorization", "Bearer "+rawToken) req.Header.Add("Authorization", "Bearer "+string(rawToken))
ctx := context.WithValue(context.Background(), edgeHTTP.ContextKeyOriginRequest, req) ctx := context.WithValue(context.Background(), edgeHTTP.ContextKeyOriginRequest, req)
if _, err := server.ExecFuncByName("testAuth", ctx); err != nil { if _, err := server.ExecFuncByName(ctx, "testAuth", ctx); err != nil {
t.Fatalf("%+v", errors.WithStack(err)) t.Fatalf("%+v", errors.WithStack(err))
} }
} }
@ -75,11 +81,11 @@ func TestAuthAnonymousModule(t *testing.T) {
logger.SetLevel(slog.LevelDebug) logger.SetLevel(slog.LevelDebug)
keyFunc, _ := getKeyFunc() key := getDummyKey()
server := app.NewServer( server := app.NewServer(
module.ConsoleModuleFactory(), module.ConsoleModuleFactory(),
ModuleFactory(WithJWT(keyFunc)), ModuleFactory(WithJWT(getDummyKeySet(key))),
) )
data, err := ioutil.ReadFile("testdata/auth_anonymous.js") data, err := ioutil.ReadFile("testdata/auth_anonymous.js")
@ -104,21 +110,34 @@ func TestAuthAnonymousModule(t *testing.T) {
ctx := context.WithValue(context.Background(), edgeHTTP.ContextKeyOriginRequest, req) ctx := context.WithValue(context.Background(), edgeHTTP.ContextKeyOriginRequest, req)
if _, err := server.ExecFuncByName("testAuth", ctx); err != nil { if _, err := server.ExecFuncByName(ctx, "testAuth", ctx); err != nil {
t.Fatalf("%+v", errors.WithStack(err)) t.Fatalf("%+v", errors.WithStack(err))
} }
} }
func getKeyFunc() (jwt.Keyfunc, []byte) { func getDummyKey() jwk.Key {
secret := []byte("not_so_secret") secret := []byte("not_so_secret")
keyFunc := func(t *jwt.Token) (interface{}, error) { key, err := jwk.FromRaw(secret)
if _, ok := t.Method.(*jwt.SigningMethodHMAC); !ok { if err != nil {
return nil, fmt.Errorf("Unexpected signing method: %v", t.Header["alg"]) panic(errors.WithStack(err))
}
return secret, nil
} }
return keyFunc, secret if err := key.Set(jwk.AlgorithmKey, jwa.HS256); err != nil {
panic(errors.WithStack(err))
}
return key
}
func getDummyKeySet(key jwk.Key) GetKeySetFunc {
return func() (jwk.Set, error) {
set := jwk.NewSet()
if err := set.AddKey(key); err != nil {
return nil, errors.WithStack(err)
}
return set, nil
}
} }

View File

@ -3,6 +3,8 @@ package auth
import ( import (
"context" "context"
"net/http" "net/http"
"github.com/pkg/errors"
) )
type GetClaimFunc func(ctx context.Context, r *http.Request, claimName string) (string, error) type GetClaimFunc func(ctx context.Context, r *http.Request, claimName string) (string, error)
@ -13,6 +15,16 @@ type Option struct {
type OptionFunc func(*Option) type OptionFunc func(*Option)
func defaultOptions() *Option {
return &Option{
GetClaim: dummyGetClaim,
}
}
func dummyGetClaim(ctx context.Context, r *http.Request, claimName string) (string, error) {
return "", errors.Errorf("dummy getclaim func cannot retrieve claim '%s'", claimName)
}
func WithGetClaim(fn GetClaimFunc) OptionFunc { func WithGetClaim(fn GetClaimFunc) OptionFunc {
return func(o *Option) { return func(o *Option) {
o.GetClaim = fn o.GetClaim = fn

View File

@ -88,7 +88,7 @@ func (m *BlobModule) handleUploadRequest(req *MessageUploadRequest) (*MessageUpl
"contentType": req.FileHeader.Header.Get("Content-Type"), "contentType": req.FileHeader.Header.Get("Content-Type"),
} }
rawResult, err := m.server.ExecFuncByName("onBlobUpload", ctx, blobID, blobInfo, req.Metadata) rawResult, err := m.server.ExecFuncByName(ctx, "onBlobUpload", ctx, blobID, blobInfo, req.Metadata)
if err != nil { if err != nil {
if errors.Is(err, app.ErrFuncDoesNotExist) { if errors.Is(err, app.ErrFuncDoesNotExist) {
res.Allow = false res.Allow = false
@ -193,7 +193,7 @@ func (m *BlobModule) saveBlob(ctx context.Context, bucketName string, blobID sto
func (m *BlobModule) handleDownloadRequest(req *MessageDownloadRequest) (*MessageDownloadResponse, error) { func (m *BlobModule) handleDownloadRequest(req *MessageDownloadRequest) (*MessageDownloadResponse, error) {
res := NewMessageDownloadResponse(req.RequestID) res := NewMessageDownloadResponse(req.RequestID)
rawResult, err := m.server.ExecFuncByName("onBlobDownload", req.Context, req.Bucket, req.BlobID) rawResult, err := m.server.ExecFuncByName(req.Context, "onBlobDownload", req.Context, req.Bucket, req.BlobID)
if err != nil { if err != nil {
if errors.Is(err, app.ErrFuncDoesNotExist) { if errors.Is(err, app.ErrFuncDoesNotExist) {
res.Allow = false res.Allow = false

View File

@ -1,6 +1,7 @@
package cast package cast
import ( import (
"context"
"io/ioutil" "io/ioutil"
"os" "os"
"testing" "testing"
@ -79,7 +80,7 @@ func TestCastModuleRefreshDevices(t *testing.T) {
defer server.Stop() defer server.Stop()
result, err := server.ExecFuncByName("refreshDevices") result, err := server.ExecFuncByName(context.Background(), "refreshDevices")
if err != nil { if err != nil {
t.Error(errors.WithStack(err)) t.Error(errors.WithStack(err))
} }

View File

@ -21,7 +21,7 @@ func (m *LifecycleModule) Export(export *goja.Object) {
} }
func (m *LifecycleModule) OnInit() error { func (m *LifecycleModule) OnInit() error {
if _, err := m.server.ExecFuncByName("onInit"); err != nil { if _, err := m.server.ExecFuncByName(context.Background(), "onInit"); err != nil {
if errors.Is(err, app.ErrFuncDoesNotExist) { if errors.Is(err, app.ErrFuncDoesNotExist) {
logger.Warn(context.Background(), "could not find onInit() function", logger.E(errors.WithStack(err))) logger.Warn(context.Background(), "could not find onInit() function", logger.E(errors.WithStack(err)))

View File

@ -38,9 +38,10 @@ func (m *Module) broadcast(call goja.FunctionCall, rt *goja.Runtime) goja.Value
} }
data := call.Argument(0).Export() data := call.Argument(0).Export()
ctx := context.Background()
msg := module.NewServerMessage(nil, data) msg := module.NewServerMessage(ctx, data)
if err := m.bus.Publish(context.Background(), msg); err != nil { if err := m.bus.Publish(ctx, msg); err != nil {
panic(rt.ToValue(errors.WithStack(err))) panic(rt.ToValue(errors.WithStack(err)))
} }
@ -129,7 +130,7 @@ func (m *Module) handleClientMessages() {
logger.F("message", clientMessage), logger.F("message", clientMessage),
) )
if _, err := m.server.ExecFuncByName("onClientMessage", clientMessage.Context, clientMessage.Data); err != nil { if _, err := m.server.ExecFuncByName(clientMessage.Context, "onClientMessage", clientMessage.Context, clientMessage.Data); err != nil {
if errors.Is(err, app.ErrFuncDoesNotExist) { if errors.Is(err, app.ErrFuncDoesNotExist) {
continue continue
} }

View File

@ -161,7 +161,7 @@ func (m *RPCModule) handleMessages() {
continue continue
} }
result, err := m.server.Exec(callable, clientMessage.Context, req.Params) result, err := m.server.Exec(clientMessage.Context, callable, clientMessage.Context, req.Params)
if err != nil { if err != nil {
logger.Error( logger.Error(
ctx, "rpc call error", ctx, "rpc call error",

View File

@ -102,7 +102,7 @@ func (m *Module) query(call goja.FunctionCall, rt *goja.Runtime) goja.Value {
} }
if queryOptions.Offset != nil { if queryOptions.Offset != nil {
queryOptionsFuncs = append(queryOptionsFuncs, storage.WithOffset(*queryOptions.Limit)) queryOptionsFuncs = append(queryOptionsFuncs, storage.WithOffset(*queryOptions.Offset))
} }
if queryOptions.OrderDirection != nil { if queryOptions.OrderDirection != nil {

View File

@ -1,6 +1,7 @@
package store package store
import ( import (
"context"
"io/ioutil" "io/ioutil"
"testing" "testing"
@ -34,7 +35,7 @@ func TestStoreModule(t *testing.T) {
t.Fatalf("%+v", errors.WithStack(err)) t.Fatalf("%+v", errors.WithStack(err))
} }
if _, err := server.ExecFuncByName("testStore"); err != nil { if _, err := server.ExecFuncByName(context.Background(), "testStore"); err != nil {
t.Fatalf("%+v", errors.WithStack(err)) t.Fatalf("%+v", errors.WithStack(err))
} }

4094
pkg/sdk/client/dist/client.js vendored Normal file
View File

@ -0,0 +1,4094 @@
var Edge = (() => {
var __create = Object.create;
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __getProtoOf = Object.getPrototypeOf;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __commonJS = (cb, mod) => function __require() {
return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
};
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
// If the importer is in node compatibility mode or this is not an ESM
// file that has been converted to a CommonJS file using a Babel-
// compatible transform (i.e. "__esModule" has not been set), then set
// "default" to the CommonJS "module.exports" for node compatibility.
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
mod
));
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
// node_modules/sockjs-client/lib/utils/browser-crypto.js
var require_browser_crypto = __commonJS({
"node_modules/sockjs-client/lib/utils/browser-crypto.js"(exports, module) {
"use strict";
if (window.crypto && window.crypto.getRandomValues) {
module.exports.randomBytes = function(length) {
var bytes = new Uint8Array(length);
window.crypto.getRandomValues(bytes);
return bytes;
};
} else {
module.exports.randomBytes = function(length) {
var bytes = new Array(length);
for (var i = 0; i < length; i++) {
bytes[i] = Math.floor(Math.random() * 256);
}
return bytes;
};
}
}
});
// node_modules/sockjs-client/lib/utils/random.js
var require_random = __commonJS({
"node_modules/sockjs-client/lib/utils/random.js"(exports, module) {
"use strict";
var crypto = require_browser_crypto();
var _randomStringChars = "abcdefghijklmnopqrstuvwxyz012345";
module.exports = {
string: function(length) {
var max = _randomStringChars.length;
var bytes = crypto.randomBytes(length);
var ret = [];
for (var i = 0; i < length; i++) {
ret.push(_randomStringChars.substr(bytes[i] % max, 1));
}
return ret.join("");
},
number: function(max) {
return Math.floor(Math.random() * max);
},
numberString: function(max) {
var t = ("" + (max - 1)).length;
var p = new Array(t + 1).join("0");
return (p + this.number(max)).slice(-t);
}
};
}
});
// node_modules/sockjs-client/lib/utils/event.js
var require_event = __commonJS({
"node_modules/sockjs-client/lib/utils/event.js"(exports, module) {
"use strict";
var random = require_random();
var onUnload = {};
var afterUnload = false;
var isChromePackagedApp = window.chrome && window.chrome.app && window.chrome.app.runtime;
module.exports = {
attachEvent: function(event, listener) {
if (typeof window.addEventListener !== "undefined") {
window.addEventListener(event, listener, false);
} else if (window.document && window.attachEvent) {
window.document.attachEvent("on" + event, listener);
window.attachEvent("on" + event, listener);
}
},
detachEvent: function(event, listener) {
if (typeof window.addEventListener !== "undefined") {
window.removeEventListener(event, listener, false);
} else if (window.document && window.detachEvent) {
window.document.detachEvent("on" + event, listener);
window.detachEvent("on" + event, listener);
}
},
unloadAdd: function(listener) {
if (isChromePackagedApp) {
return null;
}
var ref = random.string(8);
onUnload[ref] = listener;
if (afterUnload) {
setTimeout(this.triggerUnloadCallbacks, 0);
}
return ref;
},
unloadDel: function(ref) {
if (ref in onUnload) {
delete onUnload[ref];
}
},
triggerUnloadCallbacks: function() {
for (var ref in onUnload) {
onUnload[ref]();
delete onUnload[ref];
}
}
};
var unloadTriggered = function() {
if (afterUnload) {
return;
}
afterUnload = true;
module.exports.triggerUnloadCallbacks();
};
if (!isChromePackagedApp) {
module.exports.attachEvent("unload", unloadTriggered);
}
}
});
// node_modules/requires-port/index.js
var require_requires_port = __commonJS({
"node_modules/requires-port/index.js"(exports, module) {
"use strict";
module.exports = function required(port, protocol) {
protocol = protocol.split(":")[0];
port = +port;
if (!port)
return false;
switch (protocol) {
case "http":
case "ws":
return port !== 80;
case "https":
case "wss":
return port !== 443;
case "ftp":
return port !== 21;
case "gopher":
return port !== 70;
case "file":
return false;
}
return port !== 0;
};
}
});
// node_modules/querystringify/index.js
var require_querystringify = __commonJS({
"node_modules/querystringify/index.js"(exports) {
"use strict";
var has = Object.prototype.hasOwnProperty;
var undef;
function decode(input) {
try {
return decodeURIComponent(input.replace(/\+/g, " "));
} catch (e) {
return null;
}
}
function encode(input) {
try {
return encodeURIComponent(input);
} catch (e) {
return null;
}
}
function querystring(query) {
var parser = /([^=?#&]+)=?([^&]*)/g, result = {}, part;
while (part = parser.exec(query)) {
var key = decode(part[1]), value = decode(part[2]);
if (key === null || value === null || key in result)
continue;
result[key] = value;
}
return result;
}
function querystringify(obj, prefix) {
prefix = prefix || "";
var pairs = [], value, key;
if ("string" !== typeof prefix)
prefix = "?";
for (key in obj) {
if (has.call(obj, key)) {
value = obj[key];
if (!value && (value === null || value === undef || isNaN(value))) {
value = "";
}
key = encode(key);
value = encode(value);
if (key === null || value === null)
continue;
pairs.push(key + "=" + value);
}
}
return pairs.length ? prefix + pairs.join("&") : "";
}
exports.stringify = querystringify;
exports.parse = querystring;
}
});
// node_modules/url-parse/index.js
var require_url_parse = __commonJS({
"node_modules/url-parse/index.js"(exports, module) {
"use strict";
var required = require_requires_port();
var qs = require_querystringify();
var controlOrWhitespace = /^[\x00-\x20\u00a0\u1680\u2000-\u200a\u2028\u2029\u202f\u205f\u3000\ufeff]+/;
var CRHTLF = /[\n\r\t]/g;
var slashes = /^[A-Za-z][A-Za-z0-9+-.]*:\/\//;
var port = /:\d+$/;
var protocolre = /^([a-z][a-z0-9.+-]*:)?(\/\/)?([\\/]+)?([\S\s]*)/i;
var windowsDriveLetter = /^[a-zA-Z]:/;
function trimLeft(str) {
return (str ? str : "").toString().replace(controlOrWhitespace, "");
}
var rules = [
["#", "hash"],
// Extract from the back.
["?", "query"],
// Extract from the back.
function sanitize(address, url) {
return isSpecial(url.protocol) ? address.replace(/\\/g, "/") : address;
},
["/", "pathname"],
// Extract from the back.
["@", "auth", 1],
// Extract from the front.
[NaN, "host", void 0, 1, 1],
// Set left over value.
[/:(\d*)$/, "port", void 0, 1],
// RegExp the back.
[NaN, "hostname", void 0, 1, 1]
// Set left over.
];
var ignore = { hash: 1, query: 1 };
function lolcation(loc) {
var globalVar;
if (typeof window !== "undefined")
globalVar = window;
else if (typeof window !== "undefined")
globalVar = window;
else if (typeof self !== "undefined")
globalVar = self;
else
globalVar = {};
var location = globalVar.location || {};
loc = loc || location;
var finaldestination = {}, type = typeof loc, key;
if ("blob:" === loc.protocol) {
finaldestination = new Url(unescape(loc.pathname), {});
} else if ("string" === type) {
finaldestination = new Url(loc, {});
for (key in ignore)
delete finaldestination[key];
} else if ("object" === type) {
for (key in loc) {
if (key in ignore)
continue;
finaldestination[key] = loc[key];
}
if (finaldestination.slashes === void 0) {
finaldestination.slashes = slashes.test(loc.href);
}
}
return finaldestination;
}
function isSpecial(scheme) {
return scheme === "file:" || scheme === "ftp:" || scheme === "http:" || scheme === "https:" || scheme === "ws:" || scheme === "wss:";
}
function extractProtocol(address, location) {
address = trimLeft(address);
address = address.replace(CRHTLF, "");
location = location || {};
var match = protocolre.exec(address);
var protocol = match[1] ? match[1].toLowerCase() : "";
var forwardSlashes = !!match[2];
var otherSlashes = !!match[3];
var slashesCount = 0;
var rest;
if (forwardSlashes) {
if (otherSlashes) {
rest = match[2] + match[3] + match[4];
slashesCount = match[2].length + match[3].length;
} else {
rest = match[2] + match[4];
slashesCount = match[2].length;
}
} else {
if (otherSlashes) {
rest = match[3] + match[4];
slashesCount = match[3].length;
} else {
rest = match[4];
}
}
if (protocol === "file:") {
if (slashesCount >= 2) {
rest = rest.slice(2);
}
} else if (isSpecial(protocol)) {
rest = match[4];
} else if (protocol) {
if (forwardSlashes) {
rest = rest.slice(2);
}
} else if (slashesCount >= 2 && isSpecial(location.protocol)) {
rest = match[4];
}
return {
protocol,
slashes: forwardSlashes || isSpecial(protocol),
slashesCount,
rest
};
}
function resolve(relative, base) {
if (relative === "")
return base;
var path = (base || "/").split("/").slice(0, -1).concat(relative.split("/")), i = path.length, last = path[i - 1], unshift = false, up = 0;
while (i--) {
if (path[i] === ".") {
path.splice(i, 1);
} else if (path[i] === "..") {
path.splice(i, 1);
up++;
} else if (up) {
if (i === 0)
unshift = true;
path.splice(i, 1);
up--;
}
}
if (unshift)
path.unshift("");
if (last === "." || last === "..")
path.push("");
return path.join("/");
}
function Url(address, location, parser) {
address = trimLeft(address);
address = address.replace(CRHTLF, "");
if (!(this instanceof Url)) {
return new Url(address, location, parser);
}
var relative, extracted, parse, instruction, index, key, instructions = rules.slice(), type = typeof location, url = this, i = 0;
if ("object" !== type && "string" !== type) {
parser = location;
location = null;
}
if (parser && "function" !== typeof parser)
parser = qs.parse;
location = lolcation(location);
extracted = extractProtocol(address || "", location);
relative = !extracted.protocol && !extracted.slashes;
url.slashes = extracted.slashes || relative && location.slashes;
url.protocol = extracted.protocol || location.protocol || "";
address = extracted.rest;
if (extracted.protocol === "file:" && (extracted.slashesCount !== 2 || windowsDriveLetter.test(address)) || !extracted.slashes && (extracted.protocol || extracted.slashesCount < 2 || !isSpecial(url.protocol))) {
instructions[3] = [/(.*)/, "pathname"];
}
for (; i < instructions.length; i++) {
instruction = instructions[i];
if (typeof instruction === "function") {
address = instruction(address, url);
continue;
}
parse = instruction[0];
key = instruction[1];
if (parse !== parse) {
url[key] = address;
} else if ("string" === typeof parse) {
index = parse === "@" ? address.lastIndexOf(parse) : address.indexOf(parse);
if (~index) {
if ("number" === typeof instruction[2]) {
url[key] = address.slice(0, index);
address = address.slice(index + instruction[2]);
} else {
url[key] = address.slice(index);
address = address.slice(0, index);
}
}
} else if (index = parse.exec(address)) {
url[key] = index[1];
address = address.slice(0, index.index);
}
url[key] = url[key] || (relative && instruction[3] ? location[key] || "" : "");
if (instruction[4])
url[key] = url[key].toLowerCase();
}
if (parser)
url.query = parser(url.query);
if (relative && location.slashes && url.pathname.charAt(0) !== "/" && (url.pathname !== "" || location.pathname !== "")) {
url.pathname = resolve(url.pathname, location.pathname);
}
if (url.pathname.charAt(0) !== "/" && isSpecial(url.protocol)) {
url.pathname = "/" + url.pathname;
}
if (!required(url.port, url.protocol)) {
url.host = url.hostname;
url.port = "";
}
url.username = url.password = "";
if (url.auth) {
index = url.auth.indexOf(":");
if (~index) {
url.username = url.auth.slice(0, index);
url.username = encodeURIComponent(decodeURIComponent(url.username));
url.password = url.auth.slice(index + 1);
url.password = encodeURIComponent(decodeURIComponent(url.password));
} else {
url.username = encodeURIComponent(decodeURIComponent(url.auth));
}
url.auth = url.password ? url.username + ":" + url.password : url.username;
}
url.origin = url.protocol !== "file:" && isSpecial(url.protocol) && url.host ? url.protocol + "//" + url.host : "null";
url.href = url.toString();
}
function set(part, value, fn) {
var url = this;
switch (part) {
case "query":
if ("string" === typeof value && value.length) {
value = (fn || qs.parse)(value);
}
url[part] = value;
break;
case "port":
url[part] = value;
if (!required(value, url.protocol)) {
url.host = url.hostname;
url[part] = "";
} else if (value) {
url.host = url.hostname + ":" + value;
}
break;
case "hostname":
url[part] = value;
if (url.port)
value += ":" + url.port;
url.host = value;
break;
case "host":
url[part] = value;
if (port.test(value)) {
value = value.split(":");
url.port = value.pop();
url.hostname = value.join(":");
} else {
url.hostname = value;
url.port = "";
}
break;
case "protocol":
url.protocol = value.toLowerCase();
url.slashes = !fn;
break;
case "pathname":
case "hash":
if (value) {
var char = part === "pathname" ? "/" : "#";
url[part] = value.charAt(0) !== char ? char + value : value;
} else {
url[part] = value;
}
break;
case "username":
case "password":
url[part] = encodeURIComponent(value);
break;
case "auth":
var index = value.indexOf(":");
if (~index) {
url.username = value.slice(0, index);
url.username = encodeURIComponent(decodeURIComponent(url.username));
url.password = value.slice(index + 1);
url.password = encodeURIComponent(decodeURIComponent(url.password));
} else {
url.username = encodeURIComponent(decodeURIComponent(value));
}
}
for (var i = 0; i < rules.length; i++) {
var ins = rules[i];
if (ins[4])
url[ins[1]] = url[ins[1]].toLowerCase();
}
url.auth = url.password ? url.username + ":" + url.password : url.username;
url.origin = url.protocol !== "file:" && isSpecial(url.protocol) && url.host ? url.protocol + "//" + url.host : "null";
url.href = url.toString();
return url;
}
function toString(stringify) {
if (!stringify || "function" !== typeof stringify)
stringify = qs.stringify;
var query, url = this, host = url.host, protocol = url.protocol;
if (protocol && protocol.charAt(protocol.length - 1) !== ":")
protocol += ":";
var result = protocol + (url.protocol && url.slashes || isSpecial(url.protocol) ? "//" : "");
if (url.username) {
result += url.username;
if (url.password)
result += ":" + url.password;
result += "@";
} else if (url.password) {
result += ":" + url.password;
result += "@";
} else if (url.protocol !== "file:" && isSpecial(url.protocol) && !host && url.pathname !== "/") {
result += "@";
}
if (host[host.length - 1] === ":" || port.test(url.hostname) && !url.port) {
host += ":";
}
result += host + url.pathname;
query = "object" === typeof url.query ? stringify(url.query) : url.query;
if (query)
result += "?" !== query.charAt(0) ? "?" + query : query;
if (url.hash)
result += url.hash;
return result;
}
Url.prototype = { set, toString };
Url.extractProtocol = extractProtocol;
Url.location = lolcation;
Url.trimLeft = trimLeft;
Url.qs = qs;
module.exports = Url;
}
});
// node_modules/ms/index.js
var require_ms = __commonJS({
"node_modules/ms/index.js"(exports, module) {
var s = 1e3;
var m = s * 60;
var h = m * 60;
var d = h * 24;
var w = d * 7;
var y = d * 365.25;
module.exports = function(val, options) {
options = options || {};
var type = typeof val;
if (type === "string" && val.length > 0) {
return parse(val);
} else if (type === "number" && isFinite(val)) {
return options.long ? fmtLong(val) : fmtShort(val);
}
throw new Error(
"val is not a non-empty string or a valid number. val=" + JSON.stringify(val)
);
};
function parse(str) {
str = String(str);
if (str.length > 100) {
return;
}
var match = /^(-?(?:\d+)?\.?\d+) *(milliseconds?|msecs?|ms|seconds?|secs?|s|minutes?|mins?|m|hours?|hrs?|h|days?|d|weeks?|w|years?|yrs?|y)?$/i.exec(
str
);
if (!match) {
return;
}
var n = parseFloat(match[1]);
var type = (match[2] || "ms").toLowerCase();
switch (type) {
case "years":
case "year":
case "yrs":
case "yr":
case "y":
return n * y;
case "weeks":
case "week":
case "w":
return n * w;
case "days":
case "day":
case "d":
return n * d;
case "hours":
case "hour":
case "hrs":
case "hr":
case "h":
return n * h;
case "minutes":
case "minute":
case "mins":
case "min":
case "m":
return n * m;
case "seconds":
case "second":
case "secs":
case "sec":
case "s":
return n * s;
case "milliseconds":
case "millisecond":
case "msecs":
case "msec":
case "ms":
return n;
default:
return void 0;
}
}
function fmtShort(ms) {
var msAbs = Math.abs(ms);
if (msAbs >= d) {
return Math.round(ms / d) + "d";
}
if (msAbs >= h) {
return Math.round(ms / h) + "h";
}
if (msAbs >= m) {
return Math.round(ms / m) + "m";
}
if (msAbs >= s) {
return Math.round(ms / s) + "s";
}
return ms + "ms";
}
function fmtLong(ms) {
var msAbs = Math.abs(ms);
if (msAbs >= d) {
return plural(ms, msAbs, d, "day");
}
if (msAbs >= h) {
return plural(ms, msAbs, h, "hour");
}
if (msAbs >= m) {
return plural(ms, msAbs, m, "minute");
}
if (msAbs >= s) {
return plural(ms, msAbs, s, "second");
}
return ms + " ms";
}
function plural(ms, msAbs, n, name) {
var isPlural = msAbs >= n * 1.5;
return Math.round(ms / n) + " " + name + (isPlural ? "s" : "");
}
}
});
// node_modules/debug/src/common.js
var require_common = __commonJS({
"node_modules/debug/src/common.js"(exports, module) {
"use strict";
function setup(env) {
createDebug.debug = createDebug;
createDebug.default = createDebug;
createDebug.coerce = coerce;
createDebug.disable = disable;
createDebug.enable = enable;
createDebug.enabled = enabled;
createDebug.humanize = require_ms();
Object.keys(env).forEach(function(key) {
createDebug[key] = env[key];
});
createDebug.instances = [];
createDebug.names = [];
createDebug.skips = [];
createDebug.formatters = {};
function selectColor(namespace) {
var hash = 0;
for (var i = 0; i < namespace.length; i++) {
hash = (hash << 5) - hash + namespace.charCodeAt(i);
hash |= 0;
}
return createDebug.colors[Math.abs(hash) % createDebug.colors.length];
}
createDebug.selectColor = selectColor;
function createDebug(namespace) {
var prevTime;
function debug() {
if (!debug.enabled) {
return;
}
for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
args[_key] = arguments[_key];
}
var self2 = debug;
var curr = Number(/* @__PURE__ */ new Date());
var ms = curr - (prevTime || curr);
self2.diff = ms;
self2.prev = prevTime;
self2.curr = curr;
prevTime = curr;
args[0] = createDebug.coerce(args[0]);
if (typeof args[0] !== "string") {
args.unshift("%O");
}
var index = 0;
args[0] = args[0].replace(/%([a-zA-Z%])/g, function(match, format) {
if (match === "%%") {
return match;
}
index++;
var formatter = createDebug.formatters[format];
if (typeof formatter === "function") {
var val = args[index];
match = formatter.call(self2, val);
args.splice(index, 1);
index--;
}
return match;
});
createDebug.formatArgs.call(self2, args);
var logFn = self2.log || createDebug.log;
logFn.apply(self2, args);
}
debug.namespace = namespace;
debug.enabled = createDebug.enabled(namespace);
debug.useColors = createDebug.useColors();
debug.color = selectColor(namespace);
debug.destroy = destroy;
debug.extend = extend;
if (typeof createDebug.init === "function") {
createDebug.init(debug);
}
createDebug.instances.push(debug);
return debug;
}
function destroy() {
var index = createDebug.instances.indexOf(this);
if (index !== -1) {
createDebug.instances.splice(index, 1);
return true;
}
return false;
}
function extend(namespace, delimiter) {
return createDebug(this.namespace + (typeof delimiter === "undefined" ? ":" : delimiter) + namespace);
}
function enable(namespaces) {
createDebug.save(namespaces);
createDebug.names = [];
createDebug.skips = [];
var i;
var split = (typeof namespaces === "string" ? namespaces : "").split(/[\s,]+/);
var len = split.length;
for (i = 0; i < len; i++) {
if (!split[i]) {
continue;
}
namespaces = split[i].replace(/\*/g, ".*?");
if (namespaces[0] === "-") {
createDebug.skips.push(new RegExp("^" + namespaces.substr(1) + "$"));
} else {
createDebug.names.push(new RegExp("^" + namespaces + "$"));
}
}
for (i = 0; i < createDebug.instances.length; i++) {
var instance = createDebug.instances[i];
instance.enabled = createDebug.enabled(instance.namespace);
}
}
function disable() {
createDebug.enable("");
}
function enabled(name) {
if (name[name.length - 1] === "*") {
return true;
}
var i;
var len;
for (i = 0, len = createDebug.skips.length; i < len; i++) {
if (createDebug.skips[i].test(name)) {
return false;
}
}
for (i = 0, len = createDebug.names.length; i < len; i++) {
if (createDebug.names[i].test(name)) {
return true;
}
}
return false;
}
function coerce(val) {
if (val instanceof Error) {
return val.stack || val.message;
}
return val;
}
createDebug.enable(createDebug.load());
return createDebug;
}
module.exports = setup;
}
});
// node_modules/debug/src/browser.js
var require_browser = __commonJS({
"node_modules/debug/src/browser.js"(exports, module) {
"use strict";
function _typeof(obj) {
if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") {
_typeof = function _typeof2(obj2) {
return typeof obj2;
};
} else {
_typeof = function _typeof2(obj2) {
return obj2 && typeof Symbol === "function" && obj2.constructor === Symbol && obj2 !== Symbol.prototype ? "symbol" : typeof obj2;
};
}
return _typeof(obj);
}
exports.log = log;
exports.formatArgs = formatArgs;
exports.save = save;
exports.load = load;
exports.useColors = useColors;
exports.storage = localstorage();
exports.colors = ["#0000CC", "#0000FF", "#0033CC", "#0033FF", "#0066CC", "#0066FF", "#0099CC", "#0099FF", "#00CC00", "#00CC33", "#00CC66", "#00CC99", "#00CCCC", "#00CCFF", "#3300CC", "#3300FF", "#3333CC", "#3333FF", "#3366CC", "#3366FF", "#3399CC", "#3399FF", "#33CC00", "#33CC33", "#33CC66", "#33CC99", "#33CCCC", "#33CCFF", "#6600CC", "#6600FF", "#6633CC", "#6633FF", "#66CC00", "#66CC33", "#9900CC", "#9900FF", "#9933CC", "#9933FF", "#99CC00", "#99CC33", "#CC0000", "#CC0033", "#CC0066", "#CC0099", "#CC00CC", "#CC00FF", "#CC3300", "#CC3333", "#CC3366", "#CC3399", "#CC33CC", "#CC33FF", "#CC6600", "#CC6633", "#CC9900", "#CC9933", "#CCCC00", "#CCCC33", "#FF0000", "#FF0033", "#FF0066", "#FF0099", "#FF00CC", "#FF00FF", "#FF3300", "#FF3333", "#FF3366", "#FF3399", "#FF33CC", "#FF33FF", "#FF6600", "#FF6633", "#FF9900", "#FF9933", "#FFCC00", "#FFCC33"];
function useColors() {
if (typeof window !== "undefined" && window.process && (window.process.type === "renderer" || window.process.__nwjs)) {
return true;
}
if (typeof navigator !== "undefined" && navigator.userAgent && navigator.userAgent.toLowerCase().match(/(edge|trident)\/(\d+)/)) {
return false;
}
return typeof document !== "undefined" && document.documentElement && document.documentElement.style && document.documentElement.style.WebkitAppearance || // Is firebug? http://stackoverflow.com/a/398120/376773
typeof window !== "undefined" && window.console && (window.console.firebug || window.console.exception && window.console.table) || // Is firefox >= v31?
// https://developer.mozilla.org/en-US/docs/Tools/Web_Console#Styling_messages
typeof navigator !== "undefined" && navigator.userAgent && navigator.userAgent.toLowerCase().match(/firefox\/(\d+)/) && parseInt(RegExp.$1, 10) >= 31 || // Double check webkit in userAgent just in case we are in a worker
typeof navigator !== "undefined" && navigator.userAgent && navigator.userAgent.toLowerCase().match(/applewebkit\/(\d+)/);
}
function formatArgs(args) {
args[0] = (this.useColors ? "%c" : "") + this.namespace + (this.useColors ? " %c" : " ") + args[0] + (this.useColors ? "%c " : " ") + "+" + module.exports.humanize(this.diff);
if (!this.useColors) {
return;
}
var c = "color: " + this.color;
args.splice(1, 0, c, "color: inherit");
var index = 0;
var lastC = 0;
args[0].replace(/%[a-zA-Z%]/g, function(match) {
if (match === "%%") {
return;
}
index++;
if (match === "%c") {
lastC = index;
}
});
args.splice(lastC, 0, c);
}
function log() {
var _console;
return (typeof console === "undefined" ? "undefined" : _typeof(console)) === "object" && console.log && (_console = console).log.apply(_console, arguments);
}
function save(namespaces) {
try {
if (namespaces) {
exports.storage.setItem("debug", namespaces);
} else {
exports.storage.removeItem("debug");
}
} catch (error) {
}
}
function load() {
var r;
try {
r = exports.storage.getItem("debug");
} catch (error) {
}
if (!r && typeof process !== "undefined" && "env" in process) {
r = process.env.DEBUG;
}
return r;
}
function localstorage() {
try {
return localStorage;
} catch (error) {
}
}
module.exports = require_common()(exports);
var formatters = module.exports.formatters;
formatters.j = function(v) {
try {
return JSON.stringify(v);
} catch (error) {
return "[UnexpectedJSONParseError]: " + error.message;
}
};
}
});
// node_modules/sockjs-client/lib/utils/url.js
var require_url = __commonJS({
"node_modules/sockjs-client/lib/utils/url.js"(exports, module) {
"use strict";
var URL = require_url_parse();
var debug = function() {
};
if (true) {
debug = require_browser()("sockjs-client:utils:url");
}
module.exports = {
getOrigin: function(url) {
if (!url) {
return null;
}
var p = new URL(url);
if (p.protocol === "file:") {
return null;
}
var port = p.port;
if (!port) {
port = p.protocol === "https:" ? "443" : "80";
}
return p.protocol + "//" + p.hostname + ":" + port;
},
isOriginEqual: function(a, b) {
var res = this.getOrigin(a) === this.getOrigin(b);
debug("same", a, b, res);
return res;
},
isSchemeEqual: function(a, b) {
return a.split(":")[0] === b.split(":")[0];
},
addPath: function(url, path) {
var qs = url.split("?");
return qs[0] + path + (qs[1] ? "?" + qs[1] : "");
},
addQuery: function(url, q) {
return url + (url.indexOf("?") === -1 ? "?" + q : "&" + q);
},
isLoopbackAddr: function(addr) {
return /^127\.([0-9]{1,3})\.([0-9]{1,3})\.([0-9]{1,3})$/i.test(addr) || /^\[::1\]$/.test(addr);
}
};
}
});
// node_modules/inherits/inherits_browser.js
var require_inherits_browser = __commonJS({
"node_modules/inherits/inherits_browser.js"(exports, module) {
if (typeof Object.create === "function") {
module.exports = function inherits(ctor, superCtor) {
if (superCtor) {
ctor.super_ = superCtor;
ctor.prototype = Object.create(superCtor.prototype, {
constructor: {
value: ctor,
enumerable: false,
writable: true,
configurable: true
}
});
}
};
} else {
module.exports = function inherits(ctor, superCtor) {
if (superCtor) {
ctor.super_ = superCtor;
var TempCtor = function() {
};
TempCtor.prototype = superCtor.prototype;
ctor.prototype = new TempCtor();
ctor.prototype.constructor = ctor;
}
};
}
}
});
// node_modules/sockjs-client/lib/event/eventtarget.js
var require_eventtarget = __commonJS({
"node_modules/sockjs-client/lib/event/eventtarget.js"(exports, module) {
"use strict";
function EventTarget2() {
this._listeners = {};
}
EventTarget2.prototype.addEventListener = function(eventType, listener) {
if (!(eventType in this._listeners)) {
this._listeners[eventType] = [];
}
var arr = this._listeners[eventType];
if (arr.indexOf(listener) === -1) {
arr = arr.concat([listener]);
}
this._listeners[eventType] = arr;
};
EventTarget2.prototype.removeEventListener = function(eventType, listener) {
var arr = this._listeners[eventType];
if (!arr) {
return;
}
var idx = arr.indexOf(listener);
if (idx !== -1) {
if (arr.length > 1) {
this._listeners[eventType] = arr.slice(0, idx).concat(arr.slice(idx + 1));
} else {
delete this._listeners[eventType];
}
return;
}
};
EventTarget2.prototype.dispatchEvent = function() {
var event = arguments[0];
var t = event.type;
var args = arguments.length === 1 ? [event] : Array.apply(null, arguments);
if (this["on" + t]) {
this["on" + t].apply(this, args);
}
if (t in this._listeners) {
var listeners = this._listeners[t];
for (var i = 0; i < listeners.length; i++) {
listeners[i].apply(this, args);
}
}
};
module.exports = EventTarget2;
}
});
// node_modules/sockjs-client/lib/event/emitter.js
var require_emitter = __commonJS({
"node_modules/sockjs-client/lib/event/emitter.js"(exports, module) {
"use strict";
var inherits = require_inherits_browser();
var EventTarget2 = require_eventtarget();
function EventEmitter() {
EventTarget2.call(this);
}
inherits(EventEmitter, EventTarget2);
EventEmitter.prototype.removeAllListeners = function(type) {
if (type) {
delete this._listeners[type];
} else {
this._listeners = {};
}
};
EventEmitter.prototype.once = function(type, listener) {
var self2 = this, fired = false;
function g() {
self2.removeListener(type, g);
if (!fired) {
fired = true;
listener.apply(this, arguments);
}
}
this.on(type, g);
};
EventEmitter.prototype.emit = function() {
var type = arguments[0];
var listeners = this._listeners[type];
if (!listeners) {
return;
}
var l = arguments.length;
var args = new Array(l - 1);
for (var ai = 1; ai < l; ai++) {
args[ai - 1] = arguments[ai];
}
for (var i = 0; i < listeners.length; i++) {
listeners[i].apply(this, args);
}
};
EventEmitter.prototype.on = EventEmitter.prototype.addListener = EventTarget2.prototype.addEventListener;
EventEmitter.prototype.removeListener = EventTarget2.prototype.removeEventListener;
module.exports.EventEmitter = EventEmitter;
}
});
// node_modules/sockjs-client/lib/transport/browser/websocket.js
var require_websocket = __commonJS({
"node_modules/sockjs-client/lib/transport/browser/websocket.js"(exports, module) {
"use strict";
var Driver = window.WebSocket || window.MozWebSocket;
if (Driver) {
module.exports = function WebSocketBrowserDriver(url) {
return new Driver(url);
};
} else {
module.exports = void 0;
}
}
});
// node_modules/sockjs-client/lib/transport/websocket.js
var require_websocket2 = __commonJS({
"node_modules/sockjs-client/lib/transport/websocket.js"(exports, module) {
"use strict";
var utils = require_event();
var urlUtils = require_url();
var inherits = require_inherits_browser();
var EventEmitter = require_emitter().EventEmitter;
var WebsocketDriver = require_websocket();
var debug = function() {
};
if (true) {
debug = require_browser()("sockjs-client:websocket");
}
function WebSocketTransport(transUrl, ignore, options) {
if (!WebSocketTransport.enabled()) {
throw new Error("Transport created when disabled");
}
EventEmitter.call(this);
debug("constructor", transUrl);
var self2 = this;
var url = urlUtils.addPath(transUrl, "/websocket");
if (url.slice(0, 5) === "https") {
url = "wss" + url.slice(5);
} else {
url = "ws" + url.slice(4);
}
this.url = url;
this.ws = new WebsocketDriver(this.url, [], options);
this.ws.onmessage = function(e) {
debug("message event", e.data);
self2.emit("message", e.data);
};
this.unloadRef = utils.unloadAdd(function() {
debug("unload");
self2.ws.close();
});
this.ws.onclose = function(e) {
debug("close event", e.code, e.reason);
self2.emit("close", e.code, e.reason);
self2._cleanup();
};
this.ws.onerror = function(e) {
debug("error event", e);
self2.emit("close", 1006, "WebSocket connection broken");
self2._cleanup();
};
}
inherits(WebSocketTransport, EventEmitter);
WebSocketTransport.prototype.send = function(data) {
var msg = "[" + data + "]";
debug("send", msg);
this.ws.send(msg);
};
WebSocketTransport.prototype.close = function() {
debug("close");
var ws = this.ws;
this._cleanup();
if (ws) {
ws.close();
}
};
WebSocketTransport.prototype._cleanup = function() {
debug("_cleanup");
var ws = this.ws;
if (ws) {
ws.onmessage = ws.onclose = ws.onerror = null;
}
utils.unloadDel(this.unloadRef);
this.unloadRef = this.ws = null;
this.removeAllListeners();
};
WebSocketTransport.enabled = function() {
debug("enabled");
return !!WebsocketDriver;
};
WebSocketTransport.transportName = "websocket";
WebSocketTransport.roundTrips = 2;
module.exports = WebSocketTransport;
}
});
// node_modules/sockjs-client/lib/transport/lib/buffered-sender.js
var require_buffered_sender = __commonJS({
"node_modules/sockjs-client/lib/transport/lib/buffered-sender.js"(exports, module) {
"use strict";
var inherits = require_inherits_browser();
var EventEmitter = require_emitter().EventEmitter;
var debug = function() {
};
if (true) {
debug = require_browser()("sockjs-client:buffered-sender");
}
function BufferedSender(url, sender) {
debug(url);
EventEmitter.call(this);
this.sendBuffer = [];
this.sender = sender;
this.url = url;
}
inherits(BufferedSender, EventEmitter);
BufferedSender.prototype.send = function(message) {
debug("send", message);
this.sendBuffer.push(message);
if (!this.sendStop) {
this.sendSchedule();
}
};
BufferedSender.prototype.sendScheduleWait = function() {
debug("sendScheduleWait");
var self2 = this;
var tref;
this.sendStop = function() {
debug("sendStop");
self2.sendStop = null;
clearTimeout(tref);
};
tref = setTimeout(function() {
debug("timeout");
self2.sendStop = null;
self2.sendSchedule();
}, 25);
};
BufferedSender.prototype.sendSchedule = function() {
debug("sendSchedule", this.sendBuffer.length);
var self2 = this;
if (this.sendBuffer.length > 0) {
var payload = "[" + this.sendBuffer.join(",") + "]";
this.sendStop = this.sender(this.url, payload, function(err) {
self2.sendStop = null;
if (err) {
debug("error", err);
self2.emit("close", err.code || 1006, "Sending error: " + err);
self2.close();
} else {
self2.sendScheduleWait();
}
});
this.sendBuffer = [];
}
};
BufferedSender.prototype._cleanup = function() {
debug("_cleanup");
this.removeAllListeners();
};
BufferedSender.prototype.close = function() {
debug("close");
this._cleanup();
if (this.sendStop) {
this.sendStop();
this.sendStop = null;
}
};
module.exports = BufferedSender;
}
});
// node_modules/sockjs-client/lib/transport/lib/polling.js
var require_polling = __commonJS({
"node_modules/sockjs-client/lib/transport/lib/polling.js"(exports, module) {
"use strict";
var inherits = require_inherits_browser();
var EventEmitter = require_emitter().EventEmitter;
var debug = function() {
};
if (true) {
debug = require_browser()("sockjs-client:polling");
}
function Polling(Receiver, receiveUrl, AjaxObject) {
debug(receiveUrl);
EventEmitter.call(this);
this.Receiver = Receiver;
this.receiveUrl = receiveUrl;
this.AjaxObject = AjaxObject;
this._scheduleReceiver();
}
inherits(Polling, EventEmitter);
Polling.prototype._scheduleReceiver = function() {
debug("_scheduleReceiver");
var self2 = this;
var poll = this.poll = new this.Receiver(this.receiveUrl, this.AjaxObject);
poll.on("message", function(msg) {
debug("message", msg);
self2.emit("message", msg);
});
poll.once("close", function(code, reason) {
debug("close", code, reason, self2.pollIsClosing);
self2.poll = poll = null;
if (!self2.pollIsClosing) {
if (reason === "network") {
self2._scheduleReceiver();
} else {
self2.emit("close", code || 1006, reason);
self2.removeAllListeners();
}
}
});
};
Polling.prototype.abort = function() {
debug("abort");
this.removeAllListeners();
this.pollIsClosing = true;
if (this.poll) {
this.poll.abort();
}
};
module.exports = Polling;
}
});
// node_modules/sockjs-client/lib/transport/lib/sender-receiver.js
var require_sender_receiver = __commonJS({
"node_modules/sockjs-client/lib/transport/lib/sender-receiver.js"(exports, module) {
"use strict";
var inherits = require_inherits_browser();
var urlUtils = require_url();
var BufferedSender = require_buffered_sender();
var Polling = require_polling();
var debug = function() {
};
if (true) {
debug = require_browser()("sockjs-client:sender-receiver");
}
function SenderReceiver(transUrl, urlSuffix, senderFunc, Receiver, AjaxObject) {
var pollUrl = urlUtils.addPath(transUrl, urlSuffix);
debug(pollUrl);
var self2 = this;
BufferedSender.call(this, transUrl, senderFunc);
this.poll = new Polling(Receiver, pollUrl, AjaxObject);
this.poll.on("message", function(msg) {
debug("poll message", msg);
self2.emit("message", msg);
});
this.poll.once("close", function(code, reason) {
debug("poll close", code, reason);
self2.poll = null;
self2.emit("close", code, reason);
self2.close();
});
}
inherits(SenderReceiver, BufferedSender);
SenderReceiver.prototype.close = function() {
BufferedSender.prototype.close.call(this);
debug("close");
this.removeAllListeners();
if (this.poll) {
this.poll.abort();
this.poll = null;
}
};
module.exports = SenderReceiver;
}
});
// node_modules/sockjs-client/lib/transport/lib/ajax-based.js
var require_ajax_based = __commonJS({
"node_modules/sockjs-client/lib/transport/lib/ajax-based.js"(exports, module) {
"use strict";
var inherits = require_inherits_browser();
var urlUtils = require_url();
var SenderReceiver = require_sender_receiver();
var debug = function() {
};
if (true) {
debug = require_browser()("sockjs-client:ajax-based");
}
function createAjaxSender(AjaxObject) {
return function(url, payload, callback) {
debug("create ajax sender", url, payload);
var opt = {};
if (typeof payload === "string") {
opt.headers = { "Content-type": "text/plain" };
}
var ajaxUrl = urlUtils.addPath(url, "/xhr_send");
var xo = new AjaxObject("POST", ajaxUrl, payload, opt);
xo.once("finish", function(status) {
debug("finish", status);
xo = null;
if (status !== 200 && status !== 204) {
return callback(new Error("http status " + status));
}
callback();
});
return function() {
debug("abort");
xo.close();
xo = null;
var err = new Error("Aborted");
err.code = 1e3;
callback(err);
};
};
}
function AjaxBasedTransport(transUrl, urlSuffix, Receiver, AjaxObject) {
SenderReceiver.call(this, transUrl, urlSuffix, createAjaxSender(AjaxObject), Receiver, AjaxObject);
}
inherits(AjaxBasedTransport, SenderReceiver);
module.exports = AjaxBasedTransport;
}
});
// node_modules/sockjs-client/lib/transport/receiver/xhr.js
var require_xhr = __commonJS({
"node_modules/sockjs-client/lib/transport/receiver/xhr.js"(exports, module) {
"use strict";
var inherits = require_inherits_browser();
var EventEmitter = require_emitter().EventEmitter;
var debug = function() {
};
if (true) {
debug = require_browser()("sockjs-client:receiver:xhr");
}
function XhrReceiver(url, AjaxObject) {
debug(url);
EventEmitter.call(this);
var self2 = this;
this.bufferPosition = 0;
this.xo = new AjaxObject("POST", url, null);
this.xo.on("chunk", this._chunkHandler.bind(this));
this.xo.once("finish", function(status, text) {
debug("finish", status, text);
self2._chunkHandler(status, text);
self2.xo = null;
var reason = status === 200 ? "network" : "permanent";
debug("close", reason);
self2.emit("close", null, reason);
self2._cleanup();
});
}
inherits(XhrReceiver, EventEmitter);
XhrReceiver.prototype._chunkHandler = function(status, text) {
debug("_chunkHandler", status);
if (status !== 200 || !text) {
return;
}
for (var idx = -1; ; this.bufferPosition += idx + 1) {
var buf = text.slice(this.bufferPosition);
idx = buf.indexOf("\n");
if (idx === -1) {
break;
}
var msg = buf.slice(0, idx);
if (msg) {
debug("message", msg);
this.emit("message", msg);
}
}
};
XhrReceiver.prototype._cleanup = function() {
debug("_cleanup");
this.removeAllListeners();
};
XhrReceiver.prototype.abort = function() {
debug("abort");
if (this.xo) {
this.xo.close();
debug("close");
this.emit("close", null, "user");
this.xo = null;
}
this._cleanup();
};
module.exports = XhrReceiver;
}
});
// node_modules/sockjs-client/lib/transport/browser/abstract-xhr.js
var require_abstract_xhr = __commonJS({
"node_modules/sockjs-client/lib/transport/browser/abstract-xhr.js"(exports, module) {
"use strict";
var EventEmitter = require_emitter().EventEmitter;
var inherits = require_inherits_browser();
var utils = require_event();
var urlUtils = require_url();
var XHR = window.XMLHttpRequest;
var debug = function() {
};
if (true) {
debug = require_browser()("sockjs-client:browser:xhr");
}
function AbstractXHRObject(method, url, payload, opts) {
debug(method, url);
var self2 = this;
EventEmitter.call(this);
setTimeout(function() {
self2._start(method, url, payload, opts);
}, 0);
}
inherits(AbstractXHRObject, EventEmitter);
AbstractXHRObject.prototype._start = function(method, url, payload, opts) {
var self2 = this;
try {
this.xhr = new XHR();
} catch (x) {
}
if (!this.xhr) {
debug("no xhr");
this.emit("finish", 0, "no xhr support");
this._cleanup();
return;
}
url = urlUtils.addQuery(url, "t=" + +/* @__PURE__ */ new Date());
this.unloadRef = utils.unloadAdd(function() {
debug("unload cleanup");
self2._cleanup(true);
});
try {
this.xhr.open(method, url, true);
if (this.timeout && "timeout" in this.xhr) {
this.xhr.timeout = this.timeout;
this.xhr.ontimeout = function() {
debug("xhr timeout");
self2.emit("finish", 0, "");
self2._cleanup(false);
};
}
} catch (e) {
debug("exception", e);
this.emit("finish", 0, "");
this._cleanup(false);
return;
}
if ((!opts || !opts.noCredentials) && AbstractXHRObject.supportsCORS) {
debug("withCredentials");
this.xhr.withCredentials = true;
}
if (opts && opts.headers) {
for (var key in opts.headers) {
this.xhr.setRequestHeader(key, opts.headers[key]);
}
}
this.xhr.onreadystatechange = function() {
if (self2.xhr) {
var x = self2.xhr;
var text, status;
debug("readyState", x.readyState);
switch (x.readyState) {
case 3:
try {
status = x.status;
text = x.responseText;
} catch (e) {
}
debug("status", status);
if (status === 1223) {
status = 204;
}
if (status === 200 && text && text.length > 0) {
debug("chunk");
self2.emit("chunk", status, text);
}
break;
case 4:
status = x.status;
debug("status", status);
if (status === 1223) {
status = 204;
}
if (status === 12005 || status === 12029) {
status = 0;
}
debug("finish", status, x.responseText);
self2.emit("finish", status, x.responseText);
self2._cleanup(false);
break;
}
}
};
try {
self2.xhr.send(payload);
} catch (e) {
self2.emit("finish", 0, "");
self2._cleanup(false);
}
};
AbstractXHRObject.prototype._cleanup = function(abort) {
debug("cleanup");
if (!this.xhr) {
return;
}
this.removeAllListeners();
utils.unloadDel(this.unloadRef);
this.xhr.onreadystatechange = function() {
};
if (this.xhr.ontimeout) {
this.xhr.ontimeout = null;
}
if (abort) {
try {
this.xhr.abort();
} catch (x) {
}
}
this.unloadRef = this.xhr = null;
};
AbstractXHRObject.prototype.close = function() {
debug("close");
this._cleanup(true);
};
AbstractXHRObject.enabled = !!XHR;
var axo = ["Active"].concat("Object").join("X");
if (!AbstractXHRObject.enabled && axo in window) {
debug("overriding xmlhttprequest");
XHR = function() {
try {
return new window[axo]("Microsoft.XMLHTTP");
} catch (e) {
return null;
}
};
AbstractXHRObject.enabled = !!new XHR();
}
var cors = false;
try {
cors = "withCredentials" in new XHR();
} catch (ignored) {
}
AbstractXHRObject.supportsCORS = cors;
module.exports = AbstractXHRObject;
}
});
// node_modules/sockjs-client/lib/transport/sender/xhr-cors.js
var require_xhr_cors = __commonJS({
"node_modules/sockjs-client/lib/transport/sender/xhr-cors.js"(exports, module) {
"use strict";
var inherits = require_inherits_browser();
var XhrDriver = require_abstract_xhr();
function XHRCorsObject(method, url, payload, opts) {
XhrDriver.call(this, method, url, payload, opts);
}
inherits(XHRCorsObject, XhrDriver);
XHRCorsObject.enabled = XhrDriver.enabled && XhrDriver.supportsCORS;
module.exports = XHRCorsObject;
}
});
// node_modules/sockjs-client/lib/transport/sender/xhr-local.js
var require_xhr_local = __commonJS({
"node_modules/sockjs-client/lib/transport/sender/xhr-local.js"(exports, module) {
"use strict";
var inherits = require_inherits_browser();
var XhrDriver = require_abstract_xhr();
function XHRLocalObject(method, url, payload) {
XhrDriver.call(this, method, url, payload, {
noCredentials: true
});
}
inherits(XHRLocalObject, XhrDriver);
XHRLocalObject.enabled = XhrDriver.enabled;
module.exports = XHRLocalObject;
}
});
// node_modules/sockjs-client/lib/utils/browser.js
var require_browser2 = __commonJS({
"node_modules/sockjs-client/lib/utils/browser.js"(exports, module) {
"use strict";
module.exports = {
isOpera: function() {
return window.navigator && /opera/i.test(window.navigator.userAgent);
},
isKonqueror: function() {
return window.navigator && /konqueror/i.test(window.navigator.userAgent);
},
hasDomain: function() {
if (!window.document) {
return true;
}
try {
return !!window.document.domain;
} catch (e) {
return false;
}
}
};
}
});
// node_modules/sockjs-client/lib/transport/xhr-streaming.js
var require_xhr_streaming = __commonJS({
"node_modules/sockjs-client/lib/transport/xhr-streaming.js"(exports, module) {
"use strict";
var inherits = require_inherits_browser();
var AjaxBasedTransport = require_ajax_based();
var XhrReceiver = require_xhr();
var XHRCorsObject = require_xhr_cors();
var XHRLocalObject = require_xhr_local();
var browser = require_browser2();
function XhrStreamingTransport(transUrl) {
if (!XHRLocalObject.enabled && !XHRCorsObject.enabled) {
throw new Error("Transport created when disabled");
}
AjaxBasedTransport.call(this, transUrl, "/xhr_streaming", XhrReceiver, XHRCorsObject);
}
inherits(XhrStreamingTransport, AjaxBasedTransport);
XhrStreamingTransport.enabled = function(info) {
if (info.nullOrigin) {
return false;
}
if (browser.isOpera()) {
return false;
}
return XHRCorsObject.enabled;
};
XhrStreamingTransport.transportName = "xhr-streaming";
XhrStreamingTransport.roundTrips = 2;
XhrStreamingTransport.needBody = !!window.document;
module.exports = XhrStreamingTransport;
}
});
// node_modules/sockjs-client/lib/transport/sender/xdr.js
var require_xdr = __commonJS({
"node_modules/sockjs-client/lib/transport/sender/xdr.js"(exports, module) {
"use strict";
var EventEmitter = require_emitter().EventEmitter;
var inherits = require_inherits_browser();
var eventUtils = require_event();
var browser = require_browser2();
var urlUtils = require_url();
var debug = function() {
};
if (true) {
debug = require_browser()("sockjs-client:sender:xdr");
}
function XDRObject(method, url, payload) {
debug(method, url);
var self2 = this;
EventEmitter.call(this);
setTimeout(function() {
self2._start(method, url, payload);
}, 0);
}
inherits(XDRObject, EventEmitter);
XDRObject.prototype._start = function(method, url, payload) {
debug("_start");
var self2 = this;
var xdr = new window.XDomainRequest();
url = urlUtils.addQuery(url, "t=" + +/* @__PURE__ */ new Date());
xdr.onerror = function() {
debug("onerror");
self2._error();
};
xdr.ontimeout = function() {
debug("ontimeout");
self2._error();
};
xdr.onprogress = function() {
debug("progress", xdr.responseText);
self2.emit("chunk", 200, xdr.responseText);
};
xdr.onload = function() {
debug("load");
self2.emit("finish", 200, xdr.responseText);
self2._cleanup(false);
};
this.xdr = xdr;
this.unloadRef = eventUtils.unloadAdd(function() {
self2._cleanup(true);
});
try {
this.xdr.open(method, url);
if (this.timeout) {
this.xdr.timeout = this.timeout;
}
this.xdr.send(payload);
} catch (x) {
this._error();
}
};
XDRObject.prototype._error = function() {
this.emit("finish", 0, "");
this._cleanup(false);
};
XDRObject.prototype._cleanup = function(abort) {
debug("cleanup", abort);
if (!this.xdr) {
return;
}
this.removeAllListeners();
eventUtils.unloadDel(this.unloadRef);
this.xdr.ontimeout = this.xdr.onerror = this.xdr.onprogress = this.xdr.onload = null;
if (abort) {
try {
this.xdr.abort();
} catch (x) {
}
}
this.unloadRef = this.xdr = null;
};
XDRObject.prototype.close = function() {
debug("close");
this._cleanup(true);
};
XDRObject.enabled = !!(window.XDomainRequest && browser.hasDomain());
module.exports = XDRObject;
}
});
// node_modules/sockjs-client/lib/transport/xdr-streaming.js
var require_xdr_streaming = __commonJS({
"node_modules/sockjs-client/lib/transport/xdr-streaming.js"(exports, module) {
"use strict";
var inherits = require_inherits_browser();
var AjaxBasedTransport = require_ajax_based();
var XhrReceiver = require_xhr();
var XDRObject = require_xdr();
function XdrStreamingTransport(transUrl) {
if (!XDRObject.enabled) {
throw new Error("Transport created when disabled");
}
AjaxBasedTransport.call(this, transUrl, "/xhr_streaming", XhrReceiver, XDRObject);
}
inherits(XdrStreamingTransport, AjaxBasedTransport);
XdrStreamingTransport.enabled = function(info) {
if (info.cookie_needed || info.nullOrigin) {
return false;
}
return XDRObject.enabled && info.sameScheme;
};
XdrStreamingTransport.transportName = "xdr-streaming";
XdrStreamingTransport.roundTrips = 2;
module.exports = XdrStreamingTransport;
}
});
// node_modules/sockjs-client/lib/transport/browser/eventsource.js
var require_eventsource = __commonJS({
"node_modules/sockjs-client/lib/transport/browser/eventsource.js"(exports, module) {
module.exports = window.EventSource;
}
});
// node_modules/sockjs-client/lib/transport/receiver/eventsource.js
var require_eventsource2 = __commonJS({
"node_modules/sockjs-client/lib/transport/receiver/eventsource.js"(exports, module) {
"use strict";
var inherits = require_inherits_browser();
var EventEmitter = require_emitter().EventEmitter;
var EventSourceDriver = require_eventsource();
var debug = function() {
};
if (true) {
debug = require_browser()("sockjs-client:receiver:eventsource");
}
function EventSourceReceiver(url) {
debug(url);
EventEmitter.call(this);
var self2 = this;
var es = this.es = new EventSourceDriver(url);
es.onmessage = function(e) {
debug("message", e.data);
self2.emit("message", decodeURI(e.data));
};
es.onerror = function(e) {
debug("error", es.readyState, e);
var reason = es.readyState !== 2 ? "network" : "permanent";
self2._cleanup();
self2._close(reason);
};
}
inherits(EventSourceReceiver, EventEmitter);
EventSourceReceiver.prototype.abort = function() {
debug("abort");
this._cleanup();
this._close("user");
};
EventSourceReceiver.prototype._cleanup = function() {
debug("cleanup");
var es = this.es;
if (es) {
es.onmessage = es.onerror = null;
es.close();
this.es = null;
}
};
EventSourceReceiver.prototype._close = function(reason) {
debug("close", reason);
var self2 = this;
setTimeout(function() {
self2.emit("close", null, reason);
self2.removeAllListeners();
}, 200);
};
module.exports = EventSourceReceiver;
}
});
// node_modules/sockjs-client/lib/transport/eventsource.js
var require_eventsource3 = __commonJS({
"node_modules/sockjs-client/lib/transport/eventsource.js"(exports, module) {
"use strict";
var inherits = require_inherits_browser();
var AjaxBasedTransport = require_ajax_based();
var EventSourceReceiver = require_eventsource2();
var XHRCorsObject = require_xhr_cors();
var EventSourceDriver = require_eventsource();
function EventSourceTransport(transUrl) {
if (!EventSourceTransport.enabled()) {
throw new Error("Transport created when disabled");
}
AjaxBasedTransport.call(this, transUrl, "/eventsource", EventSourceReceiver, XHRCorsObject);
}
inherits(EventSourceTransport, AjaxBasedTransport);
EventSourceTransport.enabled = function() {
return !!EventSourceDriver;
};
EventSourceTransport.transportName = "eventsource";
EventSourceTransport.roundTrips = 2;
module.exports = EventSourceTransport;
}
});
// node_modules/sockjs-client/lib/version.js
var require_version = __commonJS({
"node_modules/sockjs-client/lib/version.js"(exports, module) {
module.exports = "1.6.1";
}
});
// node_modules/sockjs-client/lib/utils/iframe.js
var require_iframe = __commonJS({
"node_modules/sockjs-client/lib/utils/iframe.js"(exports, module) {
"use strict";
var eventUtils = require_event();
var browser = require_browser2();
var debug = function() {
};
if (true) {
debug = require_browser()("sockjs-client:utils:iframe");
}
module.exports = {
WPrefix: "_jp",
currentWindowId: null,
polluteGlobalNamespace: function() {
if (!(module.exports.WPrefix in window)) {
window[module.exports.WPrefix] = {};
}
},
postMessage: function(type, data) {
if (window.parent !== window) {
window.parent.postMessage(JSON.stringify({
windowId: module.exports.currentWindowId,
type,
data: data || ""
}), "*");
} else {
debug("Cannot postMessage, no parent window.", type, data);
}
},
createIframe: function(iframeUrl, errorCallback) {
var iframe = window.document.createElement("iframe");
var tref, unloadRef;
var unattach = function() {
debug("unattach");
clearTimeout(tref);
try {
iframe.onload = null;
} catch (x) {
}
iframe.onerror = null;
};
var cleanup = function() {
debug("cleanup");
if (iframe) {
unattach();
setTimeout(function() {
if (iframe) {
iframe.parentNode.removeChild(iframe);
}
iframe = null;
}, 0);
eventUtils.unloadDel(unloadRef);
}
};
var onerror = function(err) {
debug("onerror", err);
if (iframe) {
cleanup();
errorCallback(err);
}
};
var post = function(msg, origin) {
debug("post", msg, origin);
setTimeout(function() {
try {
if (iframe && iframe.contentWindow) {
iframe.contentWindow.postMessage(msg, origin);
}
} catch (x) {
}
}, 0);
};
iframe.src = iframeUrl;
iframe.style.display = "none";
iframe.style.position = "absolute";
iframe.onerror = function() {
onerror("onerror");
};
iframe.onload = function() {
debug("onload");
clearTimeout(tref);
tref = setTimeout(function() {
onerror("onload timeout");
}, 2e3);
};
window.document.body.appendChild(iframe);
tref = setTimeout(function() {
onerror("timeout");
}, 15e3);
unloadRef = eventUtils.unloadAdd(cleanup);
return {
post,
cleanup,
loaded: unattach
};
},
createHtmlfile: function(iframeUrl, errorCallback) {
var axo = ["Active"].concat("Object").join("X");
var doc = new window[axo]("htmlfile");
var tref, unloadRef;
var iframe;
var unattach = function() {
clearTimeout(tref);
iframe.onerror = null;
};
var cleanup = function() {
if (doc) {
unattach();
eventUtils.unloadDel(unloadRef);
iframe.parentNode.removeChild(iframe);
iframe = doc = null;
CollectGarbage();
}
};
var onerror = function(r) {
debug("onerror", r);
if (doc) {
cleanup();
errorCallback(r);
}
};
var post = function(msg, origin) {
try {
setTimeout(function() {
if (iframe && iframe.contentWindow) {
iframe.contentWindow.postMessage(msg, origin);
}
}, 0);
} catch (x) {
}
};
doc.open();
doc.write('<html><script>document.domain="' + window.document.domain + '";<\/script></html>');
doc.close();
doc.parentWindow[module.exports.WPrefix] = window[module.exports.WPrefix];
var c = doc.createElement("div");
doc.body.appendChild(c);
iframe = doc.createElement("iframe");
c.appendChild(iframe);
iframe.src = iframeUrl;
iframe.onerror = function() {
onerror("onerror");
};
tref = setTimeout(function() {
onerror("timeout");
}, 15e3);
unloadRef = eventUtils.unloadAdd(cleanup);
return {
post,
cleanup,
loaded: unattach
};
}
};
module.exports.iframeEnabled = false;
if (window.document) {
module.exports.iframeEnabled = (typeof window.postMessage === "function" || typeof window.postMessage === "object") && !browser.isKonqueror();
}
}
});
// node_modules/sockjs-client/lib/transport/iframe.js
var require_iframe2 = __commonJS({
"node_modules/sockjs-client/lib/transport/iframe.js"(exports, module) {
"use strict";
var inherits = require_inherits_browser();
var EventEmitter = require_emitter().EventEmitter;
var version = require_version();
var urlUtils = require_url();
var iframeUtils = require_iframe();
var eventUtils = require_event();
var random = require_random();
var debug = function() {
};
if (true) {
debug = require_browser()("sockjs-client:transport:iframe");
}
function IframeTransport(transport, transUrl, baseUrl) {
if (!IframeTransport.enabled()) {
throw new Error("Transport created when disabled");
}
EventEmitter.call(this);
var self2 = this;
this.origin = urlUtils.getOrigin(baseUrl);
this.baseUrl = baseUrl;
this.transUrl = transUrl;
this.transport = transport;
this.windowId = random.string(8);
var iframeUrl = urlUtils.addPath(baseUrl, "/iframe.html") + "#" + this.windowId;
debug(transport, transUrl, iframeUrl);
this.iframeObj = iframeUtils.createIframe(iframeUrl, function(r) {
debug("err callback");
self2.emit("close", 1006, "Unable to load an iframe (" + r + ")");
self2.close();
});
this.onmessageCallback = this._message.bind(this);
eventUtils.attachEvent("message", this.onmessageCallback);
}
inherits(IframeTransport, EventEmitter);
IframeTransport.prototype.close = function() {
debug("close");
this.removeAllListeners();
if (this.iframeObj) {
eventUtils.detachEvent("message", this.onmessageCallback);
try {
this.postMessage("c");
} catch (x) {
}
this.iframeObj.cleanup();
this.iframeObj = null;
this.onmessageCallback = this.iframeObj = null;
}
};
IframeTransport.prototype._message = function(e) {
debug("message", e.data);
if (!urlUtils.isOriginEqual(e.origin, this.origin)) {
debug("not same origin", e.origin, this.origin);
return;
}
var iframeMessage;
try {
iframeMessage = JSON.parse(e.data);
} catch (ignored) {
debug("bad json", e.data);
return;
}
if (iframeMessage.windowId !== this.windowId) {
debug("mismatched window id", iframeMessage.windowId, this.windowId);
return;
}
switch (iframeMessage.type) {
case "s":
this.iframeObj.loaded();
this.postMessage("s", JSON.stringify([
version,
this.transport,
this.transUrl,
this.baseUrl
]));
break;
case "t":
this.emit("message", iframeMessage.data);
break;
case "c":
var cdata;
try {
cdata = JSON.parse(iframeMessage.data);
} catch (ignored) {
debug("bad json", iframeMessage.data);
return;
}
this.emit("close", cdata[0], cdata[1]);
this.close();
break;
}
};
IframeTransport.prototype.postMessage = function(type, data) {
debug("postMessage", type, data);
this.iframeObj.post(JSON.stringify({
windowId: this.windowId,
type,
data: data || ""
}), this.origin);
};
IframeTransport.prototype.send = function(message) {
debug("send", message);
this.postMessage("m", message);
};
IframeTransport.enabled = function() {
return iframeUtils.iframeEnabled;
};
IframeTransport.transportName = "iframe";
IframeTransport.roundTrips = 2;
module.exports = IframeTransport;
}
});
// node_modules/sockjs-client/lib/utils/object.js
var require_object = __commonJS({
"node_modules/sockjs-client/lib/utils/object.js"(exports, module) {
"use strict";
module.exports = {
isObject: function(obj) {
var type = typeof obj;
return type === "function" || type === "object" && !!obj;
},
extend: function(obj) {
if (!this.isObject(obj)) {
return obj;
}
var source, prop;
for (var i = 1, length = arguments.length; i < length; i++) {
source = arguments[i];
for (prop in source) {
if (Object.prototype.hasOwnProperty.call(source, prop)) {
obj[prop] = source[prop];
}
}
}
return obj;
}
};
}
});
// node_modules/sockjs-client/lib/transport/lib/iframe-wrap.js
var require_iframe_wrap = __commonJS({
"node_modules/sockjs-client/lib/transport/lib/iframe-wrap.js"(exports, module) {
"use strict";
var inherits = require_inherits_browser();
var IframeTransport = require_iframe2();
var objectUtils = require_object();
module.exports = function(transport) {
function IframeWrapTransport(transUrl, baseUrl) {
IframeTransport.call(this, transport.transportName, transUrl, baseUrl);
}
inherits(IframeWrapTransport, IframeTransport);
IframeWrapTransport.enabled = function(url, info) {
if (!window.document) {
return false;
}
var iframeInfo = objectUtils.extend({}, info);
iframeInfo.sameOrigin = true;
return transport.enabled(iframeInfo) && IframeTransport.enabled();
};
IframeWrapTransport.transportName = "iframe-" + transport.transportName;
IframeWrapTransport.needBody = true;
IframeWrapTransport.roundTrips = IframeTransport.roundTrips + transport.roundTrips - 1;
IframeWrapTransport.facadeTransport = transport;
return IframeWrapTransport;
};
}
});
// node_modules/sockjs-client/lib/transport/receiver/htmlfile.js
var require_htmlfile = __commonJS({
"node_modules/sockjs-client/lib/transport/receiver/htmlfile.js"(exports, module) {
"use strict";
var inherits = require_inherits_browser();
var iframeUtils = require_iframe();
var urlUtils = require_url();
var EventEmitter = require_emitter().EventEmitter;
var random = require_random();
var debug = function() {
};
if (true) {
debug = require_browser()("sockjs-client:receiver:htmlfile");
}
function HtmlfileReceiver(url) {
debug(url);
EventEmitter.call(this);
var self2 = this;
iframeUtils.polluteGlobalNamespace();
this.id = "a" + random.string(6);
url = urlUtils.addQuery(url, "c=" + decodeURIComponent(iframeUtils.WPrefix + "." + this.id));
debug("using htmlfile", HtmlfileReceiver.htmlfileEnabled);
var constructFunc = HtmlfileReceiver.htmlfileEnabled ? iframeUtils.createHtmlfile : iframeUtils.createIframe;
window[iframeUtils.WPrefix][this.id] = {
start: function() {
debug("start");
self2.iframeObj.loaded();
},
message: function(data) {
debug("message", data);
self2.emit("message", data);
},
stop: function() {
debug("stop");
self2._cleanup();
self2._close("network");
}
};
this.iframeObj = constructFunc(url, function() {
debug("callback");
self2._cleanup();
self2._close("permanent");
});
}
inherits(HtmlfileReceiver, EventEmitter);
HtmlfileReceiver.prototype.abort = function() {
debug("abort");
this._cleanup();
this._close("user");
};
HtmlfileReceiver.prototype._cleanup = function() {
debug("_cleanup");
if (this.iframeObj) {
this.iframeObj.cleanup();
this.iframeObj = null;
}
delete window[iframeUtils.WPrefix][this.id];
};
HtmlfileReceiver.prototype._close = function(reason) {
debug("_close", reason);
this.emit("close", null, reason);
this.removeAllListeners();
};
HtmlfileReceiver.htmlfileEnabled = false;
var axo = ["Active"].concat("Object").join("X");
if (axo in window) {
try {
HtmlfileReceiver.htmlfileEnabled = !!new window[axo]("htmlfile");
} catch (x) {
}
}
HtmlfileReceiver.enabled = HtmlfileReceiver.htmlfileEnabled || iframeUtils.iframeEnabled;
module.exports = HtmlfileReceiver;
}
});
// node_modules/sockjs-client/lib/transport/htmlfile.js
var require_htmlfile2 = __commonJS({
"node_modules/sockjs-client/lib/transport/htmlfile.js"(exports, module) {
"use strict";
var inherits = require_inherits_browser();
var HtmlfileReceiver = require_htmlfile();
var XHRLocalObject = require_xhr_local();
var AjaxBasedTransport = require_ajax_based();
function HtmlFileTransport(transUrl) {
if (!HtmlfileReceiver.enabled) {
throw new Error("Transport created when disabled");
}
AjaxBasedTransport.call(this, transUrl, "/htmlfile", HtmlfileReceiver, XHRLocalObject);
}
inherits(HtmlFileTransport, AjaxBasedTransport);
HtmlFileTransport.enabled = function(info) {
return HtmlfileReceiver.enabled && info.sameOrigin;
};
HtmlFileTransport.transportName = "htmlfile";
HtmlFileTransport.roundTrips = 2;
module.exports = HtmlFileTransport;
}
});
// node_modules/sockjs-client/lib/transport/xhr-polling.js
var require_xhr_polling = __commonJS({
"node_modules/sockjs-client/lib/transport/xhr-polling.js"(exports, module) {
"use strict";
var inherits = require_inherits_browser();
var AjaxBasedTransport = require_ajax_based();
var XhrReceiver = require_xhr();
var XHRCorsObject = require_xhr_cors();
var XHRLocalObject = require_xhr_local();
function XhrPollingTransport(transUrl) {
if (!XHRLocalObject.enabled && !XHRCorsObject.enabled) {
throw new Error("Transport created when disabled");
}
AjaxBasedTransport.call(this, transUrl, "/xhr", XhrReceiver, XHRCorsObject);
}
inherits(XhrPollingTransport, AjaxBasedTransport);
XhrPollingTransport.enabled = function(info) {
if (info.nullOrigin) {
return false;
}
if (XHRLocalObject.enabled && info.sameOrigin) {
return true;
}
return XHRCorsObject.enabled;
};
XhrPollingTransport.transportName = "xhr-polling";
XhrPollingTransport.roundTrips = 2;
module.exports = XhrPollingTransport;
}
});
// node_modules/sockjs-client/lib/transport/xdr-polling.js
var require_xdr_polling = __commonJS({
"node_modules/sockjs-client/lib/transport/xdr-polling.js"(exports, module) {
"use strict";
var inherits = require_inherits_browser();
var AjaxBasedTransport = require_ajax_based();
var XdrStreamingTransport = require_xdr_streaming();
var XhrReceiver = require_xhr();
var XDRObject = require_xdr();
function XdrPollingTransport(transUrl) {
if (!XDRObject.enabled) {
throw new Error("Transport created when disabled");
}
AjaxBasedTransport.call(this, transUrl, "/xhr", XhrReceiver, XDRObject);
}
inherits(XdrPollingTransport, AjaxBasedTransport);
XdrPollingTransport.enabled = XdrStreamingTransport.enabled;
XdrPollingTransport.transportName = "xdr-polling";
XdrPollingTransport.roundTrips = 2;
module.exports = XdrPollingTransport;
}
});
// node_modules/sockjs-client/lib/transport/receiver/jsonp.js
var require_jsonp = __commonJS({
"node_modules/sockjs-client/lib/transport/receiver/jsonp.js"(exports, module) {
"use strict";
var utils = require_iframe();
var random = require_random();
var browser = require_browser2();
var urlUtils = require_url();
var inherits = require_inherits_browser();
var EventEmitter = require_emitter().EventEmitter;
var debug = function() {
};
if (true) {
debug = require_browser()("sockjs-client:receiver:jsonp");
}
function JsonpReceiver(url) {
debug(url);
var self2 = this;
EventEmitter.call(this);
utils.polluteGlobalNamespace();
this.id = "a" + random.string(6);
var urlWithId = urlUtils.addQuery(url, "c=" + encodeURIComponent(utils.WPrefix + "." + this.id));
window[utils.WPrefix][this.id] = this._callback.bind(this);
this._createScript(urlWithId);
this.timeoutId = setTimeout(function() {
debug("timeout");
self2._abort(new Error("JSONP script loaded abnormally (timeout)"));
}, JsonpReceiver.timeout);
}
inherits(JsonpReceiver, EventEmitter);
JsonpReceiver.prototype.abort = function() {
debug("abort");
if (window[utils.WPrefix][this.id]) {
var err = new Error("JSONP user aborted read");
err.code = 1e3;
this._abort(err);
}
};
JsonpReceiver.timeout = 35e3;
JsonpReceiver.scriptErrorTimeout = 1e3;
JsonpReceiver.prototype._callback = function(data) {
debug("_callback", data);
this._cleanup();
if (this.aborting) {
return;
}
if (data) {
debug("message", data);
this.emit("message", data);
}
this.emit("close", null, "network");
this.removeAllListeners();
};
JsonpReceiver.prototype._abort = function(err) {
debug("_abort", err);
this._cleanup();
this.aborting = true;
this.emit("close", err.code, err.message);
this.removeAllListeners();
};
JsonpReceiver.prototype._cleanup = function() {
debug("_cleanup");
clearTimeout(this.timeoutId);
if (this.script2) {
this.script2.parentNode.removeChild(this.script2);
this.script2 = null;
}
if (this.script) {
var script = this.script;
script.parentNode.removeChild(script);
script.onreadystatechange = script.onerror = script.onload = script.onclick = null;
this.script = null;
}
delete window[utils.WPrefix][this.id];
};
JsonpReceiver.prototype._scriptError = function() {
debug("_scriptError");
var self2 = this;
if (this.errorTimer) {
return;
}
this.errorTimer = setTimeout(function() {
if (!self2.loadedOkay) {
self2._abort(new Error("JSONP script loaded abnormally (onerror)"));
}
}, JsonpReceiver.scriptErrorTimeout);
};
JsonpReceiver.prototype._createScript = function(url) {
debug("_createScript", url);
var self2 = this;
var script = this.script = window.document.createElement("script");
var script2;
script.id = "a" + random.string(8);
script.src = url;
script.type = "text/javascript";
script.charset = "UTF-8";
script.onerror = this._scriptError.bind(this);
script.onload = function() {
debug("onload");
self2._abort(new Error("JSONP script loaded abnormally (onload)"));
};
script.onreadystatechange = function() {
debug("onreadystatechange", script.readyState);
if (/loaded|closed/.test(script.readyState)) {
if (script && script.htmlFor && script.onclick) {
self2.loadedOkay = true;
try {
script.onclick();
} catch (x) {
}
}
if (script) {
self2._abort(new Error("JSONP script loaded abnormally (onreadystatechange)"));
}
}
};
if (typeof script.async === "undefined" && window.document.attachEvent) {
if (!browser.isOpera()) {
try {
script.htmlFor = script.id;
script.event = "onclick";
} catch (x) {
}
script.async = true;
} else {
script2 = this.script2 = window.document.createElement("script");
script2.text = "try{var a = document.getElementById('" + script.id + "'); if(a)a.onerror();}catch(x){};";
script.async = script2.async = false;
}
}
if (typeof script.async !== "undefined") {
script.async = true;
}
var head = window.document.getElementsByTagName("head")[0];
head.insertBefore(script, head.firstChild);
if (script2) {
head.insertBefore(script2, head.firstChild);
}
};
module.exports = JsonpReceiver;
}
});
// node_modules/sockjs-client/lib/transport/sender/jsonp.js
var require_jsonp2 = __commonJS({
"node_modules/sockjs-client/lib/transport/sender/jsonp.js"(exports, module) {
"use strict";
var random = require_random();
var urlUtils = require_url();
var debug = function() {
};
if (true) {
debug = require_browser()("sockjs-client:sender:jsonp");
}
var form;
var area;
function createIframe(id) {
debug("createIframe", id);
try {
return window.document.createElement('<iframe name="' + id + '">');
} catch (x) {
var iframe = window.document.createElement("iframe");
iframe.name = id;
return iframe;
}
}
function createForm() {
debug("createForm");
form = window.document.createElement("form");
form.style.display = "none";
form.style.position = "absolute";
form.method = "POST";
form.enctype = "application/x-www-form-urlencoded";
form.acceptCharset = "UTF-8";
area = window.document.createElement("textarea");
area.name = "d";
form.appendChild(area);
window.document.body.appendChild(form);
}
module.exports = function(url, payload, callback) {
debug(url, payload);
if (!form) {
createForm();
}
var id = "a" + random.string(8);
form.target = id;
form.action = urlUtils.addQuery(urlUtils.addPath(url, "/jsonp_send"), "i=" + id);
var iframe = createIframe(id);
iframe.id = id;
iframe.style.display = "none";
form.appendChild(iframe);
try {
area.value = payload;
} catch (e) {
}
form.submit();
var completed = function(err) {
debug("completed", id, err);
if (!iframe.onerror) {
return;
}
iframe.onreadystatechange = iframe.onerror = iframe.onload = null;
setTimeout(function() {
debug("cleaning up", id);
iframe.parentNode.removeChild(iframe);
iframe = null;
}, 500);
area.value = "";
callback(err);
};
iframe.onerror = function() {
debug("onerror", id);
completed();
};
iframe.onload = function() {
debug("onload", id);
completed();
};
iframe.onreadystatechange = function(e) {
debug("onreadystatechange", id, iframe.readyState, e);
if (iframe.readyState === "complete") {
completed();
}
};
return function() {
debug("aborted", id);
completed(new Error("Aborted"));
};
};
}
});
// node_modules/sockjs-client/lib/transport/jsonp-polling.js
var require_jsonp_polling = __commonJS({
"node_modules/sockjs-client/lib/transport/jsonp-polling.js"(exports, module) {
"use strict";
var inherits = require_inherits_browser();
var SenderReceiver = require_sender_receiver();
var JsonpReceiver = require_jsonp();
var jsonpSender = require_jsonp2();
function JsonPTransport(transUrl) {
if (!JsonPTransport.enabled()) {
throw new Error("Transport created when disabled");
}
SenderReceiver.call(this, transUrl, "/jsonp", jsonpSender, JsonpReceiver);
}
inherits(JsonPTransport, SenderReceiver);
JsonPTransport.enabled = function() {
return !!window.document;
};
JsonPTransport.transportName = "jsonp-polling";
JsonPTransport.roundTrips = 1;
JsonPTransport.needBody = true;
module.exports = JsonPTransport;
}
});
// node_modules/sockjs-client/lib/transport-list.js
var require_transport_list = __commonJS({
"node_modules/sockjs-client/lib/transport-list.js"(exports, module) {
"use strict";
module.exports = [
// streaming transports
require_websocket2(),
require_xhr_streaming(),
require_xdr_streaming(),
require_eventsource3(),
require_iframe_wrap()(require_eventsource3()),
require_htmlfile2(),
require_iframe_wrap()(require_htmlfile2()),
require_xhr_polling(),
require_xdr_polling(),
require_iframe_wrap()(require_xhr_polling()),
require_jsonp_polling()
];
}
});
// node_modules/sockjs-client/lib/shims.js
var require_shims = __commonJS({
"node_modules/sockjs-client/lib/shims.js"() {
"use strict";
var ArrayPrototype = Array.prototype;
var ObjectPrototype = Object.prototype;
var FunctionPrototype = Function.prototype;
var StringPrototype = String.prototype;
var array_slice = ArrayPrototype.slice;
var _toString = ObjectPrototype.toString;
var isFunction = function(val) {
return ObjectPrototype.toString.call(val) === "[object Function]";
};
var isArray = function isArray2(obj) {
return _toString.call(obj) === "[object Array]";
};
var isString = function isString2(obj) {
return _toString.call(obj) === "[object String]";
};
var supportsDescriptors = Object.defineProperty && function() {
try {
Object.defineProperty({}, "x", {});
return true;
} catch (e) {
return false;
}
}();
var defineProperty;
if (supportsDescriptors) {
defineProperty = function(object, name, method, forceAssign) {
if (!forceAssign && name in object) {
return;
}
Object.defineProperty(object, name, {
configurable: true,
enumerable: false,
writable: true,
value: method
});
};
} else {
defineProperty = function(object, name, method, forceAssign) {
if (!forceAssign && name in object) {
return;
}
object[name] = method;
};
}
var defineProperties = function(object, map, forceAssign) {
for (var name in map) {
if (ObjectPrototype.hasOwnProperty.call(map, name)) {
defineProperty(object, name, map[name], forceAssign);
}
}
};
var toObject = function(o) {
if (o == null) {
throw new TypeError("can't convert " + o + " to object");
}
return Object(o);
};
function toInteger(num) {
var n = +num;
if (n !== n) {
n = 0;
} else if (n !== 0 && n !== 1 / 0 && n !== -(1 / 0)) {
n = (n > 0 || -1) * Math.floor(Math.abs(n));
}
return n;
}
function ToUint32(x) {
return x >>> 0;
}
function Empty() {
}
defineProperties(FunctionPrototype, {
bind: function bind(that) {
var target = this;
if (!isFunction(target)) {
throw new TypeError("Function.prototype.bind called on incompatible " + target);
}
var args = array_slice.call(arguments, 1);
var binder = function() {
if (this instanceof bound) {
var result = target.apply(
this,
args.concat(array_slice.call(arguments))
);
if (Object(result) === result) {
return result;
}
return this;
} else {
return target.apply(
that,
args.concat(array_slice.call(arguments))
);
}
};
var boundLength = Math.max(0, target.length - args.length);
var boundArgs = [];
for (var i = 0; i < boundLength; i++) {
boundArgs.push("$" + i);
}
var bound = Function("binder", "return function (" + boundArgs.join(",") + "){ return binder.apply(this, arguments); }")(binder);
if (target.prototype) {
Empty.prototype = target.prototype;
bound.prototype = new Empty();
Empty.prototype = null;
}
return bound;
}
});
defineProperties(Array, { isArray });
var boxedString = Object("a");
var splitString = boxedString[0] !== "a" || !(0 in boxedString);
var properlyBoxesContext = function properlyBoxed(method) {
var properlyBoxesNonStrict = true;
var properlyBoxesStrict = true;
if (method) {
method.call("foo", function(_, __, context) {
if (typeof context !== "object") {
properlyBoxesNonStrict = false;
}
});
method.call([1], function() {
"use strict";
properlyBoxesStrict = typeof this === "string";
}, "x");
}
return !!method && properlyBoxesNonStrict && properlyBoxesStrict;
};
defineProperties(ArrayPrototype, {
forEach: function forEach(fun) {
var object = toObject(this), self2 = splitString && isString(this) ? this.split("") : object, thisp = arguments[1], i = -1, length = self2.length >>> 0;
if (!isFunction(fun)) {
throw new TypeError();
}
while (++i < length) {
if (i in self2) {
fun.call(thisp, self2[i], i, object);
}
}
}
}, !properlyBoxesContext(ArrayPrototype.forEach));
var hasFirefox2IndexOfBug = Array.prototype.indexOf && [0, 1].indexOf(1, 2) !== -1;
defineProperties(ArrayPrototype, {
indexOf: function indexOf(sought) {
var self2 = splitString && isString(this) ? this.split("") : toObject(this), length = self2.length >>> 0;
if (!length) {
return -1;
}
var i = 0;
if (arguments.length > 1) {
i = toInteger(arguments[1]);
}
i = i >= 0 ? i : Math.max(0, length + i);
for (; i < length; i++) {
if (i in self2 && self2[i] === sought) {
return i;
}
}
return -1;
}
}, hasFirefox2IndexOfBug);
var string_split = StringPrototype.split;
if ("ab".split(/(?:ab)*/).length !== 2 || ".".split(/(.?)(.?)/).length !== 4 || "tesst".split(/(s)*/)[1] === "t" || "test".split(/(?:)/, -1).length !== 4 || "".split(/.?/).length || ".".split(/()()/).length > 1) {
(function() {
var compliantExecNpcg = /()??/.exec("")[1] === void 0;
StringPrototype.split = function(separator, limit) {
var string = this;
if (separator === void 0 && limit === 0) {
return [];
}
if (_toString.call(separator) !== "[object RegExp]") {
return string_split.call(this, separator, limit);
}
var output = [], flags = (separator.ignoreCase ? "i" : "") + (separator.multiline ? "m" : "") + (separator.extended ? "x" : "") + // Proposed for ES6
(separator.sticky ? "y" : ""), lastLastIndex = 0, separator2, match, lastIndex, lastLength;
separator = new RegExp(separator.source, flags + "g");
string += "";
if (!compliantExecNpcg) {
separator2 = new RegExp("^" + separator.source + "$(?!\\s)", flags);
}
limit = limit === void 0 ? -1 >>> 0 : (
// Math.pow(2, 32) - 1
ToUint32(limit)
);
while (match = separator.exec(string)) {
lastIndex = match.index + match[0].length;
if (lastIndex > lastLastIndex) {
output.push(string.slice(lastLastIndex, match.index));
if (!compliantExecNpcg && match.length > 1) {
match[0].replace(separator2, function() {
for (var i = 1; i < arguments.length - 2; i++) {
if (arguments[i] === void 0) {
match[i] = void 0;
}
}
});
}
if (match.length > 1 && match.index < string.length) {
ArrayPrototype.push.apply(output, match.slice(1));
}
lastLength = match[0].length;
lastLastIndex = lastIndex;
if (output.length >= limit) {
break;
}
}
if (separator.lastIndex === match.index) {
separator.lastIndex++;
}
}
if (lastLastIndex === string.length) {
if (lastLength || !separator.test("")) {
output.push("");
}
} else {
output.push(string.slice(lastLastIndex));
}
return output.length > limit ? output.slice(0, limit) : output;
};
})();
} else if ("0".split(void 0, 0).length) {
StringPrototype.split = function split(separator, limit) {
if (separator === void 0 && limit === 0) {
return [];
}
return string_split.call(this, separator, limit);
};
}
var string_substr = StringPrototype.substr;
var hasNegativeSubstrBug = "".substr && "0b".substr(-1) !== "b";
defineProperties(StringPrototype, {
substr: function substr(start, length) {
return string_substr.call(
this,
start < 0 ? (start = this.length + start) < 0 ? 0 : start : start,
length
);
}
}, hasNegativeSubstrBug);
}
});
// node_modules/sockjs-client/lib/utils/escape.js
var require_escape = __commonJS({
"node_modules/sockjs-client/lib/utils/escape.js"(exports, module) {
"use strict";
var extraEscapable = /[\x00-\x1f\ud800-\udfff\ufffe\uffff\u0300-\u0333\u033d-\u0346\u034a-\u034c\u0350-\u0352\u0357-\u0358\u035c-\u0362\u0374\u037e\u0387\u0591-\u05af\u05c4\u0610-\u0617\u0653-\u0654\u0657-\u065b\u065d-\u065e\u06df-\u06e2\u06eb-\u06ec\u0730\u0732-\u0733\u0735-\u0736\u073a\u073d\u073f-\u0741\u0743\u0745\u0747\u07eb-\u07f1\u0951\u0958-\u095f\u09dc-\u09dd\u09df\u0a33\u0a36\u0a59-\u0a5b\u0a5e\u0b5c-\u0b5d\u0e38-\u0e39\u0f43\u0f4d\u0f52\u0f57\u0f5c\u0f69\u0f72-\u0f76\u0f78\u0f80-\u0f83\u0f93\u0f9d\u0fa2\u0fa7\u0fac\u0fb9\u1939-\u193a\u1a17\u1b6b\u1cda-\u1cdb\u1dc0-\u1dcf\u1dfc\u1dfe\u1f71\u1f73\u1f75\u1f77\u1f79\u1f7b\u1f7d\u1fbb\u1fbe\u1fc9\u1fcb\u1fd3\u1fdb\u1fe3\u1feb\u1fee-\u1fef\u1ff9\u1ffb\u1ffd\u2000-\u2001\u20d0-\u20d1\u20d4-\u20d7\u20e7-\u20e9\u2126\u212a-\u212b\u2329-\u232a\u2adc\u302b-\u302c\uaab2-\uaab3\uf900-\ufa0d\ufa10\ufa12\ufa15-\ufa1e\ufa20\ufa22\ufa25-\ufa26\ufa2a-\ufa2d\ufa30-\ufa6d\ufa70-\ufad9\ufb1d\ufb1f\ufb2a-\ufb36\ufb38-\ufb3c\ufb3e\ufb40-\ufb41\ufb43-\ufb44\ufb46-\ufb4e\ufff0-\uffff]/g;
var extraLookup;
var unrollLookup = function(escapable) {
var i;
var unrolled = {};
var c = [];
for (i = 0; i < 65536; i++) {
c.push(String.fromCharCode(i));
}
escapable.lastIndex = 0;
c.join("").replace(escapable, function(a) {
unrolled[a] = "\\u" + ("0000" + a.charCodeAt(0).toString(16)).slice(-4);
return "";
});
escapable.lastIndex = 0;
return unrolled;
};
module.exports = {
quote: function(string) {
var quoted = JSON.stringify(string);
extraEscapable.lastIndex = 0;
if (!extraEscapable.test(quoted)) {
return quoted;
}
if (!extraLookup) {
extraLookup = unrollLookup(extraEscapable);
}
return quoted.replace(extraEscapable, function(a) {
return extraLookup[a];
});
}
};
}
});
// node_modules/sockjs-client/lib/utils/transport.js
var require_transport = __commonJS({
"node_modules/sockjs-client/lib/utils/transport.js"(exports, module) {
"use strict";
var debug = function() {
};
if (true) {
debug = require_browser()("sockjs-client:utils:transport");
}
module.exports = function(availableTransports) {
return {
filterToEnabled: function(transportsWhitelist, info) {
var transports = {
main: [],
facade: []
};
if (!transportsWhitelist) {
transportsWhitelist = [];
} else if (typeof transportsWhitelist === "string") {
transportsWhitelist = [transportsWhitelist];
}
availableTransports.forEach(function(trans) {
if (!trans) {
return;
}
if (trans.transportName === "websocket" && info.websocket === false) {
debug("disabled from server", "websocket");
return;
}
if (transportsWhitelist.length && transportsWhitelist.indexOf(trans.transportName) === -1) {
debug("not in whitelist", trans.transportName);
return;
}
if (trans.enabled(info)) {
debug("enabled", trans.transportName);
transports.main.push(trans);
if (trans.facadeTransport) {
transports.facade.push(trans.facadeTransport);
}
} else {
debug("disabled", trans.transportName);
}
});
return transports;
}
};
};
}
});
// node_modules/sockjs-client/lib/utils/log.js
var require_log = __commonJS({
"node_modules/sockjs-client/lib/utils/log.js"(exports, module) {
"use strict";
var logObject = {};
["log", "debug", "warn"].forEach(function(level) {
var levelExists;
try {
levelExists = window.console && window.console[level] && window.console[level].apply;
} catch (e) {
}
logObject[level] = levelExists ? function() {
return window.console[level].apply(window.console, arguments);
} : level === "log" ? function() {
} : logObject.log;
});
module.exports = logObject;
}
});
// node_modules/sockjs-client/lib/event/event.js
var require_event2 = __commonJS({
"node_modules/sockjs-client/lib/event/event.js"(exports, module) {
"use strict";
function Event(eventType) {
this.type = eventType;
}
Event.prototype.initEvent = function(eventType, canBubble, cancelable) {
this.type = eventType;
this.bubbles = canBubble;
this.cancelable = cancelable;
this.timeStamp = +/* @__PURE__ */ new Date();
return this;
};
Event.prototype.stopPropagation = function() {
};
Event.prototype.preventDefault = function() {
};
Event.CAPTURING_PHASE = 1;
Event.AT_TARGET = 2;
Event.BUBBLING_PHASE = 3;
module.exports = Event;
}
});
// node_modules/sockjs-client/lib/location.js
var require_location = __commonJS({
"node_modules/sockjs-client/lib/location.js"(exports, module) {
"use strict";
module.exports = window.location || {
origin: "http://localhost:80",
protocol: "http:",
host: "localhost",
port: 80,
href: "http://localhost/",
hash: ""
};
}
});
// node_modules/sockjs-client/lib/event/close.js
var require_close = __commonJS({
"node_modules/sockjs-client/lib/event/close.js"(exports, module) {
"use strict";
var inherits = require_inherits_browser();
var Event = require_event2();
function CloseEvent() {
Event.call(this);
this.initEvent("close", false, false);
this.wasClean = false;
this.code = 0;
this.reason = "";
}
inherits(CloseEvent, Event);
module.exports = CloseEvent;
}
});
// node_modules/sockjs-client/lib/event/trans-message.js
var require_trans_message = __commonJS({
"node_modules/sockjs-client/lib/event/trans-message.js"(exports, module) {
"use strict";
var inherits = require_inherits_browser();
var Event = require_event2();
function TransportMessageEvent(data) {
Event.call(this);
this.initEvent("message", false, false);
this.data = data;
}
inherits(TransportMessageEvent, Event);
module.exports = TransportMessageEvent;
}
});
// node_modules/sockjs-client/lib/transport/sender/xhr-fake.js
var require_xhr_fake = __commonJS({
"node_modules/sockjs-client/lib/transport/sender/xhr-fake.js"(exports, module) {
"use strict";
var EventEmitter = require_emitter().EventEmitter;
var inherits = require_inherits_browser();
function XHRFake() {
var self2 = this;
EventEmitter.call(this);
this.to = setTimeout(function() {
self2.emit("finish", 200, "{}");
}, XHRFake.timeout);
}
inherits(XHRFake, EventEmitter);
XHRFake.prototype.close = function() {
clearTimeout(this.to);
};
XHRFake.timeout = 2e3;
module.exports = XHRFake;
}
});
// node_modules/sockjs-client/lib/info-ajax.js
var require_info_ajax = __commonJS({
"node_modules/sockjs-client/lib/info-ajax.js"(exports, module) {
"use strict";
var EventEmitter = require_emitter().EventEmitter;
var inherits = require_inherits_browser();
var objectUtils = require_object();
var debug = function() {
};
if (true) {
debug = require_browser()("sockjs-client:info-ajax");
}
function InfoAjax(url, AjaxObject) {
EventEmitter.call(this);
var self2 = this;
var t0 = +/* @__PURE__ */ new Date();
this.xo = new AjaxObject("GET", url);
this.xo.once("finish", function(status, text) {
var info, rtt;
if (status === 200) {
rtt = +/* @__PURE__ */ new Date() - t0;
if (text) {
try {
info = JSON.parse(text);
} catch (e) {
debug("bad json", text);
}
}
if (!objectUtils.isObject(info)) {
info = {};
}
}
self2.emit("finish", info, rtt);
self2.removeAllListeners();
});
}
inherits(InfoAjax, EventEmitter);
InfoAjax.prototype.close = function() {
this.removeAllListeners();
this.xo.close();
};
module.exports = InfoAjax;
}
});
// node_modules/sockjs-client/lib/info-iframe-receiver.js
var require_info_iframe_receiver = __commonJS({
"node_modules/sockjs-client/lib/info-iframe-receiver.js"(exports, module) {
"use strict";
var inherits = require_inherits_browser();
var EventEmitter = require_emitter().EventEmitter;
var XHRLocalObject = require_xhr_local();
var InfoAjax = require_info_ajax();
function InfoReceiverIframe(transUrl) {
var self2 = this;
EventEmitter.call(this);
this.ir = new InfoAjax(transUrl, XHRLocalObject);
this.ir.once("finish", function(info, rtt) {
self2.ir = null;
self2.emit("message", JSON.stringify([info, rtt]));
});
}
inherits(InfoReceiverIframe, EventEmitter);
InfoReceiverIframe.transportName = "iframe-info-receiver";
InfoReceiverIframe.prototype.close = function() {
if (this.ir) {
this.ir.close();
this.ir = null;
}
this.removeAllListeners();
};
module.exports = InfoReceiverIframe;
}
});
// node_modules/sockjs-client/lib/info-iframe.js
var require_info_iframe = __commonJS({
"node_modules/sockjs-client/lib/info-iframe.js"(exports, module) {
"use strict";
var EventEmitter = require_emitter().EventEmitter;
var inherits = require_inherits_browser();
var utils = require_event();
var IframeTransport = require_iframe2();
var InfoReceiverIframe = require_info_iframe_receiver();
var debug = function() {
};
if (true) {
debug = require_browser()("sockjs-client:info-iframe");
}
function InfoIframe(baseUrl, url) {
var self2 = this;
EventEmitter.call(this);
var go = function() {
var ifr = self2.ifr = new IframeTransport(InfoReceiverIframe.transportName, url, baseUrl);
ifr.once("message", function(msg) {
if (msg) {
var d;
try {
d = JSON.parse(msg);
} catch (e) {
debug("bad json", msg);
self2.emit("finish");
self2.close();
return;
}
var info = d[0], rtt = d[1];
self2.emit("finish", info, rtt);
}
self2.close();
});
ifr.once("close", function() {
self2.emit("finish");
self2.close();
});
};
if (!window.document.body) {
utils.attachEvent("load", go);
} else {
go();
}
}
inherits(InfoIframe, EventEmitter);
InfoIframe.enabled = function() {
return IframeTransport.enabled();
};
InfoIframe.prototype.close = function() {
if (this.ifr) {
this.ifr.close();
}
this.removeAllListeners();
this.ifr = null;
};
module.exports = InfoIframe;
}
});
// node_modules/sockjs-client/lib/info-receiver.js
var require_info_receiver = __commonJS({
"node_modules/sockjs-client/lib/info-receiver.js"(exports, module) {
"use strict";
var EventEmitter = require_emitter().EventEmitter;
var inherits = require_inherits_browser();
var urlUtils = require_url();
var XDR = require_xdr();
var XHRCors = require_xhr_cors();
var XHRLocal = require_xhr_local();
var XHRFake = require_xhr_fake();
var InfoIframe = require_info_iframe();
var InfoAjax = require_info_ajax();
var debug = function() {
};
if (true) {
debug = require_browser()("sockjs-client:info-receiver");
}
function InfoReceiver(baseUrl, urlInfo) {
debug(baseUrl);
var self2 = this;
EventEmitter.call(this);
setTimeout(function() {
self2.doXhr(baseUrl, urlInfo);
}, 0);
}
inherits(InfoReceiver, EventEmitter);
InfoReceiver._getReceiver = function(baseUrl, url, urlInfo) {
if (urlInfo.sameOrigin) {
return new InfoAjax(url, XHRLocal);
}
if (XHRCors.enabled) {
return new InfoAjax(url, XHRCors);
}
if (XDR.enabled && urlInfo.sameScheme) {
return new InfoAjax(url, XDR);
}
if (InfoIframe.enabled()) {
return new InfoIframe(baseUrl, url);
}
return new InfoAjax(url, XHRFake);
};
InfoReceiver.prototype.doXhr = function(baseUrl, urlInfo) {
var self2 = this, url = urlUtils.addPath(baseUrl, "/info");
debug("doXhr", url);
this.xo = InfoReceiver._getReceiver(baseUrl, url, urlInfo);
this.timeoutRef = setTimeout(function() {
debug("timeout");
self2._cleanup(false);
self2.emit("finish");
}, InfoReceiver.timeout);
this.xo.once("finish", function(info, rtt) {
debug("finish", info, rtt);
self2._cleanup(true);
self2.emit("finish", info, rtt);
});
};
InfoReceiver.prototype._cleanup = function(wasClean) {
debug("_cleanup");
clearTimeout(this.timeoutRef);
this.timeoutRef = null;
if (!wasClean && this.xo) {
this.xo.close();
}
this.xo = null;
};
InfoReceiver.prototype.close = function() {
debug("close");
this.removeAllListeners();
this._cleanup(false);
};
InfoReceiver.timeout = 8e3;
module.exports = InfoReceiver;
}
});
// node_modules/sockjs-client/lib/facade.js
var require_facade = __commonJS({
"node_modules/sockjs-client/lib/facade.js"(exports, module) {
"use strict";
var iframeUtils = require_iframe();
function FacadeJS(transport) {
this._transport = transport;
transport.on("message", this._transportMessage.bind(this));
transport.on("close", this._transportClose.bind(this));
}
FacadeJS.prototype._transportClose = function(code, reason) {
iframeUtils.postMessage("c", JSON.stringify([code, reason]));
};
FacadeJS.prototype._transportMessage = function(frame) {
iframeUtils.postMessage("t", frame);
};
FacadeJS.prototype._send = function(data) {
this._transport.send(data);
};
FacadeJS.prototype._close = function() {
this._transport.close();
this._transport.removeAllListeners();
};
module.exports = FacadeJS;
}
});
// node_modules/sockjs-client/lib/iframe-bootstrap.js
var require_iframe_bootstrap = __commonJS({
"node_modules/sockjs-client/lib/iframe-bootstrap.js"(exports, module) {
"use strict";
var urlUtils = require_url();
var eventUtils = require_event();
var FacadeJS = require_facade();
var InfoIframeReceiver = require_info_iframe_receiver();
var iframeUtils = require_iframe();
var loc = require_location();
var debug = function() {
};
if (true) {
debug = require_browser()("sockjs-client:iframe-bootstrap");
}
module.exports = function(SockJS2, availableTransports) {
var transportMap = {};
availableTransports.forEach(function(at) {
if (at.facadeTransport) {
transportMap[at.facadeTransport.transportName] = at.facadeTransport;
}
});
transportMap[InfoIframeReceiver.transportName] = InfoIframeReceiver;
var parentOrigin;
SockJS2.bootstrap_iframe = function() {
var facade;
iframeUtils.currentWindowId = loc.hash.slice(1);
var onMessage = function(e) {
if (e.source !== parent) {
return;
}
if (typeof parentOrigin === "undefined") {
parentOrigin = e.origin;
}
if (e.origin !== parentOrigin) {
return;
}
var iframeMessage;
try {
iframeMessage = JSON.parse(e.data);
} catch (ignored) {
debug("bad json", e.data);
return;
}
if (iframeMessage.windowId !== iframeUtils.currentWindowId) {
return;
}
switch (iframeMessage.type) {
case "s":
var p;
try {
p = JSON.parse(iframeMessage.data);
} catch (ignored) {
debug("bad json", iframeMessage.data);
break;
}
var version = p[0];
var transport = p[1];
var transUrl = p[2];
var baseUrl = p[3];
debug(version, transport, transUrl, baseUrl);
if (version !== SockJS2.version) {
throw new Error('Incompatible SockJS! Main site uses: "' + version + '", the iframe: "' + SockJS2.version + '".');
}
if (!urlUtils.isOriginEqual(transUrl, loc.href) || !urlUtils.isOriginEqual(baseUrl, loc.href)) {
throw new Error("Can't connect to different domain from within an iframe. (" + loc.href + ", " + transUrl + ", " + baseUrl + ")");
}
facade = new FacadeJS(new transportMap[transport](transUrl, baseUrl));
break;
case "m":
facade._send(iframeMessage.data);
break;
case "c":
if (facade) {
facade._close();
}
facade = null;
break;
}
};
eventUtils.attachEvent("message", onMessage);
iframeUtils.postMessage("s");
};
};
}
});
// node_modules/sockjs-client/lib/main.js
var require_main = __commonJS({
"node_modules/sockjs-client/lib/main.js"(exports, module) {
"use strict";
require_shims();
var URL = require_url_parse();
var inherits = require_inherits_browser();
var random = require_random();
var escape = require_escape();
var urlUtils = require_url();
var eventUtils = require_event();
var transport = require_transport();
var objectUtils = require_object();
var browser = require_browser2();
var log = require_log();
var Event = require_event2();
var EventTarget2 = require_eventtarget();
var loc = require_location();
var CloseEvent = require_close();
var TransportMessageEvent = require_trans_message();
var InfoReceiver = require_info_receiver();
var debug = function() {
};
if (true) {
debug = require_browser()("sockjs-client:main");
}
var transports;
function SockJS2(url, protocols, options) {
if (!(this instanceof SockJS2)) {
return new SockJS2(url, protocols, options);
}
if (arguments.length < 1) {
throw new TypeError("Failed to construct 'SockJS: 1 argument required, but only 0 present");
}
EventTarget2.call(this);
this.readyState = SockJS2.CONNECTING;
this.extensions = "";
this.protocol = "";
options = options || {};
if (options.protocols_whitelist) {
log.warn("'protocols_whitelist' is DEPRECATED. Use 'transports' instead.");
}
this._transportsWhitelist = options.transports;
this._transportOptions = options.transportOptions || {};
this._timeout = options.timeout || 0;
var sessionId = options.sessionId || 8;
if (typeof sessionId === "function") {
this._generateSessionId = sessionId;
} else if (typeof sessionId === "number") {
this._generateSessionId = function() {
return random.string(sessionId);
};
} else {
throw new TypeError("If sessionId is used in the options, it needs to be a number or a function.");
}
this._server = options.server || random.numberString(1e3);
var parsedUrl = new URL(url);
if (!parsedUrl.host || !parsedUrl.protocol) {
throw new SyntaxError("The URL '" + url + "' is invalid");
} else if (parsedUrl.hash) {
throw new SyntaxError("The URL must not contain a fragment");
} else if (parsedUrl.protocol !== "http:" && parsedUrl.protocol !== "https:") {
throw new SyntaxError("The URL's scheme must be either 'http:' or 'https:'. '" + parsedUrl.protocol + "' is not allowed.");
}
var secure = parsedUrl.protocol === "https:";
if (loc.protocol === "https:" && !secure) {
if (!urlUtils.isLoopbackAddr(parsedUrl.hostname)) {
throw new Error("SecurityError: An insecure SockJS connection may not be initiated from a page loaded over HTTPS");
}
}
if (!protocols) {
protocols = [];
} else if (!Array.isArray(protocols)) {
protocols = [protocols];
}
var sortedProtocols = protocols.sort();
sortedProtocols.forEach(function(proto, i) {
if (!proto) {
throw new SyntaxError("The protocols entry '" + proto + "' is invalid.");
}
if (i < sortedProtocols.length - 1 && proto === sortedProtocols[i + 1]) {
throw new SyntaxError("The protocols entry '" + proto + "' is duplicated.");
}
});
var o = urlUtils.getOrigin(loc.href);
this._origin = o ? o.toLowerCase() : null;
parsedUrl.set("pathname", parsedUrl.pathname.replace(/\/+$/, ""));
this.url = parsedUrl.href;
debug("using url", this.url);
this._urlInfo = {
nullOrigin: !browser.hasDomain(),
sameOrigin: urlUtils.isOriginEqual(this.url, loc.href),
sameScheme: urlUtils.isSchemeEqual(this.url, loc.href)
};
this._ir = new InfoReceiver(this.url, this._urlInfo);
this._ir.once("finish", this._receiveInfo.bind(this));
}
inherits(SockJS2, EventTarget2);
function userSetCode(code) {
return code === 1e3 || code >= 3e3 && code <= 4999;
}
SockJS2.prototype.close = function(code, reason) {
if (code && !userSetCode(code)) {
throw new Error("InvalidAccessError: Invalid code");
}
if (reason && reason.length > 123) {
throw new SyntaxError("reason argument has an invalid length");
}
if (this.readyState === SockJS2.CLOSING || this.readyState === SockJS2.CLOSED) {
return;
}
var wasClean = true;
this._close(code || 1e3, reason || "Normal closure", wasClean);
};
SockJS2.prototype.send = function(data) {
if (typeof data !== "string") {
data = "" + data;
}
if (this.readyState === SockJS2.CONNECTING) {
throw new Error("InvalidStateError: The connection has not been established yet");
}
if (this.readyState !== SockJS2.OPEN) {
return;
}
this._transport.send(escape.quote(data));
};
SockJS2.version = require_version();
SockJS2.CONNECTING = 0;
SockJS2.OPEN = 1;
SockJS2.CLOSING = 2;
SockJS2.CLOSED = 3;
SockJS2.prototype._receiveInfo = function(info, rtt) {
debug("_receiveInfo", rtt);
this._ir = null;
if (!info) {
this._close(1002, "Cannot connect to server");
return;
}
this._rto = this.countRTO(rtt);
this._transUrl = info.base_url ? info.base_url : this.url;
info = objectUtils.extend(info, this._urlInfo);
debug("info", info);
var enabledTransports = transports.filterToEnabled(this._transportsWhitelist, info);
this._transports = enabledTransports.main;
debug(this._transports.length + " enabled transports");
this._connect();
};
SockJS2.prototype._connect = function() {
for (var Transport = this._transports.shift(); Transport; Transport = this._transports.shift()) {
debug("attempt", Transport.transportName);
if (Transport.needBody) {
if (!window.document.body || typeof window.document.readyState !== "undefined" && window.document.readyState !== "complete" && window.document.readyState !== "interactive") {
debug("waiting for body");
this._transports.unshift(Transport);
eventUtils.attachEvent("load", this._connect.bind(this));
return;
}
}
var timeoutMs = Math.max(this._timeout, this._rto * Transport.roundTrips || 5e3);
this._transportTimeoutId = setTimeout(this._transportTimeout.bind(this), timeoutMs);
debug("using timeout", timeoutMs);
var transportUrl = urlUtils.addPath(this._transUrl, "/" + this._server + "/" + this._generateSessionId());
var options = this._transportOptions[Transport.transportName];
debug("transport url", transportUrl);
var transportObj = new Transport(transportUrl, this._transUrl, options);
transportObj.on("message", this._transportMessage.bind(this));
transportObj.once("close", this._transportClose.bind(this));
transportObj.transportName = Transport.transportName;
this._transport = transportObj;
return;
}
this._close(2e3, "All transports failed", false);
};
SockJS2.prototype._transportTimeout = function() {
debug("_transportTimeout");
if (this.readyState === SockJS2.CONNECTING) {
if (this._transport) {
this._transport.close();
}
this._transportClose(2007, "Transport timed out");
}
};
SockJS2.prototype._transportMessage = function(msg) {
debug("_transportMessage", msg);
var self2 = this, type = msg.slice(0, 1), content = msg.slice(1), payload;
switch (type) {
case "o":
this._open();
return;
case "h":
this.dispatchEvent(new Event("heartbeat"));
debug("heartbeat", this.transport);
return;
}
if (content) {
try {
payload = JSON.parse(content);
} catch (e) {
debug("bad json", content);
}
}
if (typeof payload === "undefined") {
debug("empty payload", content);
return;
}
switch (type) {
case "a":
if (Array.isArray(payload)) {
payload.forEach(function(p) {
debug("message", self2.transport, p);
self2.dispatchEvent(new TransportMessageEvent(p));
});
}
break;
case "m":
debug("message", this.transport, payload);
this.dispatchEvent(new TransportMessageEvent(payload));
break;
case "c":
if (Array.isArray(payload) && payload.length === 2) {
this._close(payload[0], payload[1], true);
}
break;
}
};
SockJS2.prototype._transportClose = function(code, reason) {
debug("_transportClose", this.transport, code, reason);
if (this._transport) {
this._transport.removeAllListeners();
this._transport = null;
this.transport = null;
}
if (!userSetCode(code) && code !== 2e3 && this.readyState === SockJS2.CONNECTING) {
this._connect();
return;
}
this._close(code, reason);
};
SockJS2.prototype._open = function() {
debug("_open", this._transport && this._transport.transportName, this.readyState);
if (this.readyState === SockJS2.CONNECTING) {
if (this._transportTimeoutId) {
clearTimeout(this._transportTimeoutId);
this._transportTimeoutId = null;
}
this.readyState = SockJS2.OPEN;
this.transport = this._transport.transportName;
this.dispatchEvent(new Event("open"));
debug("connected", this.transport);
} else {
this._close(1006, "Server lost session");
}
};
SockJS2.prototype._close = function(code, reason, wasClean) {
debug("_close", this.transport, code, reason, wasClean, this.readyState);
var forceFail = false;
if (this._ir) {
forceFail = true;
this._ir.close();
this._ir = null;
}
if (this._transport) {
this._transport.close();
this._transport = null;
this.transport = null;
}
if (this.readyState === SockJS2.CLOSED) {
throw new Error("InvalidStateError: SockJS has already been closed");
}
this.readyState = SockJS2.CLOSING;
setTimeout(function() {
this.readyState = SockJS2.CLOSED;
if (forceFail) {
this.dispatchEvent(new Event("error"));
}
var e = new CloseEvent("close");
e.wasClean = wasClean || false;
e.code = code || 1e3;
e.reason = reason;
this.dispatchEvent(e);
this.onmessage = this.onclose = this.onerror = null;
debug("disconnected");
}.bind(this), 0);
};
SockJS2.prototype.countRTO = function(rtt) {
if (rtt > 100) {
return 4 * rtt;
}
return 300 + rtt;
};
module.exports = function(availableTransports) {
transports = transport(availableTransports);
require_iframe_bootstrap()(SockJS2, availableTransports);
return SockJS2;
};
}
});
// node_modules/sockjs-client/lib/entry.js
var require_entry = __commonJS({
"node_modules/sockjs-client/lib/entry.js"(exports, module) {
"use strict";
var transportList = require_transport_list();
module.exports = require_main()(transportList);
if ("_sockjs_onload" in window) {
setTimeout(window._sockjs_onload, 1);
}
}
});
// pkg/sdk/client/src/index.ts
var src_exports = {};
__export(src_exports, {
default: () => src_default
});
// pkg/sdk/client/src/event-target.ts
var EventTarget = class {
constructor() {
this.listeners = {};
}
addEventListener(type, callback) {
if (!(type in this.listeners)) {
this.listeners[type] = [];
}
this.listeners[type].push(callback);
}
removeEventListener(type, callback) {
if (!(type in this.listeners)) {
return;
}
const stack = this.listeners[type];
for (var i = 0, l = stack.length; i < l; i++) {
if (stack[i] === callback) {
stack.splice(i, 1);
return;
}
}
}
dispatchEvent(event) {
if (!(event.type in this.listeners)) {
return true;
}
const stack = this.listeners[event.type].slice();
for (let i = 0, l = stack.length; i < l; i++) {
stack[i].call(this, event);
if (event.cancelBubble)
return;
}
return !event.defaultPrevented;
}
};
// pkg/sdk/client/src/message.ts
var TypeMessage = "message";
var Message = class {
constructor(type, payload) {
this._type = type;
this._payload = payload;
}
getType() {
return this._type;
}
getPayload() {
return this._payload;
}
toJSON() {
return {
t: this._type,
p: this._payload
};
}
};
function messageFrom(raw) {
return new Message(raw.t, raw.p);
}
// pkg/sdk/client/src/rpc-error.ts
var RPCError = class extends Error {
constructor(code, message, data) {
super(message);
this.code = code;
this.data = data;
if (Error.captureStackTrace)
Error.captureStackTrace(this, RPCError);
}
};
// pkg/sdk/client/src/client.ts
var import_sockjs_client = __toESM(require_entry());
var EventTypeMessage = "message";
var EdgeAuth = "edge-auth";
var Client = class extends EventTarget {
constructor(autoReconnect = true) {
super();
this._conn = null;
this._onConnectionClose = this._onConnectionClose.bind(this);
this._onConnectionMessage = this._onConnectionMessage.bind(this);
this._handleRPCResponse = this._handleRPCResponse.bind(this);
this._rpcID = 0;
this._pendingRPC = {};
this._queue = [];
this._reconnectionDelay = 250;
this._autoReconnect = autoReconnect;
this.debug = false;
this.connect = this.connect.bind(this);
this.disconnect = this.disconnect.bind(this);
this.rpc = this.rpc.bind(this);
this.send = this.send.bind(this);
this.upload = this.upload.bind(this);
this.addEventListener(EventTypeMessage, this._handleRPCResponse);
}
connect(token = "") {
return new Promise((resolve, reject) => {
if (token == "") {
token = this._getAuthCookieToken();
}
const url = `//${document.location.host}/edge/sock?${EdgeAuth}=${token}`;
this._log("opening connection to", url);
const conn = new import_sockjs_client.default(url);
const onOpen = () => {
this._log("client connected");
resetHandlers();
conn.onclose = this._onConnectionClose;
conn.onmessage = this._onConnectionMessage;
this._conn = conn;
this._sendQueued();
setTimeout(() => {
this._dispatchConnect();
}, 0);
return resolve(this);
};
const onError = (evt) => {
resetHandlers();
this._scheduleReconnection();
return reject(evt);
};
const resetHandlers = () => {
conn.removeEventListener("open", onOpen);
conn.removeEventListener("close", onError);
conn.removeEventListener("error", onError);
};
conn.addEventListener("open", onOpen);
conn.addEventListener("error", onError);
conn.addEventListener("close", onError);
});
}
disconnect() {
this._cleanupConnection();
}
_getAuthCookieToken() {
const cookie = document.cookie.split("; ").find((row) => row.startsWith(EdgeAuth));
if (cookie) {
return cookie.split("=")[1];
}
return "";
}
_onConnectionMessage(evt) {
const rawMessage = JSON.parse(evt.data);
const message = messageFrom(rawMessage);
const event = new CustomEvent(message.getType(), {
cancelable: true,
detail: message.getPayload()
});
this.dispatchEvent(event);
}
_handleRPCResponse(evt) {
const { jsonrpc, id, error, result } = evt.detail;
if (jsonrpc !== "2.0" || id === void 0)
return;
if (!evt.detail.hasOwnProperty("error") && !evt.detail.hasOwnProperty("result"))
return;
evt.stopImmediatePropagation();
const pending = this._pendingRPC[id];
if (!pending)
return;
delete this._pendingRPC[id];
if (error) {
pending.reject(new RPCError(error.code, error.message, error.data));
return;
}
pending.resolve(result);
}
_onConnectionClose(evt) {
this._log("client disconnected");
this._dispatchDisconnect();
this._cleanupConnection();
this._scheduleReconnection();
}
_dispatchDisconnect() {
const event = new CustomEvent("disconnect");
this.dispatchEvent(event);
}
_dispatchConnect() {
const event = new CustomEvent("connect");
this.dispatchEvent(event);
}
_scheduleReconnection() {
if (!this._autoReconnect)
return;
this._reconnectionDelay = this._reconnectionDelay * 2 + Math.random();
this._log("client will try to reconnect in %dms", this._reconnectionDelay);
setTimeout(this.connect.bind(this), this._reconnectionDelay);
}
_cleanupConnection() {
if (!this._conn)
return;
this._conn.onopen = null;
this._conn.onerror = null;
this._conn.onclose = null;
this._conn.onmessage = null;
this._conn.close();
this._conn = null;
}
_send(message) {
if (!this._conn)
return false;
this._log("sending message", message);
this._conn.send(JSON.stringify(message));
return true;
}
_sendQueued() {
this._log("sending queued messages", this._queue.length);
let msg = this._queue.shift();
while (msg) {
const sent = this._send(msg);
if (!sent)
return;
msg = this._queue.shift();
}
}
_log(...args) {
if (!this.debug)
return;
console.log(...args);
}
_sendOrQueue(msg) {
if (this.isConnected()) {
this._sendQueued();
this._send(msg);
} else {
this._log("queuing message", msg);
this._queue.push(msg);
}
}
send(data) {
const msg = new Message(TypeMessage, data);
this._sendOrQueue(msg);
}
rpc(method, params) {
return new Promise((resolve, reject) => {
const id = this._rpcID++;
const rpc = new Message(TypeMessage, {
jsonrpc: "2.0",
id,
method,
params
});
this._sendOrQueue(rpc);
this._pendingRPC[id.toString()] = { resolve, reject };
});
}
isConnected() {
return this._conn !== null;
}
upload(blob, metadata) {
return new Promise((resolve, reject) => {
const formData = new FormData();
formData.set("file", blob);
if (metadata) {
try {
formData.set("metadata", JSON.stringify(metadata));
} catch (err) {
return reject(err);
}
}
const xhr = new XMLHttpRequest();
const result = {
onProgress: null,
abort: () => xhr.abort(),
result: () => {
return new Promise((resolve2, reject2) => {
xhr.onload = () => {
let data;
try {
data = JSON.parse(xhr.responseText);
} catch (err) {
reject2(err);
return;
}
resolve2(data);
};
xhr.onerror = reject2;
xhr.onabort = reject2;
});
}
};
xhr.upload.onprogress = (evt) => {
if (typeof result.onProgress !== "function")
return;
result.onProgress(evt.loaded, evt.total);
};
xhr.onabort = reject;
xhr.onerror = reject;
xhr.open("POST", `/edge/api/v1/upload`);
xhr.send(formData);
resolve(result);
});
}
blobUrl(bucket, blobId) {
return `/edge/api/v1/download/${bucket}/${blobId}`;
}
};
// pkg/sdk/client/src/index.ts
var src_default = new Client();
return __toCommonJS(src_exports);
})();
Edge=Edge.default;
//# sourceMappingURL=client.js.map

7
pkg/sdk/client/dist/client.js.map vendored Normal file

File diff suppressed because one or more lines are too long

View File

@ -1,9 +1,10 @@
import { EventTarget } from "./event-target"; import { EventTarget } from "./event-target";
import { messageFrom,Message, TypeMessage } from "./message"; import { messageFrom, Message, TypeMessage } from "./message";
import { RPCError } from "./rpc-error"; import { RPCError } from "./rpc-error";
import SockJS from 'sockjs-client'; import SockJS from 'sockjs-client';
const EventTypeMessage = "message"; const EventTypeMessage = "message";
const EdgeAuth = "edge-auth"
export class Client extends EventTarget { export class Client extends EventTarget {
@ -35,12 +36,16 @@ export class Client extends EventTarget {
this.send = this.send.bind(this); this.send = this.send.bind(this);
this.upload = this.upload.bind(this); this.upload = this.upload.bind(this);
this.addEventListener("message", this._handleRPCResponse); this.addEventListener(EventTypeMessage, this._handleRPCResponse);
} }
connect(token = "") { connect(token = "") {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
const url = `//${document.location.host}/edge/sock?token=${token}`; if (token == "") {
token = this._getAuthCookieToken()
}
const url = `//${document.location.host}/edge/sock?${EdgeAuth}=${token}`;
this._log("opening connection to", url); this._log("opening connection to", url);
const conn: any = new SockJS(url); const conn: any = new SockJS(url);
@ -79,6 +84,17 @@ export class Client extends EventTarget {
this._cleanupConnection(); this._cleanupConnection();
} }
_getAuthCookieToken() {
const cookie = document.cookie.split("; ")
.find((row) => row.startsWith(EdgeAuth));
if (cookie) {
return cookie.split("=")[1];
}
return "";
}
_onConnectionMessage(evt) { _onConnectionMessage(evt) {
const rawMessage = JSON.parse(evt.data); const rawMessage = JSON.parse(evt.data);
const message = messageFrom(rawMessage); const message = messageFrom(rawMessage);
@ -93,6 +109,7 @@ export class Client extends EventTarget {
const { jsonrpc, id, error, result } = evt.detail; const { jsonrpc, id, error, result } = evt.detail;
if (jsonrpc !== '2.0' || id === undefined) return; if (jsonrpc !== '2.0' || id === undefined) return;
if (!evt.detail.hasOwnProperty("error") && !evt.detail.hasOwnProperty("result")) return;
// Prevent additional handlers to catch this event // Prevent additional handlers to catch this event
evt.stopImmediatePropagation(); evt.stopImmediatePropagation();
@ -178,7 +195,7 @@ export class Client extends EventTarget {
} }
send(data) { send(data) {
const msg = new Message("message", data); const msg = new Message(TypeMessage, data);
this._sendOrQueue(msg); this._sendOrQueue(msg);
} }

View File

@ -7,35 +7,35 @@ const (
OrderDirectionDesc OrderDirection = "DESC" OrderDirectionDesc OrderDirection = "DESC"
) )
type QueryOption struct { type QueryOptions struct {
Limit *int Limit *int
Offset *int Offset *int
OrderBy *string OrderBy *string
OrderDirection *OrderDirection OrderDirection *OrderDirection
} }
type QueryOptionFunc func(o *QueryOption) type QueryOptionFunc func(o *QueryOptions)
func WithLimit(limit int) QueryOptionFunc { func WithLimit(limit int) QueryOptionFunc {
return func(o *QueryOption) { return func(o *QueryOptions) {
o.Limit = &limit o.Limit = &limit
} }
} }
func WithOffset(offset int) QueryOptionFunc { func WithOffset(offset int) QueryOptionFunc {
return func(o *QueryOption) { return func(o *QueryOptions) {
o.Offset = &offset o.Offset = &offset
} }
} }
func WithOrderBy(orderBy string) QueryOptionFunc { func WithOrderBy(orderBy string) QueryOptionFunc {
return func(o *QueryOption) { return func(o *QueryOptions) {
o.OrderBy = &orderBy o.OrderBy = &orderBy
} }
} }
func WithOrderDirection(direction OrderDirection) QueryOptionFunc { func WithOrderDirection(direction OrderDirection) QueryOptionFunc {
return func(o *QueryOption) { return func(o *QueryOptions) {
o.OrderDirection = &direction o.OrderDirection = &direction
} }
} }

View File

@ -4,6 +4,7 @@ import (
"context" "context"
"database/sql" "database/sql"
"fmt" "fmt"
"math"
"sync" "sync"
"time" "time"
@ -90,6 +91,11 @@ func (s *DocumentStore) Get(ctx context.Context, collection string, id storage.D
// Query implements storage.DocumentStore // Query implements storage.DocumentStore
func (s *DocumentStore) Query(ctx context.Context, collection string, filter *filter.Filter, funcs ...storage.QueryOptionFunc) ([]storage.Document, error) { func (s *DocumentStore) Query(ctx context.Context, collection string, filter *filter.Filter, funcs ...storage.QueryOptionFunc) ([]storage.Document, error) {
opts := &storage.QueryOptions{}
for _, fn := range funcs {
fn(opts)
}
var documents []storage.Document var documents []storage.Document
err := s.withTx(ctx, func(tx *sql.Tx) error { err := s.withTx(ctx, func(tx *sql.Tx) error {
@ -120,6 +126,29 @@ func (s *DocumentStore) Query(ctx context.Context, collection string, filter *fi
args = append([]interface{}{collection}, args...) args = append([]interface{}{collection}, args...)
if opts.OrderBy != nil {
direction := storage.OrderDirectionAsc
if opts.OrderDirection != nil {
direction = *opts.OrderDirection
}
query, args = withOrderByClause(query, args, *opts.OrderBy, direction)
}
if opts.Offset != nil || opts.Limit != nil {
offset := 0
if opts.Offset != nil {
offset = *opts.Offset
}
limit := math.MaxInt
if opts.Limit != nil {
limit = *opts.Limit
}
query, args = withLimitOffsetClause(query, args, limit, offset)
}
logger.Debug( logger.Debug(
ctx, "executing query", ctx, "executing query",
logger.F("query", query), logger.F("query", query),
@ -331,6 +360,41 @@ func (s *DocumentStore) ensureTables(ctx context.Context, db *sql.DB) error {
return nil return nil
} }
func withOrderByClause(query string, args []any, orderBy string, orderDirection storage.OrderDirection) (string, []any) {
direction := "ASC"
if orderDirection == storage.OrderDirectionDesc {
direction = "DESC"
}
var column string
switch orderBy {
case storage.DocumentAttrID:
column = "id"
case storage.DocumentAttrCreatedAt:
column = "created_at"
case storage.DocumentAttrUpdatedAt:
column = "updated_at"
default:
column = fmt.Sprintf("json_extract(data, '$.' || $%d)", len(args)+1)
args = append(args, orderBy)
}
query += fmt.Sprintf(` ORDER BY %s %s`, column, direction)
return query, args
}
func withLimitOffsetClause(query string, args []any, limit int, offset int) (string, []any) {
query += fmt.Sprintf(` LIMIT $%d OFFSET $%d`, len(args)+1, len(args)+2)
args = append(args, limit, offset)
return query, args
}
func NewDocumentStore(path string) *DocumentStore { func NewDocumentStore(path string) *DocumentStore {
return &DocumentStore{ return &DocumentStore{
db: nil, db: nil,

View File

@ -7,8 +7,19 @@ import (
"github.com/pkg/errors" "github.com/pkg/errors"
"gitlab.com/wpetit/goweb/logger" "gitlab.com/wpetit/goweb/logger"
_ "modernc.org/sqlite"
) )
func Open(path string) (*sql.DB, error) {
db, err := sql.Open("sqlite", path)
if err != nil {
return nil, errors.Wrapf(err, "could not open database with path '%s'", path)
}
return db, nil
}
func withTx(ctx context.Context, db *sql.DB, fn func(tx *sql.Tx) error) error { func withTx(ctx context.Context, db *sql.DB, fn func(tx *sql.Tx) error) error {
var tx *sql.Tx var tx *sql.Tx

View File

@ -41,7 +41,7 @@ var documentStoreOpsTestCases = []documentStoreOpsTestCase{
}), }),
) )
results, err := store.Query(ctx, collection, filter, nil) results, err := store.Query(ctx, collection, filter)
if err != nil { if err != nil {
return errors.WithStack(err) return errors.WithStack(err)
} }
@ -82,7 +82,7 @@ var documentStoreOpsTestCases = []documentStoreOpsTestCase{
}), }),
) )
results, err := store.Query(ctx, collection, filter, nil) results, err := store.Query(ctx, collection, filter)
if err != nil { if err != nil {
return errors.WithStack(err) return errors.WithStack(err)
} }
@ -127,7 +127,7 @@ var documentStoreOpsTestCases = []documentStoreOpsTestCase{
), ),
) )
results, err := store.Query(ctx, collection, filter, nil) results, err := store.Query(ctx, collection, filter)
if err != nil { if err != nil {
return errors.WithStack(err) return errors.WithStack(err)
} }
@ -219,7 +219,7 @@ var documentStoreOpsTestCases = []documentStoreOpsTestCase{
// Verify that there is no additional created document in the collection // Verify that there is no additional created document in the collection
results, err := store.Query(ctx, collection, nil, nil) results, err := store.Query(ctx, collection, nil)
if err != nil { if err != nil {
return errors.WithStack(err) return errors.WithStack(err)
} }
@ -228,6 +228,206 @@ var documentStoreOpsTestCases = []documentStoreOpsTestCase{
return errors.Errorf("len(results): expected '%v', got '%v'", e, g) return errors.Errorf("len(results): expected '%v', got '%v'", e, g)
} }
return nil
},
},
{
Name: "Query order by document field",
Run: func(ctx context.Context, store storage.DocumentStore) error {
docs := []storage.Document{
{
"sortedField": 0,
"name": "Item 1",
},
{
"sortedField": 1,
"name": "Item 2",
},
{
"sortedField": 2,
"name": "Item 3",
},
}
collection := "ordered_query_by_document_field"
for _, doc := range docs {
if _, err := store.Upsert(ctx, collection, doc); err != nil {
return errors.WithStack(err)
}
}
results, err := store.Query(
ctx, collection, nil,
storage.WithOrderBy("sortedField"),
storage.WithOrderDirection(storage.OrderDirectionAsc),
)
if err != nil {
return errors.WithStack(err)
}
if e, g := 3, len(results); e != g {
return errors.Errorf("len(results): expected '%v', got '%v'", e, g)
}
if e, g := docs[0]["name"], results[0]["name"]; e != g {
return errors.Errorf("results[0][\"name\"]: expected '%v', got '%v'", e, g)
}
if e, g := docs[2]["name"], results[2]["name"]; e != g {
return errors.Errorf("results[2][\"name\"]: expected '%v', got '%v'", e, g)
}
results, err = store.Query(
ctx, collection, nil,
storage.WithOrderBy("sortedField"),
storage.WithOrderDirection(storage.OrderDirectionDesc),
)
if err != nil {
return errors.WithStack(err)
}
if e, g := 3, len(results); e != g {
return errors.Errorf("len(results): expected '%v', got '%v'", e, g)
}
if e, g := docs[2]["name"], results[0]["name"]; e != g {
return errors.Errorf("results[0][\"name\"]: expected '%v', got '%v'", e, g)
}
if e, g := docs[0]["name"], results[2]["name"]; e != g {
return errors.Errorf("results[2][\"name\"]: expected '%v', got '%v'", e, g)
}
return nil
},
},
{
Name: "Query order by special attr",
Run: func(ctx context.Context, store storage.DocumentStore) error {
docs := []storage.Document{
{
"name": "Item 1",
},
{
"name": "Item 2",
},
{
"name": "Item 3",
},
}
collection := "ordered_query_by_special_attr"
for _, doc := range docs {
if _, err := store.Upsert(ctx, collection, doc); err != nil {
return errors.WithStack(err)
}
}
results, err := store.Query(
ctx, collection, nil,
storage.WithOrderBy(storage.DocumentAttrCreatedAt),
storage.WithOrderDirection(storage.OrderDirectionAsc),
)
if err != nil {
return errors.WithStack(err)
}
if e, g := 3, len(results); e != g {
return errors.Errorf("len(results): expected '%v', got '%v'", e, g)
}
if e, g := docs[0]["name"], results[0]["name"]; e != g {
return errors.Errorf("results[0][\"name\"]: expected '%v', got '%v'", e, g)
}
if e, g := docs[2]["name"], results[2]["name"]; e != g {
return errors.Errorf("results[2][\"name\"]: expected '%v', got '%v'", e, g)
}
results, err = store.Query(
ctx, collection, nil,
storage.WithOrderBy(storage.DocumentAttrCreatedAt),
storage.WithOrderDirection(storage.OrderDirectionDesc),
)
if err != nil {
return errors.WithStack(err)
}
if e, g := 3, len(results); e != g {
return errors.Errorf("len(results): expected '%v', got '%v'", e, g)
}
if e, g := docs[2]["name"], results[0]["name"]; e != g {
return errors.Errorf("results[0][\"name\"]: expected '%v', got '%v'", e, g)
}
if e, g := docs[0]["name"], results[2]["name"]; e != g {
return errors.Errorf("results[2][\"name\"]: expected '%v', got '%v'", e, g)
}
return nil
},
},
{
Name: "Query limit and offset",
Run: func(ctx context.Context, store storage.DocumentStore) error {
docs := []storage.Document{
{"name": "Item 1"},
{"name": "Item 2"},
{"name": "Item 3"},
{"name": "Item 4"},
}
collection := "query_limit_and_offset"
for _, doc := range docs {
if _, err := store.Upsert(ctx, collection, doc); err != nil {
return errors.WithStack(err)
}
}
results, err := store.Query(
ctx, collection, nil,
storage.WithLimit(2),
)
if err != nil {
return errors.WithStack(err)
}
if e, g := 2, len(results); e != g {
return errors.Errorf("len(results): expected '%v', got '%v'", e, g)
}
if e, g := docs[0]["name"], results[0]["name"]; e != g {
return errors.Errorf("results[0][\"name\"]: expected '%v', got '%v'", e, g)
}
if e, g := docs[1]["name"], results[1]["name"]; e != g {
return errors.Errorf("results[1][\"name\"]: expected '%v', got '%v'", e, g)
}
results, err = store.Query(
ctx, collection, nil,
storage.WithOffset(2),
)
if err != nil {
return errors.WithStack(err)
}
if e, g := 2, len(results); e != g {
return errors.Errorf("len(results): expected '%v', got '%v'", e, g)
}
if e, g := docs[2]["name"], results[0]["name"]; e != g {
return errors.Errorf("results[0][\"name\"]: expected '%v', got '%v'", e, g)
}
if e, g := docs[3]["name"], results[1]["name"]; e != g {
return errors.Errorf("results[1][\"name\"]: expected '%v', got '%v'", e, g)
}
return nil return nil
}, },
}, },