feat: initial commit

This commit is contained in:
2023-02-09 12:16:36 +01:00
commit 65a866efe1
113 changed files with 17880 additions and 0 deletions

16
pkg/app/app.go Normal file
View File

@ -0,0 +1,16 @@
package app
type ID string
type Manifest struct {
ID ID `yaml:"id"`
Version string `yaml:"version"`
Title string `yaml:"title"`
Description string `yaml:"description"`
Tags []string `yaml:"tags"`
}
type App struct {
ID ID
Manifest *Manifest
}

182
pkg/app/backend.go Normal file
View File

@ -0,0 +1,182 @@
package app
import (
"math/rand"
"sync"
"github.com/dop251/goja"
"github.com/dop251/goja_nodejs/eventloop"
"github.com/pkg/errors"
)
var ErrFuncDoesNotExist = errors.New("function does not exist")
type Backend struct {
runtime *goja.Runtime
loop *eventloop.EventLoop
modules []BackendModule
}
func (b *Backend) Load(name string, src string) error {
_, err := b.runtime.RunScript(name, src)
if err != nil {
return errors.Wrap(err, "could not run js script")
}
return nil
}
func (b *Backend) ExecFuncByName(funcName string, args ...interface{}) (goja.Value, error) {
callable, ok := goja.AssertFunction(b.runtime.Get(funcName))
if !ok {
return nil, errors.WithStack(ErrFuncDoesNotExist)
}
return b.Exec(callable, args...)
}
func (b *Backend) Exec(callable goja.Callable, args ...interface{}) (goja.Value, error) {
var (
wg sync.WaitGroup
value goja.Value
err error
)
wg.Add(1)
b.loop.RunOnLoop(func(vm *goja.Runtime) {
jsArgs := make([]goja.Value, 0, len(args))
for _, a := range args {
jsArgs = append(jsArgs, vm.ToValue(a))
}
value, err = callable(nil, jsArgs...)
if err != nil {
err = errors.WithStack(err)
}
wg.Done()
})
wg.Wait()
return value, err
}
func (b *Backend) IsPromise(v goja.Value) (*goja.Promise, bool) {
promise, ok := v.Export().(*goja.Promise)
return promise, ok
}
func (b *Backend) WaitForPromise(promise *goja.Promise) goja.Value {
var (
wg sync.WaitGroup
value goja.Value
)
wg.Add(1)
// Wait for promise completion
go func() {
for {
var loopWait sync.WaitGroup
loopWait.Add(1)
breakLoop := false
b.loop.RunOnLoop(func(vm *goja.Runtime) {
defer loopWait.Done()
if promise.State() == goja.PromiseStatePending {
return
}
value = promise.Result()
breakLoop = true
})
loopWait.Wait()
if breakLoop {
wg.Done()
return
}
}
}()
wg.Wait()
return value
}
func (b *Backend) NewPromise() *PromiseProxy {
promise, resolve, reject := b.runtime.NewPromise()
return NewPromiseProxy(promise, resolve, reject)
}
func (b *Backend) ToValue(v interface{}) goja.Value {
return b.runtime.ToValue(v)
}
func (b *Backend) Start() error {
b.loop.Start()
for _, mod := range b.modules {
initMod, ok := mod.(InitializableModule)
if !ok {
continue
}
if err := initMod.OnInit(); err != nil {
return errors.WithStack(err)
}
}
return nil
}
func (b *Backend) Stop() {
b.loop.Stop()
}
func (b *Backend) initModules(factories ...BackendModuleFactory) {
runtime := goja.New()
runtime.SetFieldNameMapper(goja.UncapFieldNameMapper())
runtime.SetRandSource(createRandomSource())
modules := make([]BackendModule, 0, len(factories))
for _, moduleFactory := range factories {
mod := moduleFactory(b)
export := runtime.NewObject()
mod.Export(export)
runtime.Set(mod.Name(), export)
modules = append(modules, mod)
}
b.runtime = runtime
b.modules = modules
}
func NewBackend(factories ...BackendModuleFactory) *Backend {
backend := &Backend{
loop: eventloop.NewEventLoop(
eventloop.EnableConsole(false),
),
}
backend.initModules(factories...)
return backend
}
func createRandomSource() goja.RandSource {
rnd := rand.New(&cryptoSource{})
return rnd.Float64
}

17
pkg/app/backend_module.go Normal file
View File

@ -0,0 +1,17 @@
package app
import (
"github.com/dop251/goja"
)
type BackendModuleFactory func(*Backend) BackendModule
type BackendModule interface {
Name() string
Export(*goja.Object)
}
type InitializableModule interface {
BackendModule
OnInit() error
}

25
pkg/app/crypto.go Normal file
View File

@ -0,0 +1,25 @@
package app
import (
"crypto/rand"
"encoding/binary"
"github.com/pkg/errors"
)
type cryptoSource struct{}
func (s cryptoSource) Seed(seed int64) {}
func (s cryptoSource) Int63() int64 {
return int64(s.Uint64() & ^uint64(1<<63))
}
func (s cryptoSource) Uint64() (v uint64) {
err := binary.Read(rand.Reader, binary.BigEndian, &v)
if err != nil {
panic(errors.Wrap(err, "could not read number for random source"))
}
return v
}

5
pkg/app/error.go Normal file
View File

@ -0,0 +1,5 @@
package app
import "github.com/pkg/errors"
var ErrUnknownBundleArchiveFormat = errors.New("unknown bundle archive format")

101
pkg/app/loader.go Normal file
View File

@ -0,0 +1,101 @@
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("arcad.yml")
if err != nil {
return nil, errors.Wrap(err, "could not read arcad.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 arcad.yml")
}
return manifest, nil
}

41
pkg/app/promise_proxy.go Normal file
View File

@ -0,0 +1,41 @@
package app
import (
"sync"
"github.com/dop251/goja"
)
type PromiseProxy struct {
*goja.Promise
wg sync.WaitGroup
resolve func(result interface{})
reject func(reason interface{})
}
func (p *PromiseProxy) Resolve(result interface{}) {
defer p.wg.Done()
p.resolve(result)
}
func (p *PromiseProxy) Reject(reason interface{}) {
defer p.wg.Done()
p.resolve(reason)
}
func (p *PromiseProxy) Wait() {
p.wg.Wait()
}
func NewPromiseProxy(promise *goja.Promise, resolve func(result interface{}), reject func(reason interface{})) *PromiseProxy {
proxy := &PromiseProxy{
Promise: promise,
wg: sync.WaitGroup{},
resolve: resolve,
reject: reject,
}
proxy.wg.Add(1)
return proxy
}

11
pkg/bundle/bundle.go Normal file
View File

@ -0,0 +1,11 @@
package bundle
import (
"io"
"os"
)
type Bundle interface {
File(string) (io.ReadCloser, os.FileInfo, error)
Dir(string) ([]os.FileInfo, error)
}

70
pkg/bundle/bundle_test.go Normal file
View File

@ -0,0 +1,70 @@
package bundle
import (
"fmt"
"testing"
"github.com/pkg/errors"
"gitlab.com/wpetit/goweb/logger"
)
func TestBundle(t *testing.T) {
t.Parallel()
logger.SetLevel(logger.LevelDebug)
bundles := []Bundle{
NewDirectoryBundle("testdata/bundle"),
NewTarBundle("testdata/bundle.tar.gz"),
NewZipBundle("testdata/bundle.zip"),
}
for _, b := range bundles {
func(b Bundle) {
t.Run(fmt.Sprintf("'%T'", b), func(t *testing.T) {
t.Parallel()
reader, info, err := b.File("data/test/foo.txt")
if err != nil {
t.Error(err)
}
if reader == nil {
t.Fatal("File(data/test/foo.txt): reader should not be nil")
}
defer func() {
if err := reader.Close(); err != nil {
t.Error(errors.WithStack(err))
}
}()
if info == nil {
t.Error("File(data/test/foo.txt): info should not be nil")
}
files, err := b.Dir("data")
if err != nil {
t.Error(err)
}
if e, g := 1, len(files); e != g {
t.Errorf("len(files): expected '%v', got '%v'", e, g)
}
files, err = b.Dir("data/test")
if err != nil {
t.Error(err)
}
if e, g := 1, len(files); e != g {
t.Fatalf("len(files): expected '%v', got '%v'", e, g)
}
if e, g := "foo.txt", files[0].Name(); e != g {
t.Errorf("files[0].Name(): expected '%v', got '%v'", e, g)
}
})
}(b)
}
}

View File

@ -0,0 +1,54 @@
package bundle
import (
"context"
"io"
"io/ioutil"
"os"
"path"
"gitlab.com/wpetit/goweb/logger"
"github.com/pkg/errors"
)
type DirectoryBundle struct {
baseDir string
}
func (b *DirectoryBundle) File(filename string) (io.ReadCloser, os.FileInfo, error) {
ctx := context.Background()
fullPath := path.Join(b.baseDir, filename)
logger.Debug(ctx, "accessing bundle file", logger.F("file", fullPath))
info, err := os.Stat(fullPath)
if err != nil {
if os.IsNotExist(err) {
return nil, nil, err
}
return nil, nil, errors.Wrapf(err, "stat '%s'", fullPath)
}
reader, err := os.Open(fullPath)
if err != nil {
return nil, nil, errors.Wrapf(err, "open '%s'", fullPath)
}
return reader, info, nil
}
func (b *DirectoryBundle) Dir(dirname string) ([]os.FileInfo, error) {
fullPath := path.Join(b.baseDir, dirname)
ctx := context.Background()
logger.Debug(ctx, "accessing bundle directory", logger.F("file", fullPath))
return ioutil.ReadDir(fullPath)
}
func NewDirectoryBundle(baseDir string) *DirectoryBundle {
return &DirectoryBundle{
baseDir: baseDir,
}
}

5
pkg/bundle/error.go Normal file
View File

@ -0,0 +1,5 @@
package bundle
import "errors"
var ErrUnknownBundleArchiveExt = errors.New("unknown bundle archive extension")

101
pkg/bundle/filesystem.go Normal file
View File

@ -0,0 +1,101 @@
package bundle
import (
"bytes"
"context"
"io/ioutil"
"net/http"
"os"
"path"
"path/filepath"
"strings"
"github.com/pkg/errors"
"gitlab.com/wpetit/goweb/logger"
)
type FileSystem struct {
prefix string
bundle Bundle
}
func (fs *FileSystem) Open(name string) (http.File, error) {
if filepath.Separator != '/' && strings.ContainsRune(name, filepath.Separator) ||
strings.Contains(name, "\x00") {
return nil, errors.New("http: invalid character in file path")
}
p := path.Join(fs.prefix, strings.TrimPrefix(name, "/"))
ctx := logger.With(
context.Background(),
logger.F("filename", name),
)
logger.Debug(ctx, "opening file")
readCloser, fileInfo, err := fs.bundle.File(p)
if err != nil {
if os.IsNotExist(err) {
return nil, err
}
logger.Error(ctx, "could not open bundle file", logger.E(err))
return nil, errors.Wrapf(err, "could not open bundle file '%s'", p)
}
defer readCloser.Close()
file := &File{
fi: fileInfo,
}
if fileInfo.IsDir() {
files, err := fs.bundle.Dir(p)
if err != nil {
logger.Error(ctx, "could not read bundle directory", logger.E(err))
return nil, errors.Wrapf(err, "could not read bundle directory '%s'", p)
}
file.files = files
} else {
data, err := ioutil.ReadAll(readCloser)
if err != nil {
logger.Error(ctx, "could not read bundle file", logger.E(err))
return nil, errors.Wrapf(err, "could not read bundle file '%s'", p)
}
file.Reader = bytes.NewReader(data)
}
return file, nil
}
func NewFileSystem(prefix string, bundle Bundle) *FileSystem {
return &FileSystem{prefix, bundle}
}
type File struct {
*bytes.Reader
fi os.FileInfo
files []os.FileInfo
}
// A noop-closer.
func (f *File) Close() error {
return nil
}
func (f *File) Readdir(count int) ([]os.FileInfo, error) {
if f.fi.IsDir() && f.files != nil {
return f.files, nil
}
return nil, os.ErrNotExist
}
func (f *File) Stat() (os.FileInfo, error) {
return f.fi, nil
}

60
pkg/bundle/from_path.go Normal file
View File

@ -0,0 +1,60 @@
package bundle
import (
"fmt"
"os"
"path/filepath"
"github.com/pkg/errors"
)
type ArchiveExt string
const (
ExtZip ArchiveExt = "zip"
ExtTarGz ArchiveExt = "tar.gz"
)
func FromPath(path string) (Bundle, error) {
stat, err := os.Stat(path)
if err != nil {
return nil, errors.Wrapf(err, "could not stat file '%s'", path)
}
var b Bundle
if stat.IsDir() {
b = NewDirectoryBundle(path)
} else {
b, err = matchArchivePattern(path)
if err != nil {
return nil, errors.WithStack(err)
}
}
return b, nil
}
func matchArchivePattern(archivePath string) (Bundle, error) {
base := filepath.Base(archivePath)
matches, err := filepath.Match(fmt.Sprintf("*.%s", ExtTarGz), base)
if err != nil {
return nil, errors.Wrapf(err, "could not match file archive '%s'", archivePath)
}
if matches {
return NewTarBundle(archivePath), nil
}
matches, err = filepath.Match(fmt.Sprintf("*.%s", ExtZip), base)
if err != nil {
return nil, errors.Wrapf(err, "could not match file archive '%s'", archivePath)
}
if matches {
return NewZipBundle(archivePath), nil
}
return nil, errors.WithStack(ErrUnknownBundleArchiveExt)
}

146
pkg/bundle/tar_bundle.go Normal file
View File

@ -0,0 +1,146 @@
package bundle
import (
"archive/tar"
"compress/gzip"
"context"
"io"
"os"
"path/filepath"
"strings"
"github.com/pkg/errors"
"gitlab.com/wpetit/goweb/logger"
)
type TarBundle struct {
archivePath string
}
func (b *TarBundle) File(filename string) (io.ReadCloser, os.FileInfo, error) {
reader, archive, err := b.openArchive()
if err != nil {
return nil, nil, err
}
ctx := logger.With(
context.Background(),
logger.F("filename", filename),
)
logger.Debug(ctx, "opening file")
for {
header, err := reader.Next()
if err == io.EOF {
break
}
if err != nil {
return nil, nil, errors.Wrap(err, "could not get next tar file")
}
p := strings.TrimPrefix(strings.TrimSuffix(header.Name, "/"), "./")
logger.Debug(ctx, "reading archive file", logger.F("path", p))
if filename != p {
continue
}
if header.Typeflag != tar.TypeReg && header.Typeflag != tar.TypeDir {
continue
}
rc := &archiveFile{reader, archive}
return rc, header.FileInfo(), nil
}
return nil, nil, os.ErrNotExist
}
func (b *TarBundle) Dir(dirname string) ([]os.FileInfo, error) {
reader, archive, err := b.openArchive()
if err != nil {
return nil, err
}
defer archive.Close()
files := make([]os.FileInfo, 0)
ctx := context.Background()
for {
header, err := reader.Next()
if errors.Is(err, io.EOF) {
break
}
if err != nil {
return nil, errors.Wrap(err, "could not get next tar file")
}
if header.Typeflag != tar.TypeReg && header.Typeflag != tar.TypeDir {
continue
}
if !strings.HasPrefix(header.Name, dirname) {
continue
}
relPath, err := filepath.Rel(dirname, header.Name)
if err != nil {
return nil, errors.Wrap(err, "could not get relative path")
}
logger.Debug(
ctx, "checking file prefix",
logger.F("dirname", dirname),
logger.F("filename", header.Name),
logger.F("relpath", relPath),
)
if relPath == filepath.Base(header.Name) {
files = append(files, header.FileInfo())
}
}
return files, nil
}
func (b *TarBundle) openArchive() (*tar.Reader, *os.File, error) {
f, err := os.Open(b.archivePath)
if err != nil {
return nil, nil, errors.Wrapf(err, "could not open '%v'", b.archivePath)
}
gzf, err := gzip.NewReader(f)
if err != nil {
return nil, nil, errors.Wrapf(err, "could not decompress '%v'", b.archivePath)
}
tr := tar.NewReader(gzf)
return tr, f, nil
}
func NewTarBundle(archivePath string) *TarBundle {
return &TarBundle{
archivePath: archivePath,
}
}
type archiveFile struct {
reader io.Reader
closer io.Closer
}
func (f *archiveFile) Read(p []byte) (n int, err error) {
return f.reader.Read(p)
}
func (f *archiveFile) Close() error {
return f.closer.Close()
}

