diff --git a/graphql/schema/types/stash-box.graphql b/graphql/schema/types/stash-box.graphql index 71ea757f443..1d9ceeebd58 100644 --- a/graphql/schema/types/stash-box.graphql +++ b/graphql/schema/types/stash-box.graphql @@ -13,11 +13,13 @@ input StashBoxInput { type StashID { endpoint: String! stash_id: String! + updated_at: Time! } input StashIDInput { endpoint: String! stash_id: String! + updated_at: Time! } input StashBoxFingerprintSubmissionInput { diff --git a/internal/identify/identify.go b/internal/identify/identify.go index 5eecd0d9927..a3a13ac58b2 100644 --- a/internal/identify/identify.go +++ b/internal/identify/identify.go @@ -8,6 +8,7 @@ import ( "errors" "fmt" "strconv" + "time" "github.com/stashapp/stash/pkg/logger" "github.com/stashapp/stash/pkg/models" @@ -244,7 +245,8 @@ func (t *SceneIdentifier) getSceneUpdater(ctx context.Context, s *models.Scene, } } - stashIDs, err := rel.stashIDs(ctx) + currentTime := time.Now() + stashIDs, err := rel.stashIDs(ctx, currentTime) if err != nil { return nil, err } diff --git a/internal/identify/scene.go b/internal/identify/scene.go index 05f1ba90076..cd3ca54b3ad 100644 --- a/internal/identify/scene.go +++ b/internal/identify/scene.go @@ -7,6 +7,7 @@ import ( "fmt" "strconv" "strings" + "time" "github.com/stashapp/stash/pkg/logger" "github.com/stashapp/stash/pkg/models" @@ -182,7 +183,7 @@ func (g sceneRelationships) tags(ctx context.Context) ([]int, error) { return tagIDs, nil } -func (g sceneRelationships) stashIDs(ctx context.Context) ([]models.StashID, error) { +func (g sceneRelationships) stashIDs(ctx context.Context, updateTime time.Time) ([]models.StashID, error) { remoteSiteID := g.result.result.RemoteSiteID fieldStrategy := g.fieldOptions["stash_ids"] target := g.scene @@ -210,13 +211,9 @@ func (g sceneRelationships) stashIDs(ctx context.Context) ([]models.StashID, err for i, stashID := range stashIDs { if endpoint == stashID.Endpoint { - // if stashID is the same, then don't set - if stashID.StashID == *remoteSiteID { - return nil, nil - } - // replace the stash id and return stashID.StashID = *remoteSiteID + stashID.UpdatedAt = updateTime stashIDs[i] = stashID return stashIDs, nil } @@ -224,8 +221,9 @@ func (g sceneRelationships) stashIDs(ctx context.Context) ([]models.StashID, err // not found, create new entry stashIDs = append(stashIDs, models.StashID{ - StashID: *remoteSiteID, - Endpoint: endpoint, + StashID: *remoteSiteID, + Endpoint: endpoint, + UpdatedAt: updateTime, }) if sliceutil.SliceSame(originalStashIDs, stashIDs) { diff --git a/internal/identify/scene_test.go b/internal/identify/scene_test.go index 272ca43cb1d..51888aba5f0 100644 --- a/internal/identify/scene_test.go +++ b/internal/identify/scene_test.go @@ -5,6 +5,7 @@ import ( "reflect" "strconv" "testing" + "time" "github.com/stashapp/stash/pkg/models" "github.com/stashapp/stash/pkg/models/mocks" @@ -548,8 +549,9 @@ func Test_sceneRelationships_stashIDs(t *testing.T) { ID: sceneWithStashID, StashIDs: models.NewRelatedStashIDs([]models.StashID{ { - StashID: remoteSiteID, - Endpoint: existingEndpoint, + StashID: remoteSiteID, + Endpoint: existingEndpoint, + UpdatedAt: time.Time{}, }, }), } @@ -605,7 +607,13 @@ func Test_sceneRelationships_stashIDs(t *testing.T) { defaultOptions, existingEndpoint, &remoteSiteID, - nil, + []models.StashID{ + { + StashID: remoteSiteID, + Endpoint: existingEndpoint, + UpdatedAt: time.Time{}, + }, + }, false, }, { @@ -616,8 +624,9 @@ func Test_sceneRelationships_stashIDs(t *testing.T) { &newRemoteSiteID, []models.StashID{ { - StashID: newRemoteSiteID, - Endpoint: existingEndpoint, + StashID: newRemoteSiteID, + Endpoint: existingEndpoint, + UpdatedAt: time.Time{}, }, }, false, @@ -630,12 +639,14 @@ func Test_sceneRelationships_stashIDs(t *testing.T) { &newRemoteSiteID, []models.StashID{ { - StashID: remoteSiteID, - Endpoint: existingEndpoint, + StashID: remoteSiteID, + Endpoint: existingEndpoint, + UpdatedAt: time.Time{}, }, { - StashID: newRemoteSiteID, - Endpoint: newEndpoint, + StashID: newRemoteSiteID, + Endpoint: newEndpoint, + UpdatedAt: time.Time{}, }, }, false, @@ -650,8 +661,9 @@ func Test_sceneRelationships_stashIDs(t *testing.T) { &newRemoteSiteID, []models.StashID{ { - StashID: newRemoteSiteID, - Endpoint: newEndpoint, + StashID: newRemoteSiteID, + Endpoint: newEndpoint, + UpdatedAt: time.Time{}, }, }, false, @@ -681,7 +693,8 @@ func Test_sceneRelationships_stashIDs(t *testing.T) { }, } - got, err := tr.stashIDs(testCtx) + got, err := tr.stashIDs(testCtx, time.Time{}) + if (err != nil) != tt.wantErr { t.Errorf("sceneRelationships.stashIDs() error = %v, wantErr %v", err, tt.wantErr) return diff --git a/pkg/models/model_scraped_item.go b/pkg/models/model_scraped_item.go index 35f781109cb..43e3e985b3b 100644 --- a/pkg/models/model_scraped_item.go +++ b/pkg/models/model_scraped_item.go @@ -3,6 +3,7 @@ package models import ( "context" "strconv" + "time" "github.com/stashapp/stash/pkg/sliceutil/stringslice" "github.com/stashapp/stash/pkg/utils" @@ -29,8 +30,9 @@ func (s *ScrapedStudio) ToStudio(endpoint string, excluded map[string]bool) *Stu if s.RemoteSiteID != nil && endpoint != "" { ret.StashIDs = NewRelatedStashIDs([]StashID{ { - Endpoint: endpoint, - StashID: *s.RemoteSiteID, + Endpoint: endpoint, + StashID: *s.RemoteSiteID, + UpdatedAt: time.Now(), }, }) } @@ -65,6 +67,7 @@ func (s *ScrapedStudio) GetImage(ctx context.Context, excluded map[string]bool) func (s *ScrapedStudio) ToPartial(id string, endpoint string, excluded map[string]bool, existingStashIDs []StashID) StudioPartial { ret := NewStudioPartial() ret.ID, _ = strconv.Atoi(id) + currentTime := time.Now() if s.Name != "" && !excluded["name"] { ret.Name = NewOptionalString(s.Name) @@ -90,8 +93,9 @@ func (s *ScrapedStudio) ToPartial(id string, endpoint string, excluded map[strin Mode: RelationshipUpdateModeSet, } ret.StashIDs.Set(StashID{ - Endpoint: endpoint, - StashID: *s.RemoteSiteID, + Endpoint: endpoint, + StashID: *s.RemoteSiteID, + UpdatedAt: currentTime, }) } @@ -137,6 +141,7 @@ func (ScrapedPerformer) IsScrapedContent() {} func (p *ScrapedPerformer) ToPerformer(endpoint string, excluded map[string]bool) *Performer { ret := NewPerformer() + currentTime := time.Now() ret.Name = *p.Name if p.Aliases != nil && !excluded["aliases"] { @@ -244,8 +249,9 @@ func (p *ScrapedPerformer) ToPerformer(endpoint string, excluded map[string]bool if p.RemoteSiteID != nil && endpoint != "" { ret.StashIDs = NewRelatedStashIDs([]StashID{ { - Endpoint: endpoint, - StashID: *p.RemoteSiteID, + Endpoint: endpoint, + StashID: *p.RemoteSiteID, + UpdatedAt: currentTime, }, }) } @@ -375,8 +381,9 @@ func (p *ScrapedPerformer) ToPartial(endpoint string, excluded map[string]bool, Mode: RelationshipUpdateModeSet, } ret.StashIDs.Set(StashID{ - Endpoint: endpoint, - StashID: *p.RemoteSiteID, + Endpoint: endpoint, + StashID: *p.RemoteSiteID, + UpdatedAt: time.Now(), }) } diff --git a/pkg/models/model_scraped_item_test.go b/pkg/models/model_scraped_item_test.go index 87ce2ad57dc..1e8edccb410 100644 --- a/pkg/models/model_scraped_item_test.go +++ b/pkg/models/model_scraped_item_test.go @@ -87,6 +87,11 @@ func Test_scrapedToStudioInput(t *testing.T) { got.CreatedAt = time.Time{} got.UpdatedAt = time.Time{} + if got.StashIDs.Loaded() && len(got.StashIDs.List()) > 0 { + for stid := range got.StashIDs.List() { + got.StashIDs.List()[stid].UpdatedAt = time.Time{} + } + } assert.Equal(t, tt.want, got) }) } @@ -243,6 +248,12 @@ func Test_scrapedToPerformerInput(t *testing.T) { got.CreatedAt = time.Time{} got.UpdatedAt = time.Time{} + + if got.StashIDs.Loaded() && len(got.StashIDs.List()) > 0 { + for stid := range got.StashIDs.List() { + got.StashIDs.List()[stid].UpdatedAt = time.Time{} + } + } assert.Equal(t, tt.want, got) }) } @@ -263,7 +274,7 @@ func TestScrapedStudio_ToPartial(t *testing.T) { images = []string{image} existingEndpoint = "existingEndpoint" - existingStashID = StashID{"existingStashID", existingEndpoint} + existingStashID = StashID{"existingStashID", existingEndpoint, time.Time{}} existingStashIDs = []StashID{existingStashID} ) @@ -362,6 +373,11 @@ func TestScrapedStudio_ToPartial(t *testing.T) { // unset updatedAt - we don't need to compare it got.UpdatedAt = OptionalTime{} + if got.StashIDs != nil && len(got.StashIDs.StashIDs) > 0 { + for stid := range got.StashIDs.StashIDs { + got.StashIDs.StashIDs[stid].UpdatedAt = time.Time{} + } + } assert.Equal(t, tt.want, got) }) diff --git a/pkg/models/stash_ids.go b/pkg/models/stash_ids.go index fcc2bdec0c2..8cd79b1243c 100644 --- a/pkg/models/stash_ids.go +++ b/pkg/models/stash_ids.go @@ -1,8 +1,11 @@ package models +import "time" + type StashID struct { - StashID string `db:"stash_id" json:"stash_id"` - Endpoint string `db:"endpoint" json:"endpoint"` + StashID string `db:"stash_id" json:"stash_id"` + Endpoint string `db:"endpoint" json:"endpoint"` + UpdatedAt time.Time `db:"updated_at" json:"updated_at"` } type UpdateStashIDs struct { diff --git a/pkg/sqlite/database.go b/pkg/sqlite/database.go index 0510d7baf26..965c44ef9f4 100644 --- a/pkg/sqlite/database.go +++ b/pkg/sqlite/database.go @@ -34,7 +34,7 @@ const ( cacheSizeEnv = "STASH_SQLITE_CACHE_SIZE" ) -var appSchemaVersion uint = 68 +var appSchemaVersion uint = 69 //go:embed migrations/*.sql var migrationsBox embed.FS diff --git a/pkg/sqlite/migrations/69_stash_id_updated_at.up.sql b/pkg/sqlite/migrations/69_stash_id_updated_at.up.sql new file mode 100644 index 00000000000..1ffb280bd48 --- /dev/null +++ b/pkg/sqlite/migrations/69_stash_id_updated_at.up.sql @@ -0,0 +1,3 @@ +ALTER TABLE `performer_stash_ids` ADD COLUMN `updated_at` datetime not null default '1970-01-01T00:00:00Z'; +ALTER TABLE `scene_stash_ids` ADD COLUMN `updated_at` datetime not null default '1970-01-01T00:00:00Z'; +ALTER TABLE `studio_stash_ids` ADD COLUMN `updated_at` datetime not null default '1970-01-01T00:00:00Z'; diff --git a/pkg/sqlite/repository.go b/pkg/sqlite/repository.go index 8eb87b9aff1..2035b11c2fc 100644 --- a/pkg/sqlite/repository.go +++ b/pkg/sqlite/repository.go @@ -14,11 +14,6 @@ import ( const idColumn = "id" -type objectList interface { - Append(o interface{}) - New() interface{} -} - type repository struct { tableName string idColumn string @@ -124,17 +119,6 @@ func (r *repository) queryFunc(ctx context.Context, query string, args []interfa return nil } -func (r *repository) query(ctx context.Context, query string, args []interface{}, out objectList) error { - return r.queryFunc(ctx, query, args, false, func(rows *sqlx.Rows) error { - object := out.New() - if err := rows.StructScan(object); err != nil { - return err - } - out.Append(object) - return nil - }) -} - func (r *repository) queryStruct(ctx context.Context, query string, args []interface{}, out interface{}) error { if err := r.queryFunc(ctx, query, args, true, func(rows *sqlx.Rows) error { if err := rows.StructScan(out); err != nil { @@ -421,7 +405,7 @@ type stashIDRepository struct { type stashIDs []models.StashID func (s *stashIDs) Append(o interface{}) { - *s = append(*s, *o.(*models.StashID)) + *s = append(*s, o.(models.StashID)) } func (s *stashIDs) New() interface{} { @@ -429,10 +413,17 @@ func (s *stashIDs) New() interface{} { } func (r *stashIDRepository) get(ctx context.Context, id int) ([]models.StashID, error) { - query := fmt.Sprintf("SELECT stash_id, endpoint from %s WHERE %s = ?", r.tableName, r.idColumn) + query := fmt.Sprintf("SELECT stash_id, endpoint, updated_at from %s WHERE %s = ?", r.tableName, r.idColumn) var ret stashIDs - err := r.query(ctx, query, []interface{}{id}, &ret) - return []models.StashID(ret), err + err := r.queryFunc(ctx, query, []interface{}{id}, false, func(rows *sqlx.Rows) error { + var v stashIDRow + if err := rows.StructScan(&v); err != nil { + return err + } + ret.Append(v.resolve()) + return nil + }) + return ret, err } type filesRepository struct { diff --git a/pkg/sqlite/table.go b/pkg/sqlite/table.go index 80d6b718a7f..e374f0790e3 100644 --- a/pkg/sqlite/table.go +++ b/pkg/sqlite/table.go @@ -275,19 +275,21 @@ type stashIDTable struct { } type stashIDRow struct { - StashID null.String `db:"stash_id"` - Endpoint null.String `db:"endpoint"` + StashID null.String `db:"stash_id"` + Endpoint null.String `db:"endpoint"` + UpdatedAt Timestamp `db:"updated_at"` } func (r *stashIDRow) resolve() models.StashID { return models.StashID{ - StashID: r.StashID.String, - Endpoint: r.Endpoint.String, + StashID: r.StashID.String, + Endpoint: r.Endpoint.String, + UpdatedAt: r.UpdatedAt.Timestamp, } } func (t *stashIDTable) get(ctx context.Context, id int) ([]models.StashID, error) { - q := dialect.Select("endpoint", "stash_id").From(t.table.table).Where(t.idColumn.Eq(id)) + q := dialect.Select("endpoint", "stash_id", "updated_at").From(t.table.table).Where(t.idColumn.Eq(id)) const single = false var ret []models.StashID @@ -308,8 +310,8 @@ func (t *stashIDTable) get(ctx context.Context, id int) ([]models.StashID, error } func (t *stashIDTable) insertJoin(ctx context.Context, id int, v models.StashID) (sql.Result, error) { - q := dialect.Insert(t.table.table).Cols(t.idColumn.GetCol(), "endpoint", "stash_id").Vals( - goqu.Vals{id, v.Endpoint, v.StashID}, + var q = dialect.Insert(t.table.table).Cols(t.idColumn.GetCol(), "endpoint", "stash_id", "updated_at").Vals( + goqu.Vals{id, v.Endpoint, v.StashID, v.UpdatedAt}, ) ret, err := exec(ctx, q) if err != nil { diff --git a/ui/v2.5/graphql/data/performer-slim.graphql b/ui/v2.5/graphql/data/performer-slim.graphql index 1a4b9833bc8..56a30842ddb 100644 --- a/ui/v2.5/graphql/data/performer-slim.graphql +++ b/ui/v2.5/graphql/data/performer-slim.graphql @@ -27,6 +27,7 @@ fragment SlimPerformerData on Performer { stash_ids { endpoint stash_id + updated_at } rating100 death_date diff --git a/ui/v2.5/graphql/data/performer.graphql b/ui/v2.5/graphql/data/performer.graphql index 144382a4522..0aa60ce21bb 100644 --- a/ui/v2.5/graphql/data/performer.graphql +++ b/ui/v2.5/graphql/data/performer.graphql @@ -34,6 +34,7 @@ fragment PerformerData on Performer { stash_ids { stash_id endpoint + updated_at } rating100 details diff --git a/ui/v2.5/graphql/data/scene-slim.graphql b/ui/v2.5/graphql/data/scene-slim.graphql index 7e2a4ffad2d..d5899a24764 100644 --- a/ui/v2.5/graphql/data/scene-slim.graphql +++ b/ui/v2.5/graphql/data/scene-slim.graphql @@ -84,5 +84,6 @@ fragment SlimSceneData on Scene { stash_ids { endpoint stash_id + updated_at } } diff --git a/ui/v2.5/graphql/data/scene.graphql b/ui/v2.5/graphql/data/scene.graphql index ef58922295a..e4a6e5cc69f 100644 --- a/ui/v2.5/graphql/data/scene.graphql +++ b/ui/v2.5/graphql/data/scene.graphql @@ -71,6 +71,7 @@ fragment SceneData on Scene { stash_ids { endpoint stash_id + updated_at } sceneStreams { diff --git a/ui/v2.5/graphql/data/studio-slim.graphql b/ui/v2.5/graphql/data/studio-slim.graphql index 406a2ffa70a..cf101bd047c 100644 --- a/ui/v2.5/graphql/data/studio-slim.graphql +++ b/ui/v2.5/graphql/data/studio-slim.graphql @@ -5,6 +5,7 @@ fragment SlimStudioData on Studio { stash_ids { endpoint stash_id + updated_at } parent_studio { id diff --git a/ui/v2.5/graphql/data/studio.graphql b/ui/v2.5/graphql/data/studio.graphql index feb35136fed..25e77675549 100644 --- a/ui/v2.5/graphql/data/studio.graphql +++ b/ui/v2.5/graphql/data/studio.graphql @@ -28,6 +28,7 @@ fragment StudioData on Studio { stash_ids { stash_id endpoint + updated_at } details rating100 diff --git a/ui/v2.5/src/components/Performers/PerformerDetails/PerformerEditPanel.tsx b/ui/v2.5/src/components/Performers/PerformerDetails/PerformerEditPanel.tsx index e7d7a8b41e3..2adcb601e1e 100644 --- a/ui/v2.5/src/components/Performers/PerformerDetails/PerformerEditPanel.tsx +++ b/ui/v2.5/src/components/Performers/PerformerDetails/PerformerEditPanel.tsx @@ -282,7 +282,10 @@ export const PerformerEditPanel: React.FC = ({ formik.setFieldValue("penis_length", state.penis_length); } - const remoteSiteID = state.remote_site_id; + updateStashIDs(state.remote_site_id); + } + + function updateStashIDs(remoteSiteID: string | null | undefined) { if (remoteSiteID && (scraper as IStashBox).endpoint) { const newIDs = formik.values.stash_ids?.filter( @@ -291,6 +294,7 @@ export const PerformerEditPanel: React.FC = ({ newIDs?.push({ endpoint: (scraper as IStashBox).endpoint, stash_id: remoteSiteID, + updated_at: new Date().toISOString(), }); formik.setFieldValue("stash_ids", newIDs); } @@ -438,6 +442,7 @@ export const PerformerEditPanel: React.FC = ({ setScraper(undefined); } else { setScrapedPerformer(result); + updateStashIDs(performerResult.remote_site_id); } } diff --git a/ui/v2.5/src/components/Scenes/SceneDetails/SceneEditPanel.tsx b/ui/v2.5/src/components/Scenes/SceneDetails/SceneEditPanel.tsx index 2eef3de1fb4..fb91cd44925 100644 --- a/ui/v2.5/src/components/Scenes/SceneDetails/SceneEditPanel.tsx +++ b/ui/v2.5/src/components/Scenes/SceneDetails/SceneEditPanel.tsx @@ -508,6 +508,7 @@ export const SceneEditPanel: React.FC = ({ return { endpoint, stash_id: updatedScene.remote_site_id, + updated_at: new Date().toISOString(), }; } @@ -521,6 +522,7 @@ export const SceneEditPanel: React.FC = ({ formik.values.stash_ids.concat({ endpoint, stash_id: updatedScene.remote_site_id, + updated_at: new Date().toISOString(), }) ); } diff --git a/ui/v2.5/src/components/Tagger/PerformerModal.tsx b/ui/v2.5/src/components/Tagger/PerformerModal.tsx index 37a2009aa76..d4c8bba1636 100755 --- a/ui/v2.5/src/components/Tagger/PerformerModal.tsx +++ b/ui/v2.5/src/components/Tagger/PerformerModal.tsx @@ -272,6 +272,7 @@ const PerformerModal: React.FC = ({ { endpoint, stash_id: remoteSiteID, + updated_at: new Date().toISOString(), }, ]; } diff --git a/ui/v2.5/src/components/Tagger/context.tsx b/ui/v2.5/src/components/Tagger/context.tsx index dc35208c5f2..9b1e996de24 100644 --- a/ui/v2.5/src/components/Tagger/context.tsx +++ b/ui/v2.5/src/components/Tagger/context.tsx @@ -613,12 +613,14 @@ export const TaggerContext: React.FC = ({ children }) => { return { endpoint: e.endpoint, stash_id: e.stash_id, + updated_at: e.updated_at, }; }); stashIDs.push({ stash_id: performer.remote_site_id, endpoint: currentSource?.sourceInput.stash_box_endpoint, + updated_at: new Date().toISOString(), }); await updatePerformer({ @@ -770,12 +772,14 @@ export const TaggerContext: React.FC = ({ children }) => { return { endpoint: e.endpoint, stash_id: e.stash_id, + updated_at: e.updated_at, }; }); stashIDs.push({ stash_id: studio.remote_site_id, endpoint: currentSource?.sourceInput.stash_box_endpoint, + updated_at: new Date().toISOString(), }); await updateStudio({ diff --git a/ui/v2.5/src/components/Tagger/scenes/StashSearchResult.tsx b/ui/v2.5/src/components/Tagger/scenes/StashSearchResult.tsx index cc8f6a132e6..4be285907b6 100755 --- a/ui/v2.5/src/components/Tagger/scenes/StashSearchResult.tsx +++ b/ui/v2.5/src/components/Tagger/scenes/StashSearchResult.tsx @@ -413,6 +413,7 @@ const StashSearchResult: React.FC = ({ return { endpoint: s.endpoint, stash_id: s.stash_id, + updated_at: s.updated_at, }; }) .filter( @@ -421,6 +422,7 @@ const StashSearchResult: React.FC = ({ { endpoint: currentSource.sourceInput.stash_box_endpoint, stash_id: scene.remote_site_id, + updated_at: new Date().toISOString(), }, ]; } else { diff --git a/ui/v2.5/src/components/Tagger/scenes/StudioModal.tsx b/ui/v2.5/src/components/Tagger/scenes/StudioModal.tsx index b57c796ab28..249e34e7401 100644 --- a/ui/v2.5/src/components/Tagger/scenes/StudioModal.tsx +++ b/ui/v2.5/src/components/Tagger/scenes/StudioModal.tsx @@ -198,11 +198,13 @@ const StudioModal: React.FC = ({ // stashid handling code const remoteSiteID = studio.remote_site_id; + const timeNow = new Date().toISOString(); if (remoteSiteID && endpoint) { studioData.stash_ids = [ { endpoint, stash_id: remoteSiteID, + updated_at: timeNow, }, ]; } @@ -230,6 +232,7 @@ const StudioModal: React.FC = ({ { endpoint, stash_id: parentRemoteSiteID, + updated_at: timeNow, }, ]; } diff --git a/ui/v2.5/src/utils/stashIds.ts b/ui/v2.5/src/utils/stashIds.ts index 3240b2a0f56..289ce9c9d70 100644 --- a/ui/v2.5/src/utils/stashIds.ts +++ b/ui/v2.5/src/utils/stashIds.ts @@ -1,5 +1,8 @@ -export const getStashIDs = (ids?: { stash_id: string; endpoint: string }[]) => - (ids ?? []).map(({ stash_id, endpoint }) => ({ +export const getStashIDs = ( + ids?: { stash_id: string; endpoint: string; updated_at: string }[] +) => + (ids ?? []).map(({ stash_id, endpoint, updated_at }) => ({ stash_id, endpoint, + updated_at, }));