diff --git a/src/cmd/factory/impl/common.go b/src/cmd/factory/impl/common.go index 275630993..a139d1d5b 100644 --- a/src/cmd/factory/impl/common.go +++ b/src/cmd/factory/impl/common.go @@ -1,11 +1,8 @@ package impl import ( - "bytes" "context" - "encoding/json" "fmt" - "io" "os" "strings" "time" @@ -20,7 +17,6 @@ import ( "github.com/alcionai/corso/src/internal/common/ptr" "github.com/alcionai/corso/src/internal/connector" exchMock "github.com/alcionai/corso/src/internal/connector/exchange/mock" - "github.com/alcionai/corso/src/internal/connector/onedrive/metadata" "github.com/alcionai/corso/src/internal/data" "github.com/alcionai/corso/src/internal/tester" "github.com/alcionai/corso/src/internal/version" @@ -83,7 +79,7 @@ func generateAndRestoreItems( } collections := []collection{{ - pathElements: []string{destFldr}, + PathElements: []string{destFldr}, category: cat, items: items, }} @@ -160,7 +156,7 @@ type collection struct { // only contain elements after the prefix that corso uses for the path. For // example, a collection for the Inbox folder in exchange mail would just be // "Inbox". - pathElements []string + PathElements []string category path.CategoryType items []item } @@ -180,7 +176,7 @@ func buildCollections( service, c.category, false, - c.pathElements...) + c.PathElements...) if err != nil { return nil, err } @@ -198,45 +194,6 @@ func buildCollections( return collections, nil } -type permData struct { - user string // user is only for older versions - entityID string - roles []string - sharingMode metadata.SharingMode -} - -type itemData struct { - name string - data []byte - perms permData -} - -type itemInfo struct { - // lookupKey is a string that can be used to find this data from a set of - // other data in the same collection. This key should be something that will - // be the same before and after restoring the item in M365 and may not be - // the M365 ID. When restoring items out of place, the item is assigned a - // new ID making it unsuitable for a lookup key. - lookupKey string - name string - data []byte -} - -type onedriveCollection struct { - service path.ServiceType - pathElements []string - items []itemInfo - aux []itemInfo - backupVersion int -} - -type onedriveColInfo struct { - pathElements []string - perms permData - files []itemData - folders []itemData -} - var ( folderAName = "folder-a" folderBName = "b" @@ -292,7 +249,7 @@ func generateAndRestoreDriveItems( } var ( - cols []onedriveColInfo + cols []connector.OnedriveColInfo rootPath = []string{"drives", driveID, "root:"} folderAPath = []string{"drives", driveID, "root:", folderAName} @@ -306,43 +263,43 @@ func generateAndRestoreDriveItems( ) for i := 0; i < count; i++ { - col := []onedriveColInfo{ + col := []connector.OnedriveColInfo{ // basic folder and file creation { - pathElements: rootPath, - files: []itemData{ + PathElements: rootPath, + Files: []connector.ItemData{ { - name: fmt.Sprintf("file-1st-count-%d-at-%s", i, currentTime), - data: fileAData, - perms: permData{ - user: secondaryUserName, - entityID: secondaryUserID, - roles: writePerm, + Name: fmt.Sprintf("file-1st-count-%d-at-%s", i, currentTime), + Data: fileAData, + Perms: connector.PermData{ + User: secondaryUserName, + EntityID: secondaryUserID, + Roles: writePerm, }, }, { - name: fmt.Sprintf("file-2nd-count-%d-at-%s", i, currentTime), - data: fileBData, + Name: fmt.Sprintf("file-2nd-count-%d-at-%s", i, currentTime), + Data: fileBData, }, }, - folders: []itemData{ + Folders: []connector.ItemData{ { - name: folderBName, + Name: folderBName, }, { - name: folderAName, - perms: permData{ - user: secondaryUserName, - entityID: secondaryUserID, - roles: readPerm, + Name: folderAName, + Perms: connector.PermData{ + User: secondaryUserName, + EntityID: secondaryUserID, + Roles: readPerm, }, }, { - name: folderCName, - perms: permData{ - user: secondaryUserName, - entityID: secondaryUserID, - roles: readPerm, + Name: folderCName, + Perms: connector.PermData{ + User: secondaryUserName, + EntityID: secondaryUserID, + Roles: readPerm, }, }, }, @@ -350,62 +307,62 @@ func generateAndRestoreDriveItems( { // a folder that has permissions with an item in the folder with // the different permissions. - pathElements: folderAPath, - files: []itemData{ + PathElements: folderAPath, + Files: []connector.ItemData{ { - name: fmt.Sprintf("file-count-%d-at-%s", i, currentTime), - data: fileEData, - perms: permData{ - user: secondaryUserName, - entityID: secondaryUserID, - roles: writePerm, + Name: fmt.Sprintf("file-count-%d-at-%s", i, currentTime), + Data: fileEData, + Perms: connector.PermData{ + User: secondaryUserName, + EntityID: secondaryUserID, + Roles: writePerm, }, }, }, - perms: permData{ - user: secondaryUserName, - entityID: secondaryUserID, - roles: readPerm, + Perms: connector.PermData{ + User: secondaryUserName, + EntityID: secondaryUserID, + Roles: readPerm, }, }, { // a folder that has permissions with an item in the folder with // no permissions. - pathElements: folderCPath, - files: []itemData{ + PathElements: folderCPath, + Files: []connector.ItemData{ { - name: fmt.Sprintf("file-count-%d-at-%s", i, currentTime), - data: fileAData, + Name: fmt.Sprintf("file-count-%d-at-%s", i, currentTime), + Data: fileAData, }, }, - perms: permData{ - user: secondaryUserName, - entityID: secondaryUserID, - roles: readPerm, + Perms: connector.PermData{ + User: secondaryUserName, + EntityID: secondaryUserID, + Roles: readPerm, }, }, { - pathElements: folderBPath, - files: []itemData{ + PathElements: folderBPath, + Files: []connector.ItemData{ { // restoring a file in a non-root folder that doesn't inherit // permissions. - name: fmt.Sprintf("file-count-%d-at-%s", i, currentTime), - data: fileBData, - perms: permData{ - user: secondaryUserName, - entityID: secondaryUserID, - roles: writePerm, + Name: fmt.Sprintf("file-count-%d-at-%s", i, currentTime), + Data: fileBData, + Perms: connector.PermData{ + User: secondaryUserName, + EntityID: secondaryUserID, + Roles: writePerm, }, }, }, - folders: []itemData{ + Folders: []connector.ItemData{ { - name: folderAName, - perms: permData{ - user: secondaryUserName, - entityID: secondaryUserID, - roles: readPerm, + Name: folderAName, + Perms: connector.PermData{ + User: secondaryUserName, + EntityID: secondaryUserID, + Roles: readPerm, }, }, }, @@ -415,302 +372,40 @@ func generateAndRestoreDriveItems( cols = append(cols, col...) } - input := dataForInfo(service, cols, version.Backup) + input, err := connector.DataForInfo(service, cols, version.Backup) + if err != nil { + return nil, err + } - collections := getCollections( - service, - tenantID, - []string{resourceOwner}, - input, - version.Backup) + // collections := getCollections( + // service, + // tenantID, + // []string{resourceOwner}, + // input, + // version.Backup) opts := control.Options{ RestorePermissions: true, ToggleFeatures: control.Toggles{}, } + config := connector.ConfigInfo{ + Acct: acct, + Opts: opts, + Resource: connector.Users, + Service: service, + Tenant: tenantID, + ResourceOwners: []string{resourceOwner}, + Dest: tester.DefaultTestRestoreDestination(""), + } + + _, _, collections, _, err := connector.GetCollectionsAndExpected( + config, + input, + version.Backup) + if err != nil { + return nil, err + } + return gc.ConsumeRestoreCollections(ctx, version.Backup, acct, sel, dest, opts, collections, errs) } - -func getCollections( - service path.ServiceType, - tenant string, - resourceOwners []string, - testCollections []colInfo, - backupVersion int, -) []data.RestoreCollection { - var collections []data.RestoreCollection - - for _, owner := range resourceOwners { - ownerCollections := collectionsForInfo( - service, - tenant, - owner, - testCollections, - backupVersion, - ) - - collections = append(collections, ownerCollections...) - } - - return collections -} - -type mockRestoreCollection struct { - data.Collection - auxItems map[string]data.Stream -} - -func (rc mockRestoreCollection) Fetch( - ctx context.Context, - name string, -) (data.Stream, error) { - res := rc.auxItems[name] - if res == nil { - return nil, data.ErrNotFound - } - - return res, nil -} - -func collectionsForInfo( - service path.ServiceType, - tenant, user string, - allInfo []colInfo, - backupVersion int, -) []data.RestoreCollection { - collections := make([]data.RestoreCollection, 0, len(allInfo)) - - for _, info := range allInfo { - pth := mustToDataLayerPath( - service, - tenant, - user, - info.category, - info.pathElements, - false) - - mc := exchMock.NewCollection(pth, pth, len(info.items)) - - for i := 0; i < len(info.items); i++ { - mc.Names[i] = info.items[i].name - mc.Data[i] = info.items[i].data - - // We do not count metadata files against item count - if backupVersion > 0 && metadata.HasMetaSuffix(info.items[i].name) && - (service == path.OneDriveService || service == path.SharePointService) { - continue - } - } - - c := mockRestoreCollection{Collection: mc, auxItems: map[string]data.Stream{}} - - for _, aux := range info.auxItems { - c.auxItems[aux.name] = &exchMock.Data{ - ID: aux.name, - Reader: io.NopCloser(bytes.NewReader(aux.data)), - } - } - - collections = append(collections, c) - } - - return collections -} - -func mustToDataLayerPath( - service path.ServiceType, - tenant, resourceOwner string, - category path.CategoryType, - elements []string, - isItem bool, -) path.Path { - res, err := path.Build(tenant, resourceOwner, service, category, isItem, elements...) - if err != nil { - fmt.Println("building path", clues.ToCore(err)) - } - - return res -} - -type colInfo struct { - // Elements (in order) for the path representing this collection. Should - // only contain elements after the prefix that corso uses for the path. For - // example, a collection for the Inbox folder in exchange mail would just be - // "Inbox". - pathElements []string - category path.CategoryType - items []itemInfo - // auxItems are items that can be retrieved with Fetch but won't be returned - // by Items(). - auxItems []itemInfo -} - -func newOneDriveCollection( - service path.ServiceType, - pathElements []string, - backupVersion int, -) *onedriveCollection { - return &onedriveCollection{ - service: service, - pathElements: pathElements, - backupVersion: backupVersion, - } -} - -func dataForInfo( - service path.ServiceType, - cols []onedriveColInfo, - backupVersion int, -) []colInfo { - var res []colInfo - - for _, c := range cols { - onedriveCol := newOneDriveCollection(service, c.pathElements, backupVersion) - - for _, f := range c.files { - onedriveCol.withFile(f.name, f.data, f.perms) - } - - onedriveCol.withPermissions(c.perms) - - res = append(res, onedriveCol.collection()) - } - - return res -} - -func (c onedriveCollection) collection() colInfo { - cat := path.FilesCategory - if c.service == path.SharePointService { - cat = path.LibrariesCategory - } - - return colInfo{ - pathElements: c.pathElements, - category: cat, - items: c.items, - auxItems: c.aux, - } -} - -func (c *onedriveCollection) withFile(name string, fileData []byte, perm permData) *onedriveCollection { - c.items = append(c.items, onedriveItemWithData( - name+metadata.DataFileSuffix, - name+metadata.DataFileSuffix, - fileData)) - - md := onedriveMetadata( - name, - name+metadata.MetaFileSuffix, - name, - perm, - true) - c.items = append(c.items, md) - c.aux = append(c.aux, md) - - return c -} - -// withPermissions adds permissions to the folder represented by this -// onedriveCollection. -func (c *onedriveCollection) withPermissions(perm permData) *onedriveCollection { - if c.backupVersion < version.OneDrive4DirIncludesPermissions { - return c - } - - name := c.pathElements[len(c.pathElements)-1] - metaName := name - - if c.backupVersion >= version.OneDrive5DirMetaNoName { - // We switched to just .dirmeta for metadata file names. - metaName = "" - } - - if name == "root:" { - return c - } - - md := onedriveMetadata( - name, - metaName+metadata.DirMetaFileSuffix, - metaName+metadata.DirMetaFileSuffix, - perm, - true) - - c.items = append(c.items, md) - c.aux = append(c.aux, md) - - return c -} - -type oneDriveData struct { - FileName string `json:"fileName,omitempty"` - Data []byte `json:"data,omitempty"` -} - -func onedriveItemWithData( - name, lookupKey string, - fileData []byte, -) itemInfo { - content := oneDriveData{ - FileName: lookupKey, - Data: fileData, - } - - serialized, _ := json.Marshal(content) - - return itemInfo{ - name: name, - data: serialized, - lookupKey: lookupKey, - } -} - -func onedriveMetadata( - fileName, itemID, lookupKey string, - perm permData, - permUseID bool, -) itemInfo { - meta := getMetadata(fileName, perm, permUseID) - - metaJSON, err := json.Marshal(meta) - if err != nil { - fmt.Println("marshalling metadata", clues.ToCore(err)) - } - - return itemInfo{ - name: itemID, - data: metaJSON, - lookupKey: lookupKey, - } -} - -func getMetadata(fileName string, perm permData, permUseID bool) metadata.Metadata { - if len(perm.user) == 0 || len(perm.roles) == 0 || - perm.sharingMode != metadata.SharingModeCustom { - return metadata.Metadata{ - FileName: fileName, - SharingMode: perm.sharingMode, - } - } - - // In case of permissions, the id will usually be same for same - // user/role combo unless deleted and readded, but we have to do - // this as we only have two users of which one is already taken. - id := uuid.NewString() - uperm := metadata.Permission{ID: id, Roles: perm.roles} - - if permUseID { - uperm.EntityID = perm.entityID - } else { - uperm.Email = perm.user - } - - meta := metadata.Metadata{ - FileName: fileName, - Permissions: []metadata.Permission{uperm}, - } - - return meta -} diff --git a/src/go.mod b/src/go.mod index a90058680..d2ce254ff 100644 --- a/src/go.mod +++ b/src/go.mod @@ -8,7 +8,7 @@ require ( github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.2.0 github.com/alcionai/clues v0.0.0-20230406223931-f48777f4773c github.com/armon/go-metrics v0.4.1 - github.com/aws/aws-sdk-go v1.44.262 + github.com/aws/aws-sdk-go v1.44.263 github.com/aws/aws-xray-sdk-go v1.8.1 github.com/cenkalti/backoff/v4 v4.2.1 github.com/google/uuid v1.3.0 diff --git a/src/go.sum b/src/go.sum index f8a86e102..9a5fd2e66 100644 --- a/src/go.sum +++ b/src/go.sum @@ -66,8 +66,8 @@ github.com/andybalholm/brotli v1.0.4 h1:V7DdXeJtZscaqfNuAdSRuRFzuiKlHSC/Zh3zl9qY github.com/andybalholm/brotli v1.0.4/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig= github.com/armon/go-metrics v0.4.1 h1:hR91U9KYmb6bLBYLQjyM+3j+rcd/UhE+G78SFnF8gJA= github.com/armon/go-metrics v0.4.1/go.mod h1:E6amYzXo6aW1tqzoZGT755KkbgrJsSdpwZ+3JqfkOG4= -github.com/aws/aws-sdk-go v1.44.262 h1:gyXpcJptWoNkK+DiAiaBltlreoWKQXjAIh6FRh60F+I= -github.com/aws/aws-sdk-go v1.44.262/go.mod h1:aVsgQcEevwlmQ7qHE9I3h+dtQgpqhFB+i8Phjh7fkwI= +github.com/aws/aws-sdk-go v1.44.263 h1:Dkt5fcdtL8QtK3cz0bOTQ84m9dGx+YDeTsDl+wY2yW4= +github.com/aws/aws-sdk-go v1.44.263/go.mod h1:aVsgQcEevwlmQ7qHE9I3h+dtQgpqhFB+i8Phjh7fkwI= github.com/aws/aws-xray-sdk-go v1.8.1 h1:O4pXV+hnCskaamGsZnFpzHyAmgPGusBMN6i7nnsy0Fo= github.com/aws/aws-xray-sdk-go v1.8.1/go.mod h1:wMmVYzej3sykAttNBkXQHK/+clAPWTOrPiajEk7Cp3A= github.com/benbjohnson/clock v1.1.0 h1:Q92kusRqC1XV2MjkWETPvjJVqKetz1OzxZB7mHJLju8= diff --git a/src/internal/connector/exchange/api/contacts.go b/src/internal/connector/exchange/api/contacts.go index 1c5555ca1..9812d0539 100644 --- a/src/internal/connector/exchange/api/contacts.go +++ b/src/internal/connector/exchange/api/contacts.go @@ -222,13 +222,13 @@ func NewContactPager( return &contactPager{gs, builder, options}, nil } -func (p *contactPager) getPage(ctx context.Context) (api.PageLinker, error) { +func (p *contactPager) getPage(ctx context.Context) (api.DeltaPageLinker, error) { resp, err := p.builder.Get(ctx, p.options) if err != nil { return nil, graph.Stack(ctx, err) } - return resp, nil + return api.EmptyDeltaLinker[models.Contactable]{PageLinkValuer: resp}, nil } func (p *contactPager) setNext(nextLink string) { @@ -301,7 +301,7 @@ func NewContactDeltaPager( return &contactDeltaPager{gs, user, directoryID, builder, options}, nil } -func (p *contactDeltaPager) getPage(ctx context.Context) (api.PageLinker, error) { +func (p *contactDeltaPager) getPage(ctx context.Context) (api.DeltaPageLinker, error) { resp, err := p.builder.Get(ctx, p.options) if err != nil { return nil, graph.Stack(ctx, err) diff --git a/src/internal/connector/exchange/api/events.go b/src/internal/connector/exchange/api/events.go index 8edeffaba..c6429e897 100644 --- a/src/internal/connector/exchange/api/events.go +++ b/src/internal/connector/exchange/api/events.go @@ -283,13 +283,13 @@ func NewEventPager( return &eventPager{gs, builder, options}, nil } -func (p *eventPager) getPage(ctx context.Context) (api.PageLinker, error) { +func (p *eventPager) getPage(ctx context.Context) (api.DeltaPageLinker, error) { resp, err := p.builder.Get(ctx, p.options) if err != nil { return nil, graph.Stack(ctx, err) } - return resp, nil + return api.EmptyDeltaLinker[models.Eventable]{PageLinkValuer: resp}, nil } func (p *eventPager) setNext(nextLink string) { @@ -359,7 +359,7 @@ func getEventDeltaBuilder( return builder } -func (p *eventDeltaPager) getPage(ctx context.Context) (api.PageLinker, error) { +func (p *eventDeltaPager) getPage(ctx context.Context) (api.DeltaPageLinker, error) { resp, err := p.builder.Get(ctx, p.options) if err != nil { return nil, graph.Stack(ctx, err) diff --git a/src/internal/connector/exchange/api/mail.go b/src/internal/connector/exchange/api/mail.go index fb9f98e84..d4fbf377c 100644 --- a/src/internal/connector/exchange/api/mail.go +++ b/src/internal/connector/exchange/api/mail.go @@ -385,13 +385,13 @@ func NewMailPager( return &mailPager{gs, builder, options}, nil } -func (p *mailPager) getPage(ctx context.Context) (api.PageLinker, error) { +func (p *mailPager) getPage(ctx context.Context) (api.DeltaPageLinker, error) { page, err := p.builder.Get(ctx, p.options) if err != nil { return nil, graph.Stack(ctx, err) } - return page, nil + return api.EmptyDeltaLinker[models.Messageable]{PageLinkValuer: page}, nil } func (p *mailPager) setNext(nextLink string) { @@ -465,7 +465,7 @@ func NewMailDeltaPager( return &mailDeltaPager{gs, user, directoryID, builder, options}, nil } -func (p *mailDeltaPager) getPage(ctx context.Context) (api.PageLinker, error) { +func (p *mailDeltaPager) getPage(ctx context.Context) (api.DeltaPageLinker, error) { page, err := p.builder.Get(ctx, p.options) if err != nil { return nil, graph.Stack(ctx, err) diff --git a/src/internal/connector/exchange/api/shared.go b/src/internal/connector/exchange/api/shared.go index 87d579140..139eb5ecc 100644 --- a/src/internal/connector/exchange/api/shared.go +++ b/src/internal/connector/exchange/api/shared.go @@ -18,7 +18,7 @@ import ( type itemPager interface { // getPage get a page with the specified options from graph - getPage(context.Context) (api.PageLinker, error) + getPage(context.Context) (api.DeltaPageLinker, error) // setNext is used to pass in the next url got from graph setNext(string) // reset is used to clear delta url in delta pagers. When @@ -119,8 +119,6 @@ func getItemsAddedAndRemovedFromContainer( addedIDs = []string{} removedIDs = []string{} deltaURL string - nextLink string - deltaLink string ) itemCount := 0 @@ -160,13 +158,7 @@ func getItemsAddedAndRemovedFromContainer( } } - dresp, ok := resp.(api.DeltaPageLinker) - if ok { - nextLink, deltaLink = api.NextAndDeltaLink(dresp) - } else { - nextLink = api.NextLink(resp) - deltaLink = "" // to make sure we don't use an old value - } + nextLink, deltaLink := api.NextAndDeltaLink(resp) // the deltaLink is kind of like a cursor for overall data state. // once we run through pages of nextLinks, the last query will diff --git a/src/internal/connector/exchange/api/shared_test.go b/src/internal/connector/exchange/api/shared_test.go index 447d1b2c8..6a2fd1e25 100644 --- a/src/internal/connector/exchange/api/shared_test.go +++ b/src/internal/connector/exchange/api/shared_test.go @@ -9,6 +9,7 @@ import ( "github.com/stretchr/testify/require" "github.com/stretchr/testify/suite" + "github.com/alcionai/corso/src/internal/common/ptr" "github.com/alcionai/corso/src/internal/connector/graph" "github.com/alcionai/corso/src/internal/connector/graph/api" "github.com/alcionai/corso/src/internal/tester" @@ -31,8 +32,13 @@ func (v testPagerValue) GetAdditionalData() map[string]any { type testPage struct{} func (p testPage) GetOdataNextLink() *string { - next := "" // no next, just one page - return &next + // no next, just one page + return ptr.To("") +} + +func (p testPage) GetOdataDeltaLink() *string { + // delta is not tested here + return ptr.To("") } var _ itemPager = &testPager{} @@ -45,7 +51,7 @@ type testPager struct { needsReset bool } -func (p *testPager) getPage(ctx context.Context) (api.PageLinker, error) { +func (p *testPager) getPage(ctx context.Context) (api.DeltaPageLinker, error) { if p.errorCode != "" { ierr := odataerrors.NewMainError() ierr.SetCode(&p.errorCode) diff --git a/src/internal/connector/graph/api/api.go b/src/internal/connector/graph/api/api.go index 0870f9ea0..3db26bf85 100644 --- a/src/internal/connector/graph/api/api.go +++ b/src/internal/connector/graph/api/api.go @@ -27,3 +27,25 @@ func NextLink(pl PageLinker) string { func NextAndDeltaLink(pl DeltaPageLinker) (string, string) { return NextLink(pl), ptr.Val(pl.GetOdataDeltaLink()) } + +type Valuer[T any] interface { + GetValue() []T +} + +type PageLinkValuer[T any] interface { + PageLinker + Valuer[T] +} + +// EmptyDeltaLinker is used to convert PageLinker to DeltaPageLinker +type EmptyDeltaLinker[T any] struct { + PageLinkValuer[T] +} + +func (EmptyDeltaLinker[T]) GetOdataDeltaLink() *string { + return ptr.To("") +} + +func (e EmptyDeltaLinker[T]) GetValue() []T { + return e.PageLinkValuer.GetValue() +} diff --git a/src/internal/connector/graph_connector_helper_test.go b/src/internal/connector/graph_connector_helper_test.go index 6066b8671..caaa2c038 100644 --- a/src/internal/connector/graph_connector_helper_test.go +++ b/src/internal/connector/graph_connector_helper_test.go @@ -1,7 +1,6 @@ package connector import ( - "bytes" "context" "encoding/json" "io" @@ -17,33 +16,16 @@ import ( "golang.org/x/exp/slices" "github.com/alcionai/corso/src/internal/common/ptr" - exchMock "github.com/alcionai/corso/src/internal/connector/exchange/mock" "github.com/alcionai/corso/src/internal/connector/onedrive" "github.com/alcionai/corso/src/internal/connector/onedrive/metadata" "github.com/alcionai/corso/src/internal/connector/support" "github.com/alcionai/corso/src/internal/data" "github.com/alcionai/corso/src/internal/tester" - "github.com/alcionai/corso/src/pkg/account" - "github.com/alcionai/corso/src/pkg/control" "github.com/alcionai/corso/src/pkg/fault" "github.com/alcionai/corso/src/pkg/path" "github.com/alcionai/corso/src/pkg/selectors" ) -func mustToDataLayerPath( - t *testing.T, - service path.ServiceType, - tenant, resourceOwner string, - category path.CategoryType, - elements []string, - isItem bool, -) path.Path { - res, err := path.Build(tenant, resourceOwner, service, category, isItem, elements...) - require.NoError(t, err, clues.ToCore(err)) - - return res -} - func testElementsMatch[T any]( t *testing.T, expected []T, @@ -116,52 +98,17 @@ func testElementsMatch[T any]( unexpected) } -type configInfo struct { - acct account.Account - opts control.Options - resource Resource - service path.ServiceType - tenant string - resourceOwners []string - dest control.RestoreDestination -} - -type itemInfo struct { - // lookupKey is a string that can be used to find this data from a set of - // other data in the same collection. This key should be something that will - // be the same before and after restoring the item in M365 and may not be - // the M365 ID. When restoring items out of place, the item is assigned a - // new ID making it unsuitable for a lookup key. - lookupKey string - name string - data []byte -} - -type colInfo struct { - // Elements (in order) for the path representing this collection. Should - // only contain elements after the prefix that corso uses for the path. For - // example, a collection for the Inbox folder in exchange mail would just be - // "Inbox". - pathElements []string - category path.CategoryType - items []itemInfo - // auxItems are items that can be retrieved with Fetch but won't be returned - // by Items(). These files do not directly participate in comparisosn at the - // end of a test. - auxItems []itemInfo -} - type restoreBackupInfo struct { name string service path.ServiceType - collections []colInfo + collections []ColInfo resource Resource } type restoreBackupInfoMultiVersion struct { service path.ServiceType - collectionsLatest []colInfo - collectionsPrevious []colInfo + collectionsLatest []ColInfo + collectionsPrevious []ColInfo resource Resource backupVersion int } @@ -734,7 +681,7 @@ func compareDriveItem( t *testing.T, expected map[string][]byte, item data.Stream, - config configInfo, + config ConfigInfo, rootDir bool, ) bool { // Skip Drive permissions in the folder that used to be the root. We don't @@ -814,7 +761,7 @@ func compareDriveItem( assert.Equal(t, expectedMeta.FileName, itemMeta.FileName) } - if !config.opts.RestorePermissions { + if !config.Opts.RestorePermissions { assert.Equal(t, 0, len(itemMeta.Permissions)) return true } @@ -835,7 +782,7 @@ func compareDriveItem( // sharepoint retrieves a superset of permissions // (all site admins, site groups, built in by default) // relative to the permissions changed by the test. - config.service == path.SharePointService, + config.Service == path.SharePointService, permissionEqual) return true @@ -877,7 +824,7 @@ func compareItem( service path.ServiceType, category path.CategoryType, item data.Stream, - config configInfo, + config ConfigInfo, rootDir bool, ) bool { if mt, ok := item.(data.StreamModTime); ok { @@ -971,7 +918,7 @@ func checkCollections( expectedItems int, expected map[string]map[string][]byte, got []data.BackupCollection, - config configInfo, + config ConfigInfo, ) int { collectionsWithItems := []data.BackupCollection{} @@ -985,7 +932,7 @@ func checkCollections( category = returned.FullPath().Category() expectedColData = expected[returned.FullPath().String()] folders = returned.FullPath().Elements() - rootDir = folders[len(folders)-1] == config.dest.ContainerName + rootDir = folders[len(folders)-1] == config.Dest.ContainerName ) // Need to iterate through all items even if we don't expect to find a match @@ -1166,127 +1113,6 @@ func backupSelectorForExpected( return selectors.Selector{} } -// backupOutputPathFromRestore returns a path.Path denoting the location in -// kopia the data will be placed at. The location is a data-type specific -// combination of the location the data was recently restored to and where the -// data was originally in the hierarchy. -func backupOutputPathFromRestore( - t *testing.T, - restoreDest control.RestoreDestination, - inputPath path.Path, -) path.Path { - base := []string{restoreDest.ContainerName} - - // OneDrive has leading information like the drive ID. - if inputPath.Service() == path.OneDriveService || inputPath.Service() == path.SharePointService { - folders := inputPath.Folders() - base = append(append([]string{}, folders[:3]...), restoreDest.ContainerName) - - if len(folders) > 3 { - base = append(base, folders[3:]...) - } - } - - if inputPath.Service() == path.ExchangeService && inputPath.Category() == path.EmailCategory { - base = append(base, inputPath.Folders()...) - } - - return mustToDataLayerPath( - t, - inputPath.Service(), - inputPath.Tenant(), - inputPath.ResourceOwner(), - inputPath.Category(), - base, - false, - ) -} - -// TODO(ashmrtn): Make this an actual mock class that can be used in other -// packages. -type mockRestoreCollection struct { - data.Collection - auxItems map[string]data.Stream -} - -func (rc mockRestoreCollection) Fetch( - ctx context.Context, - name string, -) (data.Stream, error) { - res := rc.auxItems[name] - if res == nil { - return nil, data.ErrNotFound - } - - return res, nil -} - -func collectionsForInfo( - t *testing.T, - service path.ServiceType, - tenant, user string, - dest control.RestoreDestination, - allInfo []colInfo, - backupVersion int, -) (int, int, []data.RestoreCollection, map[string]map[string][]byte) { - var ( - collections = make([]data.RestoreCollection, 0, len(allInfo)) - expectedData = make(map[string]map[string][]byte, len(allInfo)) - totalItems = 0 - kopiaEntries = 0 - ) - - for _, info := range allInfo { - pth := mustToDataLayerPath( - t, - service, - tenant, - user, - info.category, - info.pathElements, - false) - - mc := exchMock.NewCollection(pth, pth, len(info.items)) - baseDestPath := backupOutputPathFromRestore(t, dest, pth) - - baseExpected := expectedData[baseDestPath.String()] - if len(baseExpected) == 0 { - expectedData[baseDestPath.String()] = make(map[string][]byte, len(info.items)) - baseExpected = expectedData[baseDestPath.String()] - } - - for i := 0; i < len(info.items); i++ { - mc.Names[i] = info.items[i].name - mc.Data[i] = info.items[i].data - - baseExpected[info.items[i].lookupKey] = info.items[i].data - - // We do not count metadata files against item count - if backupVersion > 0 && - (service == path.OneDriveService || service == path.SharePointService) && - metadata.HasMetaSuffix(info.items[i].name) { - continue - } - - totalItems++ - } - - c := mockRestoreCollection{Collection: mc, auxItems: map[string]data.Stream{}} - - for _, aux := range info.auxItems { - c.auxItems[aux.name] = &exchMock.Data{ - ID: aux.name, - Reader: io.NopCloser(bytes.NewReader(aux.data)), - } - } - - collections = append(collections, c) - kopiaEntries += len(info.items) - } - - return totalItems, kopiaEntries, collections, expectedData -} - func getSelectorWith( t *testing.T, service path.ServiceType, diff --git a/src/internal/connector/graph_connector_onedrive_test.go b/src/internal/connector/graph_connector_onedrive_test.go index 2f2fcf486..fad9737d7 100644 --- a/src/internal/connector/graph_connector_onedrive_test.go +++ b/src/internal/connector/graph_connector_onedrive_test.go @@ -2,13 +2,11 @@ package connector import ( "context" - "encoding/json" "fmt" "strings" "testing" "github.com/alcionai/clues" - "github.com/google/uuid" "github.com/microsoftgraph/msgraph-sdk-go/models" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" @@ -25,86 +23,6 @@ import ( "github.com/alcionai/corso/src/pkg/path" ) -// For any version post this(inclusive), we expect to be using IDs for -// permission instead of email -const versionPermissionSwitchedToID = version.OneDrive4DirIncludesPermissions - -func getMetadata(fileName string, perm permData, permUseID bool) metadata.Metadata { - if len(perm.user) == 0 || len(perm.roles) == 0 || - perm.sharingMode != metadata.SharingModeCustom { - return metadata.Metadata{ - FileName: fileName, - SharingMode: perm.sharingMode, - } - } - - // In case of permissions, the id will usually be same for same - // user/role combo unless deleted and readded, but we have to do - // this as we only have two users of which one is already taken. - id := uuid.NewString() - uperm := metadata.Permission{ID: id, Roles: perm.roles} - - if permUseID { - uperm.EntityID = perm.entityID - } else { - uperm.Email = perm.user - } - - testMeta := metadata.Metadata{ - FileName: fileName, - Permissions: []metadata.Permission{uperm}, - } - - return testMeta -} - -type testOneDriveData struct { - FileName string `json:"fileName,omitempty"` - Data []byte `json:"data,omitempty"` -} - -func onedriveItemWithData( - t *testing.T, - name, lookupKey string, - fileData []byte, -) itemInfo { - t.Helper() - - content := testOneDriveData{ - FileName: lookupKey, - Data: fileData, - } - - serialized, err := json.Marshal(content) - require.NoError(t, err, clues.ToCore(err)) - - return itemInfo{ - name: name, - data: serialized, - lookupKey: lookupKey, - } -} - -func onedriveMetadata( - t *testing.T, - fileName, itemID, lookupKey string, - perm permData, - permUseID bool, -) itemInfo { - t.Helper() - - testMeta := getMetadata(fileName, perm, permUseID) - - testMetaJSON, err := json.Marshal(testMeta) - require.NoError(t, err, "marshalling metadata", clues.ToCore(err)) - - return itemInfo{ - name: itemID, - data: testMetaJSON, - lookupKey: lookupKey, - } -} - var ( fileName = "test-file.txt" folderAName = "folder-a" @@ -122,204 +40,6 @@ var ( readPerm = []string{"read"} ) -func newOneDriveCollection( - t *testing.T, - service path.ServiceType, - pathElements []string, - backupVersion int, -) *onedriveCollection { - return &onedriveCollection{ - service: service, - pathElements: pathElements, - backupVersion: backupVersion, - t: t, - } -} - -type onedriveCollection struct { - service path.ServiceType - pathElements []string - items []itemInfo - aux []itemInfo - backupVersion int - t *testing.T -} - -func (c onedriveCollection) collection() colInfo { - cat := path.FilesCategory - if c.service == path.SharePointService { - cat = path.LibrariesCategory - } - - return colInfo{ - pathElements: c.pathElements, - category: cat, - items: c.items, - auxItems: c.aux, - } -} - -func (c *onedriveCollection) withFile(name string, fileData []byte, perm permData) *onedriveCollection { - switch c.backupVersion { - case 0: - // Lookups will occur using the most recent version of things so we need - // the embedded file name to match that. - c.items = append(c.items, onedriveItemWithData( - c.t, - name, - name+metadata.DataFileSuffix, - fileData)) - - // v1-5, early metadata design - case version.OneDrive1DataAndMetaFiles, 2, version.OneDrive3IsMetaMarker, - version.OneDrive4DirIncludesPermissions, version.OneDrive5DirMetaNoName: - c.items = append(c.items, onedriveItemWithData( - c.t, - name+metadata.DataFileSuffix, - name+metadata.DataFileSuffix, - fileData)) - - md := onedriveMetadata( - c.t, - "", - name+metadata.MetaFileSuffix, - name+metadata.MetaFileSuffix, - perm, - c.backupVersion >= versionPermissionSwitchedToID) - c.items = append(c.items, md) - c.aux = append(c.aux, md) - - // v6+ current metadata design - case version.OneDrive6NameInMeta, version.OneDrive7LocationRef, version.All8MigrateUserPNToID: - c.items = append(c.items, onedriveItemWithData( - c.t, - name+metadata.DataFileSuffix, - name+metadata.DataFileSuffix, - fileData)) - - md := onedriveMetadata( - c.t, - name, - name+metadata.MetaFileSuffix, - name, - perm, - c.backupVersion >= versionPermissionSwitchedToID) - c.items = append(c.items, md) - c.aux = append(c.aux, md) - - default: - assert.FailNowf(c.t, "bad backup version", "version %d", c.backupVersion) - } - - return c -} - -func (c *onedriveCollection) withFolder(name string, perm permData) *onedriveCollection { - switch c.backupVersion { - case 0, version.OneDrive4DirIncludesPermissions, version.OneDrive5DirMetaNoName, - version.OneDrive6NameInMeta, version.OneDrive7LocationRef, version.All8MigrateUserPNToID: - return c - - case version.OneDrive1DataAndMetaFiles, 2, version.OneDrive3IsMetaMarker: - c.items = append( - c.items, - onedriveMetadata( - c.t, - "", - name+metadata.DirMetaFileSuffix, - name+metadata.DirMetaFileSuffix, - perm, - c.backupVersion >= versionPermissionSwitchedToID)) - - default: - assert.FailNowf(c.t, "bad backup version", "version %d", c.backupVersion) - } - - return c -} - -// withPermissions adds permissions to the folder represented by this -// onedriveCollection. -func (c *onedriveCollection) withPermissions(perm permData) *onedriveCollection { - // These versions didn't store permissions for the folder or didn't store them - // in the folder's collection. - if c.backupVersion < version.OneDrive4DirIncludesPermissions { - return c - } - - name := c.pathElements[len(c.pathElements)-1] - metaName := name - - if c.backupVersion >= version.OneDrive5DirMetaNoName { - // We switched to just .dirmeta for metadata file names. - metaName = "" - } - - if name == odConsts.RootPathDir { - return c - } - - md := onedriveMetadata( - c.t, - name, - metaName+metadata.DirMetaFileSuffix, - metaName+metadata.DirMetaFileSuffix, - perm, - c.backupVersion >= versionPermissionSwitchedToID) - - c.items = append(c.items, md) - c.aux = append(c.aux, md) - - return c -} - -type permData struct { - user string // user is only for older versions - entityID string - roles []string - sharingMode metadata.SharingMode -} - -type itemData struct { - name string - data []byte - perms permData -} - -type driveColInfo struct { - pathElements []string - perms permData - files []itemData - folders []itemData -} - -func testDataForInfo( - t *testing.T, - service path.ServiceType, - cols []driveColInfo, - backupVersion int, -) []colInfo { - var res []colInfo - - for _, c := range cols { - onedriveCol := newOneDriveCollection(t, service, c.pathElements, backupVersion) - - for _, f := range c.files { - onedriveCol.withFile(f.name, f.data, f.perms) - } - - for _, d := range c.folders { - onedriveCol.withFolder(d.name, d.perms) - } - - onedriveCol.withPermissions(c.perms) - - res = append(res, onedriveCol.collection()) - } - - return res -} - func mustGetDefaultDriveID( t *testing.T, ctx context.Context, //revive:disable-line:context-as-argument @@ -675,78 +395,80 @@ func testRestoreAndBackupMultipleFilesAndFoldersNoPermissions( folderBName, } - cols := []driveColInfo{ + cols := []OnedriveColInfo{ { - pathElements: rootPath, - files: []itemData{ + PathElements: rootPath, + Files: []ItemData{ { - name: fileName, - data: fileAData, + Name: fileName, + Data: fileAData, }, }, - folders: []itemData{ + Folders: []ItemData{ { - name: folderAName, + Name: folderAName, }, { - name: folderBName, + Name: folderBName, }, }, }, { - pathElements: folderAPath, - files: []itemData{ + PathElements: folderAPath, + Files: []ItemData{ { - name: fileName, - data: fileBData, + Name: fileName, + Data: fileBData, }, }, - folders: []itemData{ + Folders: []ItemData{ { - name: folderBName, + Name: folderBName, }, }, }, { - pathElements: subfolderBPath, - files: []itemData{ + PathElements: subfolderBPath, + Files: []ItemData{ { - name: fileName, - data: fileCData, + Name: fileName, + Data: fileCData, }, }, - folders: []itemData{ + Folders: []ItemData{ { - name: folderAName, + Name: folderAName, }, }, }, { - pathElements: subfolderAPath, - files: []itemData{ + PathElements: subfolderAPath, + Files: []ItemData{ { - name: fileName, - data: fileDData, + Name: fileName, + Data: fileDData, }, }, }, { - pathElements: folderBPath, - files: []itemData{ + PathElements: folderBPath, + Files: []ItemData{ { - name: fileName, - data: fileEData, + Name: fileName, + Data: fileEData, }, }, }, } - expected := testDataForInfo(suite.T(), suite.BackupService(), cols, version.Backup) + expected, err := DataForInfo(suite.BackupService(), cols, version.Backup) + require.NoError(suite.T(), err) for vn := startVersion; vn <= version.Backup; vn++ { suite.Run(fmt.Sprintf("Version%d", vn), func() { t := suite.T() - input := testDataForInfo(t, suite.BackupService(), cols, vn) + input, err := DataForInfo(suite.BackupService(), cols, vn) + require.NoError(suite.T(), err) testData := restoreBackupInfoMultiVersion{ service: suite.BackupService(), @@ -819,71 +541,71 @@ func testPermissionsRestoreAndBackup(suite oneDriveSuite, startVersion int) { folderCName, } - cols := []driveColInfo{ + cols := []OnedriveColInfo{ { - pathElements: rootPath, - files: []itemData{ + PathElements: rootPath, + Files: []ItemData{ { // Test restoring a file that doesn't inherit permissions. - name: fileName, - data: fileAData, - perms: permData{ - user: secondaryUserName, - entityID: secondaryUserID, - roles: writePerm, + Name: fileName, + Data: fileAData, + Perms: PermData{ + User: secondaryUserName, + EntityID: secondaryUserID, + Roles: writePerm, }, }, { // Test restoring a file that doesn't inherit permissions and has // no permissions. - name: fileName2, - data: fileBData, + Name: fileName2, + Data: fileBData, }, }, - folders: []itemData{ + Folders: []ItemData{ { - name: folderBName, + Name: folderBName, }, { - name: folderAName, - perms: permData{ - user: secondaryUserName, - entityID: secondaryUserID, - roles: readPerm, + Name: folderAName, + Perms: PermData{ + User: secondaryUserName, + EntityID: secondaryUserID, + Roles: readPerm, }, }, { - name: folderCName, - perms: permData{ - user: secondaryUserName, - entityID: secondaryUserID, - roles: readPerm, + Name: folderCName, + Perms: PermData{ + User: secondaryUserName, + EntityID: secondaryUserID, + Roles: readPerm, }, }, }, }, { - pathElements: folderBPath, - files: []itemData{ + PathElements: folderBPath, + Files: []ItemData{ { // Test restoring a file in a non-root folder that doesn't inherit // permissions. - name: fileName, - data: fileBData, - perms: permData{ - user: secondaryUserName, - entityID: secondaryUserID, - roles: writePerm, + Name: fileName, + Data: fileBData, + Perms: PermData{ + User: secondaryUserName, + EntityID: secondaryUserID, + Roles: writePerm, }, }, }, - folders: []itemData{ + Folders: []ItemData{ { - name: folderAName, - perms: permData{ - user: secondaryUserName, - entityID: secondaryUserID, - roles: readPerm, + Name: folderAName, + Perms: PermData{ + User: secondaryUserName, + EntityID: secondaryUserID, + Roles: readPerm, }, }, }, @@ -905,52 +627,53 @@ func testPermissionsRestoreAndBackup(suite oneDriveSuite, startVersion int) { // }, // }, // }, - // perms: permData{ - // user: secondaryUserName, - // entityID: secondaryUserID, - // roles: readPerm, + // Perms: PermData{ + // User: secondaryUserName, + // EntityID: secondaryUserID, + // Roles: readPerm, // }, // }, { // Tests a folder that has permissions with an item in the folder with // the different permissions. - pathElements: folderAPath, - files: []itemData{ + PathElements: folderAPath, + Files: []ItemData{ { - name: fileName, - data: fileEData, - perms: permData{ - user: secondaryUserName, - entityID: secondaryUserID, - roles: writePerm, + Name: fileName, + Data: fileEData, + Perms: PermData{ + User: secondaryUserName, + EntityID: secondaryUserID, + Roles: writePerm, }, }, }, - perms: permData{ - user: secondaryUserName, - entityID: secondaryUserID, - roles: readPerm, + Perms: PermData{ + User: secondaryUserName, + EntityID: secondaryUserID, + Roles: readPerm, }, }, { // Tests a folder that has permissions with an item in the folder with // no permissions. - pathElements: folderCPath, - files: []itemData{ + PathElements: folderCPath, + Files: []ItemData{ { - name: fileName, - data: fileAData, + Name: fileName, + Data: fileAData, }, }, - perms: permData{ - user: secondaryUserName, - entityID: secondaryUserID, - roles: readPerm, + Perms: PermData{ + User: secondaryUserName, + EntityID: secondaryUserID, + Roles: readPerm, }, }, } - expected := testDataForInfo(suite.T(), suite.BackupService(), cols, version.Backup) + expected, err := DataForInfo(suite.BackupService(), cols, version.Backup) + require.NoError(suite.T(), err) bss := suite.BackupService().String() for vn := startVersion; vn <= version.Backup; vn++ { @@ -959,7 +682,8 @@ func testPermissionsRestoreAndBackup(suite oneDriveSuite, startVersion int) { // Ideally this can always be true or false and still // work, but limiting older versions to use emails so as // to validate that flow as well. - input := testDataForInfo(t, suite.BackupService(), cols, vn) + input, err := DataForInfo(suite.BackupService(), cols, vn) + require.NoError(suite.T(), err) testData := restoreBackupInfoMultiVersion{ service: suite.BackupService(), @@ -997,51 +721,53 @@ func testPermissionsBackupAndNoRestore(suite oneDriveSuite, startVersion int) { suite.Service(), suite.BackupResourceOwner()) - inputCols := []driveColInfo{ + inputCols := []OnedriveColInfo{ { - pathElements: []string{ + PathElements: []string{ odConsts.DrivesPathDir, driveID, odConsts.RootPathDir, }, - files: []itemData{ + Files: []ItemData{ { - name: fileName, - data: fileAData, - perms: permData{ - user: secondaryUserName, - entityID: secondaryUserID, - roles: writePerm, + Name: fileName, + Data: fileAData, + Perms: PermData{ + User: secondaryUserName, + EntityID: secondaryUserID, + Roles: writePerm, }, }, }, }, } - expectedCols := []driveColInfo{ + expectedCols := []OnedriveColInfo{ { - pathElements: []string{ + PathElements: []string{ odConsts.DrivesPathDir, driveID, odConsts.RootPathDir, }, - files: []itemData{ + Files: []ItemData{ { // No permissions on the output since they weren't restored. - name: fileName, - data: fileAData, + Name: fileName, + Data: fileAData, }, }, }, } - expected := testDataForInfo(suite.T(), suite.BackupService(), expectedCols, version.Backup) + expected, err := DataForInfo(suite.BackupService(), expectedCols, version.Backup) + require.NoError(suite.T(), err) bss := suite.BackupService().String() for vn := startVersion; vn <= version.Backup; vn++ { suite.Run(fmt.Sprintf("%s-Version%d", bss, vn), func() { t := suite.T() - input := testDataForInfo(t, suite.BackupService(), inputCols, vn) + input, err := DataForInfo(suite.BackupService(), inputCols, vn) + require.NoError(suite.T(), err) testData := restoreBackupInfoMultiVersion{ service: suite.BackupService(), @@ -1119,29 +845,29 @@ func testPermissionsInheritanceRestoreAndBackup(suite oneDriveSuite, startVersio folderCName, } - fileSet := []itemData{ + fileSet := []ItemData{ { - name: "file-custom", - data: fileAData, - perms: permData{ - user: secondaryUserName, - entityID: secondaryUserID, - roles: writePerm, - sharingMode: metadata.SharingModeCustom, + Name: "file-custom", + Data: fileAData, + Perms: PermData{ + User: secondaryUserName, + EntityID: secondaryUserID, + Roles: writePerm, + SharingMode: metadata.SharingModeCustom, }, }, { - name: "file-inherited", - data: fileAData, - perms: permData{ - sharingMode: metadata.SharingModeInherited, + Name: "file-inherited", + Data: fileAData, + Perms: PermData{ + SharingMode: metadata.SharingModeInherited, }, }, { - name: "file-empty", - data: fileAData, - perms: permData{ - sharingMode: metadata.SharingModeCustom, + Name: "file-empty", + Data: fileAData, + Perms: PermData{ + SharingMode: metadata.SharingModeCustom, }, }, } @@ -1164,55 +890,56 @@ func testPermissionsInheritanceRestoreAndBackup(suite oneDriveSuite, startVersio // - inherted-permission-file // - empty-permission-file (empty/empty might have interesting behavior) - cols := []driveColInfo{ + cols := []OnedriveColInfo{ { - pathElements: rootPath, - files: []itemData{}, - folders: []itemData{ - {name: folderAName}, + PathElements: rootPath, + Files: []ItemData{}, + Folders: []ItemData{ + {Name: folderAName}, }, }, { - pathElements: folderAPath, - files: fileSet, - folders: []itemData{ - {name: folderAName}, - {name: folderBName}, - {name: folderCName}, + PathElements: folderAPath, + Files: fileSet, + Folders: []ItemData{ + {Name: folderAName}, + {Name: folderBName}, + {Name: folderCName}, }, - perms: permData{ - user: tertiaryUserName, - entityID: tertiaryUserID, - roles: readPerm, + Perms: PermData{ + User: tertiaryUserName, + EntityID: tertiaryUserID, + Roles: readPerm, }, }, { - pathElements: subfolderAAPath, - files: fileSet, - perms: permData{ - user: tertiaryUserName, - entityID: tertiaryUserID, - roles: writePerm, - sharingMode: metadata.SharingModeCustom, + PathElements: subfolderAAPath, + Files: fileSet, + Perms: PermData{ + User: tertiaryUserName, + EntityID: tertiaryUserID, + Roles: writePerm, + SharingMode: metadata.SharingModeCustom, }, }, { - pathElements: subfolderABPath, - files: fileSet, - perms: permData{ - sharingMode: metadata.SharingModeInherited, + PathElements: subfolderABPath, + Files: fileSet, + Perms: PermData{ + SharingMode: metadata.SharingModeInherited, }, }, { - pathElements: subfolderACPath, - files: fileSet, - perms: permData{ - sharingMode: metadata.SharingModeCustom, + PathElements: subfolderACPath, + Files: fileSet, + Perms: PermData{ + SharingMode: metadata.SharingModeCustom, }, }, } - expected := testDataForInfo(suite.T(), suite.BackupService(), cols, version.Backup) + expected, err := DataForInfo(suite.BackupService(), cols, version.Backup) + require.NoError(suite.T(), err) bss := suite.BackupService().String() for vn := startVersion; vn <= version.Backup; vn++ { @@ -1221,7 +948,8 @@ func testPermissionsInheritanceRestoreAndBackup(suite oneDriveSuite, startVersio // Ideally this can always be true or false and still // work, but limiting older versions to use emails so as // to validate that flow as well. - input := testDataForInfo(t, suite.BackupService(), cols, vn) + input, err := DataForInfo(suite.BackupService(), cols, vn) + require.NoError(suite.T(), err) testData := restoreBackupInfoMultiVersion{ service: suite.BackupService(), @@ -1279,61 +1007,63 @@ func testRestoreFolderNamedFolderRegression( folderBName, } - cols := []driveColInfo{ + cols := []OnedriveColInfo{ { - pathElements: rootPath, - files: []itemData{ + PathElements: rootPath, + Files: []ItemData{ { - name: fileName, - data: fileAData, + Name: fileName, + Data: fileAData, }, }, - folders: []itemData{ + Folders: []ItemData{ { - name: folderNamedFolder, + Name: folderNamedFolder, }, { - name: folderBName, + Name: folderBName, }, }, }, { - pathElements: folderFolderPath, - files: []itemData{ + PathElements: folderFolderPath, + Files: []ItemData{ { - name: fileName, - data: fileBData, + Name: fileName, + Data: fileBData, }, }, - folders: []itemData{ + Folders: []ItemData{ { - name: folderBName, + Name: folderBName, }, }, }, { - pathElements: subfolderPath, - files: []itemData{ + PathElements: subfolderPath, + Files: []ItemData{ { - name: fileName, - data: fileCData, + Name: fileName, + Data: fileCData, }, }, - folders: []itemData{ + Folders: []ItemData{ { - name: folderNamedFolder, + Name: folderNamedFolder, }, }, }, } - expected := testDataForInfo(suite.T(), suite.BackupService(), cols, version.Backup) + expected, err := DataForInfo(suite.BackupService(), cols, version.Backup) + require.NoError(suite.T(), err) bss := suite.BackupService().String() for vn := startVersion; vn <= version.Backup; vn++ { suite.Run(fmt.Sprintf("%s-Version%d", bss, vn), func() { t := suite.T() - input := testDataForInfo(t, suite.BackupService(), cols, vn) + input, err := DataForInfo(suite.BackupService(), cols, vn) + require.NoError(suite.T(), err) testData := restoreBackupInfoMultiVersion{ service: suite.BackupService(), diff --git a/src/internal/connector/graph_connector_onedrive_test_helper.go b/src/internal/connector/graph_connector_onedrive_test_helper.go new file mode 100644 index 000000000..38b760b1a --- /dev/null +++ b/src/internal/connector/graph_connector_onedrive_test_helper.go @@ -0,0 +1,358 @@ +package connector + +import ( + "encoding/json" + "fmt" + + "github.com/alcionai/clues" + "github.com/google/uuid" + "golang.org/x/exp/maps" + + odConsts "github.com/alcionai/corso/src/internal/connector/onedrive/consts" + "github.com/alcionai/corso/src/internal/connector/onedrive/metadata" + "github.com/alcionai/corso/src/internal/data" + "github.com/alcionai/corso/src/internal/version" + "github.com/alcionai/corso/src/pkg/path" +) + +// For any version post this(inclusive), we expect to be using IDs for +// permission instead of email +const versionPermissionSwitchedToID = version.OneDrive4DirIncludesPermissions + +func getMetadata(fileName string, perm PermData, permUseID bool) metadata.Metadata { + if len(perm.User) == 0 || len(perm.Roles) == 0 || + perm.SharingMode != metadata.SharingModeCustom { + return metadata.Metadata{ + FileName: fileName, + SharingMode: perm.SharingMode, + } + } + + // In case of permissions, the id will usually be same for same + // user/role combo unless deleted and readded, but we have to do + // this as we only have two users of which one is already taken. + id := uuid.NewString() + uperm := metadata.Permission{ID: id, Roles: perm.Roles} + + if permUseID { + uperm.EntityID = perm.EntityID + } else { + uperm.Email = perm.User + } + + testMeta := metadata.Metadata{ + FileName: fileName, + Permissions: []metadata.Permission{uperm}, + } + + return testMeta +} + +type PermData struct { + User string // user is only for older versions + EntityID string + Roles []string + SharingMode metadata.SharingMode +} + +type ItemData struct { + Name string + Data []byte + Perms PermData +} + +type OnedriveColInfo struct { + PathElements []string + Perms PermData + Files []ItemData + Folders []ItemData +} + +type onedriveCollection struct { + service path.ServiceType + PathElements []string + items []ItemInfo + aux []ItemInfo + backupVersion int +} + +func (c onedriveCollection) collection() ColInfo { + cat := path.FilesCategory + if c.service == path.SharePointService { + cat = path.LibrariesCategory + } + + return ColInfo{ + PathElements: c.PathElements, + Category: cat, + Items: c.items, + AuxItems: c.aux, + } +} + +func NewOneDriveCollection( + service path.ServiceType, + PathElements []string, + backupVersion int, +) *onedriveCollection { + return &onedriveCollection{ + service: service, + PathElements: PathElements, + backupVersion: backupVersion, + } +} + +func DataForInfo( + service path.ServiceType, + cols []OnedriveColInfo, + backupVersion int, +) ([]ColInfo, error) { + var ( + res []ColInfo + err error + ) + + for _, c := range cols { + onedriveCol := NewOneDriveCollection(service, c.PathElements, backupVersion) + + for _, f := range c.Files { + _, err = onedriveCol.withFile(f.Name, f.Data, f.Perms) + if err != nil { + return res, err + } + } + + for _, d := range c.Folders { + _, err = onedriveCol.withFolder(d.Name, d.Perms) + if err != nil { + return res, err + } + } + + _, err = onedriveCol.withPermissions(c.Perms) + if err != nil { + return res, err + } + + res = append(res, onedriveCol.collection()) + } + + return res, nil +} + +func (c *onedriveCollection) withFile(name string, fileData []byte, perm PermData) (*onedriveCollection, error) { + switch c.backupVersion { + case 0: + // Lookups will occur using the most recent version of things so we need + // the embedded file name to match that. + item, err := onedriveItemWithData( + name, + name+metadata.DataFileSuffix, + fileData) + if err != nil { + return c, err + } + + c.items = append(c.items, item) + + // v1-5, early metadata design + case version.OneDrive1DataAndMetaFiles, 2, version.OneDrive3IsMetaMarker, + version.OneDrive4DirIncludesPermissions, version.OneDrive5DirMetaNoName: + items, err := onedriveItemWithData( + name+metadata.DataFileSuffix, + name+metadata.DataFileSuffix, + fileData) + if err != nil { + return c, err + } + + c.items = append(c.items, items) + + md, err := onedriveMetadata( + "", + name+metadata.MetaFileSuffix, + name+metadata.MetaFileSuffix, + perm, + c.backupVersion >= versionPermissionSwitchedToID) + if err != nil { + return c, err + } + + c.items = append(c.items, md) + c.aux = append(c.aux, md) + + // v6+ current metadata design + case version.OneDrive6NameInMeta, version.OneDrive7LocationRef, version.All8MigrateUserPNToID: + item, err := onedriveItemWithData( + name+metadata.DataFileSuffix, + name+metadata.DataFileSuffix, + fileData) + if err != nil { + return c, err + } + + c.items = append(c.items, item) + + md, err := onedriveMetadata( + name, + name+metadata.MetaFileSuffix, + name, + perm, + c.backupVersion >= versionPermissionSwitchedToID) + if err != nil { + return c, err + } + + c.items = append(c.items, md) + c.aux = append(c.aux, md) + + default: + return c, clues.New(fmt.Sprintf("bad backup version. version %d", c.backupVersion)) + } + + return c, nil +} + +func (c *onedriveCollection) withFolder(name string, perm PermData) (*onedriveCollection, error) { + switch c.backupVersion { + case 0, version.OneDrive4DirIncludesPermissions, version.OneDrive5DirMetaNoName, + version.OneDrive6NameInMeta, version.OneDrive7LocationRef, version.All8MigrateUserPNToID: + return c, nil + + case version.OneDrive1DataAndMetaFiles, 2, version.OneDrive3IsMetaMarker: + item, err := onedriveMetadata( + "", + name+metadata.DirMetaFileSuffix, + name+metadata.DirMetaFileSuffix, + perm, + c.backupVersion >= versionPermissionSwitchedToID) + + c.items = append(c.items, item) + + if err != nil { + return c, err + } + + default: + return c, clues.New(fmt.Sprintf("bad backup version.version %d", c.backupVersion)) + } + + return c, nil +} + +// withPermissions adds permissions to the folder represented by this +// onedriveCollection. +func (c *onedriveCollection) withPermissions(perm PermData) (*onedriveCollection, error) { + // These versions didn't store permissions for the folder or didn't store them + // in the folder's collection. + if c.backupVersion < version.OneDrive4DirIncludesPermissions { + return c, nil + } + + name := c.PathElements[len(c.PathElements)-1] + metaName := name + + if c.backupVersion >= version.OneDrive5DirMetaNoName { + // We switched to just .dirmeta for metadata file names. + metaName = "" + } + + if name == odConsts.RootPathDir { + return c, nil + } + + md, err := onedriveMetadata( + name, + metaName+metadata.DirMetaFileSuffix, + metaName+metadata.DirMetaFileSuffix, + perm, + c.backupVersion >= versionPermissionSwitchedToID) + if err != nil { + return c, err + } + + c.items = append(c.items, md) + c.aux = append(c.aux, md) + + return c, err +} + +type testOneDriveData struct { + FileName string `json:"fileName,omitempty"` + Data []byte `json:"data,omitempty"` +} + +func onedriveItemWithData( + name, lookupKey string, + fileData []byte, +) (ItemInfo, error) { + content := testOneDriveData{ + FileName: lookupKey, + Data: fileData, + } + + serialized, err := json.Marshal(content) + if err != nil { + return ItemInfo{}, clues.Stack(err) + } + + return ItemInfo{ + name: name, + data: serialized, + lookupKey: lookupKey, + }, nil +} + +func onedriveMetadata( + fileName, itemID, lookupKey string, + perm PermData, + permUseID bool, +) (ItemInfo, error) { + testMeta := getMetadata(fileName, perm, permUseID) + + testMetaJSON, err := json.Marshal(testMeta) + if err != nil { + return ItemInfo{}, clues.Wrap(err, "marshalling metadata") + } + + return ItemInfo{ + name: itemID, + data: testMetaJSON, + lookupKey: lookupKey, + }, nil +} + +func GetCollectionsAndExpected( + config ConfigInfo, + testCollections []ColInfo, + backupVersion int, +) (int, int, []data.RestoreCollection, map[string]map[string][]byte, error) { + var ( + collections []data.RestoreCollection + expectedData = map[string]map[string][]byte{} + totalItems = 0 + totalKopiaItems = 0 + ) + + for _, owner := range config.ResourceOwners { + numItems, kopiaItems, ownerCollections, userExpectedData, err := collectionsForInfo( + config.Service, + config.Tenant, + owner, + config.Dest, + testCollections, + backupVersion, + ) + if err != nil { + return totalItems, totalKopiaItems, collections, expectedData, err + } + + collections = append(collections, ownerCollections...) + totalItems += numItems + totalKopiaItems += kopiaItems + + maps.Copy(expectedData, userExpectedData) + } + + return totalItems, totalKopiaItems, collections, expectedData, nil +} diff --git a/src/internal/connector/graph_connector_test.go b/src/internal/connector/graph_connector_test.go index de50e8ddb..e8906d35b 100644 --- a/src/internal/connector/graph_connector_test.go +++ b/src/internal/connector/graph_connector_test.go @@ -11,7 +11,6 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "github.com/stretchr/testify/suite" - "golang.org/x/exp/maps" inMock "github.com/alcionai/corso/src/internal/common/idname/mock" exchMock "github.com/alcionai/corso/src/internal/connector/exchange/mock" @@ -407,65 +406,30 @@ func (suite *GraphConnectorIntegrationSuite) TestEmptyCollections() { // Exchange Functions //------------------------------------------------------------- -func getCollectionsAndExpected( - t *testing.T, - config configInfo, - testCollections []colInfo, - backupVersion int, -) (int, int, []data.RestoreCollection, map[string]map[string][]byte) { - t.Helper() - - var ( - collections []data.RestoreCollection - expectedData = map[string]map[string][]byte{} - totalItems = 0 - totalKopiaItems = 0 - ) - - for _, owner := range config.resourceOwners { - numItems, kopiaItems, ownerCollections, userExpectedData := collectionsForInfo( - t, - config.service, - config.tenant, - owner, - config.dest, - testCollections, - backupVersion) - - collections = append(collections, ownerCollections...) - totalItems += numItems - totalKopiaItems += kopiaItems - - maps.Copy(expectedData, userExpectedData) - } - - return totalItems, totalKopiaItems, collections, expectedData -} - func runRestore( t *testing.T, ctx context.Context, //revive:disable-line:context-as-argument - config configInfo, + config ConfigInfo, backupVersion int, collections []data.RestoreCollection, numRestoreItems int, ) { t.Logf( "Restoring collections to %s for resourceOwners(s) %v\n", - config.dest.ContainerName, - config.resourceOwners) + config.Dest.ContainerName, + config.ResourceOwners) start := time.Now() - restoreGC := loadConnector(ctx, t, config.resource) - restoreSel := getSelectorWith(t, config.service, config.resourceOwners, true) + restoreGC := loadConnector(ctx, t, config.Resource) + restoreSel := getSelectorWith(t, config.Service, config.ResourceOwners, true) deets, err := restoreGC.ConsumeRestoreCollections( ctx, backupVersion, - config.acct, + config.Acct, restoreSel, - config.dest, - config.opts, + config.Dest, + config.Opts, collections, fault.New(true)) require.NoError(t, err, clues.ToCore(err)) @@ -489,30 +453,30 @@ func runRestore( func runBackupAndCompare( t *testing.T, ctx context.Context, //revive:disable-line:context-as-argument - config configInfo, + config ConfigInfo, expectedData map[string]map[string][]byte, totalItems int, totalKopiaItems int, - inputCollections []colInfo, + inputCollections []ColInfo, ) { t.Helper() // Run a backup and compare its output with what we put in. cats := make(map[path.CategoryType]struct{}, len(inputCollections)) for _, c := range inputCollections { - cats[c.category] = struct{}{} + cats[c.Category] = struct{}{} } var ( - expectedDests = make([]destAndCats, 0, len(config.resourceOwners)) + expectedDests = make([]destAndCats, 0, len(config.ResourceOwners)) idToName = map[string]string{} nameToID = map[string]string{} ) - for _, ro := range config.resourceOwners { + for _, ro := range config.ResourceOwners { expectedDests = append(expectedDests, destAndCats{ resourceOwner: ro, - dest: config.dest.ContainerName, + dest: config.Dest.ContainerName, cats: cats, }) @@ -520,10 +484,10 @@ func runBackupAndCompare( nameToID[ro] = ro } - backupGC := loadConnector(ctx, t, config.resource) + backupGC := loadConnector(ctx, t, config.Resource) backupGC.IDNameLookup = inMock.NewCache(idToName, nameToID) - backupSel := backupSelectorForExpected(t, config.service, expectedDests) + backupSel := backupSelectorForExpected(t, config.Service, expectedDests) t.Logf("Selective backup of %s\n", backupSel) start := time.Now() @@ -533,7 +497,7 @@ func runBackupAndCompare( backupSel, nil, version.NoBackup, - config.opts, + config.Opts, fault.New(true)) require.NoError(t, err, clues.ToCore(err)) // No excludes yet because this isn't an incremental backup. @@ -570,22 +534,23 @@ func runRestoreBackupTest( ctx, flush := tester.NewContext() defer flush() - config := configInfo{ - acct: acct, - opts: opts, - resource: test.resource, - service: test.service, - tenant: tenant, - resourceOwners: resourceOwners, - dest: tester.DefaultTestRestoreDestination(""), + config := ConfigInfo{ + Acct: acct, + Opts: opts, + Resource: test.resource, + Service: test.service, + Tenant: tenant, + ResourceOwners: resourceOwners, + Dest: tester.DefaultTestRestoreDestination(""), } - totalItems, totalKopiaItems, collections, expectedData := getCollectionsAndExpected( - t, + totalItems, totalKopiaItems, collections, expectedData, err := GetCollectionsAndExpected( config, test.collections, version.Backup) + require.NoError(t, err) + runRestore( t, ctx, @@ -616,21 +581,21 @@ func runRestoreTestWithVerion( ctx, flush := tester.NewContext() defer flush() - config := configInfo{ - acct: acct, - opts: opts, - resource: test.resource, - service: test.service, - tenant: tenant, - resourceOwners: resourceOwners, - dest: tester.DefaultTestRestoreDestination(""), + config := ConfigInfo{ + Acct: acct, + Opts: opts, + Resource: test.resource, + Service: test.service, + Tenant: tenant, + ResourceOwners: resourceOwners, + Dest: tester.DefaultTestRestoreDestination(""), } - totalItems, _, collections, _ := getCollectionsAndExpected( - t, + totalItems, _, collections, _, err := GetCollectionsAndExpected( config, test.collectionsPrevious, test.backupVersion) + require.NoError(t, err) runRestore( t, @@ -655,21 +620,21 @@ func runRestoreBackupTestVersions( ctx, flush := tester.NewContext() defer flush() - config := configInfo{ - acct: acct, - opts: opts, - resource: test.resource, - service: test.service, - tenant: tenant, - resourceOwners: resourceOwners, - dest: tester.DefaultTestRestoreDestination(""), + config := ConfigInfo{ + Acct: acct, + Opts: opts, + Resource: test.resource, + Service: test.service, + Tenant: tenant, + ResourceOwners: resourceOwners, + Dest: tester.DefaultTestRestoreDestination(""), } - totalItems, _, collections, _ := getCollectionsAndExpected( - t, + totalItems, _, collections, _, err := GetCollectionsAndExpected( config, test.collectionsPrevious, test.backupVersion) + require.NoError(t, err) runRestore( t, @@ -680,11 +645,11 @@ func runRestoreBackupTestVersions( totalItems) // Get expected output for new version. - totalItems, totalKopiaItems, _, expectedData := getCollectionsAndExpected( - t, + totalItems, totalKopiaItems, _, expectedData, err := GetCollectionsAndExpected( config, test.collectionsLatest, version.Backup) + require.NoError(t, err) runBackupAndCompare( t, @@ -705,11 +670,11 @@ func (suite *GraphConnectorIntegrationSuite) TestRestoreAndBackup() { name: "EmailsWithAttachments", service: path.ExchangeService, resource: Users, - collections: []colInfo{ + collections: []ColInfo{ { - pathElements: []string{"Inbox"}, - category: path.EmailCategory, - items: []itemInfo{ + PathElements: []string{"Inbox"}, + Category: path.EmailCategory, + Items: []ItemInfo{ { name: "someencodeditemID", data: exchMock.MessageWithDirectAttachment( @@ -732,11 +697,11 @@ func (suite *GraphConnectorIntegrationSuite) TestRestoreAndBackup() { name: "MultipleEmailsMultipleFolders", service: path.ExchangeService, resource: Users, - collections: []colInfo{ + collections: []ColInfo{ { - pathElements: []string{"Inbox"}, - category: path.EmailCategory, - items: []itemInfo{ + PathElements: []string{"Inbox"}, + Category: path.EmailCategory, + Items: []ItemInfo{ { name: "someencodeditemID", data: exchMock.MessageWithBodyBytes( @@ -749,9 +714,9 @@ func (suite *GraphConnectorIntegrationSuite) TestRestoreAndBackup() { }, }, { - pathElements: []string{"Work"}, - category: path.EmailCategory, - items: []itemInfo{ + PathElements: []string{"Work"}, + Category: path.EmailCategory, + Items: []ItemInfo{ { name: "someencodeditemID2", data: exchMock.MessageWithBodyBytes( @@ -773,9 +738,9 @@ func (suite *GraphConnectorIntegrationSuite) TestRestoreAndBackup() { }, }, { - pathElements: []string{"Work", "Inbox"}, - category: path.EmailCategory, - items: []itemInfo{ + PathElements: []string{"Work", "Inbox"}, + Category: path.EmailCategory, + Items: []ItemInfo{ { name: "someencodeditemID4", data: exchMock.MessageWithBodyBytes( @@ -788,9 +753,9 @@ func (suite *GraphConnectorIntegrationSuite) TestRestoreAndBackup() { }, }, { - pathElements: []string{"Work", "Inbox", "Work"}, - category: path.EmailCategory, - items: []itemInfo{ + PathElements: []string{"Work", "Inbox", "Work"}, + Category: path.EmailCategory, + Items: []ItemInfo{ { name: "someencodeditemID5", data: exchMock.MessageWithBodyBytes( @@ -808,11 +773,11 @@ func (suite *GraphConnectorIntegrationSuite) TestRestoreAndBackup() { name: "MultipleContactsSingleFolder", service: path.ExchangeService, resource: Users, - collections: []colInfo{ + collections: []ColInfo{ { - pathElements: []string{"Contacts"}, - category: path.ContactsCategory, - items: []itemInfo{ + PathElements: []string{"Contacts"}, + Category: path.ContactsCategory, + Items: []ItemInfo{ { name: "someencodeditemID", data: exchMock.ContactBytes("Ghimley"), @@ -836,11 +801,11 @@ func (suite *GraphConnectorIntegrationSuite) TestRestoreAndBackup() { name: "MultipleContactsMultipleFolders", service: path.ExchangeService, resource: Users, - collections: []colInfo{ + collections: []ColInfo{ { - pathElements: []string{"Work"}, - category: path.ContactsCategory, - items: []itemInfo{ + PathElements: []string{"Work"}, + Category: path.ContactsCategory, + Items: []ItemInfo{ { name: "someencodeditemID", data: exchMock.ContactBytes("Ghimley"), @@ -859,9 +824,9 @@ func (suite *GraphConnectorIntegrationSuite) TestRestoreAndBackup() { }, }, { - pathElements: []string{"Personal"}, - category: path.ContactsCategory, - items: []itemInfo{ + PathElements: []string{"Personal"}, + Category: path.ContactsCategory, + Items: []ItemInfo{ { name: "someencodeditemID4", data: exchMock.ContactBytes("Argon"), @@ -971,11 +936,11 @@ func (suite *GraphConnectorIntegrationSuite) TestMultiFolderBackupDifferentNames name: "Contacts", service: path.ExchangeService, resource: Users, - collections: []colInfo{ + collections: []ColInfo{ { - pathElements: []string{"Work"}, - category: path.ContactsCategory, - items: []itemInfo{ + PathElements: []string{"Work"}, + Category: path.ContactsCategory, + Items: []ItemInfo{ { name: "someencodeditemID", data: exchMock.ContactBytes("Ghimley"), @@ -984,9 +949,9 @@ func (suite *GraphConnectorIntegrationSuite) TestMultiFolderBackupDifferentNames }, }, { - pathElements: []string{"Personal"}, - category: path.ContactsCategory, - items: []itemInfo{ + PathElements: []string{"Personal"}, + Category: path.ContactsCategory, + Items: []ItemInfo{ { name: "someencodeditemID2", data: exchMock.ContactBytes("Irgot"), @@ -1012,9 +977,9 @@ func (suite *GraphConnectorIntegrationSuite) TestMultiFolderBackupDifferentNames // }, // }, // { - // pathElements: []string{"Personal"}, - // category: path.EventsCategory, - // items: []itemInfo{ + // PathElements: []string{"Personal"}, + // Category: path.EventsCategory, + // Items: []ItemInfo{ // { // name: "someencodeditemID2", // data: exchMock.EventWithSubjectBytes("Irgot"), @@ -1045,19 +1010,20 @@ func (suite *GraphConnectorIntegrationSuite) TestMultiFolderBackupDifferentNames resourceOwner: suite.user, dest: dest.ContainerName, cats: map[path.CategoryType]struct{}{ - collection.category: {}, + collection.Category: {}, }, }) - totalItems, _, collections, expectedData := collectionsForInfo( - t, + totalItems, _, collections, expectedData, err := collectionsForInfo( test.service, suite.connector.tenant, suite.user, dest, - []colInfo{collection}, + []ColInfo{collection}, version.Backup, ) + require.NoError(t, err) + allItems += totalItems for k, v := range expectedData { @@ -1123,10 +1089,10 @@ func (suite *GraphConnectorIntegrationSuite) TestMultiFolderBackupDifferentNames t.Log("Backup enumeration complete") - ci := configInfo{ - opts: control.Options{RestorePermissions: true}, + ci := ConfigInfo{ + Opts: control.Options{RestorePermissions: true}, // Alright to be empty, needed for OneDrive. - dest: control.RestoreDestination{}, + Dest: control.RestoreDestination{}, } // Pull the data prior to waiting for the status as otherwise it will @@ -1149,11 +1115,11 @@ func (suite *GraphConnectorIntegrationSuite) TestRestoreAndBackup_largeMailAttac name: "EmailsWithLargeAttachments", service: path.ExchangeService, resource: Users, - collections: []colInfo{ + collections: []ColInfo{ { - pathElements: []string{"Inbox"}, - category: path.EmailCategory, - items: []itemInfo{ + PathElements: []string{"Inbox"}, + Category: path.EmailCategory, + Items: []ItemInfo{ { name: "35mbAttachment", data: exchMock.MessageWithSizedAttachment(subjectText, 35), diff --git a/src/internal/connector/graph_connector_test_helper.go b/src/internal/connector/graph_connector_test_helper.go new file mode 100644 index 000000000..5d91538bb --- /dev/null +++ b/src/internal/connector/graph_connector_test_helper.go @@ -0,0 +1,188 @@ +package connector + +import ( + "bytes" + "context" + "io" + + exchMock "github.com/alcionai/corso/src/internal/connector/exchange/mock" + "github.com/alcionai/corso/src/internal/connector/onedrive/metadata" + "github.com/alcionai/corso/src/internal/data" + "github.com/alcionai/corso/src/pkg/account" + "github.com/alcionai/corso/src/pkg/control" + "github.com/alcionai/corso/src/pkg/path" +) + +type ColInfo struct { + // Elements (in order) for the path representing this collection. Should + // only contain elements after the prefix that corso uses for the path. For + // example, a collection for the Inbox folder in exchange mail would just be + // "Inbox". + PathElements []string + Category path.CategoryType + Items []ItemInfo + // auxItems are items that can be retrieved with Fetch but won't be returned + // by Items(). These files do not directly participate in comparisosn at the + // end of a test. + AuxItems []ItemInfo +} + +type ItemInfo struct { + // lookupKey is a string that can be used to find this data from a set of + // other data in the same collection. This key should be something that will + // be the same before and after restoring the item in M365 and may not be + // the M365 ID. When restoring items out of place, the item is assigned a + // new ID making it unsuitable for a lookup key. + lookupKey string + name string + data []byte +} + +type ConfigInfo struct { + Acct account.Account + Opts control.Options + Resource Resource + Service path.ServiceType + Tenant string + ResourceOwners []string + Dest control.RestoreDestination +} + +func mustToDataLayerPath( + service path.ServiceType, + tenant, resourceOwner string, + category path.CategoryType, + elements []string, + isItem bool, +) (path.Path, error) { + res, err := path.Build(tenant, resourceOwner, service, category, isItem, elements...) + if err != nil { + return nil, err + } + + return res, err +} + +// backupOutputPathFromRestore returns a path.Path denoting the location in +// kopia the data will be placed at. The location is a data-type specific +// combination of the location the data was recently restored to and where the +// data was originally in the hierarchy. +func backupOutputPathFromRestore( + restoreDest control.RestoreDestination, + inputPath path.Path, +) (path.Path, error) { + base := []string{restoreDest.ContainerName} + + // OneDrive has leading information like the drive ID. + if inputPath.Service() == path.OneDriveService || inputPath.Service() == path.SharePointService { + folders := inputPath.Folders() + base = append(append([]string{}, folders[:3]...), restoreDest.ContainerName) + + if len(folders) > 3 { + base = append(base, folders[3:]...) + } + } + + if inputPath.Service() == path.ExchangeService && inputPath.Category() == path.EmailCategory { + base = append(base, inputPath.Folders()...) + } + + return mustToDataLayerPath( + inputPath.Service(), + inputPath.Tenant(), + inputPath.ResourceOwner(), + inputPath.Category(), + base, + false, + ) +} + +// TODO(ashmrtn): Make this an actual mock class that can be used in other +// packages. +type mockRestoreCollection struct { + data.Collection + auxItems map[string]data.Stream +} + +func (rc mockRestoreCollection) Fetch( + ctx context.Context, + name string, +) (data.Stream, error) { + res := rc.auxItems[name] + if res == nil { + return nil, data.ErrNotFound + } + + return res, nil +} + +func collectionsForInfo( + service path.ServiceType, + tenant, user string, + dest control.RestoreDestination, + allInfo []ColInfo, + backupVersion int, +) (int, int, []data.RestoreCollection, map[string]map[string][]byte, error) { + var ( + collections = make([]data.RestoreCollection, 0, len(allInfo)) + expectedData = make(map[string]map[string][]byte, len(allInfo)) + totalItems = 0 + kopiaEntries = 0 + ) + + for _, info := range allInfo { + pth, err := mustToDataLayerPath( + service, + tenant, + user, + info.Category, + info.PathElements, + false) + if err != nil { + return totalItems, kopiaEntries, collections, expectedData, err + } + + mc := exchMock.NewCollection(pth, pth, len(info.Items)) + + baseDestPath, err := backupOutputPathFromRestore(dest, pth) + if err != nil { + return totalItems, kopiaEntries, collections, expectedData, err + } + + baseExpected := expectedData[baseDestPath.String()] + if baseExpected == nil { + expectedData[baseDestPath.String()] = make(map[string][]byte, len(info.Items)) + baseExpected = expectedData[baseDestPath.String()] + } + + for i := 0; i < len(info.Items); i++ { + mc.Names[i] = info.Items[i].name + mc.Data[i] = info.Items[i].data + + baseExpected[info.Items[i].lookupKey] = info.Items[i].data + + // We do not count metadata files against item count + if backupVersion > 0 && + (service == path.OneDriveService || service == path.SharePointService) && + metadata.HasMetaSuffix(info.Items[i].name) { + continue + } + + totalItems++ + } + + c := mockRestoreCollection{Collection: mc, auxItems: map[string]data.Stream{}} + + for _, aux := range info.AuxItems { + c.auxItems[aux.name] = &exchMock.Data{ + ID: aux.name, + Reader: io.NopCloser(bytes.NewReader(aux.data)), + } + } + + collections = append(collections, c) + kopiaEntries += len(info.Items) + } + + return totalItems, kopiaEntries, collections, expectedData, nil +} diff --git a/website/package-lock.json b/website/package-lock.json index 2bb8cb5b1..f2d7c118f 100644 --- a/website/package-lock.json +++ b/website/package-lock.json @@ -8,9 +8,9 @@ "name": "docs", "version": "0.1.0", "dependencies": { - "@docusaurus/core": "2.4.0", + "@docusaurus/core": "2.4.1", "@docusaurus/plugin-google-gtag": "^2.4.0", - "@docusaurus/preset-classic": "2.4.0", + "@docusaurus/preset-classic": "2.4.1", "@loadable/component": "^5.15.3", "@mdx-js/react": "^1.6.22", "animate.css": "^4.1.1", @@ -30,7 +30,7 @@ "wow.js": "^1.2.2" }, "devDependencies": { - "@docusaurus/module-type-aliases": "2.4.0", + "@docusaurus/module-type-aliases": "2.4.1", "@iconify/react": "^4.1.0", "autoprefixer": "^10.4.14", "postcss": "^8.4.23", @@ -38,19 +38,19 @@ } }, "node_modules/@algolia/autocomplete-core": { - "version": "1.7.4", - "resolved": "https://registry.npmjs.org/@algolia/autocomplete-core/-/autocomplete-core-1.7.4.tgz", - "integrity": "sha512-daoLpQ3ps/VTMRZDEBfU8ixXd+amZcNJ4QSP3IERGyzqnL5Ch8uSRFt/4G8pUvW9c3o6GA4vtVv4I4lmnkdXyg==", + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/@algolia/autocomplete-core/-/autocomplete-core-1.8.2.tgz", + "integrity": "sha512-mTeshsyFhAqw/ebqNsQpMtbnjr+qVOSKXArEj4K0d7sqc8It1XD0gkASwecm9mF/jlOQ4Z9RNg1HbdA8JPdRwQ==", "dependencies": { - "@algolia/autocomplete-shared": "1.7.4" + "@algolia/autocomplete-shared": "1.8.2" } }, "node_modules/@algolia/autocomplete-preset-algolia": { - "version": "1.7.4", - "resolved": "https://registry.npmjs.org/@algolia/autocomplete-preset-algolia/-/autocomplete-preset-algolia-1.7.4.tgz", - "integrity": "sha512-s37hrvLEIfcmKY8VU9LsAXgm2yfmkdHT3DnA3SgHaY93yjZ2qL57wzb5QweVkYuEBZkT2PIREvRoLXC2sxTbpQ==", + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/@algolia/autocomplete-preset-algolia/-/autocomplete-preset-algolia-1.8.2.tgz", + "integrity": "sha512-J0oTx4me6ZM9kIKPuL3lyU3aB8DEvpVvR6xWmHVROx5rOYJGQcZsdG4ozxwcOyiiu3qxMkIbzntnV1S1VWD8yA==", "dependencies": { - "@algolia/autocomplete-shared": "1.7.4" + "@algolia/autocomplete-shared": "1.8.2" }, "peerDependencies": { "@algolia/client-search": ">= 4.9.1 < 6", @@ -58,79 +58,79 @@ } }, "node_modules/@algolia/autocomplete-shared": { - "version": "1.7.4", - "resolved": "https://registry.npmjs.org/@algolia/autocomplete-shared/-/autocomplete-shared-1.7.4.tgz", - "integrity": "sha512-2VGCk7I9tA9Ge73Km99+Qg87w0wzW4tgUruvWAn/gfey1ZXgmxZtyIRBebk35R1O8TbK77wujVtCnpsGpRy1kg==" + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/@algolia/autocomplete-shared/-/autocomplete-shared-1.8.2.tgz", + "integrity": "sha512-b6Z/X4MczChMcfhk6kfRmBzPgjoPzuS9KGR4AFsiLulLNRAAqhP+xZTKtMnZGhLuc61I20d5WqlId02AZvcO6g==" }, "node_modules/@algolia/cache-browser-local-storage": { - "version": "4.16.0", - "resolved": "https://registry.npmjs.org/@algolia/cache-browser-local-storage/-/cache-browser-local-storage-4.16.0.tgz", - "integrity": "sha512-jVrk0YB3tjOhD5/lhBtYCVCeLjZmVpf2kdi4puApofytf/R0scjWz0GdozlW4HhU+Prxmt/c9ge4QFjtv5OAzQ==", + "version": "4.17.0", + "resolved": "https://registry.npmjs.org/@algolia/cache-browser-local-storage/-/cache-browser-local-storage-4.17.0.tgz", + "integrity": "sha512-myRSRZDIMYB8uCkO+lb40YKiYHi0fjpWRtJpR/dgkaiBlSD0plRyB6lLOh1XIfmMcSeBOqDE7y9m8xZMrXYfyQ==", "dependencies": { - "@algolia/cache-common": "4.16.0" + "@algolia/cache-common": "4.17.0" } }, "node_modules/@algolia/cache-common": { - "version": "4.16.0", - "resolved": "https://registry.npmjs.org/@algolia/cache-common/-/cache-common-4.16.0.tgz", - "integrity": "sha512-4iHjkSYQYw46pITrNQgXXhvUmcekI8INz1m+SzmqLX8jexSSy4Ky4zfGhZzhhhLHXUP3+x/PK/c0qPjxEvRwKQ==" + "version": "4.17.0", + "resolved": "https://registry.npmjs.org/@algolia/cache-common/-/cache-common-4.17.0.tgz", + "integrity": "sha512-g8mXzkrcUBIPZaulAuqE7xyHhLAYAcF2xSch7d9dABheybaU3U91LjBX6eJTEB7XVhEsgK4Smi27vWtAJRhIKQ==" }, "node_modules/@algolia/cache-in-memory": { - "version": "4.16.0", - "resolved": "https://registry.npmjs.org/@algolia/cache-in-memory/-/cache-in-memory-4.16.0.tgz", - "integrity": "sha512-p7RYykvA6Ip6QENxrh99nOD77otVh1sJRivcgcVpnjoZb5sIN3t33eUY1DpB9QSBizcrW+qk19rNkdnZ43a+PQ==", + "version": "4.17.0", + "resolved": "https://registry.npmjs.org/@algolia/cache-in-memory/-/cache-in-memory-4.17.0.tgz", + "integrity": "sha512-PT32ciC/xI8z919d0oknWVu3kMfTlhQn3MKxDln3pkn+yA7F7xrxSALysxquv+MhFfNAcrtQ/oVvQVBAQSHtdw==", "dependencies": { - "@algolia/cache-common": "4.16.0" + "@algolia/cache-common": "4.17.0" } }, "node_modules/@algolia/client-account": { - "version": "4.16.0", - "resolved": "https://registry.npmjs.org/@algolia/client-account/-/client-account-4.16.0.tgz", - "integrity": "sha512-eydcfpdIyuWoKgUSz5iZ/L0wE/Wl7958kACkvTHLDNXvK/b8Z1zypoJavh6/km1ZNQmFpeYS2jrmq0kUSFn02w==", + "version": "4.17.0", + "resolved": "https://registry.npmjs.org/@algolia/client-account/-/client-account-4.17.0.tgz", + "integrity": "sha512-sSEHx9GA6m7wrlsSMNBGfyzlIfDT2fkz2u7jqfCCd6JEEwmxt8emGmxAU/0qBfbhRSuGvzojoLJlr83BSZAKjA==", "dependencies": { - "@algolia/client-common": "4.16.0", - "@algolia/client-search": "4.16.0", - "@algolia/transporter": "4.16.0" + "@algolia/client-common": "4.17.0", + "@algolia/client-search": "4.17.0", + "@algolia/transporter": "4.17.0" } }, "node_modules/@algolia/client-analytics": { - "version": "4.16.0", - "resolved": "https://registry.npmjs.org/@algolia/client-analytics/-/client-analytics-4.16.0.tgz", - "integrity": "sha512-cONWXH3BfilgdlCofUm492bJRWtpBLVW/hsUlfoFtiX1u05xoBP7qeiDwh9RR+4pSLHLodYkHAf5U4honQ55Qg==", + "version": "4.17.0", + "resolved": "https://registry.npmjs.org/@algolia/client-analytics/-/client-analytics-4.17.0.tgz", + "integrity": "sha512-84ooP8QA3mQ958hQ9wozk7hFUbAO+81CX1CjAuerxBqjKIInh1fOhXKTaku05O/GHBvcfExpPLIQuSuLYziBXQ==", "dependencies": { - "@algolia/client-common": "4.16.0", - "@algolia/client-search": "4.16.0", - "@algolia/requester-common": "4.16.0", - "@algolia/transporter": "4.16.0" + "@algolia/client-common": "4.17.0", + "@algolia/client-search": "4.17.0", + "@algolia/requester-common": "4.17.0", + "@algolia/transporter": "4.17.0" } }, "node_modules/@algolia/client-common": { - "version": "4.16.0", - "resolved": "https://registry.npmjs.org/@algolia/client-common/-/client-common-4.16.0.tgz", - "integrity": "sha512-QVdR4019ukBH6f5lFr27W60trRxQF1SfS1qo0IP6gjsKhXhUVJuHxOCA6ArF87jrNkeuHEoRoDU+GlvaecNo8g==", + "version": "4.17.0", + "resolved": "https://registry.npmjs.org/@algolia/client-common/-/client-common-4.17.0.tgz", + "integrity": "sha512-jHMks0ZFicf8nRDn6ma8DNNsdwGgP/NKiAAL9z6rS7CymJ7L0+QqTJl3rYxRW7TmBhsUH40wqzmrG6aMIN/DrQ==", "dependencies": { - "@algolia/requester-common": "4.16.0", - "@algolia/transporter": "4.16.0" + "@algolia/requester-common": "4.17.0", + "@algolia/transporter": "4.17.0" } }, "node_modules/@algolia/client-personalization": { - "version": "4.16.0", - "resolved": "https://registry.npmjs.org/@algolia/client-personalization/-/client-personalization-4.16.0.tgz", - "integrity": "sha512-irtLafssDGPuhYqIwxqOxiWlVYvrsBD+EMA1P9VJtkKi3vSNBxiWeQ0f0Tn53cUNdSRNEssfoEH84JL97SV2SQ==", + "version": "4.17.0", + "resolved": "https://registry.npmjs.org/@algolia/client-personalization/-/client-personalization-4.17.0.tgz", + "integrity": "sha512-RMzN4dZLIta1YuwT7QC9o+OeGz2cU6eTOlGNE/6RcUBLOU3l9tkCOdln5dPE2jp8GZXPl2yk54b2nSs1+pAjqw==", "dependencies": { - "@algolia/client-common": "4.16.0", - "@algolia/requester-common": "4.16.0", - "@algolia/transporter": "4.16.0" + "@algolia/client-common": "4.17.0", + "@algolia/requester-common": "4.17.0", + "@algolia/transporter": "4.17.0" } }, "node_modules/@algolia/client-search": { - "version": "4.16.0", - "resolved": "https://registry.npmjs.org/@algolia/client-search/-/client-search-4.16.0.tgz", - "integrity": "sha512-xsfrAE1jO/JDh1wFrRz+alVyW+aA6qnkzmbWWWZWEgVF3EaFqzIf9r1l/aDtDdBtNTNhX9H3Lg31+BRtd5izQA==", + "version": "4.17.0", + "resolved": "https://registry.npmjs.org/@algolia/client-search/-/client-search-4.17.0.tgz", + "integrity": "sha512-x4P2wKrrRIXszT8gb7eWsMHNNHAJs0wE7/uqbufm4tZenAp+hwU/hq5KVsY50v+PfwM0LcDwwn/1DroujsTFoA==", "dependencies": { - "@algolia/client-common": "4.16.0", - "@algolia/requester-common": "4.16.0", - "@algolia/transporter": "4.16.0" + "@algolia/client-common": "4.17.0", + "@algolia/requester-common": "4.17.0", + "@algolia/transporter": "4.17.0" } }, "node_modules/@algolia/events": { @@ -139,47 +139,47 @@ "integrity": "sha512-FQzvOCgoFXAbf5Y6mYozw2aj5KCJoA3m4heImceldzPSMbdyS4atVjJzXKMsfX3wnZTFYwkkt8/z8UesLHlSBQ==" }, "node_modules/@algolia/logger-common": { - "version": "4.16.0", - "resolved": "https://registry.npmjs.org/@algolia/logger-common/-/logger-common-4.16.0.tgz", - "integrity": "sha512-U9H8uCzSDuePJmbnjjTX21aPDRU6x74Tdq3dJmdYu2+pISx02UeBJm4kSgc9RW5jcR5j35G9gnjHY9Q3ngWbyQ==" + "version": "4.17.0", + "resolved": "https://registry.npmjs.org/@algolia/logger-common/-/logger-common-4.17.0.tgz", + "integrity": "sha512-DGuoZqpTmIKJFDeyAJ7M8E/LOenIjWiOsg1XJ1OqAU/eofp49JfqXxbfgctlVZVmDABIyOz8LqEoJ6ZP4DTyvw==" }, "node_modules/@algolia/logger-console": { - "version": "4.16.0", - "resolved": "https://registry.npmjs.org/@algolia/logger-console/-/logger-console-4.16.0.tgz", - "integrity": "sha512-+qymusiM+lPZKrkf0tDjCQA158eEJO2IU+Nr/sJ9TFyI/xkFPjNPzw/Qbc8Iy/xcOXGlc6eMgmyjtVQqAWq6UA==", + "version": "4.17.0", + "resolved": "https://registry.npmjs.org/@algolia/logger-console/-/logger-console-4.17.0.tgz", + "integrity": "sha512-zMPvugQV/gbXUvWBCzihw6m7oxIKp48w37QBIUu/XqQQfxhjoOE9xyfJr1KldUt5FrYOKZJVsJaEjTsu+bIgQg==", "dependencies": { - "@algolia/logger-common": "4.16.0" + "@algolia/logger-common": "4.17.0" } }, "node_modules/@algolia/requester-browser-xhr": { - "version": "4.16.0", - "resolved": "https://registry.npmjs.org/@algolia/requester-browser-xhr/-/requester-browser-xhr-4.16.0.tgz", - "integrity": "sha512-gK+kvs6LHl/PaOJfDuwjkopNbG1djzFLsVBklGBsSU6h6VjFkxIpo6Qq80IK14p9cplYZfhfaL12va6Q9p3KVQ==", + "version": "4.17.0", + "resolved": "https://registry.npmjs.org/@algolia/requester-browser-xhr/-/requester-browser-xhr-4.17.0.tgz", + "integrity": "sha512-aSOX/smauyTkP21Pf52pJ1O2LmNFJ5iHRIzEeTh0mwBeADO4GdG94cAWDILFA9rNblq/nK3EDh3+UyHHjplZ1A==", "dependencies": { - "@algolia/requester-common": "4.16.0" + "@algolia/requester-common": "4.17.0" } }, "node_modules/@algolia/requester-common": { - "version": "4.16.0", - "resolved": "https://registry.npmjs.org/@algolia/requester-common/-/requester-common-4.16.0.tgz", - "integrity": "sha512-3Zmcs/iMubcm4zqZ3vZG6Zum8t+hMWxGMzo0/uY2BD8o9q5vMxIYI0c4ocdgQjkXcix189WtZNkgjSOBzSbkdw==" + "version": "4.17.0", + "resolved": "https://registry.npmjs.org/@algolia/requester-common/-/requester-common-4.17.0.tgz", + "integrity": "sha512-XJjmWFEUlHu0ijvcHBoixuXfEoiRUdyzQM6YwTuB8usJNIgShua8ouFlRWF8iCeag0vZZiUm4S2WCVBPkdxFgg==" }, "node_modules/@algolia/requester-node-http": { - "version": "4.16.0", - "resolved": "https://registry.npmjs.org/@algolia/requester-node-http/-/requester-node-http-4.16.0.tgz", - "integrity": "sha512-L8JxM2VwZzh8LJ1Zb8TFS6G3icYsCKZsdWW+ahcEs1rGWmyk9SybsOe1MLnjonGBaqPWJkn9NjS7mRdjEmBtKA==", + "version": "4.17.0", + "resolved": "https://registry.npmjs.org/@algolia/requester-node-http/-/requester-node-http-4.17.0.tgz", + "integrity": "sha512-bpb/wDA1aC6WxxM8v7TsFspB7yBN3nqCGs2H1OADolQR/hiAIjAxusbuMxVbRFOdaUvAIqioIIkWvZdpYNIn8w==", "dependencies": { - "@algolia/requester-common": "4.16.0" + "@algolia/requester-common": "4.17.0" } }, "node_modules/@algolia/transporter": { - "version": "4.16.0", - "resolved": "https://registry.npmjs.org/@algolia/transporter/-/transporter-4.16.0.tgz", - "integrity": "sha512-H9BVB2EAjT65w7XGBNf5drpsW39x2aSZ942j4boSAAJPPlLmjtj5IpAP7UAtsV8g9Beslonh0bLa1XGmE/P0BA==", + "version": "4.17.0", + "resolved": "https://registry.npmjs.org/@algolia/transporter/-/transporter-4.17.0.tgz", + "integrity": "sha512-6xL6H6fe+Fi0AEP3ziSgC+G04RK37iRb4uUUqVAH9WPYFI8g+LYFq6iv5HS8Cbuc5TTut+Bwj6G+dh/asdb9uA==", "dependencies": { - "@algolia/cache-common": "4.16.0", - "@algolia/logger-common": "4.16.0", - "@algolia/requester-common": "4.16.0" + "@algolia/cache-common": "4.17.0", + "@algolia/logger-common": "4.17.0", + "@algolia/requester-common": "4.17.0" } }, "node_modules/@alloc/quick-lru": { @@ -1971,18 +1971,18 @@ } }, "node_modules/@docsearch/css": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/@docsearch/css/-/css-3.3.3.tgz", - "integrity": "sha512-6SCwI7P8ao+se1TUsdZ7B4XzL+gqeQZnBc+2EONZlcVa0dVrk0NjETxozFKgMv0eEGH8QzP1fkN+A1rH61l4eg==" + "version": "3.3.4", + "resolved": "https://registry.npmjs.org/@docsearch/css/-/css-3.3.4.tgz", + "integrity": "sha512-vDwCDoVXDgopw/hvr0zEADew2wWaGP8Qq0Bxhgii1Ewz2t4fQeyJwIRN/mWADeLFYPVkpz8TpEbxya/i6Tm0WA==" }, "node_modules/@docsearch/react": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/@docsearch/react/-/react-3.3.3.tgz", - "integrity": "sha512-pLa0cxnl+G0FuIDuYlW+EBK6Rw2jwLw9B1RHIeS4N4s2VhsfJ/wzeCi3CWcs5yVfxLd5ZK50t//TMA5e79YT7Q==", + "version": "3.3.4", + "resolved": "https://registry.npmjs.org/@docsearch/react/-/react-3.3.4.tgz", + "integrity": "sha512-aeOf1WC5zMzBEi2SI6WWznOmIo9rnpN4p7a3zHXxowVciqlI4HsZGtOR9nFOufLeolv7HibwLlaM0oyUqJxasw==", "dependencies": { - "@algolia/autocomplete-core": "1.7.4", - "@algolia/autocomplete-preset-algolia": "1.7.4", - "@docsearch/css": "3.3.3", + "@algolia/autocomplete-core": "1.8.2", + "@algolia/autocomplete-preset-algolia": "1.8.2", + "@docsearch/css": "3.3.4", "algoliasearch": "^4.0.0" }, "peerDependencies": { @@ -2003,9 +2003,9 @@ } }, "node_modules/@docusaurus/core": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/@docusaurus/core/-/core-2.4.0.tgz", - "integrity": "sha512-J55/WEoIpRcLf3afO5POHPguVZosKmJEQWKBL+K7TAnfuE7i+Y0NPLlkKtnWCehagGsgTqClfQEexH/UT4kELA==", + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/@docusaurus/core/-/core-2.4.1.tgz", + "integrity": "sha512-SNsY7PshK3Ri7vtsLXVeAJGS50nJN3RgF836zkyUfAD01Fq+sAk5EwWgLw+nnm5KVNGDu7PRR2kRGDsWvqpo0g==", "dependencies": { "@babel/core": "^7.18.6", "@babel/generator": "^7.18.7", @@ -2017,13 +2017,13 @@ "@babel/runtime": "^7.18.6", "@babel/runtime-corejs3": "^7.18.6", "@babel/traverse": "^7.18.8", - "@docusaurus/cssnano-preset": "2.4.0", - "@docusaurus/logger": "2.4.0", - "@docusaurus/mdx-loader": "2.4.0", + "@docusaurus/cssnano-preset": "2.4.1", + "@docusaurus/logger": "2.4.1", + "@docusaurus/mdx-loader": "2.4.1", "@docusaurus/react-loadable": "5.5.2", - "@docusaurus/utils": "2.4.0", - "@docusaurus/utils-common": "2.4.0", - "@docusaurus/utils-validation": "2.4.0", + "@docusaurus/utils": "2.4.1", + "@docusaurus/utils-common": "2.4.1", + "@docusaurus/utils-validation": "2.4.1", "@slorber/static-site-generator-webpack-plugin": "^4.0.7", "@svgr/webpack": "^6.2.1", "autoprefixer": "^10.4.7", @@ -2161,9 +2161,9 @@ } }, "node_modules/@docusaurus/cssnano-preset": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/@docusaurus/cssnano-preset/-/cssnano-preset-2.4.0.tgz", - "integrity": "sha512-RmdiA3IpsLgZGXRzqnmTbGv43W4OD44PCo+6Q/aYjEM2V57vKCVqNzuafE94jv0z/PjHoXUrjr69SaRymBKYYw==", + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/@docusaurus/cssnano-preset/-/cssnano-preset-2.4.1.tgz", + "integrity": "sha512-ka+vqXwtcW1NbXxWsh6yA1Ckii1klY9E53cJ4O9J09nkMBgrNX3iEFED1fWdv8wf4mJjvGi5RLZ2p9hJNjsLyQ==", "dependencies": { "cssnano-preset-advanced": "^5.3.8", "postcss": "^8.4.14", @@ -2175,9 +2175,9 @@ } }, "node_modules/@docusaurus/logger": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/@docusaurus/logger/-/logger-2.4.0.tgz", - "integrity": "sha512-T8+qR4APN+MjcC9yL2Es+xPJ2923S9hpzDmMtdsOcUGLqpCGBbU1vp3AAqDwXtVgFkq+NsEk7sHdVsfLWR/AXw==", + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/@docusaurus/logger/-/logger-2.4.1.tgz", + "integrity": "sha512-5h5ysIIWYIDHyTVd8BjheZmQZmEgWDR54aQ1BX9pjFfpyzFo5puKXKYrYJXbjEHGyVhEzmB9UXwbxGfaZhOjcg==", "dependencies": { "chalk": "^4.1.2", "tslib": "^2.4.0" @@ -2251,14 +2251,14 @@ } }, "node_modules/@docusaurus/mdx-loader": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/@docusaurus/mdx-loader/-/mdx-loader-2.4.0.tgz", - "integrity": "sha512-GWoH4izZKOmFoC+gbI2/y8deH/xKLvzz/T5BsEexBye8EHQlwsA7FMrVa48N063bJBH4FUOiRRXxk5rq9cC36g==", + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/@docusaurus/mdx-loader/-/mdx-loader-2.4.1.tgz", + "integrity": "sha512-4KhUhEavteIAmbBj7LVFnrVYDiU51H5YWW1zY6SmBSte/YLhDutztLTBE0PQl1Grux1jzUJeaSvAzHpTn6JJDQ==", "dependencies": { "@babel/parser": "^7.18.8", "@babel/traverse": "^7.18.8", - "@docusaurus/logger": "2.4.0", - "@docusaurus/utils": "2.4.0", + "@docusaurus/logger": "2.4.1", + "@docusaurus/utils": "2.4.1", "@mdx-js/mdx": "^1.6.22", "escape-html": "^1.0.3", "file-loader": "^6.2.0", @@ -2282,12 +2282,12 @@ } }, "node_modules/@docusaurus/module-type-aliases": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/@docusaurus/module-type-aliases/-/module-type-aliases-2.4.0.tgz", - "integrity": "sha512-YEQO2D3UXs72qCn8Cr+RlycSQXVGN9iEUyuHwTuK4/uL/HFomB2FHSU0vSDM23oLd+X/KibQ3Ez6nGjQLqXcHg==", + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/@docusaurus/module-type-aliases/-/module-type-aliases-2.4.1.tgz", + "integrity": "sha512-gLBuIFM8Dp2XOCWffUDSjtxY7jQgKvYujt7Mx5s4FCTfoL5dN1EVbnrn+O2Wvh8b0a77D57qoIDY7ghgmatR1A==", "dependencies": { "@docusaurus/react-loadable": "5.5.2", - "@docusaurus/types": "2.4.0", + "@docusaurus/types": "2.4.1", "@types/history": "^4.7.11", "@types/react": "*", "@types/react-router-config": "*", @@ -2301,17 +2301,17 @@ } }, "node_modules/@docusaurus/plugin-content-blog": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/@docusaurus/plugin-content-blog/-/plugin-content-blog-2.4.0.tgz", - "integrity": "sha512-YwkAkVUxtxoBAIj/MCb4ohN0SCtHBs4AS75jMhPpf67qf3j+U/4n33cELq7567hwyZ6fMz2GPJcVmctzlGGThQ==", + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/@docusaurus/plugin-content-blog/-/plugin-content-blog-2.4.1.tgz", + "integrity": "sha512-E2i7Knz5YIbE1XELI6RlTnZnGgS52cUO4BlCiCUCvQHbR+s1xeIWz4C6BtaVnlug0Ccz7nFSksfwDpVlkujg5Q==", "dependencies": { - "@docusaurus/core": "2.4.0", - "@docusaurus/logger": "2.4.0", - "@docusaurus/mdx-loader": "2.4.0", - "@docusaurus/types": "2.4.0", - "@docusaurus/utils": "2.4.0", - "@docusaurus/utils-common": "2.4.0", - "@docusaurus/utils-validation": "2.4.0", + "@docusaurus/core": "2.4.1", + "@docusaurus/logger": "2.4.1", + "@docusaurus/mdx-loader": "2.4.1", + "@docusaurus/types": "2.4.1", + "@docusaurus/utils": "2.4.1", + "@docusaurus/utils-common": "2.4.1", + "@docusaurus/utils-validation": "2.4.1", "cheerio": "^1.0.0-rc.12", "feed": "^4.2.2", "fs-extra": "^10.1.0", @@ -2331,17 +2331,17 @@ } }, "node_modules/@docusaurus/plugin-content-docs": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/@docusaurus/plugin-content-docs/-/plugin-content-docs-2.4.0.tgz", - "integrity": "sha512-ic/Z/ZN5Rk/RQo+Io6rUGpToOtNbtPloMR2JcGwC1xT2riMu6zzfSwmBi9tHJgdXH6CB5jG+0dOZZO8QS5tmDg==", + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/@docusaurus/plugin-content-docs/-/plugin-content-docs-2.4.1.tgz", + "integrity": "sha512-Lo7lSIcpswa2Kv4HEeUcGYqaasMUQNpjTXpV0N8G6jXgZaQurqp7E8NGYeGbDXnb48czmHWbzDL4S3+BbK0VzA==", "dependencies": { - "@docusaurus/core": "2.4.0", - "@docusaurus/logger": "2.4.0", - "@docusaurus/mdx-loader": "2.4.0", - "@docusaurus/module-type-aliases": "2.4.0", - "@docusaurus/types": "2.4.0", - "@docusaurus/utils": "2.4.0", - "@docusaurus/utils-validation": "2.4.0", + "@docusaurus/core": "2.4.1", + "@docusaurus/logger": "2.4.1", + "@docusaurus/mdx-loader": "2.4.1", + "@docusaurus/module-type-aliases": "2.4.1", + "@docusaurus/types": "2.4.1", + "@docusaurus/utils": "2.4.1", + "@docusaurus/utils-validation": "2.4.1", "@types/react-router-config": "^5.0.6", "combine-promises": "^1.1.0", "fs-extra": "^10.1.0", @@ -2361,15 +2361,15 @@ } }, "node_modules/@docusaurus/plugin-content-pages": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/@docusaurus/plugin-content-pages/-/plugin-content-pages-2.4.0.tgz", - "integrity": "sha512-Pk2pOeOxk8MeU3mrTU0XLIgP9NZixbdcJmJ7RUFrZp1Aj42nd0RhIT14BGvXXyqb8yTQlk4DmYGAzqOfBsFyGw==", + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/@docusaurus/plugin-content-pages/-/plugin-content-pages-2.4.1.tgz", + "integrity": "sha512-/UjuH/76KLaUlL+o1OvyORynv6FURzjurSjvn2lbWTFc4tpYY2qLYTlKpTCBVPhlLUQsfyFnshEJDLmPneq2oA==", "dependencies": { - "@docusaurus/core": "2.4.0", - "@docusaurus/mdx-loader": "2.4.0", - "@docusaurus/types": "2.4.0", - "@docusaurus/utils": "2.4.0", - "@docusaurus/utils-validation": "2.4.0", + "@docusaurus/core": "2.4.1", + "@docusaurus/mdx-loader": "2.4.1", + "@docusaurus/types": "2.4.1", + "@docusaurus/utils": "2.4.1", + "@docusaurus/utils-validation": "2.4.1", "fs-extra": "^10.1.0", "tslib": "^2.4.0", "webpack": "^5.73.0" @@ -2383,13 +2383,13 @@ } }, "node_modules/@docusaurus/plugin-debug": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/@docusaurus/plugin-debug/-/plugin-debug-2.4.0.tgz", - "integrity": "sha512-KC56DdYjYT7Txyux71vXHXGYZuP6yYtqwClvYpjKreWIHWus5Zt6VNi23rMZv3/QKhOCrN64zplUbdfQMvddBQ==", + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/@docusaurus/plugin-debug/-/plugin-debug-2.4.1.tgz", + "integrity": "sha512-7Yu9UPzRShlrH/G8btOpR0e6INFZr0EegWplMjOqelIwAcx3PKyR8mgPTxGTxcqiYj6hxSCRN0D8R7YrzImwNA==", "dependencies": { - "@docusaurus/core": "2.4.0", - "@docusaurus/types": "2.4.0", - "@docusaurus/utils": "2.4.0", + "@docusaurus/core": "2.4.1", + "@docusaurus/types": "2.4.1", + "@docusaurus/utils": "2.4.1", "fs-extra": "^10.1.0", "react-json-view": "^1.21.3", "tslib": "^2.4.0" @@ -2403,13 +2403,13 @@ } }, "node_modules/@docusaurus/plugin-google-analytics": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/@docusaurus/plugin-google-analytics/-/plugin-google-analytics-2.4.0.tgz", - "integrity": "sha512-uGUzX67DOAIglygdNrmMOvEp8qG03X20jMWadeqVQktS6nADvozpSLGx4J0xbkblhJkUzN21WiilsP9iVP+zkw==", + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/@docusaurus/plugin-google-analytics/-/plugin-google-analytics-2.4.1.tgz", + "integrity": "sha512-dyZJdJiCoL+rcfnm0RPkLt/o732HvLiEwmtoNzOoz9MSZz117UH2J6U2vUDtzUzwtFLIf32KkeyzisbwUCgcaQ==", "dependencies": { - "@docusaurus/core": "2.4.0", - "@docusaurus/types": "2.4.0", - "@docusaurus/utils-validation": "2.4.0", + "@docusaurus/core": "2.4.1", + "@docusaurus/types": "2.4.1", + "@docusaurus/utils-validation": "2.4.1", "tslib": "^2.4.0" }, "engines": { @@ -2421,13 +2421,13 @@ } }, "node_modules/@docusaurus/plugin-google-gtag": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/@docusaurus/plugin-google-gtag/-/plugin-google-gtag-2.4.0.tgz", - "integrity": "sha512-adj/70DANaQs2+TF/nRdMezDXFAV/O/pjAbUgmKBlyOTq5qoMe0Tk4muvQIwWUmiUQxFJe+sKlZGM771ownyOg==", + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/@docusaurus/plugin-google-gtag/-/plugin-google-gtag-2.4.1.tgz", + "integrity": "sha512-mKIefK+2kGTQBYvloNEKtDmnRD7bxHLsBcxgnbt4oZwzi2nxCGjPX6+9SQO2KCN5HZbNrYmGo5GJfMgoRvy6uA==", "dependencies": { - "@docusaurus/core": "2.4.0", - "@docusaurus/types": "2.4.0", - "@docusaurus/utils-validation": "2.4.0", + "@docusaurus/core": "2.4.1", + "@docusaurus/types": "2.4.1", + "@docusaurus/utils-validation": "2.4.1", "tslib": "^2.4.0" }, "engines": { @@ -2439,13 +2439,13 @@ } }, "node_modules/@docusaurus/plugin-google-tag-manager": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/@docusaurus/plugin-google-tag-manager/-/plugin-google-tag-manager-2.4.0.tgz", - "integrity": "sha512-E66uGcYs4l7yitmp/8kMEVQftFPwV9iC62ORh47Veqzs6ExwnhzBkJmwDnwIysHBF1vlxnzET0Fl2LfL5fRR3A==", + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/@docusaurus/plugin-google-tag-manager/-/plugin-google-tag-manager-2.4.1.tgz", + "integrity": "sha512-Zg4Ii9CMOLfpeV2nG74lVTWNtisFaH9QNtEw48R5QE1KIwDBdTVaiSA18G1EujZjrzJJzXN79VhINSbOJO/r3g==", "dependencies": { - "@docusaurus/core": "2.4.0", - "@docusaurus/types": "2.4.0", - "@docusaurus/utils-validation": "2.4.0", + "@docusaurus/core": "2.4.1", + "@docusaurus/types": "2.4.1", + "@docusaurus/utils-validation": "2.4.1", "tslib": "^2.4.0" }, "engines": { @@ -2457,16 +2457,16 @@ } }, "node_modules/@docusaurus/plugin-sitemap": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/@docusaurus/plugin-sitemap/-/plugin-sitemap-2.4.0.tgz", - "integrity": "sha512-pZxh+ygfnI657sN8a/FkYVIAmVv0CGk71QMKqJBOfMmDHNN1FeDeFkBjWP49ejBqpqAhjufkv5UWq3UOu2soCw==", + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/@docusaurus/plugin-sitemap/-/plugin-sitemap-2.4.1.tgz", + "integrity": "sha512-lZx+ijt/+atQ3FVE8FOHV/+X3kuok688OydDXrqKRJyXBJZKgGjA2Qa8RjQ4f27V2woaXhtnyrdPop/+OjVMRg==", "dependencies": { - "@docusaurus/core": "2.4.0", - "@docusaurus/logger": "2.4.0", - "@docusaurus/types": "2.4.0", - "@docusaurus/utils": "2.4.0", - "@docusaurus/utils-common": "2.4.0", - "@docusaurus/utils-validation": "2.4.0", + "@docusaurus/core": "2.4.1", + "@docusaurus/logger": "2.4.1", + "@docusaurus/types": "2.4.1", + "@docusaurus/utils": "2.4.1", + "@docusaurus/utils-common": "2.4.1", + "@docusaurus/utils-validation": "2.4.1", "fs-extra": "^10.1.0", "sitemap": "^7.1.1", "tslib": "^2.4.0" @@ -2480,23 +2480,23 @@ } }, "node_modules/@docusaurus/preset-classic": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/@docusaurus/preset-classic/-/preset-classic-2.4.0.tgz", - "integrity": "sha512-/5z5o/9bc6+P5ool2y01PbJhoGddEGsC0ej1MF6mCoazk8A+kW4feoUd68l7Bnv01rCnG3xy7kHUQP97Y0grUA==", + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/@docusaurus/preset-classic/-/preset-classic-2.4.1.tgz", + "integrity": "sha512-P4//+I4zDqQJ+UDgoFrjIFaQ1MeS9UD1cvxVQaI6O7iBmiHQm0MGROP1TbE7HlxlDPXFJjZUK3x3cAoK63smGQ==", "dependencies": { - "@docusaurus/core": "2.4.0", - "@docusaurus/plugin-content-blog": "2.4.0", - "@docusaurus/plugin-content-docs": "2.4.0", - "@docusaurus/plugin-content-pages": "2.4.0", - "@docusaurus/plugin-debug": "2.4.0", - "@docusaurus/plugin-google-analytics": "2.4.0", - "@docusaurus/plugin-google-gtag": "2.4.0", - "@docusaurus/plugin-google-tag-manager": "2.4.0", - "@docusaurus/plugin-sitemap": "2.4.0", - "@docusaurus/theme-classic": "2.4.0", - "@docusaurus/theme-common": "2.4.0", - "@docusaurus/theme-search-algolia": "2.4.0", - "@docusaurus/types": "2.4.0" + "@docusaurus/core": "2.4.1", + "@docusaurus/plugin-content-blog": "2.4.1", + "@docusaurus/plugin-content-docs": "2.4.1", + "@docusaurus/plugin-content-pages": "2.4.1", + "@docusaurus/plugin-debug": "2.4.1", + "@docusaurus/plugin-google-analytics": "2.4.1", + "@docusaurus/plugin-google-gtag": "2.4.1", + "@docusaurus/plugin-google-tag-manager": "2.4.1", + "@docusaurus/plugin-sitemap": "2.4.1", + "@docusaurus/theme-classic": "2.4.1", + "@docusaurus/theme-common": "2.4.1", + "@docusaurus/theme-search-algolia": "2.4.1", + "@docusaurus/types": "2.4.1" }, "engines": { "node": ">=16.14" @@ -2520,22 +2520,22 @@ } }, "node_modules/@docusaurus/theme-classic": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/@docusaurus/theme-classic/-/theme-classic-2.4.0.tgz", - "integrity": "sha512-GMDX5WU6Z0OC65eQFgl3iNNEbI9IMJz9f6KnOyuMxNUR6q0qVLsKCNopFUDfFNJ55UU50o7P7o21yVhkwpfJ9w==", + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/@docusaurus/theme-classic/-/theme-classic-2.4.1.tgz", + "integrity": "sha512-Rz0wKUa+LTW1PLXmwnf8mn85EBzaGSt6qamqtmnh9Hflkc+EqiYMhtUJeLdV+wsgYq4aG0ANc+bpUDpsUhdnwg==", "dependencies": { - "@docusaurus/core": "2.4.0", - "@docusaurus/mdx-loader": "2.4.0", - "@docusaurus/module-type-aliases": "2.4.0", - "@docusaurus/plugin-content-blog": "2.4.0", - "@docusaurus/plugin-content-docs": "2.4.0", - "@docusaurus/plugin-content-pages": "2.4.0", - "@docusaurus/theme-common": "2.4.0", - "@docusaurus/theme-translations": "2.4.0", - "@docusaurus/types": "2.4.0", - "@docusaurus/utils": "2.4.0", - "@docusaurus/utils-common": "2.4.0", - "@docusaurus/utils-validation": "2.4.0", + "@docusaurus/core": "2.4.1", + "@docusaurus/mdx-loader": "2.4.1", + "@docusaurus/module-type-aliases": "2.4.1", + "@docusaurus/plugin-content-blog": "2.4.1", + "@docusaurus/plugin-content-docs": "2.4.1", + "@docusaurus/plugin-content-pages": "2.4.1", + "@docusaurus/theme-common": "2.4.1", + "@docusaurus/theme-translations": "2.4.1", + "@docusaurus/types": "2.4.1", + "@docusaurus/utils": "2.4.1", + "@docusaurus/utils-common": "2.4.1", + "@docusaurus/utils-validation": "2.4.1", "@mdx-js/react": "^1.6.22", "clsx": "^1.2.1", "copy-text-to-clipboard": "^3.0.1", @@ -2559,17 +2559,17 @@ } }, "node_modules/@docusaurus/theme-common": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/@docusaurus/theme-common/-/theme-common-2.4.0.tgz", - "integrity": "sha512-IkG/l5f/FLY6cBIxtPmFnxpuPzc5TupuqlOx+XDN+035MdQcAh8wHXXZJAkTeYDeZ3anIUSUIvWa7/nRKoQEfg==", + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/@docusaurus/theme-common/-/theme-common-2.4.1.tgz", + "integrity": "sha512-G7Zau1W5rQTaFFB3x3soQoZpkgMbl/SYNG8PfMFIjKa3M3q8n0m/GRf5/H/e5BqOvt8c+ZWIXGCiz+kUCSHovA==", "dependencies": { - "@docusaurus/mdx-loader": "2.4.0", - "@docusaurus/module-type-aliases": "2.4.0", - "@docusaurus/plugin-content-blog": "2.4.0", - "@docusaurus/plugin-content-docs": "2.4.0", - "@docusaurus/plugin-content-pages": "2.4.0", - "@docusaurus/utils": "2.4.0", - "@docusaurus/utils-common": "2.4.0", + "@docusaurus/mdx-loader": "2.4.1", + "@docusaurus/module-type-aliases": "2.4.1", + "@docusaurus/plugin-content-blog": "2.4.1", + "@docusaurus/plugin-content-docs": "2.4.1", + "@docusaurus/plugin-content-pages": "2.4.1", + "@docusaurus/utils": "2.4.1", + "@docusaurus/utils-common": "2.4.1", "@types/history": "^4.7.11", "@types/react": "*", "@types/react-router-config": "*", @@ -2589,18 +2589,18 @@ } }, "node_modules/@docusaurus/theme-search-algolia": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/@docusaurus/theme-search-algolia/-/theme-search-algolia-2.4.0.tgz", - "integrity": "sha512-pPCJSCL1Qt4pu/Z0uxBAuke0yEBbxh0s4fOvimna7TEcBLPq0x06/K78AaABXrTVQM6S0vdocFl9EoNgU17hqA==", + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/@docusaurus/theme-search-algolia/-/theme-search-algolia-2.4.1.tgz", + "integrity": "sha512-6BcqW2lnLhZCXuMAvPRezFs1DpmEKzXFKlYjruuas+Xy3AQeFzDJKTJFIm49N77WFCTyxff8d3E4Q9pi/+5McQ==", "dependencies": { "@docsearch/react": "^3.1.1", - "@docusaurus/core": "2.4.0", - "@docusaurus/logger": "2.4.0", - "@docusaurus/plugin-content-docs": "2.4.0", - "@docusaurus/theme-common": "2.4.0", - "@docusaurus/theme-translations": "2.4.0", - "@docusaurus/utils": "2.4.0", - "@docusaurus/utils-validation": "2.4.0", + "@docusaurus/core": "2.4.1", + "@docusaurus/logger": "2.4.1", + "@docusaurus/plugin-content-docs": "2.4.1", + "@docusaurus/theme-common": "2.4.1", + "@docusaurus/theme-translations": "2.4.1", + "@docusaurus/utils": "2.4.1", + "@docusaurus/utils-validation": "2.4.1", "algoliasearch": "^4.13.1", "algoliasearch-helper": "^3.10.0", "clsx": "^1.2.1", @@ -2619,9 +2619,9 @@ } }, "node_modules/@docusaurus/theme-translations": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/@docusaurus/theme-translations/-/theme-translations-2.4.0.tgz", - "integrity": "sha512-kEoITnPXzDPUMBHk3+fzEzbopxLD3fR5sDoayNH0vXkpUukA88/aDL1bqkhxWZHA3LOfJ3f0vJbOwmnXW5v85Q==", + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/@docusaurus/theme-translations/-/theme-translations-2.4.1.tgz", + "integrity": "sha512-T1RAGP+f86CA1kfE8ejZ3T3pUU3XcyvrGMfC/zxCtc2BsnoexuNI9Vk2CmuKCb+Tacvhxjv5unhxXce0+NKyvA==", "dependencies": { "fs-extra": "^10.1.0", "tslib": "^2.4.0" @@ -2631,9 +2631,9 @@ } }, "node_modules/@docusaurus/types": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/@docusaurus/types/-/types-2.4.0.tgz", - "integrity": "sha512-xaBXr+KIPDkIaef06c+i2HeTqVNixB7yFut5fBXPGI2f1rrmEV2vLMznNGsFwvZ5XmA3Quuefd4OGRkdo97Dhw==", + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/@docusaurus/types/-/types-2.4.1.tgz", + "integrity": "sha512-0R+cbhpMkhbRXX138UOc/2XZFF8hiZa6ooZAEEJFp5scytzCw4tC1gChMFXrpa3d2tYE6AX8IrOEpSonLmfQuQ==", "dependencies": { "@types/history": "^4.7.11", "@types/react": "*", @@ -2650,11 +2650,11 @@ } }, "node_modules/@docusaurus/utils": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/@docusaurus/utils/-/utils-2.4.0.tgz", - "integrity": "sha512-89hLYkvtRX92j+C+ERYTuSUK6nF9bGM32QThcHPg2EDDHVw6FzYQXmX6/p+pU5SDyyx5nBlE4qXR92RxCAOqfg==", + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/@docusaurus/utils/-/utils-2.4.1.tgz", + "integrity": "sha512-1lvEZdAQhKNht9aPXPoh69eeKnV0/62ROhQeFKKxmzd0zkcuE/Oc5Gpnt00y/f5bIsmOsYMY7Pqfm/5rteT5GA==", "dependencies": { - "@docusaurus/logger": "2.4.0", + "@docusaurus/logger": "2.4.1", "@svgr/webpack": "^6.2.1", "escape-string-regexp": "^4.0.0", "file-loader": "^6.2.0", @@ -2684,9 +2684,9 @@ } }, "node_modules/@docusaurus/utils-common": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/@docusaurus/utils-common/-/utils-common-2.4.0.tgz", - "integrity": "sha512-zIMf10xuKxddYfLg5cS19x44zud/E9I7lj3+0bv8UIs0aahpErfNrGhijEfJpAfikhQ8tL3m35nH3hJ3sOG82A==", + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/@docusaurus/utils-common/-/utils-common-2.4.1.tgz", + "integrity": "sha512-bCVGdZU+z/qVcIiEQdyx0K13OC5mYwxhSuDUR95oFbKVuXYRrTVrwZIqQljuo1fyJvFTKHiL9L9skQOPokuFNQ==", "dependencies": { "tslib": "^2.4.0" }, @@ -2703,12 +2703,12 @@ } }, "node_modules/@docusaurus/utils-validation": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/@docusaurus/utils-validation/-/utils-validation-2.4.0.tgz", - "integrity": "sha512-IrBsBbbAp6y7mZdJx4S4pIA7dUyWSA0GNosPk6ZJ0fX3uYIEQgcQSGIgTeSC+8xPEx3c16o03en1jSDpgQgz/w==", + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/@docusaurus/utils-validation/-/utils-validation-2.4.1.tgz", + "integrity": "sha512-unII3hlJlDwZ3w8U+pMO3Lx3RhI4YEbY3YNsQj4yzrkZzlpqZOLuAiZK2JyULnD+TKbceKU0WyWkQXtYbLNDFA==", "dependencies": { - "@docusaurus/logger": "2.4.0", - "@docusaurus/utils": "2.4.0", + "@docusaurus/logger": "2.4.1", + "@docusaurus/utils": "2.4.1", "joi": "^17.6.0", "js-yaml": "^4.1.0", "tslib": "^2.4.0" @@ -3915,30 +3915,30 @@ } }, "node_modules/algoliasearch": { - "version": "4.16.0", - "resolved": "https://registry.npmjs.org/algoliasearch/-/algoliasearch-4.16.0.tgz", - "integrity": "sha512-HAjKJ6bBblaXqO4dYygF4qx251GuJ6zCZt+qbJ+kU7sOC+yc84pawEjVpJByh+cGP2APFCsao2Giz50cDlKNPA==", + "version": "4.17.0", + "resolved": "https://registry.npmjs.org/algoliasearch/-/algoliasearch-4.17.0.tgz", + "integrity": "sha512-JMRh2Mw6sEnVMiz6+APsi7lx9a2jiDFF+WUtANaUVCv6uSU9UOLdo5h9K3pdP6frRRybaM2fX8b1u0nqICS9aA==", "dependencies": { - "@algolia/cache-browser-local-storage": "4.16.0", - "@algolia/cache-common": "4.16.0", - "@algolia/cache-in-memory": "4.16.0", - "@algolia/client-account": "4.16.0", - "@algolia/client-analytics": "4.16.0", - "@algolia/client-common": "4.16.0", - "@algolia/client-personalization": "4.16.0", - "@algolia/client-search": "4.16.0", - "@algolia/logger-common": "4.16.0", - "@algolia/logger-console": "4.16.0", - "@algolia/requester-browser-xhr": "4.16.0", - "@algolia/requester-common": "4.16.0", - "@algolia/requester-node-http": "4.16.0", - "@algolia/transporter": "4.16.0" + "@algolia/cache-browser-local-storage": "4.17.0", + "@algolia/cache-common": "4.17.0", + "@algolia/cache-in-memory": "4.17.0", + "@algolia/client-account": "4.17.0", + "@algolia/client-analytics": "4.17.0", + "@algolia/client-common": "4.17.0", + "@algolia/client-personalization": "4.17.0", + "@algolia/client-search": "4.17.0", + "@algolia/logger-common": "4.17.0", + "@algolia/logger-console": "4.17.0", + "@algolia/requester-browser-xhr": "4.17.0", + "@algolia/requester-common": "4.17.0", + "@algolia/requester-node-http": "4.17.0", + "@algolia/transporter": "4.17.0" } }, "node_modules/algoliasearch-helper": { - "version": "3.12.0", - "resolved": "https://registry.npmjs.org/algoliasearch-helper/-/algoliasearch-helper-3.12.0.tgz", - "integrity": "sha512-/j1U3PEwdan0n6P/QqSnSpNSLC5+cEMvyljd5CnmNmUjDlGrys+vFEOwjVEnqELIiAGMHEA/Nl3CiKVFBUYqyQ==", + "version": "3.13.0", + "resolved": "https://registry.npmjs.org/algoliasearch-helper/-/algoliasearch-helper-3.13.0.tgz", + "integrity": "sha512-kV3c1jMQCvkARtGsSDvAwuht4PAMSsQILqPiH4WFiARoa3jXJ/r1TQoBWAjWyWF48rsNYCv7kzxgB4LTxrvvuw==", "dependencies": { "@algolia/events": "^4.0.1" }, @@ -4774,22 +4774,22 @@ } }, "node_modules/cheerio-select/node_modules/domutils": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/domutils/-/domutils-3.0.1.tgz", - "integrity": "sha512-z08c1l761iKhDFtfXO04C7kTdPBLi41zwOZl00WS8b5eiaebNpY00HKbztwBq+e3vyqWNwWF3mP9YLUeqIrF+Q==", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-3.1.0.tgz", + "integrity": "sha512-H78uMmQtI2AhgDJjWeQmHwJJ2bLPD3GMmO7Zja/ZZh84wkm+4ut+IUnUdRa8uCGX88DiVx1j6FRe1XfxEgjEZA==", "dependencies": { "dom-serializer": "^2.0.0", "domelementtype": "^2.3.0", - "domhandler": "^5.0.1" + "domhandler": "^5.0.3" }, "funding": { "url": "https://github.com/fb55/domutils?sponsor=1" } }, "node_modules/cheerio-select/node_modules/entities": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/entities/-/entities-4.4.0.tgz", - "integrity": "sha512-oYp7156SP8LkeGD0GF85ad1X9Ai79WtRsZ2gxJqtBuzH+98YUV6jkHEKlZkMbcrjJjIVJNIDP/3WL9wQkoPbWA==", + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", + "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", "engines": { "node": ">=0.12" }, @@ -4825,22 +4825,22 @@ } }, "node_modules/cheerio/node_modules/domutils": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/domutils/-/domutils-3.0.1.tgz", - "integrity": "sha512-z08c1l761iKhDFtfXO04C7kTdPBLi41zwOZl00WS8b5eiaebNpY00HKbztwBq+e3vyqWNwWF3mP9YLUeqIrF+Q==", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-3.1.0.tgz", + "integrity": "sha512-H78uMmQtI2AhgDJjWeQmHwJJ2bLPD3GMmO7Zja/ZZh84wkm+4ut+IUnUdRa8uCGX88DiVx1j6FRe1XfxEgjEZA==", "dependencies": { "dom-serializer": "^2.0.0", "domelementtype": "^2.3.0", - "domhandler": "^5.0.1" + "domhandler": "^5.0.3" }, "funding": { "url": "https://github.com/fb55/domutils?sponsor=1" } }, "node_modules/cheerio/node_modules/entities": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/entities/-/entities-4.4.0.tgz", - "integrity": "sha512-oYp7156SP8LkeGD0GF85ad1X9Ai79WtRsZ2gxJqtBuzH+98YUV6jkHEKlZkMbcrjJjIVJNIDP/3WL9wQkoPbWA==", + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", + "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", "engines": { "node": ">=0.12" }, @@ -5403,11 +5403,11 @@ } }, "node_modules/cross-fetch": { - "version": "3.1.5", - "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-3.1.5.tgz", - "integrity": "sha512-lvb1SBsI0Z7GDwmuid+mU3kWVBwTVUbe7S0H52yaaAdQOXq2YktTCZdlAcNKFzE6QtRz0snpw9bNiPeOIkkQvw==", + "version": "3.1.6", + "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-3.1.6.tgz", + "integrity": "sha512-riRvo06crlE8HiqOwIpQhxwdOk4fOeR7FVM/wXoxchFEqMNUjvbs3bfo4OTgMEMHzppd4DxFBDbyySj8Cv781g==", "dependencies": { - "node-fetch": "2.6.7" + "node-fetch": "^2.6.11" } }, "node_modules/cross-spawn": { @@ -9515,9 +9515,9 @@ } }, "node_modules/node-fetch": { - "version": "2.6.7", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz", - "integrity": "sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==", + "version": "2.6.11", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.11.tgz", + "integrity": "sha512-4I6pdBY1EthSqDmJkiNk3JIT8cswwR9nfeW/cPdUagJYEQG7R95WRH74wpz7ma8Gh/9dI9FP+OU+0E4FvtA55w==", "dependencies": { "whatwg-url": "^5.0.0" }, @@ -9934,9 +9934,9 @@ } }, "node_modules/parse5/node_modules/entities": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/entities/-/entities-4.4.0.tgz", - "integrity": "sha512-oYp7156SP8LkeGD0GF85ad1X9Ai79WtRsZ2gxJqtBuzH+98YUV6jkHEKlZkMbcrjJjIVJNIDP/3WL9wQkoPbWA==", + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", + "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", "engines": { "node": ">=0.12" }, @@ -10758,9 +10758,9 @@ } }, "node_modules/postcss-sort-media-queries": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/postcss-sort-media-queries/-/postcss-sort-media-queries-4.3.0.tgz", - "integrity": "sha512-jAl8gJM2DvuIJiI9sL1CuiHtKM4s5aEIomkU8G3LFvbP+p8i7Sz8VV63uieTgoewGqKbi+hxBTiOKJlB35upCg==", + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/postcss-sort-media-queries/-/postcss-sort-media-queries-4.4.1.tgz", + "integrity": "sha512-QDESFzDDGKgpiIh4GYXsSy6sek2yAwQx1JASl5AxBtU1Lq2JfKBljIPNdil989NcSKRQX1ToiaKphImtBuhXWw==", "dependencies": { "sort-css-media-queries": "2.1.0" }, @@ -13374,9 +13374,9 @@ } }, "node_modules/ua-parser-js": { - "version": "0.7.34", - "resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-0.7.34.tgz", - "integrity": "sha512-cJMeh/eOILyGu0ejgTKB95yKT3zOenSe9UGE3vj6WfiOwgGYnmATUsnDixMFvdU+rNMvWih83hrUP8VwhF9yXQ==", + "version": "0.7.35", + "resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-0.7.35.tgz", + "integrity": "sha512-veRf7dawaj9xaWEu9HoTVn5Pggtc/qj+kqTOFvNiN1l0YdxwC1kvel57UCjThjGa3BHBihE8/UJAHI+uQHmd/g==", "funding": [ { "type": "opencollective", @@ -14858,95 +14858,95 @@ }, "dependencies": { "@algolia/autocomplete-core": { - "version": "1.7.4", - "resolved": "https://registry.npmjs.org/@algolia/autocomplete-core/-/autocomplete-core-1.7.4.tgz", - "integrity": "sha512-daoLpQ3ps/VTMRZDEBfU8ixXd+amZcNJ4QSP3IERGyzqnL5Ch8uSRFt/4G8pUvW9c3o6GA4vtVv4I4lmnkdXyg==", + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/@algolia/autocomplete-core/-/autocomplete-core-1.8.2.tgz", + "integrity": "sha512-mTeshsyFhAqw/ebqNsQpMtbnjr+qVOSKXArEj4K0d7sqc8It1XD0gkASwecm9mF/jlOQ4Z9RNg1HbdA8JPdRwQ==", "requires": { - "@algolia/autocomplete-shared": "1.7.4" + "@algolia/autocomplete-shared": "1.8.2" } }, "@algolia/autocomplete-preset-algolia": { - "version": "1.7.4", - "resolved": "https://registry.npmjs.org/@algolia/autocomplete-preset-algolia/-/autocomplete-preset-algolia-1.7.4.tgz", - "integrity": "sha512-s37hrvLEIfcmKY8VU9LsAXgm2yfmkdHT3DnA3SgHaY93yjZ2qL57wzb5QweVkYuEBZkT2PIREvRoLXC2sxTbpQ==", + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/@algolia/autocomplete-preset-algolia/-/autocomplete-preset-algolia-1.8.2.tgz", + "integrity": "sha512-J0oTx4me6ZM9kIKPuL3lyU3aB8DEvpVvR6xWmHVROx5rOYJGQcZsdG4ozxwcOyiiu3qxMkIbzntnV1S1VWD8yA==", "requires": { - "@algolia/autocomplete-shared": "1.7.4" + "@algolia/autocomplete-shared": "1.8.2" } }, "@algolia/autocomplete-shared": { - "version": "1.7.4", - "resolved": "https://registry.npmjs.org/@algolia/autocomplete-shared/-/autocomplete-shared-1.7.4.tgz", - "integrity": "sha512-2VGCk7I9tA9Ge73Km99+Qg87w0wzW4tgUruvWAn/gfey1ZXgmxZtyIRBebk35R1O8TbK77wujVtCnpsGpRy1kg==" + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/@algolia/autocomplete-shared/-/autocomplete-shared-1.8.2.tgz", + "integrity": "sha512-b6Z/X4MczChMcfhk6kfRmBzPgjoPzuS9KGR4AFsiLulLNRAAqhP+xZTKtMnZGhLuc61I20d5WqlId02AZvcO6g==" }, "@algolia/cache-browser-local-storage": { - "version": "4.16.0", - "resolved": "https://registry.npmjs.org/@algolia/cache-browser-local-storage/-/cache-browser-local-storage-4.16.0.tgz", - "integrity": "sha512-jVrk0YB3tjOhD5/lhBtYCVCeLjZmVpf2kdi4puApofytf/R0scjWz0GdozlW4HhU+Prxmt/c9ge4QFjtv5OAzQ==", + "version": "4.17.0", + "resolved": "https://registry.npmjs.org/@algolia/cache-browser-local-storage/-/cache-browser-local-storage-4.17.0.tgz", + "integrity": "sha512-myRSRZDIMYB8uCkO+lb40YKiYHi0fjpWRtJpR/dgkaiBlSD0plRyB6lLOh1XIfmMcSeBOqDE7y9m8xZMrXYfyQ==", "requires": { - "@algolia/cache-common": "4.16.0" + "@algolia/cache-common": "4.17.0" } }, "@algolia/cache-common": { - "version": "4.16.0", - "resolved": "https://registry.npmjs.org/@algolia/cache-common/-/cache-common-4.16.0.tgz", - "integrity": "sha512-4iHjkSYQYw46pITrNQgXXhvUmcekI8INz1m+SzmqLX8jexSSy4Ky4zfGhZzhhhLHXUP3+x/PK/c0qPjxEvRwKQ==" + "version": "4.17.0", + "resolved": "https://registry.npmjs.org/@algolia/cache-common/-/cache-common-4.17.0.tgz", + "integrity": "sha512-g8mXzkrcUBIPZaulAuqE7xyHhLAYAcF2xSch7d9dABheybaU3U91LjBX6eJTEB7XVhEsgK4Smi27vWtAJRhIKQ==" }, "@algolia/cache-in-memory": { - "version": "4.16.0", - "resolved": "https://registry.npmjs.org/@algolia/cache-in-memory/-/cache-in-memory-4.16.0.tgz", - "integrity": "sha512-p7RYykvA6Ip6QENxrh99nOD77otVh1sJRivcgcVpnjoZb5sIN3t33eUY1DpB9QSBizcrW+qk19rNkdnZ43a+PQ==", + "version": "4.17.0", + "resolved": "https://registry.npmjs.org/@algolia/cache-in-memory/-/cache-in-memory-4.17.0.tgz", + "integrity": "sha512-PT32ciC/xI8z919d0oknWVu3kMfTlhQn3MKxDln3pkn+yA7F7xrxSALysxquv+MhFfNAcrtQ/oVvQVBAQSHtdw==", "requires": { - "@algolia/cache-common": "4.16.0" + "@algolia/cache-common": "4.17.0" } }, "@algolia/client-account": { - "version": "4.16.0", - "resolved": "https://registry.npmjs.org/@algolia/client-account/-/client-account-4.16.0.tgz", - "integrity": "sha512-eydcfpdIyuWoKgUSz5iZ/L0wE/Wl7958kACkvTHLDNXvK/b8Z1zypoJavh6/km1ZNQmFpeYS2jrmq0kUSFn02w==", + "version": "4.17.0", + "resolved": "https://registry.npmjs.org/@algolia/client-account/-/client-account-4.17.0.tgz", + "integrity": "sha512-sSEHx9GA6m7wrlsSMNBGfyzlIfDT2fkz2u7jqfCCd6JEEwmxt8emGmxAU/0qBfbhRSuGvzojoLJlr83BSZAKjA==", "requires": { - "@algolia/client-common": "4.16.0", - "@algolia/client-search": "4.16.0", - "@algolia/transporter": "4.16.0" + "@algolia/client-common": "4.17.0", + "@algolia/client-search": "4.17.0", + "@algolia/transporter": "4.17.0" } }, "@algolia/client-analytics": { - "version": "4.16.0", - "resolved": "https://registry.npmjs.org/@algolia/client-analytics/-/client-analytics-4.16.0.tgz", - "integrity": "sha512-cONWXH3BfilgdlCofUm492bJRWtpBLVW/hsUlfoFtiX1u05xoBP7qeiDwh9RR+4pSLHLodYkHAf5U4honQ55Qg==", + "version": "4.17.0", + "resolved": "https://registry.npmjs.org/@algolia/client-analytics/-/client-analytics-4.17.0.tgz", + "integrity": "sha512-84ooP8QA3mQ958hQ9wozk7hFUbAO+81CX1CjAuerxBqjKIInh1fOhXKTaku05O/GHBvcfExpPLIQuSuLYziBXQ==", "requires": { - "@algolia/client-common": "4.16.0", - "@algolia/client-search": "4.16.0", - "@algolia/requester-common": "4.16.0", - "@algolia/transporter": "4.16.0" + "@algolia/client-common": "4.17.0", + "@algolia/client-search": "4.17.0", + "@algolia/requester-common": "4.17.0", + "@algolia/transporter": "4.17.0" } }, "@algolia/client-common": { - "version": "4.16.0", - "resolved": "https://registry.npmjs.org/@algolia/client-common/-/client-common-4.16.0.tgz", - "integrity": "sha512-QVdR4019ukBH6f5lFr27W60trRxQF1SfS1qo0IP6gjsKhXhUVJuHxOCA6ArF87jrNkeuHEoRoDU+GlvaecNo8g==", + "version": "4.17.0", + "resolved": "https://registry.npmjs.org/@algolia/client-common/-/client-common-4.17.0.tgz", + "integrity": "sha512-jHMks0ZFicf8nRDn6ma8DNNsdwGgP/NKiAAL9z6rS7CymJ7L0+QqTJl3rYxRW7TmBhsUH40wqzmrG6aMIN/DrQ==", "requires": { - "@algolia/requester-common": "4.16.0", - "@algolia/transporter": "4.16.0" + "@algolia/requester-common": "4.17.0", + "@algolia/transporter": "4.17.0" } }, "@algolia/client-personalization": { - "version": "4.16.0", - "resolved": "https://registry.npmjs.org/@algolia/client-personalization/-/client-personalization-4.16.0.tgz", - "integrity": "sha512-irtLafssDGPuhYqIwxqOxiWlVYvrsBD+EMA1P9VJtkKi3vSNBxiWeQ0f0Tn53cUNdSRNEssfoEH84JL97SV2SQ==", + "version": "4.17.0", + "resolved": "https://registry.npmjs.org/@algolia/client-personalization/-/client-personalization-4.17.0.tgz", + "integrity": "sha512-RMzN4dZLIta1YuwT7QC9o+OeGz2cU6eTOlGNE/6RcUBLOU3l9tkCOdln5dPE2jp8GZXPl2yk54b2nSs1+pAjqw==", "requires": { - "@algolia/client-common": "4.16.0", - "@algolia/requester-common": "4.16.0", - "@algolia/transporter": "4.16.0" + "@algolia/client-common": "4.17.0", + "@algolia/requester-common": "4.17.0", + "@algolia/transporter": "4.17.0" } }, "@algolia/client-search": { - "version": "4.16.0", - "resolved": "https://registry.npmjs.org/@algolia/client-search/-/client-search-4.16.0.tgz", - "integrity": "sha512-xsfrAE1jO/JDh1wFrRz+alVyW+aA6qnkzmbWWWZWEgVF3EaFqzIf9r1l/aDtDdBtNTNhX9H3Lg31+BRtd5izQA==", + "version": "4.17.0", + "resolved": "https://registry.npmjs.org/@algolia/client-search/-/client-search-4.17.0.tgz", + "integrity": "sha512-x4P2wKrrRIXszT8gb7eWsMHNNHAJs0wE7/uqbufm4tZenAp+hwU/hq5KVsY50v+PfwM0LcDwwn/1DroujsTFoA==", "requires": { - "@algolia/client-common": "4.16.0", - "@algolia/requester-common": "4.16.0", - "@algolia/transporter": "4.16.0" + "@algolia/client-common": "4.17.0", + "@algolia/requester-common": "4.17.0", + "@algolia/transporter": "4.17.0" } }, "@algolia/events": { @@ -14955,47 +14955,47 @@ "integrity": "sha512-FQzvOCgoFXAbf5Y6mYozw2aj5KCJoA3m4heImceldzPSMbdyS4atVjJzXKMsfX3wnZTFYwkkt8/z8UesLHlSBQ==" }, "@algolia/logger-common": { - "version": "4.16.0", - "resolved": "https://registry.npmjs.org/@algolia/logger-common/-/logger-common-4.16.0.tgz", - "integrity": "sha512-U9H8uCzSDuePJmbnjjTX21aPDRU6x74Tdq3dJmdYu2+pISx02UeBJm4kSgc9RW5jcR5j35G9gnjHY9Q3ngWbyQ==" + "version": "4.17.0", + "resolved": "https://registry.npmjs.org/@algolia/logger-common/-/logger-common-4.17.0.tgz", + "integrity": "sha512-DGuoZqpTmIKJFDeyAJ7M8E/LOenIjWiOsg1XJ1OqAU/eofp49JfqXxbfgctlVZVmDABIyOz8LqEoJ6ZP4DTyvw==" }, "@algolia/logger-console": { - "version": "4.16.0", - "resolved": "https://registry.npmjs.org/@algolia/logger-console/-/logger-console-4.16.0.tgz", - "integrity": "sha512-+qymusiM+lPZKrkf0tDjCQA158eEJO2IU+Nr/sJ9TFyI/xkFPjNPzw/Qbc8Iy/xcOXGlc6eMgmyjtVQqAWq6UA==", + "version": "4.17.0", + "resolved": "https://registry.npmjs.org/@algolia/logger-console/-/logger-console-4.17.0.tgz", + "integrity": "sha512-zMPvugQV/gbXUvWBCzihw6m7oxIKp48w37QBIUu/XqQQfxhjoOE9xyfJr1KldUt5FrYOKZJVsJaEjTsu+bIgQg==", "requires": { - "@algolia/logger-common": "4.16.0" + "@algolia/logger-common": "4.17.0" } }, "@algolia/requester-browser-xhr": { - "version": "4.16.0", - "resolved": "https://registry.npmjs.org/@algolia/requester-browser-xhr/-/requester-browser-xhr-4.16.0.tgz", - "integrity": "sha512-gK+kvs6LHl/PaOJfDuwjkopNbG1djzFLsVBklGBsSU6h6VjFkxIpo6Qq80IK14p9cplYZfhfaL12va6Q9p3KVQ==", + "version": "4.17.0", + "resolved": "https://registry.npmjs.org/@algolia/requester-browser-xhr/-/requester-browser-xhr-4.17.0.tgz", + "integrity": "sha512-aSOX/smauyTkP21Pf52pJ1O2LmNFJ5iHRIzEeTh0mwBeADO4GdG94cAWDILFA9rNblq/nK3EDh3+UyHHjplZ1A==", "requires": { - "@algolia/requester-common": "4.16.0" + "@algolia/requester-common": "4.17.0" } }, "@algolia/requester-common": { - "version": "4.16.0", - "resolved": "https://registry.npmjs.org/@algolia/requester-common/-/requester-common-4.16.0.tgz", - "integrity": "sha512-3Zmcs/iMubcm4zqZ3vZG6Zum8t+hMWxGMzo0/uY2BD8o9q5vMxIYI0c4ocdgQjkXcix189WtZNkgjSOBzSbkdw==" + "version": "4.17.0", + "resolved": "https://registry.npmjs.org/@algolia/requester-common/-/requester-common-4.17.0.tgz", + "integrity": "sha512-XJjmWFEUlHu0ijvcHBoixuXfEoiRUdyzQM6YwTuB8usJNIgShua8ouFlRWF8iCeag0vZZiUm4S2WCVBPkdxFgg==" }, "@algolia/requester-node-http": { - "version": "4.16.0", - "resolved": "https://registry.npmjs.org/@algolia/requester-node-http/-/requester-node-http-4.16.0.tgz", - "integrity": "sha512-L8JxM2VwZzh8LJ1Zb8TFS6G3icYsCKZsdWW+ahcEs1rGWmyk9SybsOe1MLnjonGBaqPWJkn9NjS7mRdjEmBtKA==", + "version": "4.17.0", + "resolved": "https://registry.npmjs.org/@algolia/requester-node-http/-/requester-node-http-4.17.0.tgz", + "integrity": "sha512-bpb/wDA1aC6WxxM8v7TsFspB7yBN3nqCGs2H1OADolQR/hiAIjAxusbuMxVbRFOdaUvAIqioIIkWvZdpYNIn8w==", "requires": { - "@algolia/requester-common": "4.16.0" + "@algolia/requester-common": "4.17.0" } }, "@algolia/transporter": { - "version": "4.16.0", - "resolved": "https://registry.npmjs.org/@algolia/transporter/-/transporter-4.16.0.tgz", - "integrity": "sha512-H9BVB2EAjT65w7XGBNf5drpsW39x2aSZ942j4boSAAJPPlLmjtj5IpAP7UAtsV8g9Beslonh0bLa1XGmE/P0BA==", + "version": "4.17.0", + "resolved": "https://registry.npmjs.org/@algolia/transporter/-/transporter-4.17.0.tgz", + "integrity": "sha512-6xL6H6fe+Fi0AEP3ziSgC+G04RK37iRb4uUUqVAH9WPYFI8g+LYFq6iv5HS8Cbuc5TTut+Bwj6G+dh/asdb9uA==", "requires": { - "@algolia/cache-common": "4.16.0", - "@algolia/logger-common": "4.16.0", - "@algolia/requester-common": "4.16.0" + "@algolia/cache-common": "4.17.0", + "@algolia/logger-common": "4.17.0", + "@algolia/requester-common": "4.17.0" } }, "@alloc/quick-lru": { @@ -16096,25 +16096,25 @@ "optional": true }, "@docsearch/css": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/@docsearch/css/-/css-3.3.3.tgz", - "integrity": "sha512-6SCwI7P8ao+se1TUsdZ7B4XzL+gqeQZnBc+2EONZlcVa0dVrk0NjETxozFKgMv0eEGH8QzP1fkN+A1rH61l4eg==" + "version": "3.3.4", + "resolved": "https://registry.npmjs.org/@docsearch/css/-/css-3.3.4.tgz", + "integrity": "sha512-vDwCDoVXDgopw/hvr0zEADew2wWaGP8Qq0Bxhgii1Ewz2t4fQeyJwIRN/mWADeLFYPVkpz8TpEbxya/i6Tm0WA==" }, "@docsearch/react": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/@docsearch/react/-/react-3.3.3.tgz", - "integrity": "sha512-pLa0cxnl+G0FuIDuYlW+EBK6Rw2jwLw9B1RHIeS4N4s2VhsfJ/wzeCi3CWcs5yVfxLd5ZK50t//TMA5e79YT7Q==", + "version": "3.3.4", + "resolved": "https://registry.npmjs.org/@docsearch/react/-/react-3.3.4.tgz", + "integrity": "sha512-aeOf1WC5zMzBEi2SI6WWznOmIo9rnpN4p7a3zHXxowVciqlI4HsZGtOR9nFOufLeolv7HibwLlaM0oyUqJxasw==", "requires": { - "@algolia/autocomplete-core": "1.7.4", - "@algolia/autocomplete-preset-algolia": "1.7.4", - "@docsearch/css": "3.3.3", + "@algolia/autocomplete-core": "1.8.2", + "@algolia/autocomplete-preset-algolia": "1.8.2", + "@docsearch/css": "3.3.4", "algoliasearch": "^4.0.0" } }, "@docusaurus/core": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/@docusaurus/core/-/core-2.4.0.tgz", - "integrity": "sha512-J55/WEoIpRcLf3afO5POHPguVZosKmJEQWKBL+K7TAnfuE7i+Y0NPLlkKtnWCehagGsgTqClfQEexH/UT4kELA==", + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/@docusaurus/core/-/core-2.4.1.tgz", + "integrity": "sha512-SNsY7PshK3Ri7vtsLXVeAJGS50nJN3RgF836zkyUfAD01Fq+sAk5EwWgLw+nnm5KVNGDu7PRR2kRGDsWvqpo0g==", "requires": { "@babel/core": "^7.18.6", "@babel/generator": "^7.18.7", @@ -16126,13 +16126,13 @@ "@babel/runtime": "^7.18.6", "@babel/runtime-corejs3": "^7.18.6", "@babel/traverse": "^7.18.8", - "@docusaurus/cssnano-preset": "2.4.0", - "@docusaurus/logger": "2.4.0", - "@docusaurus/mdx-loader": "2.4.0", + "@docusaurus/cssnano-preset": "2.4.1", + "@docusaurus/logger": "2.4.1", + "@docusaurus/mdx-loader": "2.4.1", "@docusaurus/react-loadable": "5.5.2", - "@docusaurus/utils": "2.4.0", - "@docusaurus/utils-common": "2.4.0", - "@docusaurus/utils-validation": "2.4.0", + "@docusaurus/utils": "2.4.1", + "@docusaurus/utils-common": "2.4.1", + "@docusaurus/utils-validation": "2.4.1", "@slorber/static-site-generator-webpack-plugin": "^4.0.7", "@svgr/webpack": "^6.2.1", "autoprefixer": "^10.4.7", @@ -16235,9 +16235,9 @@ } }, "@docusaurus/cssnano-preset": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/@docusaurus/cssnano-preset/-/cssnano-preset-2.4.0.tgz", - "integrity": "sha512-RmdiA3IpsLgZGXRzqnmTbGv43W4OD44PCo+6Q/aYjEM2V57vKCVqNzuafE94jv0z/PjHoXUrjr69SaRymBKYYw==", + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/@docusaurus/cssnano-preset/-/cssnano-preset-2.4.1.tgz", + "integrity": "sha512-ka+vqXwtcW1NbXxWsh6yA1Ckii1klY9E53cJ4O9J09nkMBgrNX3iEFED1fWdv8wf4mJjvGi5RLZ2p9hJNjsLyQ==", "requires": { "cssnano-preset-advanced": "^5.3.8", "postcss": "^8.4.14", @@ -16246,9 +16246,9 @@ } }, "@docusaurus/logger": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/@docusaurus/logger/-/logger-2.4.0.tgz", - "integrity": "sha512-T8+qR4APN+MjcC9yL2Es+xPJ2923S9hpzDmMtdsOcUGLqpCGBbU1vp3AAqDwXtVgFkq+NsEk7sHdVsfLWR/AXw==", + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/@docusaurus/logger/-/logger-2.4.1.tgz", + "integrity": "sha512-5h5ysIIWYIDHyTVd8BjheZmQZmEgWDR54aQ1BX9pjFfpyzFo5puKXKYrYJXbjEHGyVhEzmB9UXwbxGfaZhOjcg==", "requires": { "chalk": "^4.1.2", "tslib": "^2.4.0" @@ -16300,14 +16300,14 @@ } }, "@docusaurus/mdx-loader": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/@docusaurus/mdx-loader/-/mdx-loader-2.4.0.tgz", - "integrity": "sha512-GWoH4izZKOmFoC+gbI2/y8deH/xKLvzz/T5BsEexBye8EHQlwsA7FMrVa48N063bJBH4FUOiRRXxk5rq9cC36g==", + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/@docusaurus/mdx-loader/-/mdx-loader-2.4.1.tgz", + "integrity": "sha512-4KhUhEavteIAmbBj7LVFnrVYDiU51H5YWW1zY6SmBSte/YLhDutztLTBE0PQl1Grux1jzUJeaSvAzHpTn6JJDQ==", "requires": { "@babel/parser": "^7.18.8", "@babel/traverse": "^7.18.8", - "@docusaurus/logger": "2.4.0", - "@docusaurus/utils": "2.4.0", + "@docusaurus/logger": "2.4.1", + "@docusaurus/utils": "2.4.1", "@mdx-js/mdx": "^1.6.22", "escape-html": "^1.0.3", "file-loader": "^6.2.0", @@ -16324,12 +16324,12 @@ } }, "@docusaurus/module-type-aliases": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/@docusaurus/module-type-aliases/-/module-type-aliases-2.4.0.tgz", - "integrity": "sha512-YEQO2D3UXs72qCn8Cr+RlycSQXVGN9iEUyuHwTuK4/uL/HFomB2FHSU0vSDM23oLd+X/KibQ3Ez6nGjQLqXcHg==", + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/@docusaurus/module-type-aliases/-/module-type-aliases-2.4.1.tgz", + "integrity": "sha512-gLBuIFM8Dp2XOCWffUDSjtxY7jQgKvYujt7Mx5s4FCTfoL5dN1EVbnrn+O2Wvh8b0a77D57qoIDY7ghgmatR1A==", "requires": { "@docusaurus/react-loadable": "5.5.2", - "@docusaurus/types": "2.4.0", + "@docusaurus/types": "2.4.1", "@types/history": "^4.7.11", "@types/react": "*", "@types/react-router-config": "*", @@ -16339,17 +16339,17 @@ } }, "@docusaurus/plugin-content-blog": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/@docusaurus/plugin-content-blog/-/plugin-content-blog-2.4.0.tgz", - "integrity": "sha512-YwkAkVUxtxoBAIj/MCb4ohN0SCtHBs4AS75jMhPpf67qf3j+U/4n33cELq7567hwyZ6fMz2GPJcVmctzlGGThQ==", + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/@docusaurus/plugin-content-blog/-/plugin-content-blog-2.4.1.tgz", + "integrity": "sha512-E2i7Knz5YIbE1XELI6RlTnZnGgS52cUO4BlCiCUCvQHbR+s1xeIWz4C6BtaVnlug0Ccz7nFSksfwDpVlkujg5Q==", "requires": { - "@docusaurus/core": "2.4.0", - "@docusaurus/logger": "2.4.0", - "@docusaurus/mdx-loader": "2.4.0", - "@docusaurus/types": "2.4.0", - "@docusaurus/utils": "2.4.0", - "@docusaurus/utils-common": "2.4.0", - "@docusaurus/utils-validation": "2.4.0", + "@docusaurus/core": "2.4.1", + "@docusaurus/logger": "2.4.1", + "@docusaurus/mdx-loader": "2.4.1", + "@docusaurus/types": "2.4.1", + "@docusaurus/utils": "2.4.1", + "@docusaurus/utils-common": "2.4.1", + "@docusaurus/utils-validation": "2.4.1", "cheerio": "^1.0.0-rc.12", "feed": "^4.2.2", "fs-extra": "^10.1.0", @@ -16362,17 +16362,17 @@ } }, "@docusaurus/plugin-content-docs": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/@docusaurus/plugin-content-docs/-/plugin-content-docs-2.4.0.tgz", - "integrity": "sha512-ic/Z/ZN5Rk/RQo+Io6rUGpToOtNbtPloMR2JcGwC1xT2riMu6zzfSwmBi9tHJgdXH6CB5jG+0dOZZO8QS5tmDg==", + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/@docusaurus/plugin-content-docs/-/plugin-content-docs-2.4.1.tgz", + "integrity": "sha512-Lo7lSIcpswa2Kv4HEeUcGYqaasMUQNpjTXpV0N8G6jXgZaQurqp7E8NGYeGbDXnb48czmHWbzDL4S3+BbK0VzA==", "requires": { - "@docusaurus/core": "2.4.0", - "@docusaurus/logger": "2.4.0", - "@docusaurus/mdx-loader": "2.4.0", - "@docusaurus/module-type-aliases": "2.4.0", - "@docusaurus/types": "2.4.0", - "@docusaurus/utils": "2.4.0", - "@docusaurus/utils-validation": "2.4.0", + "@docusaurus/core": "2.4.1", + "@docusaurus/logger": "2.4.1", + "@docusaurus/mdx-loader": "2.4.1", + "@docusaurus/module-type-aliases": "2.4.1", + "@docusaurus/types": "2.4.1", + "@docusaurus/utils": "2.4.1", + "@docusaurus/utils-validation": "2.4.1", "@types/react-router-config": "^5.0.6", "combine-promises": "^1.1.0", "fs-extra": "^10.1.0", @@ -16385,100 +16385,100 @@ } }, "@docusaurus/plugin-content-pages": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/@docusaurus/plugin-content-pages/-/plugin-content-pages-2.4.0.tgz", - "integrity": "sha512-Pk2pOeOxk8MeU3mrTU0XLIgP9NZixbdcJmJ7RUFrZp1Aj42nd0RhIT14BGvXXyqb8yTQlk4DmYGAzqOfBsFyGw==", + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/@docusaurus/plugin-content-pages/-/plugin-content-pages-2.4.1.tgz", + "integrity": "sha512-/UjuH/76KLaUlL+o1OvyORynv6FURzjurSjvn2lbWTFc4tpYY2qLYTlKpTCBVPhlLUQsfyFnshEJDLmPneq2oA==", "requires": { - "@docusaurus/core": "2.4.0", - "@docusaurus/mdx-loader": "2.4.0", - "@docusaurus/types": "2.4.0", - "@docusaurus/utils": "2.4.0", - "@docusaurus/utils-validation": "2.4.0", + "@docusaurus/core": "2.4.1", + "@docusaurus/mdx-loader": "2.4.1", + "@docusaurus/types": "2.4.1", + "@docusaurus/utils": "2.4.1", + "@docusaurus/utils-validation": "2.4.1", "fs-extra": "^10.1.0", "tslib": "^2.4.0", "webpack": "^5.73.0" } }, "@docusaurus/plugin-debug": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/@docusaurus/plugin-debug/-/plugin-debug-2.4.0.tgz", - "integrity": "sha512-KC56DdYjYT7Txyux71vXHXGYZuP6yYtqwClvYpjKreWIHWus5Zt6VNi23rMZv3/QKhOCrN64zplUbdfQMvddBQ==", + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/@docusaurus/plugin-debug/-/plugin-debug-2.4.1.tgz", + "integrity": "sha512-7Yu9UPzRShlrH/G8btOpR0e6INFZr0EegWplMjOqelIwAcx3PKyR8mgPTxGTxcqiYj6hxSCRN0D8R7YrzImwNA==", "requires": { - "@docusaurus/core": "2.4.0", - "@docusaurus/types": "2.4.0", - "@docusaurus/utils": "2.4.0", + "@docusaurus/core": "2.4.1", + "@docusaurus/types": "2.4.1", + "@docusaurus/utils": "2.4.1", "fs-extra": "^10.1.0", "react-json-view": "^1.21.3", "tslib": "^2.4.0" } }, "@docusaurus/plugin-google-analytics": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/@docusaurus/plugin-google-analytics/-/plugin-google-analytics-2.4.0.tgz", - "integrity": "sha512-uGUzX67DOAIglygdNrmMOvEp8qG03X20jMWadeqVQktS6nADvozpSLGx4J0xbkblhJkUzN21WiilsP9iVP+zkw==", + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/@docusaurus/plugin-google-analytics/-/plugin-google-analytics-2.4.1.tgz", + "integrity": "sha512-dyZJdJiCoL+rcfnm0RPkLt/o732HvLiEwmtoNzOoz9MSZz117UH2J6U2vUDtzUzwtFLIf32KkeyzisbwUCgcaQ==", "requires": { - "@docusaurus/core": "2.4.0", - "@docusaurus/types": "2.4.0", - "@docusaurus/utils-validation": "2.4.0", + "@docusaurus/core": "2.4.1", + "@docusaurus/types": "2.4.1", + "@docusaurus/utils-validation": "2.4.1", "tslib": "^2.4.0" } }, "@docusaurus/plugin-google-gtag": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/@docusaurus/plugin-google-gtag/-/plugin-google-gtag-2.4.0.tgz", - "integrity": "sha512-adj/70DANaQs2+TF/nRdMezDXFAV/O/pjAbUgmKBlyOTq5qoMe0Tk4muvQIwWUmiUQxFJe+sKlZGM771ownyOg==", + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/@docusaurus/plugin-google-gtag/-/plugin-google-gtag-2.4.1.tgz", + "integrity": "sha512-mKIefK+2kGTQBYvloNEKtDmnRD7bxHLsBcxgnbt4oZwzi2nxCGjPX6+9SQO2KCN5HZbNrYmGo5GJfMgoRvy6uA==", "requires": { - "@docusaurus/core": "2.4.0", - "@docusaurus/types": "2.4.0", - "@docusaurus/utils-validation": "2.4.0", + "@docusaurus/core": "2.4.1", + "@docusaurus/types": "2.4.1", + "@docusaurus/utils-validation": "2.4.1", "tslib": "^2.4.0" } }, "@docusaurus/plugin-google-tag-manager": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/@docusaurus/plugin-google-tag-manager/-/plugin-google-tag-manager-2.4.0.tgz", - "integrity": "sha512-E66uGcYs4l7yitmp/8kMEVQftFPwV9iC62ORh47Veqzs6ExwnhzBkJmwDnwIysHBF1vlxnzET0Fl2LfL5fRR3A==", + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/@docusaurus/plugin-google-tag-manager/-/plugin-google-tag-manager-2.4.1.tgz", + "integrity": "sha512-Zg4Ii9CMOLfpeV2nG74lVTWNtisFaH9QNtEw48R5QE1KIwDBdTVaiSA18G1EujZjrzJJzXN79VhINSbOJO/r3g==", "requires": { - "@docusaurus/core": "2.4.0", - "@docusaurus/types": "2.4.0", - "@docusaurus/utils-validation": "2.4.0", + "@docusaurus/core": "2.4.1", + "@docusaurus/types": "2.4.1", + "@docusaurus/utils-validation": "2.4.1", "tslib": "^2.4.0" } }, "@docusaurus/plugin-sitemap": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/@docusaurus/plugin-sitemap/-/plugin-sitemap-2.4.0.tgz", - "integrity": "sha512-pZxh+ygfnI657sN8a/FkYVIAmVv0CGk71QMKqJBOfMmDHNN1FeDeFkBjWP49ejBqpqAhjufkv5UWq3UOu2soCw==", + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/@docusaurus/plugin-sitemap/-/plugin-sitemap-2.4.1.tgz", + "integrity": "sha512-lZx+ijt/+atQ3FVE8FOHV/+X3kuok688OydDXrqKRJyXBJZKgGjA2Qa8RjQ4f27V2woaXhtnyrdPop/+OjVMRg==", "requires": { - "@docusaurus/core": "2.4.0", - "@docusaurus/logger": "2.4.0", - "@docusaurus/types": "2.4.0", - "@docusaurus/utils": "2.4.0", - "@docusaurus/utils-common": "2.4.0", - "@docusaurus/utils-validation": "2.4.0", + "@docusaurus/core": "2.4.1", + "@docusaurus/logger": "2.4.1", + "@docusaurus/types": "2.4.1", + "@docusaurus/utils": "2.4.1", + "@docusaurus/utils-common": "2.4.1", + "@docusaurus/utils-validation": "2.4.1", "fs-extra": "^10.1.0", "sitemap": "^7.1.1", "tslib": "^2.4.0" } }, "@docusaurus/preset-classic": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/@docusaurus/preset-classic/-/preset-classic-2.4.0.tgz", - "integrity": "sha512-/5z5o/9bc6+P5ool2y01PbJhoGddEGsC0ej1MF6mCoazk8A+kW4feoUd68l7Bnv01rCnG3xy7kHUQP97Y0grUA==", + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/@docusaurus/preset-classic/-/preset-classic-2.4.1.tgz", + "integrity": "sha512-P4//+I4zDqQJ+UDgoFrjIFaQ1MeS9UD1cvxVQaI6O7iBmiHQm0MGROP1TbE7HlxlDPXFJjZUK3x3cAoK63smGQ==", "requires": { - "@docusaurus/core": "2.4.0", - "@docusaurus/plugin-content-blog": "2.4.0", - "@docusaurus/plugin-content-docs": "2.4.0", - "@docusaurus/plugin-content-pages": "2.4.0", - "@docusaurus/plugin-debug": "2.4.0", - "@docusaurus/plugin-google-analytics": "2.4.0", - "@docusaurus/plugin-google-gtag": "2.4.0", - "@docusaurus/plugin-google-tag-manager": "2.4.0", - "@docusaurus/plugin-sitemap": "2.4.0", - "@docusaurus/theme-classic": "2.4.0", - "@docusaurus/theme-common": "2.4.0", - "@docusaurus/theme-search-algolia": "2.4.0", - "@docusaurus/types": "2.4.0" + "@docusaurus/core": "2.4.1", + "@docusaurus/plugin-content-blog": "2.4.1", + "@docusaurus/plugin-content-docs": "2.4.1", + "@docusaurus/plugin-content-pages": "2.4.1", + "@docusaurus/plugin-debug": "2.4.1", + "@docusaurus/plugin-google-analytics": "2.4.1", + "@docusaurus/plugin-google-gtag": "2.4.1", + "@docusaurus/plugin-google-tag-manager": "2.4.1", + "@docusaurus/plugin-sitemap": "2.4.1", + "@docusaurus/theme-classic": "2.4.1", + "@docusaurus/theme-common": "2.4.1", + "@docusaurus/theme-search-algolia": "2.4.1", + "@docusaurus/types": "2.4.1" } }, "@docusaurus/react-loadable": { @@ -16491,22 +16491,22 @@ } }, "@docusaurus/theme-classic": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/@docusaurus/theme-classic/-/theme-classic-2.4.0.tgz", - "integrity": "sha512-GMDX5WU6Z0OC65eQFgl3iNNEbI9IMJz9f6KnOyuMxNUR6q0qVLsKCNopFUDfFNJ55UU50o7P7o21yVhkwpfJ9w==", + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/@docusaurus/theme-classic/-/theme-classic-2.4.1.tgz", + "integrity": "sha512-Rz0wKUa+LTW1PLXmwnf8mn85EBzaGSt6qamqtmnh9Hflkc+EqiYMhtUJeLdV+wsgYq4aG0ANc+bpUDpsUhdnwg==", "requires": { - "@docusaurus/core": "2.4.0", - "@docusaurus/mdx-loader": "2.4.0", - "@docusaurus/module-type-aliases": "2.4.0", - "@docusaurus/plugin-content-blog": "2.4.0", - "@docusaurus/plugin-content-docs": "2.4.0", - "@docusaurus/plugin-content-pages": "2.4.0", - "@docusaurus/theme-common": "2.4.0", - "@docusaurus/theme-translations": "2.4.0", - "@docusaurus/types": "2.4.0", - "@docusaurus/utils": "2.4.0", - "@docusaurus/utils-common": "2.4.0", - "@docusaurus/utils-validation": "2.4.0", + "@docusaurus/core": "2.4.1", + "@docusaurus/mdx-loader": "2.4.1", + "@docusaurus/module-type-aliases": "2.4.1", + "@docusaurus/plugin-content-blog": "2.4.1", + "@docusaurus/plugin-content-docs": "2.4.1", + "@docusaurus/plugin-content-pages": "2.4.1", + "@docusaurus/theme-common": "2.4.1", + "@docusaurus/theme-translations": "2.4.1", + "@docusaurus/types": "2.4.1", + "@docusaurus/utils": "2.4.1", + "@docusaurus/utils-common": "2.4.1", + "@docusaurus/utils-validation": "2.4.1", "@mdx-js/react": "^1.6.22", "clsx": "^1.2.1", "copy-text-to-clipboard": "^3.0.1", @@ -16523,17 +16523,17 @@ } }, "@docusaurus/theme-common": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/@docusaurus/theme-common/-/theme-common-2.4.0.tgz", - "integrity": "sha512-IkG/l5f/FLY6cBIxtPmFnxpuPzc5TupuqlOx+XDN+035MdQcAh8wHXXZJAkTeYDeZ3anIUSUIvWa7/nRKoQEfg==", + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/@docusaurus/theme-common/-/theme-common-2.4.1.tgz", + "integrity": "sha512-G7Zau1W5rQTaFFB3x3soQoZpkgMbl/SYNG8PfMFIjKa3M3q8n0m/GRf5/H/e5BqOvt8c+ZWIXGCiz+kUCSHovA==", "requires": { - "@docusaurus/mdx-loader": "2.4.0", - "@docusaurus/module-type-aliases": "2.4.0", - "@docusaurus/plugin-content-blog": "2.4.0", - "@docusaurus/plugin-content-docs": "2.4.0", - "@docusaurus/plugin-content-pages": "2.4.0", - "@docusaurus/utils": "2.4.0", - "@docusaurus/utils-common": "2.4.0", + "@docusaurus/mdx-loader": "2.4.1", + "@docusaurus/module-type-aliases": "2.4.1", + "@docusaurus/plugin-content-blog": "2.4.1", + "@docusaurus/plugin-content-docs": "2.4.1", + "@docusaurus/plugin-content-pages": "2.4.1", + "@docusaurus/utils": "2.4.1", + "@docusaurus/utils-common": "2.4.1", "@types/history": "^4.7.11", "@types/react": "*", "@types/react-router-config": "*", @@ -16546,18 +16546,18 @@ } }, "@docusaurus/theme-search-algolia": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/@docusaurus/theme-search-algolia/-/theme-search-algolia-2.4.0.tgz", - "integrity": "sha512-pPCJSCL1Qt4pu/Z0uxBAuke0yEBbxh0s4fOvimna7TEcBLPq0x06/K78AaABXrTVQM6S0vdocFl9EoNgU17hqA==", + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/@docusaurus/theme-search-algolia/-/theme-search-algolia-2.4.1.tgz", + "integrity": "sha512-6BcqW2lnLhZCXuMAvPRezFs1DpmEKzXFKlYjruuas+Xy3AQeFzDJKTJFIm49N77WFCTyxff8d3E4Q9pi/+5McQ==", "requires": { "@docsearch/react": "^3.1.1", - "@docusaurus/core": "2.4.0", - "@docusaurus/logger": "2.4.0", - "@docusaurus/plugin-content-docs": "2.4.0", - "@docusaurus/theme-common": "2.4.0", - "@docusaurus/theme-translations": "2.4.0", - "@docusaurus/utils": "2.4.0", - "@docusaurus/utils-validation": "2.4.0", + "@docusaurus/core": "2.4.1", + "@docusaurus/logger": "2.4.1", + "@docusaurus/plugin-content-docs": "2.4.1", + "@docusaurus/theme-common": "2.4.1", + "@docusaurus/theme-translations": "2.4.1", + "@docusaurus/utils": "2.4.1", + "@docusaurus/utils-validation": "2.4.1", "algoliasearch": "^4.13.1", "algoliasearch-helper": "^3.10.0", "clsx": "^1.2.1", @@ -16569,18 +16569,18 @@ } }, "@docusaurus/theme-translations": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/@docusaurus/theme-translations/-/theme-translations-2.4.0.tgz", - "integrity": "sha512-kEoITnPXzDPUMBHk3+fzEzbopxLD3fR5sDoayNH0vXkpUukA88/aDL1bqkhxWZHA3LOfJ3f0vJbOwmnXW5v85Q==", + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/@docusaurus/theme-translations/-/theme-translations-2.4.1.tgz", + "integrity": "sha512-T1RAGP+f86CA1kfE8ejZ3T3pUU3XcyvrGMfC/zxCtc2BsnoexuNI9Vk2CmuKCb+Tacvhxjv5unhxXce0+NKyvA==", "requires": { "fs-extra": "^10.1.0", "tslib": "^2.4.0" } }, "@docusaurus/types": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/@docusaurus/types/-/types-2.4.0.tgz", - "integrity": "sha512-xaBXr+KIPDkIaef06c+i2HeTqVNixB7yFut5fBXPGI2f1rrmEV2vLMznNGsFwvZ5XmA3Quuefd4OGRkdo97Dhw==", + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/@docusaurus/types/-/types-2.4.1.tgz", + "integrity": "sha512-0R+cbhpMkhbRXX138UOc/2XZFF8hiZa6ooZAEEJFp5scytzCw4tC1gChMFXrpa3d2tYE6AX8IrOEpSonLmfQuQ==", "requires": { "@types/history": "^4.7.11", "@types/react": "*", @@ -16593,11 +16593,11 @@ } }, "@docusaurus/utils": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/@docusaurus/utils/-/utils-2.4.0.tgz", - "integrity": "sha512-89hLYkvtRX92j+C+ERYTuSUK6nF9bGM32QThcHPg2EDDHVw6FzYQXmX6/p+pU5SDyyx5nBlE4qXR92RxCAOqfg==", + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/@docusaurus/utils/-/utils-2.4.1.tgz", + "integrity": "sha512-1lvEZdAQhKNht9aPXPoh69eeKnV0/62ROhQeFKKxmzd0zkcuE/Oc5Gpnt00y/f5bIsmOsYMY7Pqfm/5rteT5GA==", "requires": { - "@docusaurus/logger": "2.4.0", + "@docusaurus/logger": "2.4.1", "@svgr/webpack": "^6.2.1", "escape-string-regexp": "^4.0.0", "file-loader": "^6.2.0", @@ -16623,20 +16623,20 @@ } }, "@docusaurus/utils-common": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/@docusaurus/utils-common/-/utils-common-2.4.0.tgz", - "integrity": "sha512-zIMf10xuKxddYfLg5cS19x44zud/E9I7lj3+0bv8UIs0aahpErfNrGhijEfJpAfikhQ8tL3m35nH3hJ3sOG82A==", + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/@docusaurus/utils-common/-/utils-common-2.4.1.tgz", + "integrity": "sha512-bCVGdZU+z/qVcIiEQdyx0K13OC5mYwxhSuDUR95oFbKVuXYRrTVrwZIqQljuo1fyJvFTKHiL9L9skQOPokuFNQ==", "requires": { "tslib": "^2.4.0" } }, "@docusaurus/utils-validation": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/@docusaurus/utils-validation/-/utils-validation-2.4.0.tgz", - "integrity": "sha512-IrBsBbbAp6y7mZdJx4S4pIA7dUyWSA0GNosPk6ZJ0fX3uYIEQgcQSGIgTeSC+8xPEx3c16o03en1jSDpgQgz/w==", + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/@docusaurus/utils-validation/-/utils-validation-2.4.1.tgz", + "integrity": "sha512-unII3hlJlDwZ3w8U+pMO3Lx3RhI4YEbY3YNsQj4yzrkZzlpqZOLuAiZK2JyULnD+TKbceKU0WyWkQXtYbLNDFA==", "requires": { - "@docusaurus/logger": "2.4.0", - "@docusaurus/utils": "2.4.0", + "@docusaurus/logger": "2.4.1", + "@docusaurus/utils": "2.4.1", "joi": "^17.6.0", "js-yaml": "^4.1.0", "tslib": "^2.4.0" @@ -17481,30 +17481,30 @@ "requires": {} }, "algoliasearch": { - "version": "4.16.0", - "resolved": "https://registry.npmjs.org/algoliasearch/-/algoliasearch-4.16.0.tgz", - "integrity": "sha512-HAjKJ6bBblaXqO4dYygF4qx251GuJ6zCZt+qbJ+kU7sOC+yc84pawEjVpJByh+cGP2APFCsao2Giz50cDlKNPA==", + "version": "4.17.0", + "resolved": "https://registry.npmjs.org/algoliasearch/-/algoliasearch-4.17.0.tgz", + "integrity": "sha512-JMRh2Mw6sEnVMiz6+APsi7lx9a2jiDFF+WUtANaUVCv6uSU9UOLdo5h9K3pdP6frRRybaM2fX8b1u0nqICS9aA==", "requires": { - "@algolia/cache-browser-local-storage": "4.16.0", - "@algolia/cache-common": "4.16.0", - "@algolia/cache-in-memory": "4.16.0", - "@algolia/client-account": "4.16.0", - "@algolia/client-analytics": "4.16.0", - "@algolia/client-common": "4.16.0", - "@algolia/client-personalization": "4.16.0", - "@algolia/client-search": "4.16.0", - "@algolia/logger-common": "4.16.0", - "@algolia/logger-console": "4.16.0", - "@algolia/requester-browser-xhr": "4.16.0", - "@algolia/requester-common": "4.16.0", - "@algolia/requester-node-http": "4.16.0", - "@algolia/transporter": "4.16.0" + "@algolia/cache-browser-local-storage": "4.17.0", + "@algolia/cache-common": "4.17.0", + "@algolia/cache-in-memory": "4.17.0", + "@algolia/client-account": "4.17.0", + "@algolia/client-analytics": "4.17.0", + "@algolia/client-common": "4.17.0", + "@algolia/client-personalization": "4.17.0", + "@algolia/client-search": "4.17.0", + "@algolia/logger-common": "4.17.0", + "@algolia/logger-console": "4.17.0", + "@algolia/requester-browser-xhr": "4.17.0", + "@algolia/requester-common": "4.17.0", + "@algolia/requester-node-http": "4.17.0", + "@algolia/transporter": "4.17.0" } }, "algoliasearch-helper": { - "version": "3.12.0", - "resolved": "https://registry.npmjs.org/algoliasearch-helper/-/algoliasearch-helper-3.12.0.tgz", - "integrity": "sha512-/j1U3PEwdan0n6P/QqSnSpNSLC5+cEMvyljd5CnmNmUjDlGrys+vFEOwjVEnqELIiAGMHEA/Nl3CiKVFBUYqyQ==", + "version": "3.13.0", + "resolved": "https://registry.npmjs.org/algoliasearch-helper/-/algoliasearch-helper-3.13.0.tgz", + "integrity": "sha512-kV3c1jMQCvkARtGsSDvAwuht4PAMSsQILqPiH4WFiARoa3jXJ/r1TQoBWAjWyWF48rsNYCv7kzxgB4LTxrvvuw==", "requires": { "@algolia/events": "^4.0.1" } @@ -18056,19 +18056,19 @@ } }, "domutils": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/domutils/-/domutils-3.0.1.tgz", - "integrity": "sha512-z08c1l761iKhDFtfXO04C7kTdPBLi41zwOZl00WS8b5eiaebNpY00HKbztwBq+e3vyqWNwWF3mP9YLUeqIrF+Q==", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-3.1.0.tgz", + "integrity": "sha512-H78uMmQtI2AhgDJjWeQmHwJJ2bLPD3GMmO7Zja/ZZh84wkm+4ut+IUnUdRa8uCGX88DiVx1j6FRe1XfxEgjEZA==", "requires": { "dom-serializer": "^2.0.0", "domelementtype": "^2.3.0", - "domhandler": "^5.0.1" + "domhandler": "^5.0.3" } }, "entities": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/entities/-/entities-4.4.0.tgz", - "integrity": "sha512-oYp7156SP8LkeGD0GF85ad1X9Ai79WtRsZ2gxJqtBuzH+98YUV6jkHEKlZkMbcrjJjIVJNIDP/3WL9wQkoPbWA==" + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", + "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==" }, "htmlparser2": { "version": "8.0.2", @@ -18127,19 +18127,19 @@ } }, "domutils": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/domutils/-/domutils-3.0.1.tgz", - "integrity": "sha512-z08c1l761iKhDFtfXO04C7kTdPBLi41zwOZl00WS8b5eiaebNpY00HKbztwBq+e3vyqWNwWF3mP9YLUeqIrF+Q==", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-3.1.0.tgz", + "integrity": "sha512-H78uMmQtI2AhgDJjWeQmHwJJ2bLPD3GMmO7Zja/ZZh84wkm+4ut+IUnUdRa8uCGX88DiVx1j6FRe1XfxEgjEZA==", "requires": { "dom-serializer": "^2.0.0", "domelementtype": "^2.3.0", - "domhandler": "^5.0.1" + "domhandler": "^5.0.3" } }, "entities": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/entities/-/entities-4.4.0.tgz", - "integrity": "sha512-oYp7156SP8LkeGD0GF85ad1X9Ai79WtRsZ2gxJqtBuzH+98YUV6jkHEKlZkMbcrjJjIVJNIDP/3WL9wQkoPbWA==" + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", + "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==" } } }, @@ -18500,11 +18500,11 @@ } }, "cross-fetch": { - "version": "3.1.5", - "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-3.1.5.tgz", - "integrity": "sha512-lvb1SBsI0Z7GDwmuid+mU3kWVBwTVUbe7S0H52yaaAdQOXq2YktTCZdlAcNKFzE6QtRz0snpw9bNiPeOIkkQvw==", + "version": "3.1.6", + "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-3.1.6.tgz", + "integrity": "sha512-riRvo06crlE8HiqOwIpQhxwdOk4fOeR7FVM/wXoxchFEqMNUjvbs3bfo4OTgMEMHzppd4DxFBDbyySj8Cv781g==", "requires": { - "node-fetch": "2.6.7" + "node-fetch": "^2.6.11" } }, "cross-spawn": { @@ -21303,9 +21303,9 @@ } }, "node-fetch": { - "version": "2.6.7", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz", - "integrity": "sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==", + "version": "2.6.11", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.11.tgz", + "integrity": "sha512-4I6pdBY1EthSqDmJkiNk3JIT8cswwR9nfeW/cPdUagJYEQG7R95WRH74wpz7ma8Gh/9dI9FP+OU+0E4FvtA55w==", "requires": { "whatwg-url": "^5.0.0" } @@ -21553,9 +21553,9 @@ }, "dependencies": { "entities": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/entities/-/entities-4.4.0.tgz", - "integrity": "sha512-oYp7156SP8LkeGD0GF85ad1X9Ai79WtRsZ2gxJqtBuzH+98YUV6jkHEKlZkMbcrjJjIVJNIDP/3WL9wQkoPbWA==" + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", + "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==" } } }, @@ -22041,9 +22041,9 @@ } }, "postcss-sort-media-queries": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/postcss-sort-media-queries/-/postcss-sort-media-queries-4.3.0.tgz", - "integrity": "sha512-jAl8gJM2DvuIJiI9sL1CuiHtKM4s5aEIomkU8G3LFvbP+p8i7Sz8VV63uieTgoewGqKbi+hxBTiOKJlB35upCg==", + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/postcss-sort-media-queries/-/postcss-sort-media-queries-4.4.1.tgz", + "integrity": "sha512-QDESFzDDGKgpiIh4GYXsSy6sek2yAwQx1JASl5AxBtU1Lq2JfKBljIPNdil989NcSKRQX1ToiaKphImtBuhXWw==", "requires": { "sort-css-media-queries": "2.1.0" } @@ -23844,9 +23844,9 @@ "peer": true }, "ua-parser-js": { - "version": "0.7.34", - "resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-0.7.34.tgz", - "integrity": "sha512-cJMeh/eOILyGu0ejgTKB95yKT3zOenSe9UGE3vj6WfiOwgGYnmATUsnDixMFvdU+rNMvWih83hrUP8VwhF9yXQ==" + "version": "0.7.35", + "resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-0.7.35.tgz", + "integrity": "sha512-veRf7dawaj9xaWEu9HoTVn5Pggtc/qj+kqTOFvNiN1l0YdxwC1kvel57UCjThjGa3BHBihE8/UJAHI+uQHmd/g==" }, "unherit": { "version": "1.1.3", diff --git a/website/package.json b/website/package.json index 98489bcb4..5cbb3db04 100644 --- a/website/package.json +++ b/website/package.json @@ -14,9 +14,9 @@ "write-heading-ids": "docusaurus write-heading-ids" }, "dependencies": { - "@docusaurus/core": "2.4.0", + "@docusaurus/core": "2.4.1", "@docusaurus/plugin-google-gtag": "^2.4.0", - "@docusaurus/preset-classic": "2.4.0", + "@docusaurus/preset-classic": "2.4.1", "@loadable/component": "^5.15.3", "@mdx-js/react": "^1.6.22", "animate.css": "^4.1.1", @@ -36,7 +36,7 @@ "wow.js": "^1.2.2" }, "devDependencies": { - "@docusaurus/module-type-aliases": "2.4.0", + "@docusaurus/module-type-aliases": "2.4.1", "@iconify/react": "^4.1.0", "autoprefixer": "^10.4.14", "postcss": "^8.4.23",