BIN
pkg/bundle/testdata/bundle.tar.gz vendored Normal file

Binary file not shown.

BIN
pkg/bundle/testdata/bundle.zip vendored Normal file

Binary file not shown.

View File

@ -0,0 +1 @@
bar

98
pkg/bundle/zip_bundle.go Normal file
View File

@ -0,0 +1,98 @@
package bundle
import (
"archive/zip"
"context"
"io"
"os"
"path/filepath"
"strings"
"github.com/pkg/errors"
"gitlab.com/wpetit/goweb/logger"
)
type ZipBundle struct {
archivePath string
}
func (b *ZipBundle) File(filename string) (io.ReadCloser, os.FileInfo, error) {
reader, err := b.openArchive()
if err != nil {
return nil, nil, err
}
ctx := logger.With(
context.Background(),
logger.F("filename", filename),
)
logger.Debug(ctx, "opening file")
f, err := reader.Open(filename)
if err != nil {
return nil, nil, errors.WithStack(err)
}
stat, err := f.Stat()
if err != nil {
return nil, nil, errors.WithStack(err)
}
return f, stat, nil
}
func (b *ZipBundle) Dir(dirname string) ([]os.FileInfo, error) {
reader, err := b.openArchive()
if err != nil {
return nil, err
}
defer func() {
if err := reader.Close(); err != nil {
panic(errors.WithStack(err))
}
}()
files := make([]os.FileInfo, 0)
ctx := context.Background()
for _, f := range reader.File {
if !strings.HasPrefix(f.Name, dirname) {
continue
}
relPath, err := filepath.Rel(dirname, f.Name)
if err != nil {
return nil, errors.Wrap(err, "could not get relative path")
}
logger.Debug(
ctx, "checking file prefix",
logger.F("dirname", dirname),
logger.F("filename", f.Name),
logger.F("relpath", relPath),
)
if relPath == filepath.Base(f.Name) {
files = append(files, f.FileInfo())
}
}
return files, nil
}
func (b *ZipBundle) openArchive() (*zip.ReadCloser, error) {
zr, err := zip.OpenReader(b.archivePath)
if err != nil {
return nil, errors.Wrapf(err, "could not decompress '%v'", b.archivePath)
}
return zr, nil
}
func NewZipBundle(archivePath string) *ZipBundle {
return &ZipBundle{
archivePath: archivePath,
}
}

13
pkg/bus/bus.go Normal file
View File

@ -0,0 +1,13 @@
package bus
import "context"
type Bus interface {
Subscribe(ctx context.Context, ns MessageNamespace) (<-chan Message, error)
Unsubscribe(ctx context.Context, ns MessageNamespace, ch <-chan Message)
Publish(ctx context.Context, msg Message) error
Request(ctx context.Context, msg Message) (Message, error)
Reply(ctx context.Context, ns MessageNamespace, h RequestHandler) error
}
type RequestHandler func(msg Message) (Message, error)

9
pkg/bus/error.go Normal file
View File

@ -0,0 +1,9 @@
package bus
import "github.com/pkg/errors"
var (
ErrPublishTimeout = errors.New("publish timeout")
ErrUnexpectedMessage = errors.New("unexpected message")
ErrNoResponse = errors.New("no response")
)

91
pkg/bus/memory/bus.go Normal file
View File

@ -0,0 +1,91 @@
package memory
import (
"context"
"forge.cadoles.com/arcad/edge/pkg/bus"
cmap "github.com/orcaman/concurrent-map"
"github.com/pkg/errors"
"gitlab.com/wpetit/goweb/logger"
)
type Bus struct {
opt *Option
dispatchers cmap.ConcurrentMap
nextRequestID uint64
}
func (b *Bus) Subscribe(ctx context.Context, ns bus.MessageNamespace) (<-chan bus.Message, error) {
logger.Debug(
ctx, "subscribing to messages",
logger.F("messageNamespace", ns),
)
dispatchers := b.getDispatchers(ns)
d := newEventDispatcher(b.opt.BufferSize)
go d.Run()
dispatchers.Add(d)
return d.Out(), nil
}
func (b *Bus) Unsubscribe(ctx context.Context, ns bus.MessageNamespace, ch <-chan bus.Message) {
logger.Debug(
ctx, "unsubscribing from messages",
logger.F("messageNamespace", ns),
)
dispatchers := b.getDispatchers(ns)
dispatchers.RemoveByOutChannel(ch)
}
func (b *Bus) Publish(ctx context.Context, msg bus.Message) error {
dispatchers := b.getDispatchers(msg.MessageNamespace())
dispatchersList := dispatchers.List()
logger.Debug(
ctx, "publishing message",
logger.F("dispatchers", len(dispatchersList)),
logger.F("messageNamespace", msg.MessageNamespace()),
)
for _, d := range dispatchersList {
if err := d.In(msg); err != nil {
return errors.WithStack(err)
}
}
return nil
}
func (b *Bus) getDispatchers(namespace bus.MessageNamespace) *eventDispatcherSet {
strNamespace := string(namespace)
rawDispatchers, exists := b.dispatchers.Get(strNamespace)
dispatchers, ok := rawDispatchers.(*eventDispatcherSet)
if !exists || !ok {
dispatchers = newEventDispatcherSet()
b.dispatchers.Set(strNamespace, dispatchers)
}
return dispatchers
}
func NewBus(funcs ...OptionFunc) *Bus {
opt := DefaultOption()
for _, fn := range funcs {
fn(opt)
}
return &Bus{
opt: opt,
dispatchers: cmap.New(),
}
}
// Check bus implementation.
var _ bus.Bus = NewBus()

View File

@ -0,0 +1,29 @@
package memory
import (
"testing"
busTesting "forge.cadoles.com/arcad/edge/pkg/bus/testing"
)
func TestMemoryBus(t *testing.T) {
if testing.Short() {
t.Skip("Test disabled when -short flag is set")
}
t.Parallel()
t.Run("PublishSubscribe", func(t *testing.T) {
t.Parallel()
b := NewBus()
busTesting.TestPublishSubscribe(t, b)
})
t.Run("RequestReply", func(t *testing.T) {
t.Parallel()
b := NewBus()
busTesting.TestRequestReply(t, b)
})
}

View File

@ -0,0 +1,117 @@
package memory
import (
"context"
"sync"
"time"
"forge.cadoles.com/arcad/edge/pkg/bus"
"gitlab.com/wpetit/goweb/logger"
)
type eventDispatcherSet struct {
mutex sync.Mutex
items map[*eventDispatcher]struct{}
}
func (s *eventDispatcherSet) Add(d *eventDispatcher) {
s.mutex.Lock()
defer s.mutex.Unlock()
s.items[d] = struct{}{}
}
func (s *eventDispatcherSet) RemoveByOutChannel(out <-chan bus.Message) {
s.mutex.Lock()
defer s.mutex.Unlock()
for d := range s.items {
if d.IsOut(out) {
d.Close()
delete(s.items, d)
}
}
}
func (s *eventDispatcherSet) List() []*eventDispatcher {
s.mutex.Lock()
defer s.mutex.Unlock()
dispatchers := make([]*eventDispatcher, 0, len(s.items))
for d := range s.items {
dispatchers = append(dispatchers, d)
}
return dispatchers
}
func newEventDispatcherSet() *eventDispatcherSet {
return &eventDispatcherSet{
items: make(map[*eventDispatcher]struct{}),
}
}
type eventDispatcher struct {
in chan bus.Message
out chan bus.Message
mutex sync.RWMutex
closed bool
}
func (d *eventDispatcher) Close() {
d.mutex.Lock()
defer d.mutex.Unlock()
d.closed = true
close(d.in)
}
func (d *eventDispatcher) In(msg bus.Message) (err error) {
d.mutex.RLock()
defer d.mutex.RUnlock()
if d.closed {
return
}
d.in <- msg
return nil
}
func (d *eventDispatcher) Out() <-chan bus.Message {
return d.out
}
func (d *eventDispatcher) IsOut(out <-chan bus.Message) bool {
return d.out == out
}
func (d *eventDispatcher) Run() {
ctx := context.Background()
for {
msg, ok := <-d.in
if !ok {
close(d.out)
return
}
timeout := time.After(2 * time.Second)
select {
case d.out <- msg:
case <-timeout:
logger.Error(ctx, "message out chan timed out", logger.F("message", msg))
}
}
}
func newEventDispatcher(bufferSize int64) *eventDispatcher {
return &eventDispatcher{
in: make(chan bus.Message, bufferSize),
out: make(chan bus.Message, bufferSize),
closed: false,
}
}

19
pkg/bus/memory/option.go Normal file
View File

@ -0,0 +1,19 @@
package memory
type Option struct {
BufferSize int64
}
type OptionFunc func(*Option)
func DefaultOption() *Option {
return &Option{
BufferSize: 16, // nolint: gomnd
}
}
func WithBufferSize(size int64) OptionFunc {
return func(o *Option) {
o.BufferSize = size
}
}

View File

@ -0,0 +1,151 @@
package memory
import (
"context"
"strconv"
"sync/atomic"
"forge.cadoles.com/arcad/edge/pkg/bus"
"github.com/pkg/errors"
"gitlab.com/wpetit/goweb/logger"
)
const (
MessageNamespaceRequest bus.MessageNamespace = "reqrep/request"
MessageNamespaceReply bus.MessageNamespace = "reqrep/reply"
)
type RequestMessage struct {
RequestID uint64
Message bus.Message
ns bus.MessageNamespace
}
func (m *RequestMessage) MessageNamespace() bus.MessageNamespace {
return m.ns
}
type ReplyMessage struct {
RequestID uint64
Message bus.Message
Error error
ns bus.MessageNamespace
}
func (m *ReplyMessage) MessageNamespace() bus.MessageNamespace {
return m.ns
}
func (b *Bus) Request(ctx context.Context, msg bus.Message) (bus.Message, error) {
requestID := atomic.AddUint64(&b.nextRequestID, 1)
req := &RequestMessage{
RequestID: requestID,
Message: msg,
ns: msg.MessageNamespace(),
}
replyNamespace := createReplyNamespace(requestID)
replies, err := b.Subscribe(ctx, replyNamespace)
if err != nil {
return nil, errors.WithStack(err)
}
defer func() {
b.Unsubscribe(ctx, replyNamespace, replies)
}()
logger.Debug(ctx, "publishing request", logger.F("request", req))
if err := b.Publish(ctx, req); err != nil {
return nil, errors.WithStack(err)
}
for {
select {
case <-ctx.Done():
return nil, errors.WithStack(ctx.Err())
case msg, ok := <-replies:
if !ok {
return nil, errors.WithStack(bus.ErrNoResponse)
}
reply, ok := msg.(*ReplyMessage)
if !ok {
return nil, errors.WithStack(bus.ErrUnexpectedMessage)
}
if reply.Error != nil {
return nil, errors.WithStack(err)
}
return reply.Message, nil
}
}
}
type RequestHandler func(evt bus.Message) (bus.Message, error)
func (b *Bus) Reply(ctx context.Context, msgNamespace bus.MessageNamespace, h bus.RequestHandler) error {
requests, err := b.Subscribe(ctx, msgNamespace)
if err != nil {
return errors.WithStack(err)
}
defer func() {
b.Unsubscribe(ctx, msgNamespace, requests)
}()
for {
select {
case <-ctx.Done():
return errors.WithStack(ctx.Err())
case msg, ok := <-requests:
if !ok {
return nil
}
request, ok := msg.(*RequestMessage)
if !ok {
return errors.WithStack(bus.ErrUnexpectedMessage)
}
logger.Debug(ctx, "handling request", logger.F("request", request))
msg, err := h(request.Message)
reply := &ReplyMessage{
RequestID: request.RequestID,
Message: nil,
Error: nil,
ns: createReplyNamespace(request.RequestID),
}
if err != nil {
reply.Error = errors.WithStack(err)
} else {
reply.Message = msg
}
logger.Debug(ctx, "publishing reply", logger.F("reply", reply))
if err := b.Publish(ctx, reply); err != nil {
return errors.WithStack(err)
}
}
}
}
func createReplyNamespace(requestID uint64) bus.MessageNamespace {
return bus.NewMessageNamespace(
MessageNamespaceReply,
bus.MessageNamespace(strconv.FormatUint(requestID, 10)),
)
}

33
pkg/bus/message.go Normal file
View File

@ -0,0 +1,33 @@
package bus
import (
"strings"
"github.com/pkg/errors"
)
type (
MessageNamespace string
)
type Message interface {
MessageNamespace() MessageNamespace
}
func NewMessageNamespace(namespaces ...MessageNamespace) MessageNamespace {
var sb strings.Builder
for i, ns := range namespaces {
if i != 0 {
if _, err := sb.WriteString(":"); err != nil {
panic(errors.Wrap(err, "could not build new message namespace"))
}
}
if _, err := sb.WriteString(string(ns)); err != nil {
panic(errors.Wrap(err, "could not build new message namespace"))
}
}
return MessageNamespace(sb.String())
}

View File

@ -0,0 +1,96 @@
package testing
import (
"context"
"sync"
"sync/atomic"
"testing"
"time"
"forge.cadoles.com/arcad/edge/pkg/bus"
"github.com/pkg/errors"
)
const (
testNamespace bus.MessageNamespace = "testNamespace"
)
type testMessage struct{}
func (e *testMessage) MessageNamespace() bus.MessageNamespace {
return testNamespace
}
func TestPublishSubscribe(t *testing.T, b bus.Bus) {
ctx, cancel := context.WithTimeout(context.Background(), time.Minute)
defer cancel()
t.Log("subscribe")
messages, err := b.Subscribe(ctx, testNamespace)
if err != nil {
t.Fatal(errors.WithStack(err))
}
var wg sync.WaitGroup
wg.Add(5)
go func() {
// 5 events should be received
t.Log("publish 0")
if err := b.Publish(ctx, &testMessage{}); err != nil {
t.Error(errors.WithStack(err))
}
t.Log("publish 1")
if err := b.Publish(ctx, &testMessage{}); err != nil {
t.Error(errors.WithStack(err))
}
t.Log("publish 2")
if err := b.Publish(ctx, &testMessage{}); err != nil {
t.Error(errors.WithStack(err))
}
t.Log("publish 3")
if err := b.Publish(ctx, &testMessage{}); err != nil {
t.Error(errors.WithStack(err))
}
t.Log("publish 4")
if err := b.Publish(ctx, &testMessage{}); err != nil {
t.Error(errors.WithStack(err))
}
}()
var count int32 = 0
go func() {
t.Log("range for events")
for msg := range messages {
t.Logf("received msg %d", atomic.LoadInt32(&count))
atomic.AddInt32(&count, 1)
if e, g := testNamespace, msg.MessageNamespace(); e != g {
t.Errorf("evt.MessageNamespace(): expected '%v', got '%v'", e, g)
}
wg.Done()
}
}()
wg.Wait()
b.Unsubscribe(ctx, testNamespace, messages)
if e, g := int32(5), count; e != g {
t.Errorf("message received count: expected '%v', got '%v'", e, g)
}
}

View File

