From 9b3268a2e3eed43418cd19fbf8bce5ad3c91275f Mon Sep 17 00:00:00 2001 From: Ben Hollis Date: Sat, 21 Dec 2024 11:58:47 -0800 Subject: [PATCH 1/9] User import --- api/db/migration-state-queries.ts | 8 ++++++ api/stately/init/migrate-users.ts | 21 +++++++++++++++ api/stately/migrator/user.ts | 44 +++++++++++++++++++++++++++++++ 3 files changed, 73 insertions(+) create mode 100644 api/stately/init/migrate-users.ts create mode 100644 api/stately/migrator/user.ts diff --git a/api/db/migration-state-queries.ts b/api/db/migration-state-queries.ts index 279dddf..3863423 100644 --- a/api/db/migration-state-queries.ts +++ b/api/db/migration-state-queries.ts @@ -27,6 +27,14 @@ interface MigrationStateRow { last_error: string | null; } +export async function getUsersToMigrate(client: ClientBase): Promise { + const results = await client.query({ + name: 'get_users_to_migrate', + text: 'select membership_id from settings where membership_id not in (select membership_id from migration_state) limit 1000', + }); + return results.rows.map((row) => row.membership_id); +} + export async function getMigrationState( client: ClientBase, bungieMembershipId: number, diff --git a/api/stately/init/migrate-users.ts b/api/stately/init/migrate-users.ts new file mode 100644 index 0000000..e6cf248 --- /dev/null +++ b/api/stately/init/migrate-users.ts @@ -0,0 +1,21 @@ +import { readTransaction } from '../../db/index.js'; +import { getUsersToMigrate } from '../../db/migration-state-queries.js'; +import { delay } from '../../utils.js'; +import { migrateUser } from '../migrator/user.js'; + +while (true) { + try { + const bungieMembershipIds = await readTransaction(async (client) => getUsersToMigrate(client)); + for (const bungieMembershipId of bungieMembershipIds) { + try { + await migrateUser(bungieMembershipId); + console.log(`Migrated user ${bungieMembershipId}`); + } catch (e) { + console.error(`Error migrating user ${bungieMembershipId}: ${e}`); + } + } + } catch (e) { + console.error(`Error getting users to migrate: ${e}`); + await delay(1000); + } +} diff --git a/api/stately/migrator/user.ts b/api/stately/migrator/user.ts new file mode 100644 index 0000000..31ada9b --- /dev/null +++ b/api/stately/migrator/user.ts @@ -0,0 +1,44 @@ +import { isEmpty } from 'es-toolkit/compat'; +import { doMigration } from '../../db/migration-state-queries.js'; +import { pgExport } from '../../routes/export.js'; +import { extractImportData, statelyImport } from '../../routes/import.js'; + +export async function migrateUser(bungieMembershipId: number): Promise { + const importToStately = async () => { + // Export from Postgres + const exportResponse = await pgExport(bungieMembershipId); + + const { settings, loadouts, itemAnnotations, triumphs, searches, itemHashTags } = + extractImportData(exportResponse); + + const profileIds = new Set(); + exportResponse.loadouts.forEach((l) => profileIds.add(l.platformMembershipId)); + exportResponse.tags.forEach((t) => profileIds.add(t.platformMembershipId)); + exportResponse.triumphs.forEach((t) => profileIds.add(t.platformMembershipId)); + + if ( + isEmpty(settings) && + loadouts.length === 0 && + itemAnnotations.length === 0 && + triumphs.length === 0 && + searches.length === 0 + ) { + // Nothing to import! + return; + } + await statelyImport( + bungieMembershipId, + [...profileIds], + settings, + loadouts, + itemAnnotations, + triumphs, + searches, + itemHashTags, + false, + ); + }; + + // For now let's leave the old data in Postgres as a backup + await doMigration(bungieMembershipId, importToStately); +} From 7fca20a217dd9104c2f186f395e01986a050a55b Mon Sep 17 00:00:00 2001 From: Ben Hollis Date: Sun, 29 Dec 2024 16:58:27 -0800 Subject: [PATCH 2/9] Fixups --- api/db/migration-state-queries.ts | 2 +- api/routes/update.ts | 2 +- api/stately/init/migrate-users.ts | 27 +++++++++++++++++++-------- api/stately/loadouts-queries.ts | 4 ++-- api/stately/settings-queries.ts | 8 ++++---- 5 files changed, 27 insertions(+), 16 deletions(-) diff --git a/api/db/migration-state-queries.ts b/api/db/migration-state-queries.ts index 3863423..191ae83 100644 --- a/api/db/migration-state-queries.ts +++ b/api/db/migration-state-queries.ts @@ -30,7 +30,7 @@ interface MigrationStateRow { export async function getUsersToMigrate(client: ClientBase): Promise { const results = await client.query({ name: 'get_users_to_migrate', - text: 'select membership_id from settings where membership_id not in (select membership_id from migration_state) limit 1000', + text: 'select distinct(s.membership_id) as membership_id from loadouts as s left join migration_state as m on s.membership_id = m.membership_id where m.membership_id is null limit 1000', }); return results.rows.map((row) => row.membership_id); } diff --git a/api/routes/update.ts b/api/routes/update.ts index 911b574..3bbe8a0 100644 --- a/api/routes/update.ts +++ b/api/routes/update.ts @@ -154,7 +154,7 @@ export const updateHandler = asyncHandler(async (req, res) => { triumphs, searches, itemHashTags, - !migrationState.lastError, + migrationState.attemptCount > 0 || Boolean(migrationState.lastError), ); }; diff --git a/api/stately/init/migrate-users.ts b/api/stately/init/migrate-users.ts index e6cf248..e4b0337 100644 --- a/api/stately/init/migrate-users.ts +++ b/api/stately/init/migrate-users.ts @@ -1,3 +1,4 @@ +import { chunk } from 'es-toolkit'; import { readTransaction } from '../../db/index.js'; import { getUsersToMigrate } from '../../db/migration-state-queries.js'; import { delay } from '../../utils.js'; @@ -6,16 +7,26 @@ import { migrateUser } from '../migrator/user.js'; while (true) { try { const bungieMembershipIds = await readTransaction(async (client) => getUsersToMigrate(client)); - for (const bungieMembershipId of bungieMembershipIds) { - try { - await migrateUser(bungieMembershipId); - console.log(`Migrated user ${bungieMembershipId}`); - } catch (e) { - console.error(`Error migrating user ${bungieMembershipId}: ${e}`); - } + if (bungieMembershipIds.length === 0) { + console.log('No users to migrate'); + break; + } + for (const idChunk of chunk(bungieMembershipIds, 10)) { + await Promise.all( + idChunk.map(async (bungieMembershipId) => { + try { + await migrateUser(bungieMembershipId); + console.log(`Migrated user ${bungieMembershipId}`); + } catch (e) { + console.error(`Error migrating user ${bungieMembershipId}: ${e}`); + } + }), + ); } } catch (e) { - console.error(`Error getting users to migrate: ${e}`); + if (e instanceof Error) { + console.error(`Error getting users to migrate: ${e}`); + } await delay(1000); } } diff --git a/api/stately/loadouts-queries.ts b/api/stately/loadouts-queries.ts index 6628d17..2cbc1a0 100644 --- a/api/stately/loadouts-queries.ts +++ b/api/stately/loadouts-queries.ts @@ -273,8 +273,8 @@ export function convertLoadoutCommonFieldsToStately( unequipped: (loadout.unequipped || []).map(convertLoadoutItemToStately), notes: loadout.notes, parameters: convertLoadoutParametersToStately(loadout.parameters), - createdAt: BigInt(loadout.createdAt ?? 0n), - lastUpdatedAt: BigInt(loadout.lastUpdatedAt ?? 0n), + createdAt: BigInt(loadout.createdAt ? new Date(loadout.createdAt).getTime() : 0n), + lastUpdatedAt: BigInt(loadout.lastUpdatedAt ? new Date(loadout.lastUpdatedAt).getTime() : 0n), }; } diff --git a/api/stately/settings-queries.ts b/api/stately/settings-queries.ts index 16e6999..c4efb59 100644 --- a/api/stately/settings-queries.ts +++ b/api/stately/settings-queries.ts @@ -214,12 +214,12 @@ export function convertToStatelyItem( }); }); - const customTotalStatsList = Object.entries(customTotalStatsByClass).map( - ([classType, customStats]) => ({ + const customTotalStatsList = Object.entries(customTotalStatsByClass) + .map(([classType, customStats]) => ({ classType: Number(classType), customStats, - }), - ); + })) + .filter((c) => c.customStats.length > 0); return client.create('Settings', { ...rest, From 4711d92f8ce67d2eae7ae5c6736debb1ff1d2a4e Mon Sep 17 00:00:00 2001 From: Ben Hollis Date: Sun, 29 Dec 2024 17:01:32 -0800 Subject: [PATCH 3/9] Default new users to Stately --- api/db/migration-state-queries.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/api/db/migration-state-queries.ts b/api/db/migration-state-queries.ts index 191ae83..0a5c33d 100644 --- a/api/db/migration-state-queries.ts +++ b/api/db/migration-state-queries.ts @@ -49,7 +49,7 @@ export async function getMigrationState( } else { return { bungieMembershipId, - state: MigrationState.Postgres, + state: MigrationState.Stately, lastStateChangeAt: 0, attemptCount: 0, }; From 8fbdfbb3386cebcbf7060561492e34434b941f31 Mon Sep 17 00:00:00 2001 From: Ben Hollis Date: Sun, 29 Dec 2024 17:07:13 -0800 Subject: [PATCH 4/9] Always import to Stately --- api/routes/import.ts | 126 ++----------------------------------------- 1 file changed, 3 insertions(+), 123 deletions(-) diff --git a/api/routes/import.ts b/api/routes/import.ts index 7b1faee..e3a40ed 100644 --- a/api/routes/import.ts +++ b/api/routes/import.ts @@ -1,25 +1,12 @@ import { isEmpty } from 'es-toolkit/compat'; import asyncHandler from 'express-async-handler'; -import { readTransaction, transaction } from '../db/index.js'; -import { updateItemAnnotation } from '../db/item-annotations-queries.js'; -import { updateItemHashTag } from '../db/item-hash-tags-queries.js'; -import { updateLoadout } from '../db/loadouts-queries.js'; -import { - doMigration, - getDesiredMigrationState, - getMigrationState, - MigrationState, -} from '../db/migration-state-queries.js'; -import { importSearch } from '../db/searches-queries.js'; -import { replaceSettings } from '../db/settings-queries.js'; -import { trackTriumph } from '../db/triumphs-queries.js'; -import { ApiApp } from '../shapes/app.js'; +import { readTransaction } from '../db/index.js'; +import { doMigration, getMigrationState, MigrationState } from '../db/migration-state-queries.js'; import { ExportResponse } from '../shapes/export.js'; import { DestinyVersion } from '../shapes/general.js'; import { ImportResponse } from '../shapes/import.js'; import { ItemAnnotation, ItemHashTag } from '../shapes/item-annotations.js'; import { Loadout } from '../shapes/loadouts.js'; -import { SearchType } from '../shapes/search.js'; import { defaultSettings, Settings } from '../shapes/settings.js'; import { UserInfo } from '../shapes/user.js'; import { deleteAllDataForUser } from '../stately/bulk-queries.js'; @@ -33,11 +20,9 @@ import { convertToStatelyItem } from '../stately/settings-queries.js'; import { batches } from '../stately/stately-utils.js'; import { importTriumphs } from '../stately/triumphs-queries.js'; import { badRequest, delay, subtractObject } from '../utils.js'; -import { deleteAllData } from './delete-all-data.js'; export const importHandler = asyncHandler(async (req, res) => { const { bungieMembershipId, profileIds } = req.user as UserInfo; - const { id: appId } = req.dimApp as ApiApp; // Support only new API exports const importData = req.body as ExportResponse; @@ -60,12 +45,6 @@ export const importHandler = asyncHandler(async (req, res) => { getMigrationState(client, bungieMembershipId), ); - // this is a great time to do the migration - const desiredMigrationState = await getDesiredMigrationState(migrationState); - const shouldMigrateToStately = - desiredMigrationState === MigrationState.Stately && - migrationState.state !== desiredMigrationState; - let numTriumphs = 0; const importToStately = async () => { numTriumphs = await statelyImport( @@ -82,22 +61,7 @@ export const importHandler = asyncHandler(async (req, res) => { switch (migrationState.state) { case MigrationState.Postgres: - if (shouldMigrateToStately) { - await doMigration(bungieMembershipId, importToStately, async (client) => - deleteAllData(client, bungieMembershipId), - ); - } else { - numTriumphs = await pgImport( - bungieMembershipId, - appId, - settings, - loadouts, - itemAnnotations, - triumphs, - searches, - itemHashTags, - ); - } + await doMigration(bungieMembershipId, importToStately); break; case MigrationState.Stately: await importToStately(); @@ -138,90 +102,6 @@ export function extractImportData(importData: ExportResponse) { }; } -async function pgImport( - bungieMembershipId: number, - appId: string, - settings: Partial, - loadouts: PlatformLoadout[], - itemAnnotations: PlatformItemAnnotation[], - triumphs: ExportResponse['triumphs'], - searches: ExportResponse['searches'], - itemHashTags: ItemHashTag[], -): Promise { - let numTriumphs = 0; - await transaction(async (client) => { - await deleteAllData(client, bungieMembershipId); - - // TODO: pass a list of keys that are being set to default? - await replaceSettings(client, appId, bungieMembershipId, settings); - - // TODO: query first so we can delete after? - for (const loadout of loadouts) { - // For now, ignore ancient loadouts - if (!loadout.platformMembershipId || !loadout.destinyVersion) { - continue; - } - await updateLoadout( - client, - appId, - bungieMembershipId, - loadout.platformMembershipId, - loadout.destinyVersion, - loadout, - ); - } - - // TODO: query first so we can delete after? - for (const annotation of itemAnnotations) { - await updateItemAnnotation( - client, - appId, - bungieMembershipId, - annotation.platformMembershipId, - annotation.destinyVersion, - annotation, - ); - } - - for (const tag of itemHashTags) { - await updateItemHashTag(client, appId, bungieMembershipId, tag); - } - - if (Array.isArray(triumphs)) { - for (const triumphData of triumphs) { - if (Array.isArray(triumphData?.triumphs)) { - for (const triumph of triumphData.triumphs) { - trackTriumph( - client, - appId, - bungieMembershipId, - triumphData.platformMembershipId, - triumph, - ); - numTriumphs++; - } - } - } - } - - for (const search of searches) { - importSearch( - client, - appId, - bungieMembershipId, - search.destinyVersion, - search.search.query, - search.search.saved, - search.search.lastUsage, - search.search.usageCount, - search.search.type ?? SearchType.Item, - ); - } - }); - - return numTriumphs; -} - export async function statelyImport( bungieMembershipId: number, platformMembershipIds: string[], From 67d7563ed91b3ede3914c823e406ca0f8ece7d36 Mon Sep 17 00:00:00 2001 From: Ben Hollis Date: Sun, 29 Dec 2024 17:07:58 -0800 Subject: [PATCH 5/9] Fixup --- api/stately/init/migrate-users.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/api/stately/init/migrate-users.ts b/api/stately/init/migrate-users.ts index e4b0337..6a6f88a 100644 --- a/api/stately/init/migrate-users.ts +++ b/api/stately/init/migrate-users.ts @@ -18,7 +18,9 @@ while (true) { await migrateUser(bungieMembershipId); console.log(`Migrated user ${bungieMembershipId}`); } catch (e) { - console.error(`Error migrating user ${bungieMembershipId}: ${e}`); + if (e instanceof Error) { + console.error(`Error migrating user ${bungieMembershipId}: ${e}`); + } } }), ); From 9cbdd816cfb94664c3ff5154fa60d1a701aef7a7 Mon Sep 17 00:00:00 2001 From: Ben Hollis Date: Sun, 29 Dec 2024 17:20:05 -0800 Subject: [PATCH 6/9] Remove test --- api/db/migration-state-queries.test.ts | 70 -------------------------- 1 file changed, 70 deletions(-) delete mode 100644 api/db/migration-state-queries.test.ts diff --git a/api/db/migration-state-queries.test.ts b/api/db/migration-state-queries.test.ts deleted file mode 100644 index 6faf5aa..0000000 --- a/api/db/migration-state-queries.test.ts +++ /dev/null @@ -1,70 +0,0 @@ -import { closeDbPool, transaction } from './index.js'; -import { - abortMigrationToStately, - deleteMigrationState, - finishMigrationToStately, - getMigrationState, - MigrationState, - startMigrationToStately, -} from './migration-state-queries.js'; - -const bungieMembershipId = 4321; - -beforeEach(() => - transaction(async (client) => { - await deleteMigrationState(client, bungieMembershipId); - }), -); - -afterAll(() => closeDbPool()); - -it('handles migration state changes', async () => { - await transaction(async (client) => { - // Check initial state - const migrationState = await getMigrationState(client, bungieMembershipId); - expect(migrationState.bungieMembershipId).toBe(bungieMembershipId); - expect(migrationState.state).toBe(MigrationState.Postgres); - expect(migrationState.attemptCount).toBe(0); - expect(migrationState.lastError).toBeUndefined(); - expect(migrationState.lastStateChangeAt).toBe(0); - - // Start migration - await startMigrationToStately(client, bungieMembershipId); - - const migrationState2 = await getMigrationState(client, bungieMembershipId); - expect(migrationState2.state).toBe(MigrationState.MigratingToStately); - expect(migrationState2.attemptCount).toBe(1); - expect(migrationState2.lastError).toBeUndefined(); - expect(migrationState2.lastStateChangeAt).not.toBe(0); - - // Try to start the migration again (should fail) - await expect(startMigrationToStately(client, bungieMembershipId)).rejects.toThrow(); - - // Fail migration - await abortMigrationToStately(client, bungieMembershipId, 'error message'); - - const migrationState3 = await getMigrationState(client, bungieMembershipId); - expect(migrationState3.state).toBe(MigrationState.Postgres); - expect(migrationState3.attemptCount).toBe(1); - expect(migrationState3.lastError).toBe('error message'); - expect(migrationState3.lastStateChangeAt).not.toBe(0); - - // OK start the migration again - await startMigrationToStately(client, bungieMembershipId); - - const migrationState4 = await getMigrationState(client, bungieMembershipId); - expect(migrationState4.state).toBe(MigrationState.MigratingToStately); - expect(migrationState4.attemptCount).toBe(2); - expect(migrationState4.lastError).toBe('error message'); - expect(migrationState4.lastStateChangeAt).not.toBe(0); - - // Finish migration - await finishMigrationToStately(client, bungieMembershipId); - - const migrationState5 = await getMigrationState(client, bungieMembershipId); - expect(migrationState5.state).toBe(MigrationState.Stately); - expect(migrationState5.attemptCount).toBe(2); - expect(migrationState5.lastError).toBe('error message'); - expect(migrationState5.lastStateChangeAt).not.toBe(0); - }); -}); From fa3df7d9ff698b56c3bf9387cd2665b59b640f9d Mon Sep 17 00:00:00 2001 From: Ben Hollis Date: Sat, 4 Jan 2025 16:51:17 -0800 Subject: [PATCH 7/9] last bits --- api/db/item-annotations-queries.ts | 2 +- api/db/migration-state-queries.ts | 4 ++-- api/routes/import.ts | 3 +-- api/stately/loadouts-queries.ts | 14 +++++++++----- api/stately/settings-queries.ts | 4 ++++ 5 files changed, 17 insertions(+), 10 deletions(-) diff --git a/api/db/item-annotations-queries.ts b/api/db/item-annotations-queries.ts index c5695b3..1164f63 100644 --- a/api/db/item-annotations-queries.ts +++ b/api/db/item-annotations-queries.ts @@ -46,7 +46,7 @@ export async function getAllItemAnnotationsForUser( ItemAnnotationRow & { platform_membership_id: string; destiny_version: DestinyVersion } >({ name: 'get_all_item_annotations', - text: 'SELECT platform_membership_id, destiny_version, inventory_item_id, tag, notes, variant, crafted_date FROM item_annotations WHERE membership_id = $1', + text: 'SELECT platform_membership_id, destiny_version, inventory_item_id, tag, notes, variant, crafted_date FROM item_annotations WHERE inventory_item_id != 0 and membership_id = $1', values: [bungieMembershipId], }); return results.rows.map((row) => ({ diff --git a/api/db/migration-state-queries.ts b/api/db/migration-state-queries.ts index 0a5c33d..377dac7 100644 --- a/api/db/migration-state-queries.ts +++ b/api/db/migration-state-queries.ts @@ -30,7 +30,7 @@ interface MigrationStateRow { export async function getUsersToMigrate(client: ClientBase): Promise { const results = await client.query({ name: 'get_users_to_migrate', - text: 'select distinct(s.membership_id) as membership_id from loadouts as s left join migration_state as m on s.membership_id = m.membership_id where m.membership_id is null limit 1000', + text: 'select membership_id from migration_state where state != 3 limit 1000', }); return results.rows.map((row) => row.membership_id); } @@ -214,7 +214,7 @@ export async function doMigration( }); metrics.increment('migration.finish.count'); } catch (e) { - console.error('Stately migration failed', e); + console.error(`Stately migration failed for ${bungieMembershipId}`, e); await transaction(async (client) => { await abortMigrationToStately( client, diff --git a/api/routes/import.ts b/api/routes/import.ts index e3a40ed..8c903a6 100644 --- a/api/routes/import.ts +++ b/api/routes/import.ts @@ -1,3 +1,4 @@ +import { StatelyError } from '@stately-cloud/client'; import { isEmpty } from 'es-toolkit/compat'; import asyncHandler from 'express-async-handler'; import { readTransaction } from '../db/index.js'; @@ -17,7 +18,6 @@ import { importHashTags } from '../stately/item-hash-tags-queries.js'; import { importLoadouts } from '../stately/loadouts-queries.js'; import { importSearches } from '../stately/searches-queries.js'; import { convertToStatelyItem } from '../stately/settings-queries.js'; -import { batches } from '../stately/stately-utils.js'; import { importTriumphs } from '../stately/triumphs-queries.js'; import { badRequest, delay, subtractObject } from '../utils.js'; @@ -151,7 +151,6 @@ export async function statelyImport( // Put the settings in first since it's in a different group await client.put({ item: settingsItem, - mustNotExist: true, }); // OK now put them in as fast as we can for (const batch of batches(items)) { diff --git a/api/stately/loadouts-queries.ts b/api/stately/loadouts-queries.ts index 2cbc1a0..20f888d 100644 --- a/api/stately/loadouts-queries.ts +++ b/api/stately/loadouts-queries.ts @@ -264,10 +264,10 @@ export function convertLoadoutCommonFieldsToStately( MessageInitShape | MessageInitShape, 'id' | '$typeName' > { - return { + const out = { destinyVersion, profileId: BigInt(platformMembershipId), - name: loadout.name, + name: loadout.name || 'Unnamed', classType: loadout.classType as number, equipped: (loadout.equipped || []).map(convertLoadoutItemToStately), unequipped: (loadout.unequipped || []).map(convertLoadoutItemToStately), @@ -276,6 +276,10 @@ export function convertLoadoutCommonFieldsToStately( createdAt: BigInt(loadout.createdAt ? new Date(loadout.createdAt).getTime() : 0n), lastUpdatedAt: BigInt(loadout.lastUpdatedAt ? new Date(loadout.lastUpdatedAt).getTime() : 0n), }; + if (out.lastUpdatedAt < out.createdAt) { + out.lastUpdatedAt = out.createdAt; + } + return out; } function convertLoadoutItemToStately(item: LoadoutItem): StatelyLoadoutItem { @@ -316,7 +320,7 @@ export function convertLoadoutParametersToStately( modsByBucket: modsByBucket ? Object.entries(modsByBucket).map(([bucketHash, modHashes]) => ({ bucketHash: Number(bucketHash), - modHashes, + modHashes: modHashes.filter((h) => Number.isInteger(h)), })) : undefined, }; @@ -328,8 +332,8 @@ export function statConstraintsToStately(statConstraints: StatConstraint[] | und return statConstraints && statConstraints.length > 0 ? statConstraints.map((c) => ({ statHash: c.statHash, - minTier: Math.max(0, c.minTier ?? 0), - maxTier: Math.min(c.maxTier ?? 10, 10), + minTier: Math.max(0, Math.floor(c.minTier ?? 0)), + maxTier: Math.min(Math.ceil(c.maxTier ?? 10), 10), })) : []; } diff --git a/api/stately/settings-queries.ts b/api/stately/settings-queries.ts index c4efb59..0b1a429 100644 --- a/api/stately/settings-queries.ts +++ b/api/stately/settings-queries.ts @@ -178,6 +178,8 @@ export function convertToStatelyItem( customStats, vaultWeaponGroupingStyle, itemPopupTab, + itemSize, + charCol, ...rest } = settings; @@ -227,6 +229,8 @@ export function convertToStatelyItem( wishListSources: wishListSource.split('|'), characterOrder: CharacterOrder[`CharacterOrder_${characterOrder}`], collapsedSections: collapsedSectionsList, + itemSize: Math.min(Math.max(0, itemSize), 66), + charCol: Math.min(Math.max(2, charCol), 5), infusionDirection: infusionDirection === InfuseDirection.FUEL ? StatelyInfuseDirection.InfuseDirection_Fuel From 302e26394aaf527a238ad66380475a213345b46a Mon Sep 17 00:00:00 2001 From: Ben Hollis Date: Sat, 4 Jan 2025 16:58:30 -0800 Subject: [PATCH 8/9] OK --- api/routes/import.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/api/routes/import.ts b/api/routes/import.ts index 8c903a6..69ef9f2 100644 --- a/api/routes/import.ts +++ b/api/routes/import.ts @@ -1,4 +1,3 @@ -import { StatelyError } from '@stately-cloud/client'; import { isEmpty } from 'es-toolkit/compat'; import asyncHandler from 'express-async-handler'; import { readTransaction } from '../db/index.js'; From 9704ad9e48c3635815d7f748b27484ec09f2fa86 Mon Sep 17 00:00:00 2001 From: Ben Hollis Date: Sat, 4 Jan 2025 17:03:30 -0800 Subject: [PATCH 9/9] Argh --- api/routes/import.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/api/routes/import.ts b/api/routes/import.ts index 69ef9f2..e63e7ad 100644 --- a/api/routes/import.ts +++ b/api/routes/import.ts @@ -17,6 +17,7 @@ import { importHashTags } from '../stately/item-hash-tags-queries.js'; import { importLoadouts } from '../stately/loadouts-queries.js'; import { importSearches } from '../stately/searches-queries.js'; import { convertToStatelyItem } from '../stately/settings-queries.js'; +import { batches } from '../stately/stately-utils.js'; import { importTriumphs } from '../stately/triumphs-queries.js'; import { badRequest, delay, subtractObject } from '../utils.js';