Skip to content

feat(/config-migration): add migration service to convert legacy configuration to the new format#641

Open
DarianM wants to merge 18 commits intomainfrom
migration-cli
Open

feat(/config-migration): add migration service to convert legacy configuration to the new format#641
DarianM wants to merge 18 commits intomainfrom
migration-cli

Conversation

@DarianM
Copy link
Copy Markdown
Member

@DarianM DarianM commented Mar 26, 2026

Summary

one-time CLI to migrate legacy S3 config data to the new format

  1. Adds a migrations CLI that reads wallet configs from the legacy S3 prefix, converts them to the new shape, writes them to the new prefix.
  • wallets already present in the new prefix are cleaned up (legacy key deleted) and counted as skipped.
  1. Adds migrations/s3/ as a standalone S3 client package wrapping client-s3, shared by the CLI.

  2. Includes a dry-run mode (--dry-run) that simulates all S3 writes/deletes without touching real data, and writes its own separate log file.

  3. Each run produces a timestamped log file under migrations recording successful, skipped, and failed wallets.

  4. Migration packages are excluded from the root pnpm workspace — they live under their own migrations/pnpm-workspace.yaml and are installed separately (cd migrations && pnpm install), so CI is not affected

@DarianM DarianM linked an issue Mar 26, 2026 that may be closed by this pull request
@github-actions
Copy link
Copy Markdown

github-actions bot commented Mar 26, 2026

Deployment results

Worker Alias URL Outcome
API - 3f954d4b success
CDN - 38d30a7e success
App - acc0ee9d success

Logs #24004982267

@DarianM DarianM marked this pull request as ready for review March 31, 2026 11:39
private readonly bucket: string

constructor(config: S3Config) {
this.bucket = config.bucket
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The reason I didn't add this AWS module globally in the root was because the migration only uses it for now.
Swapping the aws library now also requires bucket and region. we can hardcode or add as dev vars

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if the structure overall is good, we can extract in smaller PRs

- 'components'
- 'shared/*'
- 'localenv/*'
- 'migrations/*'
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These and related dependencies will be installed in CI, which won't really be used. Any way we can ignore them in CI, and only install when needed locally?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sure. introduced different workspace for migrations, but will have to cd into /migrations, manually install and run tests.

})
}

export async function dryRun(
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Having a separate function/login as dryRun won't really be a dry-run. Please add only one function, and instead pass it a mock-s3 so it acts like dry-run (for non-recoverable actions), while keeping a single flow.

Comment on lines +145 to +146
await s3.putJson(walletAddress, newData)
await s3.deleteFromLegacy(walletAddress)
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What if either of these fails? Can we have something like a transaction here?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

removed delete.
we'll manually delete everything after we make sure everything went smoothly. manually or in batch.

}
const newData = convertToConfiguration(legacyData, walletAddress)
await s3.putJson(walletAddress, newData)
await s3.deleteFromLegacy(walletAddress)
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we batch delete in end? We should write a local log file to write which files (and/or a cursor) have already been processed, then delete them in end when we're sure.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we'll manually delete everything after we make sure everything went smoothly. manually or in batch.

}

// only run main CLI if this file executed directly
if (import.meta.url === pathToFileURL(process.argv[1]).href) {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

import.meta.main?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes, since node v24.2.0,

@DarianM DarianM requested a review from sidvishnoi April 5, 2026 15:54
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

refactor: Create utility for migrating stored data formats - Phase 4

2 participants