@ -0,0 +1,110 @@
package testing
import (
"context"
"sync"
"testing"
"time"
"forge.cadoles.com/arcad/edge/pkg/bus"
"github.com/pkg/errors"
)
const (
testTypeReqRes bus.MessageNamespace = "testNamspaceReqRes"
)
type testReqResMessage struct {
i int
}
func (m *testReqResMessage) MessageNamespace() bus.MessageNamespace {
return testNamespace
}
func TestRequestReply(t *testing.T, b bus.Bus) {
expectedRoundTrips := 256
timeout := time.Now().Add(time.Duration(expectedRoundTrips) * time.Second)
var (
initWaitGroup sync.WaitGroup
resWaitGroup sync.WaitGroup
)
initWaitGroup.Add(1)
go func() {
repondCtx, cancelRespond := context.WithDeadline(context.Background(), timeout)
defer cancelRespond()
initWaitGroup.Done()
err := b.Reply(repondCtx, testNamespace, func(msg bus.Message) (bus.Message, error) {
defer resWaitGroup.Done()
req, ok := msg.(*testReqResMessage)
if !ok {
return nil, errors.WithStack(bus.ErrUnexpectedMessage)
}
result := &testReqResMessage{req.i}
// Simulate random work
time.Sleep(time.Millisecond * 100)
t.Logf("[RES] sending res #%d", req.i)
return result, nil
})
if err != nil {
t.Error(err)
}
}()
initWaitGroup.Wait()
var reqWaitGroup sync.WaitGroup
for i := 0; i < expectedRoundTrips; i++ {
resWaitGroup.Add(1)
reqWaitGroup.Add(1)
go func(i int) {
defer reqWaitGroup.Done()
requestCtx, cancelRequest := context.WithDeadline(context.Background(), timeout)
defer cancelRequest()
req := &testReqResMessage{i}
t.Logf("[REQ] sending req #%d", i)
result, err := b.Request(requestCtx, req)
if err != nil {
t.Error(err)
}
t.Logf("[REQ] received req #%d reply", i)
if result == nil {
t.Error("result should not be nil")
return
}
res, ok := result.(*testReqResMessage)
if !ok {
t.Error(errors.WithStack(bus.ErrUnexpectedMessage))
return
}
if e, g := req.i, res.i; e != g {
t.Errorf("res.i: expected '%v', got '%v'", e, g)
}
}(i)
}
reqWaitGroup.Wait()
resWaitGroup.Wait()
}

51
pkg/http/file.go Normal file
View File

@ -0,0 +1,51 @@
package http
import (
"io"
"io/fs"
"net/http"
"os"
"github.com/pkg/errors"
"gitlab.com/wpetit/goweb/logger"
)
func serveFile(w http.ResponseWriter, r *http.Request, fs fs.FS, path string) {
ctx := logger.With(r.Context(), logger.F("path", path))
file, err := fs.Open(path)
if err != nil {
if errors.Is(err, os.ErrNotExist) {
http.Error(w, http.StatusText(http.StatusNotFound), http.StatusNotFound)
return
}
logger.Error(ctx, "error while opening fs file", logger.E(errors.WithStack(err)))
http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
return
}
defer func() {
if err := file.Close(); err != nil {
logger.Error(ctx, "error while closing fs file", logger.E(errors.WithStack(err)))
}
}()
info, err := file.Stat()
if err != nil {
logger.Error(ctx, "error while retrieving fs file stat", logger.E(errors.WithStack(err)))
return
}
reader, ok := file.(io.ReadSeeker)
if !ok {
logger.Error(ctx, "could not convert file to readseeker", logger.E(errors.WithStack(err)))
return
}
http.ServeContent(w, r, path, info.ModTime(), reader)
}

106
pkg/http/handler.go Normal file
View File

@ -0,0 +1,106 @@
package http
import (
"io/ioutil"
"net/http"
"strings"
"sync"
"forge.cadoles.com/arcad/edge/pkg/app"
"forge.cadoles.com/arcad/edge/pkg/bundle"
"forge.cadoles.com/arcad/edge/pkg/bus"
"forge.cadoles.com/arcad/edge/pkg/sdk"
"github.com/igm/sockjs-go/v3/sockjs"
"github.com/pkg/errors"
)
const (
sockJSPathPrefix = "/sock"
clientJSPath = "/client.js"
backendMainScript = "backend/main.js"
)
type Handler struct {
bundle bundle.Bundle
public http.Handler
sockjs http.Handler
bus bus.Bus
sockjsOpts sockjs.Options
backend *app.Backend
backendModuleFactories []app.BackendModuleFactory
mutex sync.RWMutex
}
func (h *Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
h.mutex.RLock()
defer h.mutex.RUnlock()
switch {
case r.URL.Path == clientJSPath:
serveFile(w, r, &sdk.FS, "client/dist/client.js")
case r.URL.Path == clientJSPath+".map":
serveFile(w, r, &sdk.FS, "client/dist/client.js.map")
case strings.HasPrefix(r.URL.Path, sockJSPathPrefix):
h.sockjs.ServeHTTP(w, r)
default:
h.public.ServeHTTP(w, r)
}
}
func (h *Handler) Load(bdle bundle.Bundle) error {
h.mutex.Lock()
defer h.mutex.Unlock()
file, _, err := bdle.File(backendMainScript)
if err != nil {
return errors.Wrap(err, "could not open backend main script")
}
mainScript, err := ioutil.ReadAll(file)
if err != nil {
return errors.Wrap(err, "could not read backend main script")
}
backend := app.NewBackend(h.backendModuleFactories...)
if err := backend.Load(backendMainScript, string(mainScript)); err != nil {
return errors.WithStack(err)
}
fs := bundle.NewFileSystem("public", bdle)
public := http.FileServer(fs)
sockjs := sockjs.NewHandler(sockJSPathPrefix, h.sockjsOpts, h.handleSockJSSession)
if h.backend != nil {
h.backend.Stop()
}
if err := backend.Start(); err != nil {
return errors.WithStack(err)
}
h.bundle = bdle
h.backend = backend
h.public = public
h.sockjs = sockjs
return nil
}
func NewHandler(funcs ...HandlerOptionFunc) *Handler {
opts := defaultHandlerOptions()
for _, fn := range funcs {
fn(opts)
}
handler := &Handler{
sockjsOpts: opts.SockJS,
backendModuleFactories: opts.BackendModuleFactories,
bus: opts.Bus,
}
return handler
}

49
pkg/http/options.go Normal file
View File

@ -0,0 +1,49 @@
package http
import (
"time"
"forge.cadoles.com/arcad/edge/pkg/app"
"forge.cadoles.com/arcad/edge/pkg/bus"
"forge.cadoles.com/arcad/edge/pkg/bus/memory"
"github.com/igm/sockjs-go/v3/sockjs"
)
type HandlerOptions struct {
Bus bus.Bus
SockJS sockjs.Options
BackendModuleFactories []app.BackendModuleFactory
}
func defaultHandlerOptions() *HandlerOptions {
sockjsOptions := func() sockjs.Options {
return sockjs.DefaultOptions
}()
sockjsOptions.DisconnectDelay = 10 * time.Second
return &HandlerOptions{
Bus: memory.NewBus(),
SockJS: sockjsOptions,
BackendModuleFactories: make([]app.BackendModuleFactory, 0),
}
}
type HandlerOptionFunc func(*HandlerOptions)
func WithBackendModules(factories ...app.BackendModuleFactory) HandlerOptionFunc {
return func(opts *HandlerOptions) {
opts.BackendModuleFactories = factories
}
}
func WithSockJS(options sockjs.Options) HandlerOptionFunc {
return func(opts *HandlerOptions) {
opts.SockJS = options
}
}
func WithBus(bus bus.Bus) HandlerOptionFunc {
return func(opts *HandlerOptions) {
opts.Bus = bus
}
}

214
pkg/http/sockjs.go Normal file
View File

@ -0,0 +1,214 @@
package http
import (
"context"
"encoding/json"
"forge.cadoles.com/arcad/edge/pkg/module"
"github.com/igm/sockjs-go/v3/sockjs"
"github.com/pkg/errors"
"gitlab.com/wpetit/goweb/logger"
)
const (
statusChannelClosed = iota
)
func (h *Handler) handleSockJSSession(sess sockjs.Session) {
ctx := logger.With(sess.Request().Context(),
logger.F("sessionID", sess.ID()),
)
logger.Debug(ctx, "new sockjs session")
defer func() {
if sess.GetSessionState() == sockjs.SessionActive {
if err := sess.Close(statusChannelClosed, "channel closed"); err != nil {
logger.Error(ctx, "could not close sockjs session", logger.E(errors.WithStack(err)))
}
}
}()
go h.handleBackendMessages(ctx, sess)
h.handleClientMessages(ctx, sess)
}
func (h *Handler) handleBackendMessages(ctx context.Context, sess sockjs.Session) {
messages, err := h.bus.Subscribe(ctx, module.MessageNamespaceBackend)
if err != nil {
panic(errors.WithStack(err))
}
defer func() {
// Close messages subscriber
h.bus.Unsubscribe(ctx, module.MessageNamespaceBackend, messages)
logger.Debug(ctx, "unsubscribed")
if sess.GetSessionState() != sockjs.SessionActive {
return
}
if err := sess.Close(statusChannelClosed, "channel closed"); err != nil {
logger.Error(ctx, "could not close sockjs session", logger.E(errors.WithStack(err)))
}
}()
for {
select {
case <-ctx.Done():
return
case msg := <-messages:
backendMessage, ok := msg.(*module.BackendMessage)
if !ok {
logger.Error(
ctx,
"unexpected backend message",
logger.F("message", msg),
)
continue
}
payload, err := json.Marshal(backendMessage.Data)
if err != nil {
logger.Error(
ctx,
"could not encode message",
logger.E(err),
)
continue
}
message := NewWebsocketMessage(
WebsocketMessageTypeMessage,
json.RawMessage(payload),
)
data, err := json.Marshal(message)
if err != nil {
logger.Error(
ctx,
"could not encode message",
logger.E(err),
)
continue
}
logger.Debug(ctx, "sending message")
// Send message
if err := sess.Send(string(data)); err != nil {
logger.Error(
ctx,
"could not send message",
logger.E(err),
)
}
}
}
}
func (h *Handler) handleClientMessages(ctx context.Context, sess sockjs.Session) {
for {
select {
case <-ctx.Done():
logger.Debug(ctx, "context done")
return
default:
logger.Debug(ctx, "waiting for websocket data")
data, err := sess.RecvCtx(ctx)
if err != nil {
if errors.Is(err, sockjs.ErrSessionNotOpen) {
break
}
logger.Error(
ctx,
"could not read message",
logger.E(errors.WithStack(err)),
)
break
}
logger.Debug(ctx, "websocket data received", logger.F("data", data))
message := &WebsocketMessage{}
if err := json.Unmarshal([]byte(data), message); err != nil {
logger.Error(
ctx,
"could not decode message",
logger.E(errors.WithStack(err)),
)
break
}
switch {
case message.Type == WebsocketMessageTypeMessage:
var payload map[string]interface{}
if err := json.Unmarshal(message.Payload, &payload); err != nil {
logger.Error(
ctx,
"could not decode payload",
logger.E(errors.WithStack(err)),
)
return
}
ctx := logger.With(ctx, logger.F("payload", payload))
frontendMessage := module.NewFrontendMessage(payload)
logger.Debug(ctx, "publishing new frontend message", logger.F("message", frontendMessage))
if err := h.bus.Publish(ctx, frontendMessage); err != nil {
logger.Error(ctx, "could not publish message",
logger.E(errors.WithStack(err)),
logger.F("message", frontendMessage),
)
return
}
logger.Debug(ctx, "new frontend message published", logger.F("message", frontendMessage))
default:
logger.Error(
ctx,
"unsupported message type",
logger.F("messageType", message.Type),
)
}
}
}
}
const (
WebsocketMessageTypeMessage = "message"
)
type WebsocketMessage struct {
Type string `json:"t"`
Payload json.RawMessage `json:"p"`
}
type WebsocketMessagePayload struct {
Data map[string]interface{} `json:"d"`
}
func NewWebsocketMessage(dataType string, payload json.RawMessage) *WebsocketMessage {
return &WebsocketMessage{
Type: dataType,
Payload: payload,
}
}

1
pkg/module/.gitignore vendored Normal file
View File

@ -0,0 +1 @@
*.sqlite

109
pkg/module/authorization.go Normal file
View File

@ -0,0 +1,109 @@
package module
// import (
// "context"
// "sync"
// "forge.cadoles.com/arcad/edge/pkg/app"
// "forge.cadoles.com/arcad/edge/pkg/bus"
// "forge.cadoles.com/arcad/edge/pkg/repository"
// "github.com/dop251/goja"
// "github.com/pkg/errors"
// "gitlab.com/wpetit/goweb/logger"
// )
// type AuthorizationModule struct {
// appID app.ID
// bus bus.Bus
// backend *app.Backend
// admins sync.Map
// }
// func (m *AuthorizationModule) Name() string {
// return "authorization"
// }
// func (m *AuthorizationModule) Export(export *goja.Object) {
// if err := export.Set("isAdmin", m.isAdmin); err != nil {
// panic(errors.Wrap(err, "could not set 'register' function"))
// }
// }
// func (m *AuthorizationModule) isAdmin(call goja.FunctionCall) goja.Value {
// userID := call.Argument(0).String()
// if userID == "" {
// panic(errors.New("first argument must be a user id"))
// }
// rawValue, exists := m.admins.Load(repository.UserID(userID))
// if !exists {
// return m.backend.ToValue(false)
// }
// isAdmin, ok := rawValue.(bool)
// if !ok {
// return m.backend.ToValue(false)
// }
// return m.backend.ToValue(isAdmin)
// }
// func (m *AuthorizationModule) handleEvents() {
// ctx := logger.With(context.Background(), logger.F("moduleAppID", m.appID))
// ns := AppMessageNamespace(m.appID)
// userConnectedMessages, err := m.bus.Subscribe(ctx, ns, MessageTypeUserConnected)
// if err != nil {
// panic(errors.WithStack(err))
// }
// userDisconnectedMessages, err := m.bus.Subscribe(ctx, ns, MessageTypeUserDisconnected)
// if err != nil {
// panic(errors.WithStack(err))
// }
// defer func() {
// m.bus.Unsubscribe(ctx, ns, MessageTypeUserConnected, userConnectedMessages)
// m.bus.Unsubscribe(ctx, ns, MessageTypeUserDisconnected, userDisconnectedMessages)
// }()
// for {
// select {
// case msg := <-userConnectedMessages:
// userConnectedMsg, ok := msg.(*MessageUserConnected)
// if !ok {
// continue
// }
// logger.Debug(ctx, "user connected", logger.F("msg", userConnectedMsg))
// m.admins.Store(userConnectedMsg.UserID, userConnectedMsg.IsAdmin)
// case msg := <-userDisconnectedMessages:
// userDisconnectedMsg, ok := msg.(*MessageUserDisconnected)
// if !ok {
// continue
// }
// logger.Debug(ctx, "user disconnected", logger.F("msg", userDisconnectedMsg))
// m.admins.Delete(userDisconnectedMsg.UserID)
// }
// }
// }
// func AuthorizationModuleFactory(b bus.Bus) app.BackendModuleFactory {
// return func(appID app.ID, backend *app.Backend) app.BackendModule {
// mod := &AuthorizationModule{
// appID: appID,
// bus: b,
// backend: backend,
// admins: sync.Map{},
// }
// go mod.handleEvents()
// return mod
// }
// }

View File

