func (s *store) Query(expression string, options ...storage.QueryOption) (storage.Iterator, error) {
	err := checkForUnsupportedQueryOptions(options)
	if err != nil {
		return nil, err
	}
	if expression == "" {
		return nil, fmt.Errorf(invalidQueryExpressionFormat, expression)
	}
	expressionSplit := strings.Split(expression, ":")
	var expressionTagName string
	var expressionTagValue string
	switch len(expressionSplit) {
	case expressionTagNameOnlyLength:
		expressionTagName = expressionSplit[0]
	case expressionTagNameAndValueLength:
		expressionTagName = expressionSplit[0]
		expressionTagValue = expressionSplit[1]
	default:
		return nil, fmt.Errorf(invalidQueryExpressionFormat, expression)
	}
	matchingDatabaseKeys, err := s.getDatabaseKeysMatchingQuery(expressionTagName, expressionTagValue)
	if err != nil {
		return nil, fmt.Errorf("failed to get database keys matching query: %w", err)
	}
	return &iterator{keys: matchingDatabaseKeys, store: s}, nil
}
This provider doesn't currently support any of the current query options.
spi.WithPageSize will simply be ignored since it only relates to performance and not the actual end result.
spi.WithInitialPageNum and spi.WithSortOrder will result in an error being returned since those options do
affect the results that the Iterator returns.
package indexeddb
import (
	"encoding/base64"
	"encoding/json"
	"errors"
	"fmt"
	"strings"
	"sync"
	"syscall/js"
	"time"
	"github.com/hyperledger/aries-framework-go/pkg/didcomm/messenger"
	"github.com/hyperledger/aries-framework-go/pkg/didcomm/protocol/introduce"
	"github.com/hyperledger/aries-framework-go/pkg/didcomm/protocol/issuecredential"
	"github.com/hyperledger/aries-framework-go/pkg/didcomm/protocol/mediator"
	"github.com/hyperledger/aries-framework-go/pkg/didcomm/protocol/presentproof"
	"github.com/hyperledger/aries-framework-go/pkg/kms/localkms"
	"github.com/hyperledger/aries-framework-go/pkg/store/connection"
	"github.com/hyperledger/aries-framework-go/pkg/store/did"
	"github.com/hyperledger/aries-framework-go/pkg/store/verifiable"
	"github.com/hyperledger/aries-framework-go/pkg/vdr/peer"
	"github.com/hyperledger/aries-framework-go/spi/storage"
)
const (
	dbName                          = "aries-%s"
	defDBName                       = "aries"
	dbVersion                       = 1
	tagMapKey                       = "TagMap"
	storeConfigKey                  = "StoreConfig"
	expressionTagNameOnlyLength     = 1
	expressionTagNameAndValueLength = 2
	invalidTagName  = `"%s" is an invalid tag name since it contains one or more ':' characters`
	invalidTagValue = `"%s" is an invalid tag value since it contains one or more ':' characters`
	invalidQueryExpressionFormat = `"%s" is not in a valid expression format. ` +
		"it must be in the following format: TagName:TagValue"
)
type tagMapping map[string]map[string]struct{}  
type Provider struct {
	stores map[string]*store
	lock   sync.RWMutex
}
func NewProvider(name string) (*Provider, error) {
	p := &Provider{stores: make(map[string]*store)}
	db := defDBName
	if name != "" {
		db = fmt.Sprintf(dbName, name)
	}
	err := p.openDB(db, getStoreNames()...)
	if err != nil {
		return nil, fmt.Errorf("failed to open IndexDB : %w", err)
	}
	return p, nil
}
func (p *Provider) OpenStore(name string) (storage.Store, error) {
	if name == "" {
		return nil, fmt.Errorf("store name cannot be empty")
	}
	name = strings.ToLower(name)
	p.lock.RLock()
	openStore, ok := p.stores[name]
	p.lock.RUnlock()
	if ok {
		return openStore, nil
	}
	p.lock.Lock()
	defer p.lock.Unlock()
	err := p.openDB(fmt.Sprintf(dbName, name), name)
	if err != nil {
		return nil, err
	}
	return p.stores[name], nil
}
func (p *Provider) SetStoreConfig(name string, config storage.StoreConfiguration) error {
	for _, tagName := range config.TagNames {
		if strings.Contains(tagName, ":") {
			return fmt.Errorf(invalidTagName, tagName)
		}
	}
	name = strings.ToLower(name)
	store, ok := p.stores[name]
	if !ok {
		return storage.ErrStoreNotFound
	}
	configBytes, err := json.Marshal(config)
	if err != nil {
		return fmt.Errorf("failed to marshal store configuration: %w", err)
	}
	err = store.Put(storeConfigKey, configBytes)
	if err != nil {
		return fmt.Errorf("failed to put store configuration: %w", err)
	}
	return nil
}
func (p *Provider) GetStoreConfig(name string) (storage.StoreConfiguration, error) {
	name = strings.ToLower(name)
	store, ok := p.stores[name]
	if !ok {
		return storage.StoreConfiguration{}, storage.ErrStoreNotFound
	}
	storeConfigBytes, err := store.Get(storeConfigKey)
	if err != nil {
		return storage.StoreConfiguration{},
			fmt.Errorf(`failed to get store configuration for "%s": %w`, name, err)
	}
	var storeConfig storage.StoreConfiguration
	err = json.Unmarshal(storeConfigBytes, &storeConfig)
	if err != nil {
		return storage.StoreConfiguration{}, fmt.Errorf("failed to unmarshal store configuration: %w", err)
	}
	return storeConfig, nil
}
func (p *Provider) GetOpenStores() []storage.Store {
	return nil
}
func (p *Provider) Close() error {
	return nil
}
func (p *Provider) openDB(db string, names ...string) error {
	req := js.Global().Get("indexedDB").Call("open", db, dbVersion)
	req.Set("onupgradeneeded", js.FuncOf(func(this js.Value, inputs []js.Value) interface{} {
		m := make(map[string]interface{})
		m["keyPath"] = "key"
		for _, name := range names {
			this.Get("result").Call("createObjectStore", name, m)
		}
		return nil
	}))
	v, err := getResult(req)
	if err != nil {
		return fmt.Errorf("failed to open indexedDB: %w", err)
	}
	for _, name := range names {
		newStore := &store{name: name, db: v}
		p.stores[name] = newStore
	}
	return nil
}
type store struct {
	name string
	db   *js.Value
	lock sync.RWMutex
}
func (s *store) Put(key string, value []byte, tags ...storage.Tag) error {
	if key == "" || value == nil {
		return errors.New("key and value are mandatory")
	}
	for _, tag := range tags {
		if strings.Contains(tag.Name, ":") {
			return fmt.Errorf(invalidTagName, tag.Name)
		}
		if strings.Contains(tag.Value, ":") {
			return fmt.Errorf(invalidTagValue, tag.Value)
		}
	}
	m := make(map[string]interface{})
	m["key"] = key
	m["value"] = base64.StdEncoding.EncodeToString(value)
	if len(tags) > 0 {
		tagsBytes, err := json.Marshal(tags)
		if err != nil {
			return fmt.Errorf("failed to marshal tags: %w", err)
		}
		m["tags"] = string(tagsBytes)
		err = s.updateTagMap(key, tags)
		if err != nil {
			return fmt.Errorf("failed to update tag map: %w", err)
		}
	}
	req := s.db.Call("transaction", s.name, "readwrite").Call("objectStore", s.name).Call("put", m)
	_, err := getResult(req)
	if err != nil {
		return fmt.Errorf("failed to store data: %w", err)
	}
	return nil
}
func (s *store) Get(key string) ([]byte, error) {
	if key == "" {
		return nil, errors.New("key is mandatory")
	}
	req := s.db.Call("transaction", s.name).Call("objectStore", s.name).Call("get", key)
	data, err := getResult(req)
	if err != nil {
		return nil, fmt.Errorf("failed to get data: %w", err)
	}
	if !data.Truthy() {
		return nil, storage.ErrDataNotFound
	}
	valueBase64Encoded := data.Get("value").String()
	value, err := base64.StdEncoding.DecodeString(valueBase64Encoded)
	if err != nil {
		return nil, fmt.Errorf("failed to base64 decode the store value: %w", err)
	}
	return value, nil
}
func (s *store) GetTags(key string) ([]storage.Tag, error) {
	if key == "" {
		return nil, errors.New("key is mandatory")
	}
	req := s.db.Call("transaction", s.name).Call("objectStore", s.name).Call("get", key)
	data, err := getResult(req)
	if err != nil {
		return nil, fmt.Errorf("failed to get data: %w", err)
	}
	if !data.Truthy() {
		return nil, storage.ErrDataNotFound
	}
	tagsBytes := []byte(data.Get("tags").String())
	var tags []storage.Tag
	err = json.Unmarshal(tagsBytes, &tags)
	if err != nil {
		return nil, fmt.Errorf("failed to unmarshal tags bytes: %w", err)
	}
	return tags, nil
}
func (s *store) GetBulk(keys ...string) ([][]byte, error) {
	return nil, errors.New("not implemented")
}