@ -0,0 +1,103 @@
package module
// import (
// "context"
// "io/ioutil"
// "testing"
// "time"
// "forge.cadoles.com/arcad/edge/pkg/app"
// "forge.cadoles.com/arcad/edge/pkg/bus/memory"
// )
// func TestAuthorizationModule(t *testing.T) {
// t.Parallel()
// testAppID := app.ID("test-app")
// b := memory.NewBus()
// backend := app.NewBackend(testAppID,
// ConsoleModuleFactory(),
// AuthorizationModuleFactory(b),
// )
// data, err := ioutil.ReadFile("testdata/authorization.js")
// if err != nil {
// t.Fatal(err)
// }
// if err := backend.Load(string(data)); err != nil {
// t.Fatal(err)
// }
// backend.Start()
// defer backend.Stop()
// if err := backend.OnInit(); err != nil {
// t.Error(err)
// }
// // Test non connected user
// retValue, err := backend.ExecFuncByName("isAdmin", testUserID)
// if err != nil {
// t.Error(err)
// }
// isAdmin := retValue.ToBoolean()
// if e, g := false, isAdmin; e != g {
// t.Errorf("isAdmin: expected '%v', got '%v'", e, g)
// }
// // Test user connection as normal user
// ctx := context.Background()
// b.Publish(ctx, NewMessageUserConnected(testAppID, testUserID, false))
// time.Sleep(2 * time.Second)
// retValue, err = backend.ExecFuncByName("isAdmin", testUserID)
// if err != nil {
// t.Error(err)
// }
// isAdmin = retValue.ToBoolean()
// if e, g := false, isAdmin; e != g {
// t.Errorf("isAdmin: expected '%v', got '%v'", e, g)
// }
// // Test user connection as admin
// b.Publish(ctx, NewMessageUserConnected(testAppID, testUserID, true))
// time.Sleep(2 * time.Second)
// retValue, err = backend.ExecFuncByName("isAdmin", testUserID)
// if err != nil {
// t.Error(err)
// }
// isAdmin = retValue.ToBoolean()
// if e, g := true, isAdmin; e != g {
// t.Errorf("isAdmin: expected '%v', got '%v'", e, g)
// }
// // Test user disconnection
// b.Publish(ctx, NewMessageUserDisconnected(testAppID, testUserID))
// time.Sleep(2 * time.Second)
// retValue, err = backend.ExecFuncByName("isAdmin", testUserID)
// if err != nil {
// t.Error(err)
// }
// isAdmin = retValue.ToBoolean()
// if e, g := false, isAdmin; e != g {
// t.Errorf("isAdmin: expected '%v', got '%v'", e, g)
// }
// }

44
pkg/module/console.go Normal file
View File

@ -0,0 +1,44 @@
package module
import (
"context"
"fmt"
"strings"
"gitlab.com/wpetit/goweb/logger"
"forge.cadoles.com/arcad/edge/pkg/app"
"github.com/dop251/goja"
"github.com/pkg/errors"
)
type ConsoleModule struct{}
func (m *ConsoleModule) Name() string {
return "console"
}
func (m *ConsoleModule) log(call goja.FunctionCall) goja.Value {
var sb strings.Builder
for _, arg := range call.Arguments {
sb.WriteString(fmt.Sprintf("%+v", arg.Export()))
sb.WriteString(" ")
}
logger.Debug(context.Background(), sb.String())
return nil
}
func (m *ConsoleModule) Export(export *goja.Object) {
if err := export.Set("log", m.log); err != nil {
panic(errors.Wrap(err, "could not set 'log' function"))
}
}
func ConsoleModuleFactory() app.BackendModuleFactory {
return func(backend *app.Backend) app.BackendModule {
return &ConsoleModule{}
}
}

55
pkg/module/context.go Normal file
View File

@ -0,0 +1,55 @@
package module
import (
"context"
"sync"
"forge.cadoles.com/arcad/edge/pkg/app"
"github.com/dop251/goja"
"github.com/pkg/errors"
)
func assertContext(v goja.Value, r *goja.Runtime) context.Context {
if c, ok := v.Export().(context.Context); ok {
return c
}
panic(r.NewTypeError("value should be a context"))
}
type ContextModule struct {
ctx BackendContext
mutex sync.RWMutex
}
func (m *ContextModule) Name() string {
return "context"
}
func (m *ContextModule) get(call goja.FunctionCall, rt *goja.Runtime) goja.Value {
m.mutex.RLock()
defer m.mutex.RUnlock()
return rt.ToValue(m.ctx)
}
func (m *ContextModule) Export(export *goja.Object) {
if err := export.Set("get", m.get); err != nil {
panic(errors.Wrap(err, "could not set 'get' function"))
}
}
func ContextModuleFactory() app.BackendModuleFactory {
return func(backend *app.Backend) app.BackendModule {
return &ContextModule{
ctx: BackendContext{
Context: context.Background(),
},
mutex: sync.RWMutex{},
}
}
}
type BackendContext struct {
context.Context
}

5
pkg/module/error.go Normal file
View File

@ -0,0 +1,5 @@
package module
import "github.com/pkg/errors"
var ErrUnexpectedArgumentsNumber = errors.New("unexpected number of arguments")

293
pkg/module/file.go Normal file
View File

@ -0,0 +1,293 @@
package module
// import (
// "context"
// "fmt"
// "io"
// "mime/multipart"
// "os"
// "path/filepath"
// "time"
// "forge.cadoles.com/arcad/edge/pkg/app"
// "forge.cadoles.com/arcad/edge/pkg/bus"
// "github.com/dop251/goja"
// "github.com/genjidb/genji"
// "github.com/genjidb/genji/database"
// "github.com/genjidb/genji/document"
// "github.com/google/uuid"
// "github.com/pkg/errors"
// "github.com/spf13/afero"
// "gitlab.com/wpetit/goweb/logger"
// )
// const (
// fileKeyID = "id"
// collectionFiles = "files"
// )
// type FileEntry struct {
// ID string
// Filename string
// Size int64
// ContentType string
// CreatedAt string
// Metadata map[string]interface{}
// }
// type FileModule struct {
// appID app.ID
// backend *app.Backend
// bus bus.Bus
// db *AppDatabaseMixin
// dataDir string
// fs afero.Fs
// }
// func (m *FileModule) Name() string {
// return "file"
// }
// func (m *FileModule) Export(export *goja.Object) {
// // if err := export.Set("ls", m.ls); err != nil {
// // panic(errors.Wrap(err, "could not set 'save' function"))
// // }
// }
// func (m *FileModule) logAndPanic(msg string, err error) {
// err = errors.Wrap(err, msg)
// logger.Error(context.Background(), msg, logger.E(err))
// panic(errors.WithStack(err))
// }
// func (m *FileModule) handleMessages() {
// ctx := context.Background()
// ns := createAppMessageNamespace(m.appID)
// go func() {
// err := m.bus.Reply(ctx, ns, MessageTypeUploadRequest, func(msg bus.Message) (bus.Message, error) {
// uploadRequest, ok := msg.(*MessageUploadRequest)
// if !ok {
// return nil, errors.Wrapf(bus.ErrUnexpectedMessage, "expected message upload request, got '%s'", msg.MessageType())
// }
// res, err := m.handleUploadRequest(uploadRequest)
// if err != nil {
// logger.Error(ctx, "could not handle upload request", logger.E(errors.WithStack(err)))
// return nil, errors.WithStack(err)
// }
// logger.Debug(ctx, "upload request response", logger.F("response", res))
// return res, nil
// })
// if err != nil {
// panic(errors.WithStack(err))
// }
// }()
// err := m.bus.Reply(ctx, ns, MessageTypeDownloadRequest, func(msg bus.Message) (bus.Message, error) {
// downloadRequest, ok := msg.(*MessageDownloadRequest)
// if !ok {
// return nil, errors.Wrapf(bus.ErrUnexpectedMessage, "expected message download request, got '%s'", msg.MessageType())
// }
// res, err := m.handleDownloadRequest(downloadRequest)
// if err != nil {
// logger.Error(ctx, "could not handle download request", logger.E(errors.WithStack(err)))
// return nil, errors.WithStack(err)
// }
// return res, nil
// })
// if err != nil {
// panic(errors.WithStack(err))
// }
// }
// func (m *FileModule) handleUploadRequest(req *MessageUploadRequest) (*MessageUploadResponse, error) {
// fileInfo := map[string]interface{}{
// "filename": req.Header.Filename,
// "contentType": req.Header.Header.Get("Content-Type"),
// "size": req.Header.Size,
// "metadata": req.Metadata,
// }
// res := NewMessageUploadResponse(req.AppID, req.UserID, req.RequestID)
// fileID := uuid.New().String()
// result, err := m.backend.ExecFuncByName("onFileUpload", req.UserID, fileID, fileInfo)
// if err != nil {
// if errors.Is(err, app.ErrFuncDoesNotExist) {
// res.Allow = false
// return res, nil
// }
// return nil, errors.WithStack(err)
// }
// res.Allow = result.ToBoolean()
// if res.Allow {
// if err := m.saveFile(fileID, req.UserID, req.Header, req.File, req.Metadata); err != nil {
// return nil, errors.WithStack(err)
// }
// res.FileID = fileID
// }
// return res, nil
// }
// func (m *FileModule) saveFile(fileID string, header *multipart.FileHeader, file multipart.File, metadata map[string]interface{}) error {
// err := m.db.WithCollectionTx(collectionFiles, func(tx *genji.Tx) error {
// entry := &FileEntry{
// ID: fileID,
// Filename: header.Filename,
// Size: header.Size,
// ContentType: header.Header.Get("Content-Type"),
// CreatedAt: time.Now().UTC().String(),
// Metadata: metadata,
// }
// insertQuery := fmt.Sprintf("INSERT INTO `%s` VALUES ?", collectionFiles)
// if err := tx.Exec(insertQuery, &entry); err != nil {
// return errors.WithStack(err)
// }
// fileDir := m.getFileDir(fileID)
// if err := m.fs.MkdirAll(fileDir, 0o755); err != nil {
// return errors.WithStack(err)
// }
// filePath := filepath.Join(fileDir, fileID)
// newFile, err := m.fs.Create(filePath)
// if err != nil {
// return errors.WithStack(err)
// }
// defer newFile.Close()
// if _, err := io.Copy(newFile, file); err != nil {
// return errors.WithStack(err)
// }
// return nil
// })
// if err != nil {
// return errors.WithStack(err)
// }
// return nil
// }
// func (m *FileModule) handleDownloadRequest(req *MessageDownloadRequest) (*MessageDownloadResponse, error) {
// res := NewMessageDownloadResponse(req.AppID, req.UserID, req.RequestID)
// result, err := m.backend.ExecFuncByName("onFileDownload", req.UserID, req.FileID)
// if err != nil {
// if errors.Is(err, app.ErrFuncDoesNotExist) {
// res.Allow = false
// return res, nil
// }
// return nil, errors.WithStack(err)
// }
// res.Allow = result.ToBoolean()
// file, fileEntry, err := m.openFile(req.FileID)
// if err != nil && !os.IsNotExist(errors.Cause(err)) {
// return nil, errors.WithStack(err)
// }
// if file != nil {
// res.File = file
// }
// if fileEntry != nil {
// res.Filename = fileEntry.Filename
// res.ContentType = fileEntry.ContentType
// res.Size = fileEntry.Size
// }
// return res, nil
// }
// func (m *FileModule) openFile(fileID string) (afero.File, *FileEntry, error) {
// var (
// fileEntry *FileEntry
// file afero.File
// )
// err := m.db.WithCollectionTx(collectionFiles, func(tx *genji.Tx) error {
// selectQuery := fmt.Sprintf("SELECT * FROM `%s` WHERE id = ?", collectionFiles)
// doc, err := tx.QueryDocument(selectQuery, fileID)
// if err != nil {
// if errors.Is(err, database.ErrDocumentNotFound) {
// return nil
// }
// return errors.WithStack(err)
// }
// fileEntry = &FileEntry{}
// if err := document.StructScan(doc, fileEntry); err != nil {
// return errors.WithStack(err)
// }
// fileDir := m.getFileDir(fileID)
// filePath := filepath.Join(fileDir, fileID)
// file, err = m.fs.Open(filePath)
// if err != nil {
// file = nil
// return errors.WithStack(err)
// }
// return nil
// })
// if err != nil {
// return nil, nil, errors.WithStack(err)
// }
// return file, fileEntry, nil
// }
// func (m *FileModule) getFileDir(fileID string) string {
// return filepath.Join(m.dataDir, string(m.appID), "files", fileID[0:2], fileID[2:4], fileID[4:6])
// }
// func FileModuleFactory(dataDir string, bus bus.Bus) app.BackendModuleFactory {
// return func(appID app.ID, backend *app.Backend) app.BackendModule {
// var fs afero.Fs
// if dataDir == inMemory {
// fs = afero.NewMemMapFs()
// } else {
// fs = afero.NewOsFs()
// }
// mod := &FileModule{
// dataDir: dataDir,
// appID: appID,
// bus: bus,
// backend: backend,
// db: NewAppDatabaseMixin(dataDir, "file.db", appID),
// fs: fs,
// }
// go mod.handleMessages()
// return mod
// }
// }

127
pkg/module/file_message.go Normal file
View File

@ -0,0 +1,127 @@
package module
// import (
// "io"
// "mime/multipart"
// "forge.cadoles.com/arcad/edge/pkg/app"
// "forge.cadoles.com/arcad/edge/pkg/bus"
// "github.com/google/uuid"
// )
// const (
// MessageTypeUploadRequest bus.MessageType = "uploadRequest"
// MessageTypeUploadResponse bus.MessageType = "uploadResponse"
// MessageTypeDownloadRequest bus.MessageType = "downloadRequest"
// MessageTypeDownloadResponse bus.MessageType = "downloadResponse"
// )
// type MessageUploadRequest struct {
// AppID app.ID
// RequestID string
// Header *multipart.FileHeader
// File multipart.File
// Metadata map[string]interface{}
// ns bus.MessageNamespace
// }
// func (m *MessageUploadRequest) MessageNamespace() bus.MessageNamespace {
// return m.ns
// }
// func (m *MessageUploadRequest) MessageType() bus.MessageType {
// return MessageTypeUploadRequest
// }
// func NewMessageUploadRequest(appID app.ID, header *multipart.FileHeader, file multipart.File, metadata map[string]interface{}) *MessageUploadRequest {
// return &MessageUploadRequest{
// AppID: appID,
// RequestID: uuid.New().String(),
// Header: header,
// File: file,
// Metadata: metadata,
// ns: AppMessageNamespace(appID),
// }
// }
// type MessageUploadResponse struct {
// AppID app.ID
// RequestID string
// FileID string
// Allow bool
// ns bus.MessageNamespace
// }
// func (m *MessageUploadResponse) MessageNamespace() bus.MessageNamespace {
// return m.ns
// }
// func (m *MessageUploadResponse) MessageType() bus.MessageType {
// return MessageTypeUploadResponse
// }
// func NewMessageUploadResponse(appID app.ID, requestID string) *MessageUploadResponse {
// return &MessageUploadResponse{
// AppID: appID,
// RequestID: requestID,
// ns: AppMessageNamespace(appID),
// }
// }
// type MessageDownloadRequest struct {
// AppID app.ID
// RequestID string
// FileID string
// ns bus.MessageNamespace
// }
// func (m *MessageDownloadRequest) MessageNamespace() bus.MessageNamespace {
// return m.ns
// }
// func (m *MessageDownloadRequest) MessageType() bus.MessageType {
// return MessageTypeDownloadRequest
// }
// func NewMessageDownloadRequest(appID app.ID, fileID string) *MessageDownloadRequest {
// return &MessageDownloadRequest{
// AppID: appID,
// RequestID: uuid.New().String(),
// FileID: fileID,
// ns: AppMessageNamespace(appID),
// }
// }
// type MessageDownloadResponse struct {
// AppID app.ID
// RequestID string
// Allow bool
// File io.ReadCloser
// ContentType string
// Filename string
// Size int64
// ns bus.MessageNamespace
// }
// func (m *MessageDownloadResponse) MessageNamespace() bus.MessageNamespace {
// return m.ns
// }
// func (e *MessageDownloadResponse) MessageType() bus.MessageType {
// return MessageTypeDownloadResponse
// }
// func NewMessageDownloadResponse(appID app.ID, requestID string) *MessageDownloadResponse {
// return &MessageDownloadResponse{
// AppID: appID,
// RequestID: requestID,
// ns: AppMessageNamespace(appID),
// }
// }

191
pkg/module/lifecycle.go Normal file
View File

@ -0,0 +1,191 @@
package module
import (
"context"
"forge.cadoles.com/arcad/edge/pkg/app"
"forge.cadoles.com/arcad/edge/pkg/bus"
"github.com/dop251/goja"
"github.com/pkg/errors"
"gitlab.com/wpetit/goweb/logger"
)
type LifecycleModule struct {
backend *app.Backend
bus bus.Bus
}
func (m *LifecycleModule) Name() string {
return "lifecycle"
}
func (m *LifecycleModule) Export(export *goja.Object) {
}
func (m *LifecycleModule) OnInit() error {
if _, err := m.backend.ExecFuncByName("onInit"); err != nil {
if errors.Is(err, app.ErrFuncDoesNotExist) {
logger.Warn(context.Background(), "could not find onInit() function", logger.E(errors.WithStack(err)))
return errors.WithStack(err)
}
}
return nil
}
func (m *LifecycleModule) handleMessages() {
ctx := context.Background()
logger.Debug(
ctx,
"subscribing to bus messages",
)
userConnectedMessages, err := m.bus.Subscribe(ctx, MessageNamespaceUserConnected)
if err != nil {
panic(errors.WithStack(err))
}
userDisconnectedMessages, err := m.bus.Subscribe(ctx, MessageNamespaceUserDisconnected)
if err != nil {
panic(errors.WithStack(err))
}
frontendMessageMessages, err := m.bus.Subscribe(ctx, MessageNamespaceFrontend)
if err != nil {
panic(errors.WithStack(err))
}
defer func() {
logger.Debug(
ctx,
"unsubscribing from bus messages",
)
m.bus.Unsubscribe(ctx, MessageNamespaceFrontend, frontendMessageMessages)
m.bus.Unsubscribe(ctx, MessageNamespaceUserDisconnected, userDisconnectedMessages)
m.bus.Unsubscribe(ctx, MessageNamespaceUserConnected, userConnectedMessages)
}()
for {
logger.Debug(
ctx,
"waiting for next message",
)
select {
case <-ctx.Done():
logger.Debug(
ctx,
"context done",
)
return
case msg := <-userConnectedMessages:
userConnected, ok := msg.(*UserConnectedMessage)
if !ok {
logger.Error(
ctx,
"unexpected message type",
logger.F("message", msg),
)
continue
}
logger.Debug(
ctx,
"received user connected message",
logger.F("message", userConnected),
)
if _, err := m.backend.ExecFuncByName("onUserConnect"); err != nil {
if errors.Is(err, app.ErrFuncDoesNotExist) {
continue
}
logger.Error(
ctx,
"on user connected error",
logger.E(err),
)
}
case msg := <-userDisconnectedMessages:
userDisconnected, ok := msg.(*UserDisconnectedMessage)
if !ok {
logger.Error(
ctx,
"unexpected message type",
logger.F("message", msg),
)
continue
}
logger.Debug(
ctx,
"received user disconnected message",
logger.F("message", userDisconnected),
)
if _, err := m.backend.ExecFuncByName("onUserDisconnect"); err != nil {
if errors.Is(err, app.ErrFuncDoesNotExist) {
continue
}
logger.Error(
ctx,
"on user disconnected error",
logger.E(err),
)
}
case msg := <-frontendMessageMessages:
frontendMessage, ok := msg.(*FrontendMessage)
if !ok {
logger.Error(
ctx,
"unexpected message type",
logger.F("message", msg),
)
continue
}
logger.Debug(
ctx,
"received frontend message",
logger.F("message", frontendMessage),
)
if _, err := m.backend.ExecFuncByName("onUserMessage", frontendMessage.Data); err != nil {
if errors.Is(err, app.ErrFuncDoesNotExist) {
continue
}
logger.Error(
ctx,
"on user message error",
logger.E(err),
)
}
}
}
}
func LifecycleModuleFactory(bus bus.Bus) app.BackendModuleFactory {
return func(backend *app.Backend) app.BackendModule {
module := &LifecycleModule{
backend: backend,
bus: bus,
}
go module.handleMessages()
return module
}
}
var _ app.InitializableModule = &LifecycleModule{}

View File

@ -0,0 +1,56 @@
package module
import (
"forge.cadoles.com/arcad/edge/pkg/bus"
)
const (
MessageNamespaceFrontend bus.MessageNamespace = "frontend"
MessageNamespaceBackend bus.MessageNamespace = "backend"
MessageNamespaceUserConnected bus.MessageNamespace = "userConnected"
MessageNamespaceUserDisconnected bus.MessageNamespace = "userDisconnected"
)
type UserConnectedMessage struct{}
func (m *UserConnectedMessage) MessageNamespace() bus.MessageNamespace {
return MessageNamespaceUserConnected
}
func NewMessageUserConnected() *UserConnectedMessage {
return &UserConnectedMessage{}
}
type UserDisconnectedMessage struct{}
func (m *UserDisconnectedMessage) MessageNamespace() bus.MessageNamespace {
return MessageNamespaceUserDisconnected
}
func NewMessageUserDisconnected() *UserDisconnectedMessage {
return &UserDisconnectedMessage{}
}
type BackendMessage struct {
Data interface{}
}
func (m *BackendMessage) MessageNamespace() bus.MessageNamespace {
return MessageNamespaceBackend
}
func NewBackendMessage(data interface{}) *BackendMessage {
return &BackendMessage{data}
}
type FrontendMessage struct {
Data map[string]interface{}
}
func (m *FrontendMessage) MessageNamespace() bus.MessageNamespace {
return MessageNamespaceFrontend
}
func NewFrontendMessage(data map[string]interface{}) *FrontendMessage {
return &FrontendMessage{data}
}

68
pkg/module/net.go Normal file
View File

@ -0,0 +1,68 @@
package module
import (
"context"
"forge.cadoles.com/arcad/edge/pkg/app"
"forge.cadoles.com/arcad/edge/pkg/bus"
"github.com/dop251/goja"
"github.com/pkg/errors"
)
type NetModule struct {
backend *app.Backend
bus bus.Bus
}
func (m *NetModule) Name() string {
return "net"
}
func (m *NetModule) Export(export *goja.Object) {
if err := export.Set("broadcast", m.broadcast); err != nil {
panic(errors.Wrap(err, "could not set 'broadcast' function"))
}
if err := export.Set("send", m.send); err != nil {
panic(errors.Wrap(err, "could not set 'send' function"))
}
}
func (m *NetModule) broadcast(call goja.FunctionCall) goja.Value {
if len(call.Arguments) < 1 {
panic(m.backend.ToValue("invalid number of argument"))
}
data := call.Arguments[0].Export()
msg := NewBackendMessage(data)
if err := m.bus.Publish(context.Background(), msg); err != nil {
panic(errors.WithStack(err))
}
return nil
}
func (m *NetModule) send(call goja.FunctionCall) goja.Value {
if len(call.Arguments) < 1 {
panic(m.backend.ToValue("invalid number of argument"))
}
data := call.Arguments[0].Export()
msg := NewBackendMessage(data)
if err := m.bus.Publish(context.Background(), msg); err != nil {
panic(errors.WithStack(err))
}
return nil
}
func NetModuleFactory(bus bus.Bus) app.BackendModuleFactory {
return func(backend *app.Backend) app.BackendModule {
return &NetModule{
backend: backend,
bus: bus,
}
}
}

238
pkg/module/rpc.go Normal file
View File

@ -0,0 +1,238 @@
package module
import (
"context"
"fmt"
"sync"
"forge.cadoles.com/arcad/edge/pkg/app"
"forge.cadoles.com/arcad/edge/pkg/bus"
"github.com/dop251/goja"
"github.com/pkg/errors"
"gitlab.com/wpetit/goweb/logger"
)
type RPCRequest struct {
Method string
Params interface{}
ID interface{}
}
type RPCError struct {
Code int `json:"code"`
Message string `json:"message"`
Data interface{} `json:"data"`
}
type RPCResponse struct {
Result interface{}
Error *RPCError
ID interface{}
}
type RPCModule struct {
backend *app.Backend
bus bus.Bus
callbacks sync.Map
}
func (m *RPCModule) Name() string {
return "rpc"
}
func (m *RPCModule) Export(export *goja.Object) {
if err := export.Set("register", m.register); err != nil {
panic(errors.Wrap(err, "could not set 'register' function"))
}
if err := export.Set("unregister", m.unregister); err != nil {
panic(errors.Wrap(err, "could not set 'unregister' function"))
}
}
func (m *RPCModule) register(call goja.FunctionCall) goja.Value {
fnName := call.Argument(0).String()
if fnName == "" {
panic(errors.New("First argument must be a function name"))
}
ctx := context.Background()
logger.Debug(ctx, "registering method", logger.F("method", fnName))
m.callbacks.Store(fnName, nil)
return nil
}
func (m *RPCModule) unregister(call goja.FunctionCall) goja.Value {
fnName := call.Argument(0).String()
if fnName == "" {
panic(errors.New("First argument must be a function name"))
}
m.callbacks.Delete(fnName)
return nil
}
func (m *RPCModule) handleMessages() {
ctx := context.Background()
frontendMessages, err := m.bus.Subscribe(ctx, MessageNamespaceFrontend)
if err != nil {
panic(errors.WithStack(err))
}
defer func() {
m.bus.Unsubscribe(ctx, MessageNamespaceFrontend, frontendMessages)
}()
sendRes := func(ctx context.Context, req *RPCRequest, result goja.Value) {
res := &RPCResponse{
ID: req.ID,
Result: result.Export(),
}
logger.Debug(ctx, "sending rpc response", logger.F("response", res))
if err := m.sendResponse(ctx, res); err != nil {
logger.Error(
ctx, "could not send response",
logger.E(errors.WithStack(err)),
logger.F("response", res),
logger.F("request", req),
)
}
}
for msg := range frontendMessages {
frontendMessage, ok := msg.(*FrontendMessage)
if !ok {
logger.Warn(ctx, "unexpected bus message", logger.F("message", msg))
continue
}
ok, req := m.isRPCRequest(frontendMessage)
if !ok {
continue
}
logger.Debug(ctx, "received rpc request", logger.F("request", req))
if _, exists := m.callbacks.Load(req.Method); !exists {
logger.Debug(ctx, "method not found", logger.F("req", req))
if err := m.sendMethodNotFoundResponse(ctx, req); err != nil {
logger.Error(
ctx, "could not send method not found response",
logger.E(errors.WithStack(err)),
logger.F("request", req),
)
}
continue
}
result, err := m.backend.ExecFuncByName(req.Method, req.Params)
if err != nil {
if err := m.sendErrorResponse(ctx, req, err); err != nil {
logger.Error(
ctx, "could not send error response",
logger.E(errors.WithStack(err)),
logger.F("originalError", err),
logger.F("request", req),
)
}
continue
}
promise, ok := m.backend.IsPromise(result)
if ok {
go func(ctx context.Context, req *RPCRequest, promise *goja.Promise) {
result := m.backend.WaitForPromise(promise)
sendRes(ctx, req, result)
}(ctx, req, promise)
} else {
sendRes(ctx, req, result)
}
}
}
func (m *RPCModule) sendErrorResponse(ctx context.Context, req *RPCRequest, err error) error {
return m.sendResponse(ctx, &RPCResponse{
ID: req.ID,
Result: nil,
Error: &RPCError{
Code: -32603,
Message: err.Error(),
},
})
}
func (m *RPCModule) sendMethodNotFoundResponse(ctx context.Context, req *RPCRequest) error {
return m.sendResponse(ctx, &RPCResponse{
ID: req.ID,
Result: nil,
Error: &RPCError{
Code: -32601,
Message: fmt.Sprintf("method not found"),
},
})
}
func (m *RPCModule) sendResponse(ctx context.Context, res *RPCResponse) error {
msg := NewBackendMessage(map[string]interface{}{
"jsonrpc": "2.0",
"id": res.ID,
"error": res.Error,
"result": res.Result,
})
if err := m.bus.Publish(ctx, msg); err != nil {
return errors.WithStack(err)
}
return nil
}
func (m *RPCModule) isRPCRequest(msg *FrontendMessage) (bool, *RPCRequest) {
jsonRPC, exists := msg.Data["jsonrpc"]
if !exists || jsonRPC != "2.0" {
return false, nil
}
rawMethod, exists := msg.Data["method"]
if !exists {
return false, nil
}
method, ok := rawMethod.(string)
if !ok {
return false, nil
}
id := msg.Data["id"]
params := msg.Data["params"]
return true, &RPCRequest{
ID: id,
Method: method,
Params: params,
}
}
func RPCModuleFactory(bus bus.Bus) app.BackendModuleFactory {
return func(backend *app.Backend) app.BackendModule {
mod := &RPCModule{
backend: backend,
bus: bus,
}
go mod.handleMessages()
return mod
}
}

200
pkg/module/store.go Normal file
View File

@ -0,0 +1,200 @@
package module
import (
"fmt"
"forge.cadoles.com/arcad/edge/pkg/app"
"forge.cadoles.com/arcad/edge/pkg/storage"
"forge.cadoles.com/arcad/edge/pkg/storage/filter"
"github.com/davecgh/go-spew/spew"
"github.com/dop251/goja"
"github.com/mitchellh/mapstructure"
"github.com/pkg/errors"
)
type StoreModule struct {
backend *app.Backend
store storage.DocumentStore
}
func (m *StoreModule) Name() string {
return "store"
}
func (m *StoreModule) Export(export *goja.Object) {
if err := export.Set("upsert", m.upsert); err != nil {
panic(errors.Wrap(err, "could not set 'upsert' function"))
}
if err := export.Set("get", m.get); err != nil {
panic(errors.Wrap(err, "could not set 'get' function"))
}
if err := export.Set("query", m.query); err != nil {
panic(errors.Wrap(err, "could not set 'query' function"))
}
if err := export.Set("delete", m.delete); err != nil {
panic(errors.Wrap(err, "could not set 'delete' function"))
}
}
func (m *StoreModule) upsert(call goja.FunctionCall, rt *goja.Runtime) goja.Value {
ctx := assertContext(call.Argument(0), rt)
collection := m.assertCollection(call.Argument(1), rt)
document := m.assertDocument(call.Argument(2), rt)
document, err := m.store.Upsert(ctx, collection, document)
if err != nil {
panic(errors.Wrapf(err, "error while upserting document in collection '%s'", collection))
}
spew.Dump(document)
return rt.ToValue(map[string]interface{}(document))
}
func (m *StoreModule) get(call goja.FunctionCall, rt *goja.Runtime) goja.Value {
ctx := assertContext(call.Argument(0), rt)
collection := m.assertCollection(call.Argument(1), rt)
documentID := m.assertDocumentID(call.Argument(2), rt)
document, err := m.store.Get(ctx, collection, documentID)
if err != nil {
if errors.Is(err, storage.ErrDocumentNotFound) {
return nil
}
panic(errors.Wrapf(err, "error while getting document '%s' in collection '%s'", documentID, collection))
}
return rt.ToValue(map[string]interface{}(document))
}
type queryOptions struct {
Limit *int `mapstructure:"limit"`
Offset *int `mapstructure:"offset"`
OrderBy *string `mapstructure:"orderBy"`
OrderDirection *string `mapstructure:"orderDirection"`
}
func (m *StoreModule) query(call goja.FunctionCall, rt *goja.Runtime) goja.Value {
ctx := assertContext(call.Argument(0), rt)
collection := m.assertCollection(call.Argument(1), rt)
filter := m.assertFilter(call.Argument(2), rt)
queryOptions := m.assertQueryOptions(call.Argument(3), rt)
queryOptionsFuncs := make([]storage.QueryOptionFunc, 0)
if queryOptions.Limit != nil {
queryOptionsFuncs = append(queryOptionsFuncs, storage.WithLimit(*queryOptions.Limit))
}
if queryOptions.OrderBy != nil {
queryOptionsFuncs = append(queryOptionsFuncs, storage.WithOrderBy(*queryOptions.OrderBy))
}
if queryOptions.Offset != nil {
queryOptionsFuncs = append(queryOptionsFuncs, storage.WithOffset(*queryOptions.Limit))
}
if queryOptions.OrderDirection != nil {
queryOptionsFuncs = append(queryOptionsFuncs, storage.WithOrderDirection(
storage.OrderDirection(*queryOptions.OrderDirection),
))
}
documents, err := m.store.Query(ctx, collection, filter, queryOptionsFuncs...)
if err != nil {
panic(errors.Wrapf(err, "error while querying documents in collection '%s'", collection))
}
rawDocuments := make([]map[string]interface{}, len(documents))
for idx, doc := range documents {
rawDocuments[idx] = map[string]interface{}(doc)
}
return rt.ToValue(rawDocuments)
}
func (m *StoreModule) delete(call goja.FunctionCall, rt *goja.Runtime) goja.Value {
ctx := assertContext(call.Argument(0), rt)
collection := m.assertCollection(call.Argument(1), rt)
documentID := m.assertDocumentID(call.Argument(2), rt)
if err := m.store.Delete(ctx, collection, documentID); err != nil {
panic(errors.Wrapf(err, "error while deleting document '%s' in collection '%s'", documentID, collection))
}
return nil
}
func (m *StoreModule) assertCollection(value goja.Value, rt *goja.Runtime) string {
collection, ok := value.Export().(string)
if !ok {
panic(rt.NewTypeError(fmt.Sprintf("collection must be a string, got '%T'", value.Export())))
}
return collection
}
func (m *StoreModule) assertFilter(value goja.Value, rt *goja.Runtime) *filter.Filter {
rawFilter, ok := value.Export().(map[string]interface{})
if !ok {
panic(rt.NewTypeError(fmt.Sprintf("filter must be an object, got '%T'", value.Export())))
}
filter, err := filter.NewFrom(rawFilter)
if err != nil {
panic(errors.Wrap(err, "could not convert object to filter"))
}
return filter
}
func (m *StoreModule) assertDocumentID(value goja.Value, rt *goja.Runtime) storage.DocumentID {
documentID, ok := value.Export().(storage.DocumentID)
if !ok {
rawDocumentID, ok := value.Export().(string)
if !ok {
panic(rt.NewTypeError(fmt.Sprintf("document id must be a documentid or a string, got '%T'", value.Export())))
}
documentID = storage.DocumentID(rawDocumentID)
}
return documentID
}
func (m *StoreModule) assertQueryOptions(value goja.Value, rt *goja.Runtime) *queryOptions {
rawQueryOptions, ok := value.Export().(map[string]interface{})
if !ok {
panic(rt.NewTypeError(fmt.Sprintf("query options must be an object, got '%T'", value.Export())))
}
queryOptions := &queryOptions{}
if err := mapstructure.Decode(rawQueryOptions, queryOptions); err != nil {
panic(errors.Wrap(err, "could not convert object to query options"))
}
return queryOptions
}
func (m *StoreModule) assertDocument(value goja.Value, rt *goja.Runtime) storage.Document {
document, ok := value.Export().(map[string]interface{})
if !ok {
panic(rt.NewTypeError("document must be an object"))
}
return document
}
func StoreModuleFactory(store storage.DocumentStore) app.BackendModuleFactory {
return func(backend *app.Backend) app.BackendModule {
return &StoreModule{
backend: backend,
store: store,
}
}
}

41
pkg/module/store_test.go Normal file
View File

@ -0,0 +1,41 @@
package module
import (
"io/ioutil"
"testing"
"forge.cadoles.com/arcad/edge/pkg/app"
"forge.cadoles.com/arcad/edge/pkg/storage/sqlite"
"github.com/pkg/errors"
"gitlab.com/wpetit/goweb/logger"
)
func TestStoreModule(t *testing.T) {
logger.SetLevel(logger.LevelDebug)
store := sqlite.NewDocumentStore(":memory:")
backend := app.NewBackend(
ContextModuleFactory(),
ConsoleModuleFactory(),
StoreModuleFactory(store),
)
data, err := ioutil.ReadFile("testdata/store.js")
if err != nil {
t.Fatalf("%+v", errors.WithStack(err))
}
if err := backend.Load("testdata/store.js", string(data)); err != nil {
t.Fatalf("%+v", errors.WithStack(err))
}
if err := backend.Start(); err != nil {
t.Fatalf("%+v", errors.WithStack(err))
}
if _, err := backend.ExecFuncByName("testStore"); err != nil {
t.Fatalf("%+v", errors.WithStack(err))
}
backend.Stop()
}

32
pkg/module/testdata/store.js vendored Normal file
View File

@ -0,0 +1,32 @@
var ctx = context.get();
function testStore() {
var obj = store.upsert(ctx, "test", {"foo": "bar"});
var obj1 = store.get(ctx, "test", obj._id);
console.log(obj, obj1);
for (var key in obj) {
if (!obj.hasOwnProperty(key)) {
continue;
}
if (obj[key].toString() !== obj1[key].toString()) {
throw new Error("obj['"+key+"'] !== obj1['"+key+"']");
}
}
var results = store.query(ctx, "test", { "eq": {"foo": "bar"} }, {"orderBy": "foo", "limit": 10, "skip": 0});
if (!results || results.length !== 1) {
throw new Error("results should contains 1 item");
}
store.delete(ctx, "test", obj._id);
var obj2 = store.get(ctx, "test", obj._id);
if (obj2 != null) {
throw new Error("obj2 should be null");
}
}

59
pkg/module/user.go Normal file
View File

@ -0,0 +1,59 @@
package module
// import (
// "context"
// "github.com/dop251/goja"
// "github.com/pkg/errors"
// "forge.cadoles.com/arcad/edge/pkg/app"
// "forge.cadoles.com/arcad/edge/pkg/repository"
// "gitlab.com/wpetit/goweb/logger"
// )
// type UserModule struct {
// appID app.ID
// repo repository.UserRepository
// backend *app.Backend
// ctx context.Context
// }
// func (m *UserModule) Name() string {
// return "user"
// }
// func (m *UserModule) Export(export *goja.Object) {
// if err := export.Set("getUserById", m.getUserByID); err != nil {
// panic(errors.Wrap(err, "could not set 'getUserById' function"))
// }
// }
// func (m *UserModule) getUserByID(call goja.FunctionCall) goja.Value {
// if len(call.Arguments) != 1 {
// panic(m.backend.ToValue("invalid number of arguments"))
// }
// userID := repository.UserID(call.Arguments[0].String())
// user, err := m.repo.Get(userID)
// if err != nil {
// err = errors.Wrapf(err, "could not find user '%s'", userID)
// logger.Error(m.ctx, "could not find user", logger.E(err), logger.F("userID", userID))
// panic(m.backend.ToValue(err))
// }
// return m.backend.ToValue(user)
// }
// func UserModuleFactory(repo repository.UserRepository) app.BackendModuleFactory {
// return func(appID app.ID, backend *app.Backend) app.BackendModule {
// return &UserModule{
// appID: appID,
// repo: repo,
// backend: backend,
// ctx: logger.With(
// context.Background(),
// logger.F("appID", appID),
// ),
// }
// }
// }

70
pkg/module/user_test.go Normal file
View File

@ -0,0 +1,70 @@
package module
// import (
// "errors"
// "io/ioutil"
// "testing"
// "gitlab.com/arcadbox/arcad/internal/app"
// "gitlab.com/arcadbox/arcad/internal/repository"
// )
// func TestUserModuleGetUserByID(t *testing.T) {
// repo := &fakeUserRepository{}
// appID := app.ID("test")
// backend := app.NewBackend(appID,
// ConsoleModuleFactory(),
// UserModuleFactory(repo),
// )
// data, err := ioutil.ReadFile("testdata/user_getbyid.js")
// if err != nil {
// t.Fatal(err)
// }
// if err := backend.Load(string(data)); err != nil {
// t.Fatal(err)
// }
// backend.Start()
// defer backend.Stop()
// if err := backend.OnInit(); err != nil {
// t.Error(err)
// }
// }
// type fakeUserRepository struct{}
// func (r *fakeUserRepository) Create() (*repository.User, error) {
// return nil, errors.New("not implemented")
// }
// func (r *fakeUserRepository) Save(user *repository.User) error {
// return errors.New("not implemented")
// }
// func (r *fakeUserRepository) Get(userID repository.UserID) (*repository.User, error) {
// if userID == "0" {
// return &repository.User{}, nil
// }
// return nil, errors.New("not implemented")
// }
// func (r *fakeUserRepository) Delete(userID repository.UserID) error {
// return errors.New("not implemented")
// }
// func (r *fakeUserRepository) Touch(userID repository.UserID, rawUserAgent string) error {
// return errors.New("not implemented")
// }
// func (r *fakeUserRepository) List() ([]*repository.User, error) {
// return nil, errors.New("not implemented")
// }
// func (r *fakeUserRepository) ListByID(userIDs ...repository.UserID) ([]*repository.User, error) {
// return nil, errors.New("not implemented")
// }

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

@ -0,0 +1,4081 @@
var Arcad = (() => {
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 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("message", this._handleRPCResponse);
}
connect() {
return new Promise((resolve, reject) => {
const url = `//${document.location.host}/sock`;
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();
}
_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) {
console.log(evt);
const { jsonrpc, id, error, result } = evt.detail;
if (jsonrpc !== "2.0" || id === void 0)
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("message", 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(file, metadata) {
return new Promise((resolve, reject) => {
const formData = new FormData();
formData.set("file", file);
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.fileId);
};
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", `/api/v1/upload`);
xhr.send(formData);
resolve(result);
});
}
fileUrl(fileId) {
return `/api/v1/download/${fileId}`;
}
};
// pkg/sdk/client/src/index.ts
var src_default = new Client();
return __toCommonJS(src_exports);
})();
Arcad=Arcad.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

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

@ -0,0 +1,4112 @@
var Arcad = (() => {
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/app/sdk/client/src/index.js
var src_exports = {};
__export(src_exports, {
default: () => src_default
});
// pkg/app/sdk/client/src/message.js
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) {
switch (raw.t) {
case TypeInit:
return new InitMessage(raw.p.gid);
default:
return new Message(raw.t, raw.p);
}
}
// pkg/app/sdk/client/src/message/init.js
var TypeInit = "init";
var InitMessage = class extends Message {
constructor(appId) {
super(TypeInit, { id: appId });
}
};
// pkg/app/sdk/client/src/message/event.js
var TypeEvent = "event";
var EventMessage = class extends Message {
constructor(data) {
super(TypeEvent, { d: data });
}
};
// pkg/app/sdk/client/src/event-target.js
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/app/sdk/client/src/rpc-error.js
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/app/sdk/client/src/client.js
var import_sockjs_client = __toESM(require_entry());
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._appId = null;
this.debug = false;
this.connect = this.connect.bind(this);
this.disconnect = this.disconnect.bind(this);
this.invoke = this.invoke.bind(this);
this.send = this.send.bind(this);
this.upload = this.upload.bind(this);
this.addEventListener("event", this._handleRPCResponse);
}
connect(appId) {
return new Promise((resolve, reject) => {
const url = `//${document.location.host}/sock`;
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._sendInit(appId);
this._appId = appId;
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();
}
_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;
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._reconnectionDelay * 0.25);
this._log("client will try to reconnect in %dms", this._reconnectionDelay);
setTimeout(this.connect.bind(this, this._appId), 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;
}
_sendInit(appId) {
this._appId = appId;
this._send(new InitMessage(appId));
}
_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 EventMessage(data);
this._sendOrQueue(msg);
}
invoke(method, params) {
return new Promise((resolve, reject) => {
const id = this._rpcID++;
const rpc = new EventMessage({
jsonrpc: "2.0",
id,
method,
params
});
this._sendOrQueue(rpc);
this._pendingRPC[id.toString()] = { resolve, reject };
});
}
isConnected() {
return this._conn !== null;
}
upload(file, metadata) {
return new Promise((resolve, reject) => {
const appId = this._appId;
if (!appId)
reject(new Error("Not connected"));
const formData = new FormData();
formData.set("file", file);
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.fileId);
};
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", `/apps/${this._appId}/upload`);
xhr.send(formData);
resolve(result);
});
}
fileUrl(fileId) {
const appId = this._appId;
if (!appId)
throw new Error("Not connected");
return `/apps/${appId}/download/${fileId}`;
}
};
// pkg/app/sdk/client/src/index.js
var src_default = new Client();
return __toCommonJS(src_exports);
})();
//# sourceMappingURL=sdk.js.map

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

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,255 @@
import { EventTarget } from "./event-target";
import { messageFrom,Message, TypeMessage } from "./message";
import { RPCError } from "./rpc-error";
import SockJS from 'sockjs-client';
const EventTypeMessage = "message";
export class Client extends EventTarget {
_conn: any
_rpcID: number
_pendingRPC: {}
_queue: Message[]
_reconnectionDelay: number
_autoReconnect: boolean
debug: boolean
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("message", this._handleRPCResponse);
}
connect() {
return new Promise((resolve, reject) => {
const url = `//${document.location.host}/sock`;
this._log("opening connection to", url);
const conn: any = new SockJS(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();
}
_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) {
console.log(evt);
const { jsonrpc, id, error, result } = evt.detail;
if (jsonrpc !== '2.0' || id === undefined) return;
// Prevent additional handlers to catch this event
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("message", 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(file, metadata) {
return new Promise((resolve, reject) => {
const formData = new FormData();
formData.set("file", file);
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((resolve, reject) => {
xhr.onload = () => {
let data;
try {
data = JSON.parse(xhr.responseText);
} catch(err) {
reject(err);
return;
}
resolve(data.fileId);
};
xhr.onerror = reject;
xhr.onabort = reject;
});
}
};
xhr.upload.onprogress = evt => {
if (typeof result.onProgress !== 'function') return;
(result as any).onProgress(evt.loaded, evt.total);
};
xhr.onabort = reject;
xhr.onerror = reject;
xhr.open('POST', `/api/v1/upload`);
xhr.send(formData);
resolve(result);
});
}
fileUrl(fileId) {
return `/api/v1/download/${fileId}`;
}
}

View File

@ -0,0 +1,41 @@
export class EventTarget {
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;
};
}

View File

@ -0,0 +1,3 @@
import { Client } from './client.js';
export default new Client();

View File

@ -0,0 +1,32 @@
export const TypeMessage = "message"
export class Message {
_type: string
_payload: any
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
};
}
}
export function messageFrom(raw) {
return new Message(raw.t, raw.p);
}

View File

@ -0,0 +1,11 @@
export class RPCError extends Error {
code: string
data: any
constructor(code, message, data) {
super(message);
this.code = code;
this.data = data;
if((Error as any).captureStackTrace) (Error as any).captureStackTrace(this, RPCError);
}
}

View File

@ -0,0 +1,3 @@
import SockJS from 'sockjs-client';
window.SockJS = SockJS;

6
pkg/sdk/sdk.go Normal file
View File

@ -0,0 +1,6 @@
package sdk
import "embed"
//go:embed client/dist/*.js
var FS embed.FS

View File

@ -0,0 +1,69 @@
package storage
import (
"context"
"errors"
"time"
"forge.cadoles.com/arcad/edge/pkg/storage/filter"
"github.com/oklog/ulid/v2"
)
var ErrDocumentNotFound = errors.New("document not found")
type DocumentID string
const (
DocumentAttrID = "_id"
DocumentAttrCreatedAt = "_createdAt"
DocumentAttrUpdatedAt = "_updatedAt"
)
func NewDocumentID() DocumentID {
return DocumentID(ulid.Make().String())
}
type Document map[string]interface{}
func (d Document) ID() (DocumentID, bool) {
rawID, exists := d[DocumentAttrID]
if !exists {
return "", false
}
id, ok := rawID.(string)
if ok {
return "", false
}
return DocumentID(id), true
}
func (d Document) CreatedAt() (time.Time, bool) {
return d.timeAttr(DocumentAttrCreatedAt)
}
func (d Document) UpdatedAt() (time.Time, bool) {
return d.timeAttr(DocumentAttrUpdatedAt)
}
func (d Document) timeAttr(attr string) (time.Time, bool) {
rawTime, exists := d[attr]
if !exists {
return time.Time{}, false
}
t, ok := rawTime.(time.Time)
if ok {
return time.Time{}, false
}
return t, true
}
type DocumentStore interface {
Get(ctx context.Context, collection string, id DocumentID) (Document, error)
Query(ctx context.Context, collection string, filter *filter.Filter, funcs ...QueryOptionFunc) ([]Document, error)
Upsert(ctx context.Context, collection string, document Document) (Document, error)
Delete(ctx context.Context, collection string, id DocumentID) error
}

17
pkg/storage/filter/and.go Normal file
View File

@ -0,0 +1,17 @@
package filter
type AndOperator struct {
children []Operator
}
func (o *AndOperator) Token() Token {
return TokenAnd
}
func (o *AndOperator) Children() []Operator {
return o.children
}
func NewAndOperator(ops ...Operator) *AndOperator {
return &AndOperator{ops}
}

17
pkg/storage/filter/eq.go Normal file
View File

@ -0,0 +1,17 @@
package filter
type EqOperator struct {
fields map[string]interface{}
}
func (o *EqOperator) Token() Token {
return TokenEq
}
func (o *EqOperator) Fields() map[string]interface{} {
return o.fields
}
func NewEqOperator(fields map[string]interface{}) *EqOperator {
return &EqOperator{fields}
}

View File

@ -0,0 +1,13 @@
package filter
import "errors"
var (
ErrInvalidFieldOperator = errors.New("invalid field operator")
ErrInvalidAggregationOperator = errors.New("invalid aggregation operator")
ErrInvalidFieldMap = errors.New("invalid field map")
ErrUnknownOperator = errors.New("unknown operator")
ErrUnexpectedOperator = errors.New("unexpected operator")
ErrUnsupportedOperator = errors.New("unsupported operator")
ErrInvalidRoot = errors.New("invalid root")
)

View File

@ -0,0 +1,136 @@
package filter
import (
"github.com/pkg/errors"
)
type Filter struct {
root Operator
}
func (f *Filter) Root() Operator {
return f.root
}
func New(root Operator) *Filter {
return &Filter{root}
}
func NewFrom(raw map[string]interface{}) (*Filter, error) {
if len(raw) != 1 {
return nil, errors.WithStack(ErrInvalidRoot)
}
op, err := toFieldOperator(raw)
if err != nil {
return nil, err
}
return &Filter{op}, nil
}
func toFieldOperator(v interface{}) (Operator, error) {
vv, ok := v.(map[string]interface{})
if !ok {
return nil, errors.WithStack(ErrInvalidFieldOperator)
}
ops := make([]Operator, 0)
for rawToken, val := range vv {
var (
op Operator
err error
)
token := Token(rawToken)
switch {
case isAggregatorToken(token):
op, err = toAggregateOperator(token, val)
case isFieldToken(token):
fields, ok := val.(map[string]interface{})
if !ok {
return nil, errors.WithStack(ErrInvalidFieldMap)
}
switch token {
case TokenEq:
op = NewEqOperator(fields)
case TokenNeq:
op = NewNeqOperator(fields)
case TokenGt:
op = NewGtOperator(fields)
case TokenGte:
op = NewGteOperator(fields)
case TokenLt:
op = NewLtOperator(fields)
case TokenLte:
op = NewLteOperator(fields)
case TokenIn:
op = NewInOperator(fields)
case TokenLike:
op = NewLikeOperator(fields)
default:
return nil, errors.Wrapf(ErrUnknownOperator, "unknown operator field '%s'", token)
}
default:
return nil, errors.Wrapf(ErrUnknownOperator, "unknown operator field '%s'", token)
}
if err != nil {
return nil, err
}
ops = append(ops, op)
}
and := NewAndOperator(ops...)
return and, nil
}
func toAggregateOperator(token Token, v interface{}) (Operator, error) {
vv, ok := v.([]interface{})
if !ok {
return nil, errors.WithStack(ErrInvalidAggregationOperator)
}
ops := make([]Operator, 0)
for _, c := range vv {
op, err := toFieldOperator(c)
if err != nil {
return nil, err
}
ops = append(ops, op)
}
var aggregator Operator
switch token {
case TokenAnd:
aggregator = NewAndOperator(ops...)
case TokenOr:
aggregator = NewOrOperator(ops...)
case TokenNot:
aggregator = NewNotOperator(ops...)
}
return aggregator, nil
}
func isAggregatorToken(token Token) bool {
return token == TokenAnd || token == TokenOr || token == TokenNot
}
func isFieldToken(token Token) bool {
return token == TokenEq ||
token == TokenGt || token == TokenGte ||
token == TokenLt || token == TokenLte ||
token == TokenNeq || token == TokenIn ||
token == TokenLike
}

17
pkg/storage/filter/gt.go Normal file
View File

@ -0,0 +1,17 @@
package filter
type GtOperator struct {
fields map[string]interface{}
}
func (o *GtOperator) Token() Token {
return TokenGt
}
func (o *GtOperator) Fields() map[string]interface{} {
return o.fields
}
func NewGtOperator(fields OperatorFields) *GtOperator {
return &GtOperator{fields}
}

17
pkg/storage/filter/gte.go Normal file
View File

@ -0,0 +1,17 @@
package filter
type GteOperator struct {
fields OperatorFields
}
func (o *GteOperator) Token() Token {
return TokenGte
}
func (o *GteOperator) Fields() map[string]interface{} {
return o.fields
}
func NewGteOperator(fields OperatorFields) *GteOperator {
return &GteOperator{fields}
}

17
pkg/storage/filter/in.go Normal file
View File

@ -0,0 +1,17 @@
package filter
type InOperator struct {
fields map[string]interface{}
}
func (o *InOperator) Token() Token {
return TokenIn
}
func (o *InOperator) Fields() map[string]interface{} {
return o.fields
}
func NewInOperator(fields OperatorFields) *InOperator {
return &InOperator{fields}
}

View File

@ -0,0 +1,17 @@
package filter
type LikeOperator struct {
fields map[string]interface{}
}
func (o *LikeOperator) Token() Token {
return TokenLike
}
func (o *LikeOperator) Fields() map[string]interface{} {
return o.fields
}
func NewLikeOperator(fields OperatorFields) *LikeOperator {
return &LikeOperator{fields}
}

17
pkg/storage/filter/lt.go Normal file
View File

@ -0,0 +1,17 @@
package filter
type LtOperator struct {
fields map[string]interface{}
}
func (o *LtOperator) Token() Token {
return TokenLt
}
func (o *LtOperator) Fields() map[string]interface{} {
return o.fields
}
func NewLtOperator(fields OperatorFields) *LtOperator {
return &LtOperator{fields}
}

17
pkg/storage/filter/lte.go Normal file
View File

@ -0,0 +1,17 @@
package filter
type LteOperator struct {
fields map[string]interface{}
}
func (o *LteOperator) Token() Token {
return TokenLte
}
func (o *LteOperator) Fields() map[string]interface{} {
return o.fields
}
func NewLteOperator(fields OperatorFields) *LteOperator {
return &LteOperator{fields}
}

17
pkg/storage/filter/neq.go Normal file
View File

@ -0,0 +1,17 @@
package filter
type NeqOperator struct {
fields map[string]interface{}
}
func (o *NeqOperator) Token() Token {
return TokenNeq
}
func (o *NeqOperator) Fields() map[string]interface{} {
return o.fields
}
func NewNeqOperator(fields map[string]interface{}) *NeqOperator {
return &NeqOperator{fields}
}

17
pkg/storage/filter/not.go Normal file
View File

@ -0,0 +1,17 @@
package filter
type NotOperator struct {
children []Operator
}
func (o *NotOperator) Token() Token {
return TokenOr
}
func (o *NotOperator) Children() []Operator {
return o.children
}
func NewNotOperator(ops ...Operator) *NotOperator {
return &NotOperator{ops}
}

View File

@ -0,0 +1,23 @@
package filter
type Token string
const (
TokenAnd Token = "and"
TokenOr Token = "or"
TokenNot Token = "not"
TokenEq Token = "eq"
TokenNeq Token = "neq"
TokenGt Token = "gt"
TokenGte Token = "gte"
TokenLt Token = "lt"
TokenLte Token = "lte"
TokenIn Token = "in"
TokenLike Token = "like"
)
type OperatorFields map[string]interface{}
type Operator interface {
Token() Token
}

17
pkg/storage/filter/or.go Normal file
View File

@ -0,0 +1,17 @@
package filter
type OrOperator struct {
children []Operator
}
func (o *OrOperator) Token() Token {
return TokenOr
}
func (o *OrOperator) Children() []Operator {
return o.children
}
func NewOrOperator(ops ...Operator) *OrOperator {
return &OrOperator{ops}
}

View File

@ -0,0 +1,87 @@
package sql
import (
"strings"
"forge.cadoles.com/arcad/edge/pkg/storage/filter"
"github.com/pkg/errors"
)
func aggregatorToSQL(operator string, opt *Option, children ...filter.Operator) (string, []interface{}, error) {
args := make([]interface{}, 0)
if len(children) == 0 {
return "", args, nil
}
var sb strings.Builder
if _, err := sb.WriteString("("); err != nil {
return "", nil, errors.WithStack(err)
}
for i, c := range children {
if i != 0 {
if _, err := sb.WriteString(" " + operator + " "); err != nil {
return "", nil, errors.WithStack(err)
}
}
cSQL, cArgs, err := toSQL(c, opt)
if err != nil {
return "", nil, errors.WithStack(err)
}
args = append(args, cArgs...)
if _, err := sb.WriteString(cSQL); err != nil {
return "", nil, errors.WithStack(err)
}
}
if _, err := sb.WriteString(")"); err != nil {
return "", nil, errors.WithStack(err)
}
result := sb.String()
if result == "()" {
return "", args, nil
}
return result, args, nil
}
func fieldsToSQL(operator string, invert bool, fields map[string]interface{}, option *Option) (string, []interface{}, error) {
var sb strings.Builder
args := make([]interface{}, 0)
i := 0
for k, v := range fields {
if i != 0 {
if _, err := sb.WriteString(" AND "); err != nil {
return "", nil, errors.WithStack(err)
}
}
var (
tr string
err error
)
tr, v, err = option.Transform(operator, invert, k, v, option)
if err != nil {
return "", nil, errors.WithStack(err)
}
if _, err := sb.WriteString(tr); err != nil {
return "", nil, errors.WithStack(err)
}
args = append(args, option.ValueTransform(v))
i++
}
return sb.String(), args, nil
}

View File

@ -0,0 +1,78 @@
package sql
import (
"strconv"
)
type (
PreparedParameterFunc func() string
KeyTransformFunc func(key string) string
ValueTransformFunc func(v interface{}) interface{}
TransformFunc func(operator string, invert bool, key string, value interface{}, option *Option) (string, interface{}, error)
)
type Option struct {
PreparedParameter PreparedParameterFunc
KeyTransform KeyTransformFunc
ValueTransform ValueTransformFunc
Transform TransformFunc
}
func DefaultOption() *Option {
opt := &Option{}
defaults := []OptionFunc{
WithPreparedParameter("$", 1),
WithNoOpKeyTransform(),
WithNoOpValueTransform(),
WithDefaultTransform(),
}
for _, fn := range defaults {
fn(opt)
}
return opt
}
type OptionFunc func(*Option)
func WithPreparedParameter(prefix string, index int) OptionFunc {
return func(opt *Option) {
opt.PreparedParameter = func() string {
param := prefix + strconv.FormatInt(int64(index), 10)
index++
return param
}
}
}
func WithKeyTransform(transform KeyTransformFunc) OptionFunc {
return func(opt *Option) {
opt.KeyTransform = transform
}
}
func WithNoOpKeyTransform() OptionFunc {
return WithKeyTransform(func(key string) string {
return key
})
}
func WithValueTransform(transform ValueTransformFunc) OptionFunc {
return func(opt *Option) {
opt.ValueTransform = transform
}
}
func WithDefaultTransform() OptionFunc {
return func(opt *Option) {
opt.Transform = DefaultTransform
}
}
func WithNoOpValueTransform() OptionFunc {
return WithValueTransform(func(value interface{}) interface{} {
return value
})
}

View File

@ -0,0 +1,159 @@
package sql
import (
"forge.cadoles.com/arcad/edge/pkg/storage/filter"
"github.com/pkg/errors"
)
type transformFunc func(op filter.Operator, option *Option) (string, []interface{}, error)
var transforms map[filter.Token]transformFunc
func init() {
// Initialise transforms map
transforms = map[filter.Token]transformFunc{
filter.TokenAnd: transformAndOperator,
filter.TokenOr: transformOrOperator,
filter.TokenNot: transformNotOperator,
filter.TokenEq: transformEqOperator,
filter.TokenNeq: transformNeqOperator,
filter.TokenGt: transformGtOperator,
filter.TokenGte: transformGteOperator,
filter.TokenLte: transformLteOperator,
filter.TokenLt: transformLtOperator,
filter.TokenLike: transformLikeOperator,
filter.TokenIn: transformInOperator,
}
}
func ToSQL(op filter.Operator, funcs ...OptionFunc) (string, []interface{}, error) {
opt := DefaultOption()
for _, fn := range funcs {
fn(opt)
}
return toSQL(op, opt)
}
func toSQL(op filter.Operator, opt *Option) (string, []interface{}, error) {
if op == nil {
return "", nil, nil
}
transform, exists := transforms[op.Token()]
if !exists {
return "", nil, errors.WithStack(filter.ErrUnsupportedOperator)
}
sql, args, err := transform(op, opt)
if err != nil {
return "", nil, errors.WithStack(err)
}
return sql, args, nil
}
func transformAndOperator(op filter.Operator, option *Option) (string, []interface{}, error) {
andOp, ok := op.(*filter.AndOperator)
if !ok {
return "", nil, errors.Wrapf(filter.ErrUnexpectedOperator, "expected '%s', got '%s'", filter.TokenAnd, op.Token())
}
return aggregatorToSQL("AND", option, andOp.Children()...)
}
func transformOrOperator(op filter.Operator, option *Option) (string, []interface{}, error) {
orOp, ok := op.(*filter.OrOperator)
if !ok {
return "", nil, errors.Wrapf(filter.ErrUnexpectedOperator, "expected '%s', got '%s'", filter.TokenOr, op.Token())
}
return aggregatorToSQL("OR", option, orOp.Children()...)
}
func transformEqOperator(op filter.Operator, option *Option) (string, []interface{}, error) {
eqOp, ok := op.(*filter.EqOperator)
if !ok {
return "", nil, errors.Wrapf(filter.ErrUnexpectedOperator, "expected '%s', got '%s'", filter.TokenEq, op.Token())
}
return fieldsToSQL("=", false, eqOp.Fields(), option)
}
func transformNeqOperator(op filter.Operator, option *Option) (string, []interface{}, error) {
eqOp, ok := op.(*filter.NeqOperator)
if !ok {
return "", nil, errors.Wrapf(filter.ErrUnexpectedOperator, "expected '%s', got '%s'", filter.TokenNeq, op.Token())
}
return fieldsToSQL("!=", false, eqOp.Fields(), option)
}
func transformGtOperator(op filter.Operator, option *Option) (string, []interface{}, error) {
gtOp, ok := op.(*filter.GtOperator)
if !ok {
return "", nil, errors.Wrapf(filter.ErrUnexpectedOperator, "expected '%s', got '%s'", filter.TokenGt, op.Token())
}
return fieldsToSQL(">", false, gtOp.Fields(), option)
}
func transformGteOperator(op filter.Operator, option *Option) (string, []interface{}, error) {
gteOp, ok := op.(*filter.GteOperator)
if !ok {
return "", nil, errors.Wrapf(filter.ErrUnexpectedOperator, "expected '%s', got '%s'", filter.TokenGte, op.Token())
}
return fieldsToSQL(">=", false, gteOp.Fields(), option)
}
func transformLtOperator(op filter.Operator, option *Option) (string, []interface{}, error) {
ltOp, ok := op.(*filter.LtOperator)
if !ok {
return "", nil, errors.Wrapf(filter.ErrUnexpectedOperator, "expected '%s', got '%s'", filter.TokenLt, op.Token())
}
return fieldsToSQL("<", false, ltOp.Fields(), option)
}
func transformLteOperator(op filter.Operator, option *Option) (string, []interface{}, error) {
lteOp, ok := op.(*filter.LteOperator)
if !ok {
return "", nil, errors.Wrapf(filter.ErrUnexpectedOperator, "expected '%s', got '%s'", filter.TokenLte, op.Token())
}
return fieldsToSQL("<=", false, lteOp.Fields(), option)
}
func transformInOperator(op filter.Operator, option *Option) (string, []interface{}, error) {
inOp, ok := op.(*filter.InOperator)
if !ok {
return "", nil, errors.Wrapf(filter.ErrUnexpectedOperator, "expected '%s', got '%s'", filter.TokenIn, op.Token())
}
return fieldsToSQL("IN", true, inOp.Fields(), option)
}
func transformLikeOperator(op filter.Operator, option *Option) (string, []interface{}, error) {
likeOp, ok := op.(*filter.LikeOperator)
if !ok {
return "", nil, errors.Wrapf(filter.ErrUnexpectedOperator, "expected '%s', got '%s'", filter.TokenLike, op.Token())
}
return fieldsToSQL("LIKE", false, likeOp.Fields(), option)
}
func transformNotOperator(op filter.Operator, option *Option) (string, []interface{}, error) {
notOp, ok := op.(*filter.NotOperator)
if !ok {
return "", nil, errors.Wrapf(filter.ErrUnexpectedOperator, "expected '%s', got '%s'", filter.TokenNot, op.Token())
}
sql, args, err := aggregatorToSQL("AND", option, notOp.Children()...)
if err != nil {
return "", nil, errors.WithStack(err)
}
return "NOT " + sql, args, nil
}

View File

@ -0,0 +1,84 @@
package sql
import (
"encoding/json"
"fmt"
"testing"
"forge.cadoles.com/arcad/edge/pkg/storage/filter"
)
type (
op map[string]interface{}
aggr []interface{}
)
type testCase struct {
RawFilter string
ExpectedSQL string
ExpectedArgs []interface{}
}
var testCases = []testCase{
{
RawFilter: `
{
"or": [
{"eq": {"foo": "bar"}},
{"neq": {"hello": "world"}}
]
}
`,
ExpectedSQL: "(((foo = $1) OR (hello != $2)))",
ExpectedArgs: []interface{}{"bar", "world"},
},
}
func TestSQLFilter(t *testing.T) {
for i, tc := range testCases {
func(tc testCase) {
t.Run(fmt.Sprintf("Test case #%d", i), func(t *testing.T) {
raw := make(map[string]interface{})
if err := json.Unmarshal([]byte(tc.RawFilter), &raw); err != nil {
t.Fatal(err)
}
query, err := filter.NewFrom(raw)
if err != nil {
t.Fatal(err)
}
sql, args, err := ToSQL(query.Root())
if err != nil {
t.Error(err)
}
if e, g := tc.ExpectedSQL, sql; e != g {
t.Errorf("sql: expected '%s', got '%s'", e, g)
}
if args == nil {
t.Fatal("args should not be nil")
}
for i, a := range args {
if i >= len(tc.ExpectedArgs) {
t.Errorf("args[%d]: expected nil, got '%v'", i, a)
continue
}
if e, g := tc.ExpectedArgs[i], a; e != g {
t.Errorf("args[%d]: expected '%v', got '%v'", i, e, g)
}
}
for i, a := range tc.ExpectedArgs {
if i >= len(args) {
t.Errorf("args[%d]: expected '%v', got nil", i, a)
}
}
})
}(tc)
}
}

View File

@ -0,0 +1,45 @@
package sql
import (
"strings"
"github.com/pkg/errors"
)
func DefaultTransform(operator string, invert bool, key string, value interface{}, option *Option) (string, interface{}, error) {
var sb strings.Builder
if invert {
if _, err := sb.WriteString(option.PreparedParameter()); err != nil {
return "", nil, errors.WithStack(err)
}
} else {
if _, err := sb.WriteString(option.KeyTransform(key)); err != nil {
return "", nil, errors.WithStack(err)
}
}
if _, err := sb.WriteString(" "); err != nil {
return "", nil, errors.WithStack(err)
}
if _, err := sb.WriteString(operator); err != nil {
return "", nil, errors.WithStack(err)
}
if invert {
if _, err := sb.WriteString(" "); err != nil {
return "", nil, errors.WithStack(err)
}
if _, err := sb.WriteString(key); err != nil {
return "", nil, errors.WithStack(err)
}
} else {
if _, err := sb.WriteString(" " + option.PreparedParameter()); err != nil {
return "", nil, errors.WithStack(err)
}
}
return sb.String(), value, nil
}

View File

@ -0,0 +1,41 @@
package storage
type OrderDirection string
const (
OrderDirectionAsc OrderDirection = "ASC"
OrderDirectionDesc OrderDirection = "DESC"
)
type QueryOption struct {
Limit *int
Offset *int
OrderBy *string
OrderDirection *OrderDirection
}
type QueryOptionFunc func(o *QueryOption)
func WithLimit(limit int) QueryOptionFunc {
return func(o *QueryOption) {
o.Limit = &limit
}
}
func WithOffset(offset int) QueryOptionFunc {
return func(o *QueryOption) {
o.Offset = &offset
}
}
func WithOrderBy(orderBy string) QueryOptionFunc {
return func(o *QueryOption) {
o.OrderBy = &orderBy
}
}
func WithOrderDirection(direction OrderDirection) QueryOptionFunc {
return func(o *QueryOption) {
o.OrderDirection = &direction
}
}

View File

@ -0,0 +1,338 @@
package sqlite
import (
"context"
"database/sql"
"fmt"
"sync"
"time"
"forge.cadoles.com/arcad/edge/pkg/storage"
"forge.cadoles.com/arcad/edge/pkg/storage/filter"
filterSQL "forge.cadoles.com/arcad/edge/pkg/storage/filter/sql"
"github.com/pkg/errors"
"gitlab.com/wpetit/goweb/logger"
_ "modernc.org/sqlite"
)
type DocumentStore struct {
db *sql.DB
path string
openOnce sync.Once
}
// Delete implements storage.DocumentStore
func (s *DocumentStore) Delete(ctx context.Context, collection string, id storage.DocumentID) error {
err := s.withTx(ctx, func(tx *sql.Tx) error {
query := `
DELETE FROM documents
WHERE collection = $1 AND id = $2
`
_, err := tx.ExecContext(ctx, query, collection, string(id))
if err != nil {
return errors.WithStack(err)
}
return nil
})
if err != nil {
return errors.WithStack(err)
}
return nil
}
// Get implements storage.DocumentStore
func (s *DocumentStore) Get(ctx context.Context, collection string, id storage.DocumentID) (storage.Document, error) {
var document storage.Document
err := s.withTx(ctx, func(tx *sql.Tx) error {
query := `
SELECT id, data, created_at, updated_at
FROM documents
WHERE collection = $1 AND id = $2
`
row := tx.QueryRowContext(ctx, query, collection, string(id))
var (
createdAt time.Time
updatedAt time.Time
data JSONMap
)
err := row.Scan(&id, &data, &createdAt, &updatedAt)
if err != nil {
if errors.Is(err, sql.ErrNoRows) {
return errors.WithStack(storage.ErrDocumentNotFound)
}
return errors.WithStack(err)
}
document = storage.Document(data)
document[storage.DocumentAttrID] = id
document[storage.DocumentAttrCreatedAt] = createdAt
document[storage.DocumentAttrUpdatedAt] = updatedAt
return nil
})
if err != nil {
return nil, errors.WithStack(err)
}
return document, nil
}
// Query implements storage.DocumentStore
func (s *DocumentStore) Query(ctx context.Context, collection string, filter *filter.Filter, funcs ...storage.QueryOptionFunc) ([]storage.Document, error) {
var documents []storage.Document
err := s.withTx(ctx, func(tx *sql.Tx) error {
criteria, args, err := filterSQL.ToSQL(
filter.Root(),
filterSQL.WithPreparedParameter("$", 2),
filterSQL.WithKeyTransform(func(key string) string {
return fmt.Sprintf("json_extract(data, '$.%s')", key)
}),
)
if err != nil {
return errors.WithStack(err)
}
query := `
SELECT id, data, created_at, updated_at
FROM documents
WHERE collection = $1 AND (` + criteria + `)
`
args = append([]interface{}{collection}, args...)
logger.Debug(
ctx, "executing query",
logger.F("query", query),
logger.F("args", args),
)
rows, err := tx.QueryContext(ctx, query, args...)
if err != nil {
return errors.WithStack(err)
}
defer rows.Close()
documents = make([]storage.Document, 0)
for rows.Next() {
var (
id storage.DocumentID
createdAt time.Time
updatedAt time.Time
data JSONMap
)
if err := rows.Scan(&id, &data, &createdAt, &updatedAt); err != nil {
return errors.WithStack(err)
}
document := storage.Document(data)
document[storage.DocumentAttrID] = id
document[storage.DocumentAttrCreatedAt] = createdAt
document[storage.DocumentAttrUpdatedAt] = updatedAt
documents = append(documents, document)
}
return nil
})
if err != nil {
return nil, errors.WithStack(err)
}
return documents, nil
}
// Upsert implements storage.DocumentStore
func (s *DocumentStore) Upsert(ctx context.Context, collection string, document storage.Document) (storage.Document, error) {
var upsertedDocument storage.Document
err := s.withTx(ctx, func(tx *sql.Tx) error {
query := `
INSERT INTO documents (id, collection, data, created_at, updated_at)
VALUES($1, $2, $3, $4, $4)
ON CONFLICT (id, collection) DO UPDATE SET
data = $3, updated_at = $4
RETURNING "id", "data", "created_at", "updated_at"
`
now := time.Now().UTC()
id, exists := document.ID()
if !exists || id == "" {
id = storage.NewDocumentID()
}
delete(document, storage.DocumentAttrID)
delete(document, storage.DocumentAttrCreatedAt)
delete(document, storage.DocumentAttrUpdatedAt)
args := []any{id, collection, JSONMap(document), now, now}
row := tx.QueryRowContext(ctx, query, args...)
var (
createdAt time.Time
updatedAt time.Time
data JSONMap
)
err := row.Scan(&id, &data, &createdAt, &updatedAt)
if err != nil {
return errors.WithStack(err)
}
upsertedDocument = storage.Document(data)
upsertedDocument[storage.DocumentAttrID] = id
upsertedDocument[storage.DocumentAttrCreatedAt] = createdAt
upsertedDocument[storage.DocumentAttrUpdatedAt] = updatedAt
return nil
})
if err != nil {
return nil, errors.WithStack(err)
}
return upsertedDocument, nil
}
func (s *DocumentStore) withTx(ctx context.Context, fn func(tx *sql.Tx) error) error {
var db *sql.DB
db, err := s.getDatabase(ctx)
if err != nil {
return errors.WithStack(err)
}
if err := withTx(ctx, db, fn); err != nil {
return errors.WithStack(err)
}
return nil
}
func withTx(ctx context.Context, db *sql.DB, fn func(tx *sql.Tx) error) error {
var tx *sql.Tx
tx, err := db.Begin()
if err != nil {
return errors.WithStack(err)
}
defer func() {
if err := tx.Rollback(); err != nil {
if errors.Is(err, sql.ErrTxDone) {
return
}
panic(errors.WithStack(err))
}
}()
if err = fn(tx); err != nil {
return errors.WithStack(err)
}
if err = tx.Commit(); err != nil {
return errors.WithStack(err)
}
return nil
}
func (s *DocumentStore) getDatabase(ctx context.Context) (*sql.DB, error) {
if s.db != nil {
return s.db, nil
}
var (
db *sql.DB
err error
)
s.openOnce.Do(func() {
db, err = sql.Open("sqlite", s.path)
if err != nil {
err = errors.WithStack(err)
return
}
if err = s.ensureTables(ctx, db); err != nil {
err = errors.WithStack(err)
return
}
})
if err != nil {
return nil, errors.WithStack(err)
}
s.db = db
return db, nil
}
func (s *DocumentStore) ensureTables(ctx context.Context, db *sql.DB) error {
err := withTx(ctx, db, func(tx *sql.Tx) error {
query := `
CREATE TABLE IF NOT EXISTS documents (
id TEXT PRIMARY KEY,
collection TEXT NOT NULL,
data TEXT,
created_at TIMESTAMP NOT NULL,
updated_at TIMESTAMP NOT NULL,
UNIQUE(id, collection) ON CONFLICT REPLACE
);
`
if _, err := tx.ExecContext(ctx, query); err != nil {
return errors.WithStack(err)
}
query = `
CREATE INDEX IF NOT EXISTS collection_idx ON documents (collection);
`
if _, err := tx.ExecContext(ctx, query); err != nil {
return errors.WithStack(err)
}
return nil
})
if err != nil {
return errors.WithStack(err)
}
return nil
}
func NewDocumentStore(path string) *DocumentStore {
return &DocumentStore{
db: nil,
path: path,
openOnce: sync.Once{},
}
}
func NewDocumentStoreWithDB(db *sql.DB) *DocumentStore {
return &DocumentStore{
db: db,
path: "",
openOnce: sync.Once{},
}
}
var _ storage.DocumentStore = &DocumentStore{}

View File

@ -0,0 +1,16 @@
package sqlite
import (
"testing"
"forge.cadoles.com/arcad/edge/pkg/storage/testsuite"
"gitlab.com/wpetit/goweb/logger"
)
func TestDocumentStore(t *testing.T) {
logger.SetLevel(logger.LevelDebug)
store := NewDocumentStore(":memory:")
testsuite.TestDocumentStore(t, store)
}

View File

@ -0,0 +1,42 @@
package sqlite
import (
"database/sql/driver"
"encoding/json"
"github.com/pkg/errors"
)
type JSONMap map[string]any
func (j *JSONMap) Scan(value interface{}) error {
if value == nil {
return nil
}
var data []byte
switch typ := value.(type) {
case []byte:
data = typ
case string:
data = []byte(typ)
default:
return errors.Errorf("unexpected type '%T'", value)
}
if err := json.Unmarshal(data, &j); err != nil {
return errors.WithStack(err)
}
return nil
}
func (j JSONMap) Value() (driver.Value, error) {
data, err := json.Marshal(j)
if err != nil {
return nil, errors.WithStack(err)
}
return data, nil
}

View File

@ -0,0 +1,16 @@
package testsuite
import (
"testing"
"forge.cadoles.com/arcad/edge/pkg/storage"
)
func TestDocumentStore(t *testing.T, store storage.DocumentStore) {
t.Parallel()
t.Run("TestDocumentStoreQuery", func(t *testing.T) {
t.Parallel()
testDocumentStoreQuery(t, store)
})
}

View File

@ -0,0 +1,85 @@
package testsuite
import (
"context"
"testing"
"forge.cadoles.com/arcad/edge/pkg/storage"
"forge.cadoles.com/arcad/edge/pkg/storage/filter"
"github.com/pkg/errors"
)
type documentStoreQueryTestCase struct {
Name string
Before func(ctx context.Context, store storage.DocumentStore) error
Collection string
Filter *filter.Filter
QueryOptionsFuncs []storage.QueryOptionFunc
After func(t *testing.T, results []storage.Document, err error)
}
var documentStoreQueryTestCases = []documentStoreQueryTestCase{
{
Name: "Simple select",
Before: func(ctx context.Context, store storage.DocumentStore) error {
doc1 := storage.Document{
"attr1": "Foo",
}
if _, err := store.Upsert(ctx, "simple_select", doc1); err != nil {
return errors.WithStack(err)
}
doc2 := storage.Document{
"attr1": "Bar",
}
if _, err := store.Upsert(ctx, "simple_select", doc2); err != nil {
return errors.WithStack(err)
}
return nil
},
Collection: "simple_select",
Filter: filter.New(
filter.NewEqOperator(map[string]interface{}{
"attr1": "Foo",
}),
),
After: func(t *testing.T, results []storage.Document, err error) {
if err != nil {
t.Fatalf("%+v", errors.WithStack(err))
}
if e, g := 1, len(results); e != g {
t.Errorf("len(results): expected '%v', got '%v'", e, g)
}
if e, g := "Foo", results[0]["attr1"]; e != g {
t.Errorf("results[0][\"Attr1\"]: expected '%v', got '%v'", e, g)
}
},
},
}
func testDocumentStoreQuery(t *testing.T, store storage.DocumentStore) {
for _, tc := range documentStoreQueryTestCases {
func(tc documentStoreQueryTestCase) {
t.Run(tc.Name, func(t *testing.T) {
t.Parallel()
ctx := context.Background()
if tc.Before != nil {
if err := tc.Before(ctx, store); err != nil {
t.Fatalf("%+v", errors.WithStack(err))
}
}
documents, err := store.Query(ctx, tc.Collection, tc.Filter, tc.QueryOptionsFuncs...)
tc.After(t, documents, err)
})
}(tc)
}
}