Full Code of kyleshay/DIM for AI

master 8064466d14fe cached
1630 files
354.9 MB
2.7M tokens
2947 symbols
1 requests
Copy disabled (too large) Download .txt
Showing preview only (11,011K chars total). Download the full file to get everything.
Repository: kyleshay/DIM
Branch: master
Commit: 8064466d14fe
Files: 1630
Total size: 354.9 MB

Directory structure:
gitextract_c6q93roc/

├── .dockerignore
├── .editorconfig
├── .git-blame-ignore-revs
├── .gitattributes
├── .github/
│   ├── FUNDING.yml
│   ├── ISSUE_TEMPLATE/
│   │   ├── bug_report.yml
│   │   └── feature_request.yml
│   ├── actions/
│   │   └── setup-pnpm/
│   │       └── action.yml
│   ├── copilot-instructions.md
│   ├── dependabot.yml
│   ├── pull_request_template.md
│   ├── scripts/
│   │   ├── discord_changelog.py
│   │   └── i18n_discord.py
│   └── workflows/
│       ├── auto-merge.yml
│       ├── changelog-updater.yml
│       ├── copilot-setup-steps.yml
│       ├── deploy-beta.yml
│       ├── deploy-prod.yml
│       ├── i18n-bot-download.yml
│       ├── i18n-bot-upload.yml
│       ├── i18n-update.yml
│       ├── lint-workflows.yml
│       ├── notify-discord-changelog.yml
│       ├── notify-discord-i18n.yml
│       ├── pr-cleanup.yml
│       ├── pr-reports.yml
│       └── pr-validation.yml
├── .gitignore
├── .gitmodules
├── .husky/
│   └── pre-commit
├── .npmrc
├── .nvmrc
├── .prettierignore
├── .prettierrc
├── .stylelintrc
├── .svgo.yml
├── .vscode/
│   ├── css.json
│   ├── dim.code-snippets
│   ├── extensions.json
│   ├── launch.json
│   ├── settings.json
│   └── tasks.json
├── LICENSE.md
├── README.md
├── babel.config.cjs
├── build/
│   ├── deploy-prod.sh
│   ├── purge-cloudflare.sh
│   ├── rsync-deploy.sh
│   ├── test-changelog.js
│   └── update-changelog.js
├── config/
│   ├── .well-known/
│   │   ├── android-config.beta.json
│   │   ├── android-config.json
│   │   └── apple-config.json
│   ├── content-security-policy.ts
│   ├── cspell/
│   │   ├── bungie-dict.txt
│   │   ├── dim-dict.txt
│   │   ├── dim-username-dict.txt
│   │   └── programming-dict.txt
│   ├── dim_travis.rsa.enc
│   ├── dim_travis.rsa.pub
│   ├── feature-flags.ts
│   ├── i18n.json
│   ├── manifest-webapp.ts
│   ├── notify-webpack-plugin.ts
│   └── webpack.ts
├── crowdin.yml
├── cspell.json
├── docker-compose.yml
├── docs/
│   ├── CHANGELOG.md
│   ├── CODE_OF_CONDUCT.md
│   ├── COMMUNITY_CURATIONS.md
│   ├── CONTRIBUTING.md
│   ├── Docker.md
│   ├── OLD_CHANGELOG/
│   │   ├── OLD_CHANGELOG_3.X.X.md
│   │   ├── OLD_CHANGELOG_4.X.X.md
│   │   ├── OLD_CHANGELOG_5.X.X.md
│   │   └── OLD_CHANGELOG_6.X.X.md
│   ├── TRANSLATIONS.md
│   └── clean-changelog.rb
├── eslint.config.js
├── i18next-scanner.config.cjs
├── icons/
│   ├── build_icons.cjs
│   └── splash.json
├── jest.config.js
├── package.json
├── src/
│   ├── 404.html
│   ├── @types/
│   │   └── i18next.d.ts
│   ├── Index.tsx
│   ├── StorageTest.tsx
│   ├── __mocks__/
│   │   └── fileMock.js
│   ├── app/
│   │   ├── App.m.scss
│   │   ├── App.m.scss.d.ts
│   │   ├── App.tsx
│   │   ├── Root.tsx
│   │   ├── _variables.scss
│   │   ├── accounts/
│   │   │   ├── Account.m.scss
│   │   │   ├── Account.m.scss.d.ts
│   │   │   ├── Account.tsx
│   │   │   ├── MenuAccounts.m.scss
│   │   │   ├── MenuAccounts.m.scss.d.ts
│   │   │   ├── MenuAccounts.tsx
│   │   │   ├── SelectAccount.m.scss
│   │   │   ├── SelectAccount.m.scss.d.ts
│   │   │   ├── SelectAccount.tsx
│   │   │   ├── actions.ts
│   │   │   ├── bungie-account.ts
│   │   │   ├── destiny-account.test.ts
│   │   │   ├── destiny-account.ts
│   │   │   ├── observers.ts
│   │   │   ├── platforms.ts
│   │   │   ├── reducer.ts
│   │   │   └── selectors.ts
│   │   ├── armory/
│   │   │   ├── AllWishlistRolls.m.scss
│   │   │   ├── AllWishlistRolls.m.scss.d.ts
│   │   │   ├── AllWishlistRolls.tsx
│   │   │   ├── Armory.m.scss
│   │   │   ├── Armory.m.scss.d.ts
│   │   │   ├── Armory.tsx
│   │   │   ├── ArmoryPage.tsx
│   │   │   ├── ArmorySheet.m.scss
│   │   │   ├── ArmorySheet.m.scss.d.ts
│   │   │   ├── ArmorySheet.tsx
│   │   │   ├── ItemGrid.tsx
│   │   │   ├── LazyArmory.ts
│   │   │   ├── Links.m.scss
│   │   │   ├── Links.m.scss.d.ts
│   │   │   ├── Links.tsx
│   │   │   ├── WishListEntry.m.scss
│   │   │   ├── WishListEntry.m.scss.d.ts
│   │   │   ├── WishListEntry.tsx
│   │   │   ├── crafting-utils.ts
│   │   │   ├── trait-to-enhanced-trait.d.ts
│   │   │   ├── wishlist-collapser.test.ts
│   │   │   └── wishlist-collapser.ts
│   │   ├── bungie-api/
│   │   │   ├── README.md
│   │   │   ├── __snapshots__/
│   │   │   │   └── http-client.test.ts.snap
│   │   │   ├── authenticated-fetch.ts
│   │   │   ├── bungie-api-utils.ts
│   │   │   ├── bungie-core-api.ts
│   │   │   ├── bungie-service-helper.ts
│   │   │   ├── destiny1-api.ts
│   │   │   ├── destiny2-api.ts
│   │   │   ├── error-toaster.tsx
│   │   │   ├── http-client.test.ts
│   │   │   ├── http-client.ts
│   │   │   ├── oauth-tokens.ts
│   │   │   ├── oauth.ts
│   │   │   ├── rate-limit-config.ts
│   │   │   └── rate-limiter.ts
│   │   ├── character-tile/
│   │   │   ├── CharacterHeaderXP.m.scss
│   │   │   ├── CharacterHeaderXP.m.scss.d.ts
│   │   │   ├── CharacterHeaderXP.tsx
│   │   │   ├── CharacterTile.m.scss
│   │   │   ├── CharacterTile.m.scss.d.ts
│   │   │   ├── CharacterTile.tsx
│   │   │   ├── CharacterTileButton.m.scss
│   │   │   ├── CharacterTileButton.m.scss.d.ts
│   │   │   ├── CharacterTileButton.tsx
│   │   │   ├── StoreHeading.m.scss
│   │   │   ├── StoreHeading.m.scss.d.ts
│   │   │   ├── StoreHeading.tsx
│   │   │   ├── StoreIcon.m.scss
│   │   │   ├── StoreIcon.m.scss.d.ts
│   │   │   └── StoreIcon.tsx
│   │   ├── clarity/
│   │   │   ├── about.ts
│   │   │   ├── actions.ts
│   │   │   ├── descriptions/
│   │   │   │   ├── ClarityDescriptions.tsx
│   │   │   │   ├── Description.m.scss
│   │   │   │   ├── Description.m.scss.d.ts
│   │   │   │   ├── character-stats.ts
│   │   │   │   ├── descriptionInterface.ts
│   │   │   │   └── loadDescriptions.ts
│   │   │   ├── reducer.ts
│   │   │   └── selectors.ts
│   │   ├── compare/
│   │   │   ├── Compare.m.scss
│   │   │   ├── Compare.m.scss.d.ts
│   │   │   ├── Compare.tsx
│   │   │   ├── CompareButtons.m.scss
│   │   │   ├── CompareButtons.m.scss.d.ts
│   │   │   ├── CompareColumns.m.scss
│   │   │   ├── CompareColumns.m.scss.d.ts
│   │   │   ├── CompareColumns.tsx
│   │   │   ├── CompareContainer.tsx
│   │   │   ├── CompareItem.m.scss
│   │   │   ├── CompareItem.m.scss.d.ts
│   │   │   ├── CompareItem.tsx
│   │   │   ├── CompareStat.m.scss
│   │   │   ├── CompareStat.m.scss.d.ts
│   │   │   ├── CompareStat.tsx
│   │   │   ├── CompareSuggestions.tsx
│   │   │   ├── actions.ts
│   │   │   ├── compare-buttons.tsx
│   │   │   ├── compare-utils.ts
│   │   │   ├── reducer.ts
│   │   │   ├── selectors.ts
│   │   │   └── types.ts
│   │   ├── css-variables.ts
│   │   ├── debug/
│   │   │   ├── Debug.m.scss
│   │   │   ├── Debug.m.scss.d.ts
│   │   │   └── Debug.tsx
│   │   ├── destiny1/
│   │   │   ├── activities/
│   │   │   │   ├── Activities.m.scss
│   │   │   │   ├── Activities.m.scss.d.ts
│   │   │   │   └── Activities.tsx
│   │   │   ├── d1-bucket-categories.ts
│   │   │   ├── d1-buckets.ts
│   │   │   ├── d1-definitions.ts
│   │   │   ├── d1-factions.ts
│   │   │   ├── d1-manifest-types.ts
│   │   │   ├── loadout-builder/
│   │   │   │   ├── D1LoadoutBuilder.m.scss
│   │   │   │   ├── D1LoadoutBuilder.m.scss.d.ts
│   │   │   │   ├── D1LoadoutBuilder.tsx
│   │   │   │   ├── ExcludeItemsDropTarget.tsx
│   │   │   │   ├── GeneratedSet.m.scss
│   │   │   │   ├── GeneratedSet.m.scss.d.ts
│   │   │   │   ├── GeneratedSet.tsx
│   │   │   │   ├── LoadoutBuilderDropTarget.m.scss
│   │   │   │   ├── LoadoutBuilderDropTarget.m.scss.d.ts
│   │   │   │   ├── LoadoutBuilderDropTarget.tsx
│   │   │   │   ├── LoadoutBuilderItem.m.scss
│   │   │   │   ├── LoadoutBuilderItem.m.scss.d.ts
│   │   │   │   ├── LoadoutBuilderItem.tsx
│   │   │   │   ├── LoadoutBuilderLockPerk.m.scss
│   │   │   │   ├── LoadoutBuilderLockPerk.m.scss.d.ts
│   │   │   │   ├── LoadoutBuilderLockPerk.tsx
│   │   │   │   ├── LoadoutBuilderLocksDialog.m.scss
│   │   │   │   ├── LoadoutBuilderLocksDialog.m.scss.d.ts
│   │   │   │   ├── LoadoutBuilderLocksDialog.tsx
│   │   │   │   ├── calculate.ts
│   │   │   │   ├── types.ts
│   │   │   │   └── utils.ts
│   │   │   ├── loadout-drawer/
│   │   │   │   ├── Buttons.m.scss
│   │   │   │   ├── Buttons.m.scss.d.ts
│   │   │   │   ├── Buttons.tsx
│   │   │   │   ├── D1LoadoutDrawer.m.scss
│   │   │   │   ├── D1LoadoutDrawer.m.scss.d.ts
│   │   │   │   ├── D1LoadoutDrawer.tsx
│   │   │   │   ├── LoadoutDrawerBucket.m.scss
│   │   │   │   ├── LoadoutDrawerBucket.m.scss.d.ts
│   │   │   │   ├── LoadoutDrawerBucket.tsx
│   │   │   │   ├── LoadoutDrawerContents.m.scss
│   │   │   │   ├── LoadoutDrawerContents.m.scss.d.ts
│   │   │   │   ├── LoadoutDrawerContents.tsx
│   │   │   │   ├── LoadoutDrawerItem.m.scss
│   │   │   │   ├── LoadoutDrawerItem.m.scss.d.ts
│   │   │   │   ├── LoadoutDrawerItem.tsx
│   │   │   │   ├── LoadoutDrawerOptions.m.scss
│   │   │   │   ├── LoadoutDrawerOptions.m.scss.d.ts
│   │   │   │   └── LoadoutDrawerOptions.tsx
│   │   │   ├── record-books/
│   │   │   │   ├── RecordBooks.m.scss
│   │   │   │   ├── RecordBooks.m.scss.d.ts
│   │   │   │   └── RecordBooks.tsx
│   │   │   └── vendors/
│   │   │       ├── D1Vendor.tsx
│   │   │       ├── D1VendorItem.m.scss
│   │   │       ├── D1VendorItem.m.scss.d.ts
│   │   │       ├── D1VendorItem.tsx
│   │   │       ├── D1VendorItems.tsx
│   │   │       ├── D1Vendors.m.scss
│   │   │       ├── D1Vendors.m.scss.d.ts
│   │   │       ├── D1Vendors.tsx
│   │   │       └── vendor.service.ts
│   │   ├── destiny2/
│   │   │   ├── d2-bucket-categories.ts
│   │   │   ├── d2-buckets.ts
│   │   │   ├── d2-definitions.test.ts
│   │   │   ├── d2-definitions.ts
│   │   │   └── definitions.ts
│   │   ├── developer/
│   │   │   └── Developer.tsx
│   │   ├── dim-api/
│   │   │   ├── actions.ts
│   │   │   ├── api-permission-prompt.m.scss
│   │   │   ├── api-permission-prompt.m.scss.d.ts
│   │   │   ├── api-permission-prompt.tsx
│   │   │   ├── api-types.ts
│   │   │   ├── basic-actions.ts
│   │   │   ├── dim-api-helper.ts
│   │   │   ├── dim-api.ts
│   │   │   ├── import.ts
│   │   │   ├── reducer.test.ts
│   │   │   ├── reducer.ts
│   │   │   ├── register-app.ts
│   │   │   └── selectors.ts
│   │   ├── dim-ui/
│   │   │   ├── AlertIcon.m.scss
│   │   │   ├── AlertIcon.m.scss.d.ts
│   │   │   ├── AlertIcon.tsx
│   │   │   ├── AnimatedNumber.tsx
│   │   │   ├── AutoRefresh.tsx
│   │   │   ├── BungieImage.tsx
│   │   │   ├── CharacterSelect.m.scss
│   │   │   ├── CharacterSelect.m.scss.d.ts
│   │   │   ├── CharacterSelect.tsx
│   │   │   ├── CheckButton.m.scss
│   │   │   ├── CheckButton.m.scss.d.ts
│   │   │   ├── CheckButton.tsx
│   │   │   ├── ClassIcon.tsx
│   │   │   ├── ClickOutside.tsx
│   │   │   ├── ClickOutsideRoot.tsx
│   │   │   ├── ClosableContainer.m.scss
│   │   │   ├── ClosableContainer.m.scss.d.ts
│   │   │   ├── ClosableContainer.tsx
│   │   │   ├── CollapsibleTitle.m.scss
│   │   │   ├── CollapsibleTitle.m.scss.d.ts
│   │   │   ├── CollapsibleTitle.tsx
│   │   │   ├── ConfirmButton.m.scss
│   │   │   ├── ConfirmButton.m.scss.d.ts
│   │   │   ├── ConfirmButton.tsx
│   │   │   ├── Countdown.tsx
│   │   │   ├── CustomStatTotal.m.scss
│   │   │   ├── CustomStatTotal.m.scss.d.ts
│   │   │   ├── CustomStatTotal.tsx
│   │   │   ├── CustomStatWeights.m.scss
│   │   │   ├── CustomStatWeights.m.scss.d.ts
│   │   │   ├── CustomStatWeights.tsx
│   │   │   ├── DestinyTooltipText.m.scss
│   │   │   ├── DestinyTooltipText.m.scss.d.ts
│   │   │   ├── DestinyTooltipText.tsx
│   │   │   ├── DiamondProgress.m.scss
│   │   │   ├── DiamondProgress.m.scss.d.ts
│   │   │   ├── DiamondProgress.tsx
│   │   │   ├── Dropdown.m.scss
│   │   │   ├── Dropdown.m.scss.d.ts
│   │   │   ├── Dropdown.tsx
│   │   │   ├── ElementIcon.m.scss
│   │   │   ├── ElementIcon.m.scss.d.ts
│   │   │   ├── ElementIcon.tsx
│   │   │   ├── EnergyIncrements.m.scss
│   │   │   ├── EnergyIncrements.m.scss.d.ts
│   │   │   ├── EnergyIncrements.tsx
│   │   │   ├── ErrorBoundary.tsx
│   │   │   ├── ExpandableTextBlock.m.scss
│   │   │   ├── ExpandableTextBlock.m.scss.d.ts
│   │   │   ├── ExpandableTextBlock.tsx
│   │   │   ├── ExternalLink.tsx
│   │   │   ├── FileUpload.m.scss
│   │   │   ├── FileUpload.m.scss.d.ts
│   │   │   ├── FileUpload.tsx
│   │   │   ├── FilterPills.m.scss
│   │   │   ├── FilterPills.m.scss.d.ts
│   │   │   ├── FilterPills.tsx
│   │   │   ├── FractionalPowerLevel.m.scss
│   │   │   ├── FractionalPowerLevel.m.scss.d.ts
│   │   │   ├── FractionalPowerLevel.tsx
│   │   │   ├── HelpLink.m.scss
│   │   │   ├── HelpLink.m.scss.d.ts
│   │   │   ├── HelpLink.tsx
│   │   │   ├── ItemCategoryIcon.m.scss
│   │   │   ├── ItemCategoryIcon.m.scss.d.ts
│   │   │   ├── ItemCategoryIcon.tsx
│   │   │   ├── ItemPop.m.scss
│   │   │   ├── ItemPop.m.scss.d.ts
│   │   │   ├── KeyHelp.m.scss
│   │   │   ├── KeyHelp.m.scss.d.ts
│   │   │   ├── KeyHelp.tsx
│   │   │   ├── Loading.m.scss
│   │   │   ├── Loading.m.scss.d.ts
│   │   │   ├── Loading.tsx
│   │   │   ├── PageLoading.m.scss
│   │   │   ├── PageLoading.m.scss.d.ts
│   │   │   ├── PageLoading.tsx
│   │   │   ├── PageWithMenu.m.scss
│   │   │   ├── PageWithMenu.m.scss.d.ts
│   │   │   ├── PageWithMenu.tsx
│   │   │   ├── PressTip.m.scss
│   │   │   ├── PressTip.m.scss.d.ts
│   │   │   ├── PressTip.tsx
│   │   │   ├── README.md
│   │   │   ├── RadioButtons.m.scss
│   │   │   ├── RadioButtons.m.scss.d.ts
│   │   │   ├── RadioButtons.tsx
│   │   │   ├── Select.m.scss
│   │   │   ├── Select.m.scss.d.ts
│   │   │   ├── Select.tsx
│   │   │   ├── SetFilterButton.m.scss
│   │   │   ├── SetFilterButton.m.scss.d.ts
│   │   │   ├── SetFilterButton.tsx
│   │   │   ├── Sheet.m.scss
│   │   │   ├── Sheet.m.scss.d.ts
│   │   │   ├── Sheet.tsx
│   │   │   ├── SheetHorizontalScrollContainer.m.scss
│   │   │   ├── SheetHorizontalScrollContainer.m.scss.d.ts
│   │   │   ├── SheetHorizontalScrollContainer.tsx
│   │   │   ├── ShowPageLoading.tsx
│   │   │   ├── SpecialtyModSlotIcon.m.scss
│   │   │   ├── SpecialtyModSlotIcon.m.scss.d.ts
│   │   │   ├── SpecialtyModSlotIcon.tsx
│   │   │   ├── StaticPage.m.scss
│   │   │   ├── StaticPage.m.scss.d.ts
│   │   │   ├── StaticPage.tsx
│   │   │   ├── Switch.m.scss
│   │   │   ├── Switch.m.scss.d.ts
│   │   │   ├── Switch.tsx
│   │   │   ├── TileGrid.m.scss
│   │   │   ├── TileGrid.m.scss.d.ts
│   │   │   ├── TileGrid.tsx
│   │   │   ├── UserGuideLink.tsx
│   │   │   ├── VirtualList.m.scss
│   │   │   ├── VirtualList.m.scss.d.ts
│   │   │   ├── VirtualList.tsx
│   │   │   ├── WeaponGroupingIcon.m.scss
│   │   │   ├── WeaponGroupingIcon.m.scss.d.ts
│   │   │   ├── WeaponGroupingIcon.tsx
│   │   │   ├── _tooltip-mixins.scss
│   │   │   ├── common.m.scss
│   │   │   ├── destiny-symbols/
│   │   │   │   ├── ColorDestinySymbols.m.scss
│   │   │   │   ├── ColorDestinySymbols.m.scss.d.ts
│   │   │   │   ├── ColorDestinySymbols.tsx
│   │   │   │   ├── RichDestinyText.tsx
│   │   │   │   ├── SymbolsPicker.m.scss
│   │   │   │   ├── SymbolsPicker.m.scss.d.ts
│   │   │   │   ├── SymbolsPicker.tsx
│   │   │   │   ├── destiny-symbols.test.ts
│   │   │   │   ├── destiny-symbols.ts
│   │   │   │   └── rich-destiny-text.ts
│   │   │   ├── dim-button.scss
│   │   │   ├── scroll.ts
│   │   │   ├── sheets-open.ts
│   │   │   ├── svgs/
│   │   │   │   ├── BucketIcon.tsx
│   │   │   │   └── itemCategory.ts
│   │   │   ├── table-columns.test.ts
│   │   │   ├── table-columns.ts
│   │   │   ├── text-complete/
│   │   │   │   ├── text-complete.m.scss
│   │   │   │   ├── text-complete.m.scss.d.ts
│   │   │   │   └── text-complete.ts
│   │   │   ├── useBulkNote.m.scss
│   │   │   ├── useBulkNote.m.scss.d.ts
│   │   │   ├── useBulkNote.tsx
│   │   │   ├── useConfirm.tsx
│   │   │   ├── useDialog.m.scss
│   │   │   ├── useDialog.m.scss.d.ts
│   │   │   ├── useDialog.tsx
│   │   │   ├── useFixOverscrollBehavior.ts
│   │   │   ├── usePopper.ts
│   │   │   ├── usePrompt.m.scss
│   │   │   ├── usePrompt.m.scss.d.ts
│   │   │   └── usePrompt.tsx
│   │   ├── farming/
│   │   │   ├── Farming.m.scss
│   │   │   ├── Farming.m.scss.d.ts
│   │   │   ├── Farming.tsx
│   │   │   ├── actions.ts
│   │   │   ├── basic-actions.ts
│   │   │   ├── reducer.ts
│   │   │   └── selectors.ts
│   │   ├── gear-power/
│   │   │   ├── GearPower.m.scss
│   │   │   ├── GearPower.m.scss.d.ts
│   │   │   ├── GearPower.tsx
│   │   │   └── gear-power.ts
│   │   ├── google.ts
│   │   ├── hotkeys/
│   │   │   ├── GlobalHotkeys.tsx
│   │   │   ├── HotkeysCheatSheet.m.scss
│   │   │   ├── HotkeysCheatSheet.m.scss.d.ts
│   │   │   ├── HotkeysCheatSheet.tsx
│   │   │   ├── hotkeys.test.ts
│   │   │   ├── hotkeys.ts
│   │   │   └── useHotkey.ts
│   │   ├── i18n.ts
│   │   ├── i18next-t.ts
│   │   ├── infuse/
│   │   │   ├── InfusionFinder.m.scss
│   │   │   ├── InfusionFinder.m.scss.d.ts
│   │   │   ├── InfusionFinder.tsx
│   │   │   └── infuse.ts
│   │   ├── inventory/
│   │   │   ├── ArtifactXP.m.scss
│   │   │   ├── ArtifactXP.m.scss.d.ts
│   │   │   ├── ArtifactXP.tsx
│   │   │   ├── BadgeInfo.m.scss
│   │   │   ├── BadgeInfo.m.scss.d.ts
│   │   │   ├── BadgeInfo.tsx
│   │   │   ├── ConnectedInventoryItem.tsx
│   │   │   ├── DragPerformanceFix.m.scss
│   │   │   ├── DragPerformanceFix.m.scss.d.ts
│   │   │   ├── DragPerformanceFix.tsx
│   │   │   ├── DraggableInventoryItem.m.scss
│   │   │   ├── DraggableInventoryItem.m.scss.d.ts
│   │   │   ├── DraggableInventoryItem.tsx
│   │   │   ├── InventoryItem.m.scss
│   │   │   ├── InventoryItem.m.scss.d.ts
│   │   │   ├── InventoryItem.tsx
│   │   │   ├── ItemDragPreview.tsx
│   │   │   ├── ItemIcon.m.scss
│   │   │   ├── ItemIcon.m.scss.d.ts
│   │   │   ├── ItemIcon.tsx
│   │   │   ├── ItemIconPlaceholder.m.scss
│   │   │   ├── ItemIconPlaceholder.m.scss.d.ts
│   │   │   ├── ItemIconPlaceholder.tsx
│   │   │   ├── ItemPopupTrigger.tsx
│   │   │   ├── ItemPowerSet.m.scss
│   │   │   ├── ItemPowerSet.m.scss.d.ts
│   │   │   ├── ItemPowerSet.tsx
│   │   │   ├── MoveNotifications.m.scss
│   │   │   ├── MoveNotifications.m.scss.d.ts
│   │   │   ├── MoveNotifications.tsx
│   │   │   ├── NewItemIndicator.m.scss
│   │   │   ├── NewItemIndicator.m.scss.d.ts
│   │   │   ├── NewItemIndicator.tsx
│   │   │   ├── PullFromPostmaster.m.scss
│   │   │   ├── PullFromPostmaster.m.scss.d.ts
│   │   │   ├── PullFromPostmaster.tsx
│   │   │   ├── RatingIcon.m.scss
│   │   │   ├── RatingIcon.m.scss.d.ts
│   │   │   ├── RatingIcon.tsx
│   │   │   ├── SyncTagLock.tsx
│   │   │   ├── TagIcon.tsx
│   │   │   ├── __snapshots__/
│   │   │   │   └── d2-stores.test.ts.snap
│   │   │   ├── actions.ts
│   │   │   ├── advanced-write-actions.ts
│   │   │   ├── bulk-actions.tsx
│   │   │   ├── cross-tab.ts
│   │   │   ├── d1-stores.ts
│   │   │   ├── d2-stores.test.ts
│   │   │   ├── d2-stores.ts
│   │   │   ├── dim-item-info.ts
│   │   │   ├── drag-events.ts
│   │   │   ├── inventory-buckets.ts
│   │   │   ├── item-move-service.ts
│   │   │   ├── item-types.ts
│   │   │   ├── locate-item.ts
│   │   │   ├── manual-moves.ts
│   │   │   ├── move-item.ts
│   │   │   ├── note-hashtags.ts
│   │   │   ├── notes-hashtags.test.ts
│   │   │   ├── observers.ts
│   │   │   ├── reducer.ts
│   │   │   ├── rewards.ts
│   │   │   ├── selectors.ts
│   │   │   ├── spreadsheets.ts
│   │   │   ├── store/
│   │   │   │   ├── armor-quality.ts
│   │   │   │   ├── catalyst.ts
│   │   │   │   ├── character-utils.ts
│   │   │   │   ├── crafted.ts
│   │   │   │   ├── d1-item-factory.ts
│   │   │   │   ├── d1-store-factory.ts
│   │   │   │   ├── d2-item-factory.ts
│   │   │   │   ├── d2-store-factory.ts
│   │   │   │   ├── deepsight.ts
│   │   │   │   ├── energy.ts
│   │   │   │   ├── enhanced-info.d.ts
│   │   │   │   ├── exotic-class-item.ts
│   │   │   │   ├── exotic-to-catalyst-record.d.ts
│   │   │   │   ├── hooks.ts
│   │   │   │   ├── item-index.ts
│   │   │   │   ├── masterwork.ts
│   │   │   │   ├── missing-sources.d.ts
│   │   │   │   ├── objectives.ts
│   │   │   │   ├── override-sockets.ts
│   │   │   │   ├── patterns.ts
│   │   │   │   ├── season-d2ai.d.ts
│   │   │   │   ├── season.ts
│   │   │   │   ├── selectors.ts
│   │   │   │   ├── sockets.ts
│   │   │   │   ├── stats-conditional.ts
│   │   │   │   ├── stats-custom.ts
│   │   │   │   ├── stats.ts
│   │   │   │   └── well-rested.ts
│   │   │   ├── store-types.ts
│   │   │   ├── stores-helpers.ts
│   │   │   └── subclass.ts
│   │   ├── inventory-page/
│   │   │   ├── CategoryStrip.m.scss
│   │   │   ├── CategoryStrip.m.scss.d.ts
│   │   │   ├── CategoryStrip.tsx
│   │   │   ├── D1Reputation.m.scss
│   │   │   ├── D1Reputation.m.scss.d.ts
│   │   │   ├── D1Reputation.tsx
│   │   │   ├── D1ReputationSection.tsx
│   │   │   ├── DesktopStores.m.scss
│   │   │   ├── DesktopStores.m.scss.d.ts
│   │   │   ├── DesktopStores.tsx
│   │   │   ├── HeaderShadowDiv.m.scss
│   │   │   ├── HeaderShadowDiv.m.scss.d.ts
│   │   │   ├── HeaderShadowDiv.tsx
│   │   │   ├── Inventory.tsx
│   │   │   ├── InventoryCollapsibleTitle.m.scss
│   │   │   ├── InventoryCollapsibleTitle.m.scss.d.ts
│   │   │   ├── InventoryCollapsibleTitle.tsx
│   │   │   ├── PhoneStores.m.scss
│   │   │   ├── PhoneStores.m.scss.d.ts
│   │   │   ├── PhoneStores.tsx
│   │   │   ├── PhoneStoresHeader.m.scss
│   │   │   ├── PhoneStoresHeader.m.scss.d.ts
│   │   │   ├── PhoneStoresHeader.tsx
│   │   │   ├── StoreBucket.m.scss
│   │   │   ├── StoreBucket.m.scss.d.ts
│   │   │   ├── StoreBucket.scss
│   │   │   ├── StoreBucket.tsx
│   │   │   ├── StoreBucketDropTarget.m.scss
│   │   │   ├── StoreBucketDropTarget.m.scss.d.ts
│   │   │   ├── StoreBucketDropTarget.tsx
│   │   │   ├── StoreBuckets.m.scss
│   │   │   ├── StoreBuckets.m.scss.d.ts
│   │   │   ├── StoreBuckets.tsx
│   │   │   ├── StoreInventoryItem.tsx
│   │   │   ├── Stores.scss
│   │   │   └── Stores.tsx
│   │   ├── issue-awareness-banner/
│   │   │   ├── Game2Give.m.scss
│   │   │   ├── Game2Give.m.scss.d.ts
│   │   │   ├── Game2Give.tsx
│   │   │   ├── IssueAwarenessBanner.tsx
│   │   │   └── useGame2GiveData.tsx
│   │   ├── item-actions/
│   │   │   ├── ActionButton.m.scss
│   │   │   ├── ActionButton.m.scss.d.ts
│   │   │   ├── ActionButton.tsx
│   │   │   ├── ActionButtons.m.scss
│   │   │   ├── ActionButtons.m.scss.d.ts
│   │   │   ├── ActionButtons.tsx
│   │   │   ├── ItemAccessoryButtons.tsx
│   │   │   ├── ItemActionsDropdown.m.scss
│   │   │   ├── ItemActionsDropdown.m.scss.d.ts
│   │   │   ├── ItemActionsDropdown.tsx
│   │   │   ├── ItemMoveLocations.m.scss
│   │   │   ├── ItemMoveLocations.m.scss.d.ts
│   │   │   ├── ItemMoveLocations.tsx
│   │   │   ├── LockButton.m.scss
│   │   │   ├── LockButton.m.scss.d.ts
│   │   │   └── LockButton.tsx
│   │   ├── item-feed/
│   │   │   ├── Highlights.m.scss
│   │   │   ├── Highlights.m.scss.d.ts
│   │   │   ├── Highlights.tsx
│   │   │   ├── ItemFeed.m.scss
│   │   │   ├── ItemFeed.m.scss.d.ts
│   │   │   ├── ItemFeed.tsx
│   │   │   ├── ItemFeedPage.m.scss
│   │   │   ├── ItemFeedPage.m.scss.d.ts
│   │   │   ├── ItemFeedPage.tsx
│   │   │   ├── ItemFeedSidebar.m.scss
│   │   │   ├── ItemFeedSidebar.m.scss.d.ts
│   │   │   ├── ItemFeedSidebar.tsx
│   │   │   ├── TagButtons.m.scss
│   │   │   ├── TagButtons.m.scss.d.ts
│   │   │   └── TagButtons.tsx
│   │   ├── item-picker/
│   │   │   ├── ItemPicker.m.scss
│   │   │   ├── ItemPicker.m.scss.d.ts
│   │   │   ├── ItemPicker.tsx
│   │   │   ├── ItemPickerContainer.tsx
│   │   │   └── item-picker.ts
│   │   ├── item-popup/
│   │   │   ├── AmmoIcon.m.scss
│   │   │   ├── AmmoIcon.m.scss.d.ts
│   │   │   ├── AmmoIcon.tsx
│   │   │   ├── ApplyPerkSelection.m.scss
│   │   │   ├── ApplyPerkSelection.m.scss.d.ts
│   │   │   ├── ApplyPerkSelection.tsx
│   │   │   ├── ArchetypeSocket.m.scss
│   │   │   ├── ArchetypeSocket.m.scss.d.ts
│   │   │   ├── ArchetypeSocket.tsx
│   │   │   ├── BreakerType.m.scss
│   │   │   ├── BreakerType.m.scss.d.ts
│   │   │   ├── BreakerType.tsx
│   │   │   ├── DeepSightHarmonizerIcon.m.scss
│   │   │   ├── DeepSightHarmonizerIcon.m.scss.d.ts
│   │   │   ├── DeepsightHarmonizerIcon.tsx
│   │   │   ├── DesktopItemActions.m.scss
│   │   │   ├── DesktopItemActions.m.scss.d.ts
│   │   │   ├── DesktopItemActions.tsx
│   │   │   ├── EmblemPreview.m.scss
│   │   │   ├── EmblemPreview.m.scss.d.ts
│   │   │   ├── EmblemPreview.tsx
│   │   │   ├── EmoteSockets.m.scss
│   │   │   ├── EmoteSockets.m.scss.d.ts
│   │   │   ├── EmoteSockets.tsx
│   │   │   ├── EnergyMeter.m.scss
│   │   │   ├── EnergyMeter.m.scss.d.ts
│   │   │   ├── EnergyMeter.tsx
│   │   │   ├── ItemDescription.m.scss
│   │   │   ├── ItemDescription.m.scss.d.ts
│   │   │   ├── ItemDescription.tsx
│   │   │   ├── ItemDetails.m.scss
│   │   │   ├── ItemDetails.m.scss.d.ts
│   │   │   ├── ItemDetails.tsx
│   │   │   ├── ItemExpiration.tsx
│   │   │   ├── ItemMoveAmount.m.scss
│   │   │   ├── ItemMoveAmount.m.scss.d.ts
│   │   │   ├── ItemMoveAmount.tsx
│   │   │   ├── ItemPerks.m.scss
│   │   │   ├── ItemPerks.m.scss.d.ts
│   │   │   ├── ItemPerks.tsx
│   │   │   ├── ItemPerksList.m.scss
│   │   │   ├── ItemPerksList.m.scss.d.ts
│   │   │   ├── ItemPerksList.tsx
│   │   │   ├── ItemPopup.m.scss
│   │   │   ├── ItemPopup.m.scss.d.ts
│   │   │   ├── ItemPopup.tsx
│   │   │   ├── ItemPopupBody.scss
│   │   │   ├── ItemPopupContainer.tsx
│   │   │   ├── ItemPopupHeader.m.scss
│   │   │   ├── ItemPopupHeader.m.scss.d.ts
│   │   │   ├── ItemPopupHeader.tsx
│   │   │   ├── ItemPopupTabs.m.scss
│   │   │   ├── ItemPopupTabs.m.scss.d.ts
│   │   │   ├── ItemPopupTabs.tsx
│   │   │   ├── ItemSockets.m.scss
│   │   │   ├── ItemSockets.m.scss.d.ts
│   │   │   ├── ItemSockets.tsx
│   │   │   ├── ItemSocketsGeneral.m.scss
│   │   │   ├── ItemSocketsGeneral.m.scss.d.ts
│   │   │   ├── ItemSocketsGeneral.tsx
│   │   │   ├── ItemSocketsWeapons.m.scss
│   │   │   ├── ItemSocketsWeapons.m.scss.d.ts
│   │   │   ├── ItemSocketsWeapons.tsx
│   │   │   ├── ItemStat.m.scss
│   │   │   ├── ItemStat.m.scss.d.ts
│   │   │   ├── ItemStat.tsx
│   │   │   ├── ItemStats.m.scss
│   │   │   ├── ItemStats.m.scss.d.ts
│   │   │   ├── ItemStats.tsx
│   │   │   ├── ItemTagHotkeys.tsx
│   │   │   ├── ItemTagSelector.m.scss
│   │   │   ├── ItemTagSelector.m.scss.d.ts
│   │   │   ├── ItemTagSelector.tsx
│   │   │   ├── ItemTalentGrid.m.scss
│   │   │   ├── ItemTalentGrid.m.scss.d.ts
│   │   │   ├── ItemTalentGrid.tsx
│   │   │   ├── KillTracker.tsx
│   │   │   ├── MetricCategories.m.scss
│   │   │   ├── MetricCategories.m.scss.d.ts
│   │   │   ├── MetricCategories.tsx
│   │   │   ├── NotesArea.m.scss
│   │   │   ├── NotesArea.m.scss.d.ts
│   │   │   ├── NotesArea.tsx
│   │   │   ├── Plug.m.scss
│   │   │   ├── Plug.m.scss.d.ts
│   │   │   ├── Plug.tsx
│   │   │   ├── PlugTooltip.m.scss
│   │   │   ├── PlugTooltip.m.scss.d.ts
│   │   │   ├── PlugTooltip.tsx
│   │   │   ├── RecoilStat.tsx
│   │   │   ├── SetBonus.m.scss
│   │   │   ├── SetBonus.m.scss.d.ts
│   │   │   ├── SetBonus.tsx
│   │   │   ├── Socket.m.scss
│   │   │   ├── Socket.m.scss.d.ts
│   │   │   ├── Socket.tsx
│   │   │   ├── SocketDetails.m.scss
│   │   │   ├── SocketDetails.m.scss.d.ts
│   │   │   ├── SocketDetails.tsx
│   │   │   ├── SocketDetailsSelectedPlug.m.scss
│   │   │   ├── SocketDetailsSelectedPlug.m.scss.d.ts
│   │   │   ├── SocketDetailsSelectedPlug.tsx
│   │   │   ├── WeaponCatalystInfo.m.scss
│   │   │   ├── WeaponCatalystInfo.m.scss.d.ts
│   │   │   ├── WeaponCatalystInfo.tsx
│   │   │   ├── WeaponCraftedInfo.m.scss
│   │   │   ├── WeaponCraftedInfo.m.scss.d.ts
│   │   │   ├── WeaponCraftedInfo.tsx
│   │   │   ├── WeaponDeepsightInfo.m.scss
│   │   │   ├── WeaponDeepsightInfo.m.scss.d.ts
│   │   │   ├── WeaponDeepsightInfo.tsx
│   │   │   ├── item-popup-actions.test.ts
│   │   │   ├── item-popup-actions.ts
│   │   │   ├── item-popup.ts
│   │   │   └── sidecar-popper-modifier.ts
│   │   ├── item-triage/
│   │   │   ├── ItemTriage.m.scss
│   │   │   ├── ItemTriage.m.scss.d.ts
│   │   │   ├── ItemTriage.tsx
│   │   │   ├── TriageFactors.m.scss
│   │   │   ├── TriageFactors.m.scss.d.ts
│   │   │   ├── triage-factors.tsx
│   │   │   ├── triage-utils.test.ts
│   │   │   └── triage-utils.ts
│   │   ├── loadout/
│   │   │   ├── LoadoutView.m.scss
│   │   │   ├── LoadoutView.m.scss.d.ts
│   │   │   ├── LoadoutView.tsx
│   │   │   ├── Loadouts.m.scss
│   │   │   ├── Loadouts.m.scss.d.ts
│   │   │   ├── Loadouts.tsx
│   │   │   ├── LoadoutsRow.m.scss
│   │   │   ├── LoadoutsRow.tsx
│   │   │   ├── ModPicker.tsx
│   │   │   ├── SubclassPlugDrawer.tsx
│   │   │   ├── actions.ts
│   │   │   ├── armor-upgrade-utils.ts
│   │   │   ├── fashion/
│   │   │   │   ├── FashionDrawer.m.scss
│   │   │   │   ├── FashionDrawer.m.scss.d.ts
│   │   │   │   └── FashionDrawer.tsx
│   │   │   ├── ingame/
│   │   │   │   ├── EditInGameLoadout.m.scss
│   │   │   │   ├── EditInGameLoadout.m.scss.d.ts
│   │   │   │   ├── EditInGameLoadout.tsx
│   │   │   │   ├── EditInGameLoadoutIdentifiers.m.scss
│   │   │   │   ├── EditInGameLoadoutIdentifiers.m.scss.d.ts
│   │   │   │   ├── EditInGameLoadoutIdentifiers.tsx
│   │   │   │   ├── InGameLoadoutDetailsSheet.m.scss
│   │   │   │   ├── InGameLoadoutDetailsSheet.m.scss.d.ts
│   │   │   │   ├── InGameLoadoutDetailsSheet.tsx
│   │   │   │   ├── InGameLoadoutIcon.m.scss
│   │   │   │   ├── InGameLoadoutIcon.m.scss.d.ts
│   │   │   │   ├── InGameLoadoutIcon.tsx
│   │   │   │   ├── InGameLoadoutIdentifiersSelectButton.m.scss
│   │   │   │   ├── InGameLoadoutIdentifiersSelectButton.m.scss.d.ts
│   │   │   │   ├── InGameLoadoutIdentifiersSelectButton.tsx
│   │   │   │   ├── InGameLoadoutStrip.m.scss
│   │   │   │   ├── InGameLoadoutStrip.m.scss.d.ts
│   │   │   │   ├── InGameLoadoutStrip.tsx
│   │   │   │   ├── RadioButton.m.scss
│   │   │   │   ├── RadioButton.m.scss.d.ts
│   │   │   │   ├── RadioButton.tsx
│   │   │   │   ├── SelectInGameLoadoutIdentifiers.m.scss
│   │   │   │   ├── SelectInGameLoadoutIdentifiers.m.scss.d.ts
│   │   │   │   ├── SelectInGameLoadoutIdentifiers.tsx
│   │   │   │   ├── actions.ts
│   │   │   │   ├── ingame-loadout-apply.ts
│   │   │   │   ├── ingame-loadout-utils.ts
│   │   │   │   ├── reducer.ts
│   │   │   │   └── selectors.ts
│   │   │   ├── known-values.ts
│   │   │   ├── loadout-edit/
│   │   │   │   ├── LoadoutEdit.m.scss
│   │   │   │   ├── LoadoutEdit.m.scss.d.ts
│   │   │   │   ├── LoadoutEdit.tsx
│   │   │   │   ├── LoadoutEditBucket.m.scss
│   │   │   │   ├── LoadoutEditBucket.m.scss.d.ts
│   │   │   │   ├── LoadoutEditBucket.tsx
│   │   │   │   ├── LoadoutEditSection.m.scss
│   │   │   │   ├── LoadoutEditSection.m.scss.d.ts
│   │   │   │   ├── LoadoutEditSection.tsx
│   │   │   │   ├── LoadoutEditSubclass.m.scss
│   │   │   │   ├── LoadoutEditSubclass.m.scss.d.ts
│   │   │   │   ├── LoadoutEditSubclass.tsx
│   │   │   │   └── useEquipDropTargets.tsx
│   │   │   ├── loadout-item-utils.ts
│   │   │   ├── loadout-menu/
│   │   │   │   ├── LoadoutPopup.m.scss
│   │   │   │   ├── LoadoutPopup.m.scss.d.ts
│   │   │   │   ├── LoadoutPopup.tsx
│   │   │   │   ├── LoadoutPopupRandomize.m.scss
│   │   │   │   ├── LoadoutPopupRandomize.m.scss.d.ts
│   │   │   │   ├── LoadoutPopupRandomize.tsx
│   │   │   │   ├── MaxlightButton.m.scss
│   │   │   │   ├── MaxlightButton.m.scss.d.ts
│   │   │   │   └── MaxlightButton.tsx
│   │   │   ├── loadout-share/
│   │   │   │   ├── LoadoutImportSheet.m.scss
│   │   │   │   ├── LoadoutImportSheet.m.scss.d.ts
│   │   │   │   ├── LoadoutImportSheet.tsx
│   │   │   │   ├── LoadoutShareSheet.m.scss
│   │   │   │   ├── LoadoutShareSheet.m.scss.d.ts
│   │   │   │   ├── LoadoutShareSheet.tsx
│   │   │   │   ├── loadout-import.test.ts
│   │   │   │   └── loadout-import.ts
│   │   │   ├── loadout-type-converters.ts
│   │   │   ├── loadout-types.ts
│   │   │   ├── loadout-ui/
│   │   │   │   ├── BucketPlaceholder.m.scss
│   │   │   │   ├── BucketPlaceholder.m.scss.d.ts
│   │   │   │   ├── BucketPlaceholder.tsx
│   │   │   │   ├── EmptySubclass.tsx
│   │   │   │   ├── FashionMods.m.scss
│   │   │   │   ├── FashionMods.m.scss.d.ts
│   │   │   │   ├── FashionMods.tsx
│   │   │   │   ├── LoadoutItemCategorySection.m.scss
│   │   │   │   ├── LoadoutItemCategorySection.m.scss.d.ts
│   │   │   │   ├── LoadoutItemCategorySection.tsx
│   │   │   │   ├── LoadoutMods.m.scss
│   │   │   │   ├── LoadoutMods.m.scss.d.ts
│   │   │   │   ├── LoadoutMods.tsx
│   │   │   │   ├── LoadoutParametersDisplay.m.scss
│   │   │   │   ├── LoadoutParametersDisplay.m.scss.d.ts
│   │   │   │   ├── LoadoutParametersDisplay.tsx
│   │   │   │   ├── LoadoutSubclassSection.m.scss
│   │   │   │   ├── LoadoutSubclassSection.m.scss.d.ts
│   │   │   │   ├── LoadoutSubclassSection.tsx
│   │   │   │   ├── OptimizerButton.tsx
│   │   │   │   ├── PlugDef.tsx
│   │   │   │   ├── Sockets.m.scss
│   │   │   │   ├── Sockets.m.scss.d.ts
│   │   │   │   ├── Sockets.tsx
│   │   │   │   ├── menu-hooks.m.scss
│   │   │   │   ├── menu-hooks.m.scss.d.ts
│   │   │   │   └── menu-hooks.tsx
│   │   │   ├── loadouts-selector.ts
│   │   │   ├── mod-assignment-drawer/
│   │   │   │   ├── ModAssignmentDrawer.m.scss
│   │   │   │   ├── ModAssignmentDrawer.m.scss.d.ts
│   │   │   │   ├── ModAssignmentDrawer.tsx
│   │   │   │   └── selectors.ts
│   │   │   ├── mod-assignment-utils.test.ts
│   │   │   ├── mod-assignment-utils.ts
│   │   │   ├── mod-permutations.ts
│   │   │   ├── mod-utils.ts
│   │   │   ├── mutually-exclusive-mods.d.ts
│   │   │   ├── plug-drawer/
│   │   │   │   ├── Footer.m.scss
│   │   │   │   ├── Footer.m.scss.d.ts
│   │   │   │   ├── Footer.tsx
│   │   │   │   ├── PlugDrawer.tsx
│   │   │   │   ├── PlugSection.m.scss
│   │   │   │   ├── PlugSection.m.scss.d.ts
│   │   │   │   ├── PlugSection.tsx
│   │   │   │   ├── PlugStackableIcon.m.scss
│   │   │   │   ├── PlugStackableIcon.m.scss.d.ts
│   │   │   │   ├── PlugStackableIcon.tsx
│   │   │   │   ├── SelectablePlug.m.scss
│   │   │   │   ├── SelectablePlug.m.scss.d.ts
│   │   │   │   ├── SelectablePlug.tsx
│   │   │   │   └── types.ts
│   │   │   ├── reducer.ts
│   │   │   ├── selectors.ts
│   │   │   ├── spreadsheets.ts
│   │   │   └── stats.ts
│   │   ├── loadout-analyzer/
│   │   │   ├── analysis.test.ts
│   │   │   ├── analysis.ts
│   │   │   ├── finding-display.ts
│   │   │   ├── hooks.tsx
│   │   │   ├── store.ts
│   │   │   ├── types.ts
│   │   │   └── utils.ts
│   │   ├── loadout-builder/
│   │   │   ├── LoadoutBucketDropTarget.m.scss
│   │   │   ├── LoadoutBucketDropTarget.m.scss.d.ts
│   │   │   ├── LoadoutBucketDropTarget.tsx
│   │   │   ├── LoadoutBuilder.m.scss
│   │   │   ├── LoadoutBuilder.m.scss.d.ts
│   │   │   ├── LoadoutBuilder.tsx
│   │   │   ├── LoadoutBuilderContainer.tsx
│   │   │   ├── LoadoutBuilderItem.tsx
│   │   │   ├── NoBuildsFoundExplainer.m.scss
│   │   │   ├── NoBuildsFoundExplainer.m.scss.d.ts
│   │   │   ├── NoBuildsFoundExplainer.tsx
│   │   │   ├── README.md
│   │   │   ├── example-search.ts
│   │   │   ├── filter/
│   │   │   │   ├── EnergyOptions.m.scss
│   │   │   │   ├── EnergyOptions.m.scss.d.ts
│   │   │   │   ├── EnergyOptions.tsx
│   │   │   │   ├── ExoticArmorChoice.m.scss
│   │   │   │   ├── ExoticArmorChoice.m.scss.d.ts
│   │   │   │   ├── ExoticArmorChoice.tsx
│   │   │   │   ├── ExoticPicker.m.scss
│   │   │   │   ├── ExoticPicker.m.scss.d.ts
│   │   │   │   ├── ExoticPicker.tsx
│   │   │   │   ├── ExoticTile.m.scss
│   │   │   │   ├── ExoticTile.m.scss.d.ts
│   │   │   │   ├── ExoticTile.tsx
│   │   │   │   ├── LoadoutOptimizerExotic.m.scss
│   │   │   │   ├── LoadoutOptimizerExotic.m.scss.d.ts
│   │   │   │   ├── LoadoutOptimizerExotic.tsx
│   │   │   │   ├── LoadoutOptimizerMenuItems.m.scss
│   │   │   │   ├── LoadoutOptimizerMenuItems.m.scss.d.ts
│   │   │   │   ├── LoadoutOptimizerMenuItems.tsx
│   │   │   │   ├── LoadoutOptimizerSetBonus.m.scss
│   │   │   │   ├── LoadoutOptimizerSetBonus.m.scss.d.ts
│   │   │   │   ├── LoadoutOptimizerSetBonus.tsx
│   │   │   │   ├── LockedItem.tsx
│   │   │   │   ├── NewFeaturedGearFilter.m.scss
│   │   │   │   ├── NewFeaturedGearFilter.m.scss.d.ts
│   │   │   │   ├── NewFeaturedGearFilter.tsx
│   │   │   │   ├── TierlessStatConstraintEditor.m.scss
│   │   │   │   ├── TierlessStatConstraintEditor.m.scss.d.ts
│   │   │   │   └── TierlessStatConstraintEditor.tsx
│   │   │   ├── generated-sets/
│   │   │   │   ├── CompareLoadoutsDrawer.m.scss
│   │   │   │   ├── CompareLoadoutsDrawer.m.scss.d.ts
│   │   │   │   ├── CompareLoadoutsDrawer.tsx
│   │   │   │   ├── GeneratedSet.m.scss
│   │   │   │   ├── GeneratedSet.m.scss.d.ts
│   │   │   │   ├── GeneratedSet.tsx
│   │   │   │   ├── GeneratedSetButtons.m.scss
│   │   │   │   ├── GeneratedSetButtons.m.scss.d.ts
│   │   │   │   ├── GeneratedSetButtons.tsx
│   │   │   │   ├── GeneratedSetItem.m.scss
│   │   │   │   ├── GeneratedSetItem.m.scss.d.ts
│   │   │   │   ├── GeneratedSetItem.tsx
│   │   │   │   ├── GeneratedSets.tsx
│   │   │   │   ├── SetStats.m.scss
│   │   │   │   ├── SetStats.m.scss.d.ts
│   │   │   │   ├── SetStats.tsx
│   │   │   │   └── utils.ts
│   │   │   ├── item-filter.test.ts
│   │   │   ├── item-filter.ts
│   │   │   ├── loadout-builder-reducer.ts
│   │   │   ├── loadout-builder-vendors.ts
│   │   │   ├── loadout-params.test.ts
│   │   │   ├── loadout-params.ts
│   │   │   ├── process/
│   │   │   │   ├── mappers.test.ts
│   │   │   │   ├── mappers.ts
│   │   │   │   ├── process-wrapper.ts
│   │   │   │   └── useProcess.ts
│   │   │   ├── process-worker/
│   │   │   │   ├── ProcessWorker.ts
│   │   │   │   ├── __snapshots__/
│   │   │   │   │   ├── auto-stat-mod-utils.test.ts.snap
│   │   │   │   │   └── process-utils.test.ts.snap
│   │   │   │   ├── auto-stat-mod-utils.test.ts
│   │   │   │   ├── auto-stat-mod-utils.ts
│   │   │   │   ├── process-utils.test.ts
│   │   │   │   ├── process-utils.ts
│   │   │   │   ├── process.ts
│   │   │   │   ├── set-tracker.test.ts
│   │   │   │   ├── set-tracker.ts
│   │   │   │   ├── tsconfig.json
│   │   │   │   └── types.ts
│   │   │   ├── types.ts
│   │   │   ├── updated-loadout.ts
│   │   │   ├── useEquippedHashes.ts
│   │   │   └── utils.ts
│   │   ├── loadout-drawer/
│   │   │   ├── LoadoutDrawer.m.scss
│   │   │   ├── LoadoutDrawer.m.scss.d.ts
│   │   │   ├── LoadoutDrawer.tsx
│   │   │   ├── LoadoutDrawerContainer.tsx
│   │   │   ├── LoadoutDrawerDropTarget.m.scss
│   │   │   ├── LoadoutDrawerDropTarget.m.scss.d.ts
│   │   │   ├── LoadoutDrawerDropTarget.tsx
│   │   │   ├── LoadoutDrawerFooter.m.scss
│   │   │   ├── LoadoutDrawerFooter.m.scss.d.ts
│   │   │   ├── LoadoutDrawerFooter.tsx
│   │   │   ├── LoadoutDrawerHeader.m.scss
│   │   │   ├── LoadoutDrawerHeader.m.scss.d.ts
│   │   │   ├── LoadoutDrawerHeader.tsx
│   │   │   ├── auto-loadouts.ts
│   │   │   ├── loadout-apply-state.ts
│   │   │   ├── loadout-apply.ts
│   │   │   ├── loadout-drawer-reducer.test.ts
│   │   │   ├── loadout-drawer-reducer.ts
│   │   │   ├── loadout-events.ts
│   │   │   ├── loadout-item-conversion.ts
│   │   │   ├── loadout-utils.ts
│   │   │   └── postmaster.ts
│   │   ├── login/
│   │   │   ├── Login.m.scss
│   │   │   ├── Login.m.scss.d.ts
│   │   │   └── Login.tsx
│   │   ├── main.scss
│   │   ├── manifest/
│   │   │   ├── actions.ts
│   │   │   ├── d1-manifest-service.ts
│   │   │   ├── manifest-service-json.ts
│   │   │   ├── reducer.ts
│   │   │   └── selectors.ts
│   │   ├── material-counts/
│   │   │   ├── MaterialCounts.m.scss
│   │   │   ├── MaterialCounts.m.scss.d.ts
│   │   │   ├── MaterialCounts.tsx
│   │   │   ├── MaterialCountsWrappers.m.scss
│   │   │   ├── MaterialCountsWrappers.m.scss.d.ts
│   │   │   └── MaterialCountsWrappers.tsx
│   │   ├── notifications/
│   │   │   ├── Notification.m.scss
│   │   │   ├── Notification.m.scss.d.ts
│   │   │   ├── Notification.tsx
│   │   │   ├── NotificationButton.m.scss
│   │   │   ├── NotificationButton.m.scss.d.ts
│   │   │   ├── NotificationButton.tsx
│   │   │   ├── NotificationsContainer.m.scss
│   │   │   ├── NotificationsContainer.m.scss.d.ts
│   │   │   ├── NotificationsContainer.tsx
│   │   │   └── notifications.ts
│   │   ├── organizer/
│   │   │   ├── Columns.m.scss
│   │   │   ├── Columns.m.scss.d.ts
│   │   │   ├── Columns.tsx
│   │   │   ├── CustomStatColumns.tsx
│   │   │   ├── DropDown.m.scss
│   │   │   ├── DropDown.m.scss.d.ts
│   │   │   ├── DropDown.tsx
│   │   │   ├── EnabledColumnsSelector.tsx
│   │   │   ├── ItemActions.m.scss
│   │   │   ├── ItemActions.m.scss.d.ts
│   │   │   ├── ItemActions.tsx
│   │   │   ├── ItemTable.m.scss
│   │   │   ├── ItemTable.m.scss.d.ts
│   │   │   ├── ItemTable.tsx
│   │   │   ├── ItemTypeSelector.m.scss
│   │   │   ├── ItemTypeSelector.m.scss.d.ts
│   │   │   ├── ItemTypeSelector.tsx
│   │   │   ├── Organizer.m.scss
│   │   │   ├── Organizer.m.scss.d.ts
│   │   │   ├── Organizer.tsx
│   │   │   └── table-types.ts
│   │   ├── progress/
│   │   │   ├── ActivityModifier.m.scss
│   │   │   ├── ActivityModifier.m.scss.d.ts
│   │   │   ├── ActivityModifier.tsx
│   │   │   ├── BountyGuide.m.scss
│   │   │   ├── BountyGuide.m.scss.d.ts
│   │   │   ├── BountyGuide.tsx
│   │   │   ├── Event.m.scss
│   │   │   ├── Event.m.scss.d.ts
│   │   │   ├── Event.tsx
│   │   │   ├── FactionIcon.m.scss
│   │   │   ├── FactionIcon.m.scss.d.ts
│   │   │   ├── FactionIcon.tsx
│   │   │   ├── Milestones.m.scss
│   │   │   ├── Milestones.m.scss.d.ts
│   │   │   ├── Milestones.tsx
│   │   │   ├── Objective.m.scss
│   │   │   ├── Objective.m.scss.d.ts
│   │   │   ├── Objective.tsx
│   │   │   ├── Pathfinder.m.scss
│   │   │   ├── Pathfinder.m.scss.d.ts
│   │   │   ├── Pathfinder.tsx
│   │   │   ├── Progress.m.scss
│   │   │   ├── Progress.m.scss.d.ts
│   │   │   ├── Progress.tsx
│   │   │   ├── Pursuit.tsx
│   │   │   ├── PursuitGrid.m.scss
│   │   │   ├── PursuitGrid.m.scss.d.ts
│   │   │   ├── PursuitGrid.tsx
│   │   │   ├── PursuitItem.m.scss
│   │   │   ├── PursuitItem.m.scss.d.ts
│   │   │   ├── PursuitItem.tsx
│   │   │   ├── Pursuits.tsx
│   │   │   ├── Raid.tsx
│   │   │   ├── RaidDisplay.m.scss
│   │   │   ├── RaidDisplay.m.scss.d.ts
│   │   │   ├── RaidDisplay.tsx
│   │   │   ├── Raids.tsx
│   │   │   ├── Ranks.tsx
│   │   │   ├── ReputationRank.m.scss
│   │   │   ├── ReputationRank.m.scss.d.ts
│   │   │   ├── ReputationRank.tsx
│   │   │   ├── Reward.m.scss
│   │   │   ├── Reward.m.scss.d.ts
│   │   │   ├── Reward.tsx
│   │   │   ├── SeasonalChallenges.tsx
│   │   │   ├── SeasonalRank.m.scss
│   │   │   ├── SeasonalRank.m.scss.d.ts
│   │   │   ├── SeasonalRank.tsx
│   │   │   ├── TrackedTriumphs.m.scss
│   │   │   ├── TrackedTriumphs.m.scss.d.ts
│   │   │   ├── TrackedTriumphs.tsx
│   │   │   ├── WellRestedPerkIcon.tsx
│   │   │   ├── engrams.ts
│   │   │   ├── milestone-items.ts
│   │   │   ├── milestone.scss
│   │   │   ├── selectors.ts
│   │   │   └── xp.ts
│   │   ├── records/
│   │   │   ├── Collectible.tsx
│   │   │   ├── CollectiblesGrid.m.scss
│   │   │   ├── CollectiblesGrid.m.scss.d.ts
│   │   │   ├── CollectiblesGrid.tsx
│   │   │   ├── Craftable.tsx
│   │   │   ├── Metric.m.scss
│   │   │   ├── Metric.m.scss.d.ts
│   │   │   ├── Metric.tsx
│   │   │   ├── MetricBanner.m.scss
│   │   │   ├── MetricBanner.m.scss.d.ts
│   │   │   ├── MetricBanner.tsx
│   │   │   ├── Metrics.m.scss
│   │   │   ├── Metrics.m.scss.d.ts
│   │   │   ├── Metrics.tsx
│   │   │   ├── PresentationNode.m.scss
│   │   │   ├── PresentationNode.m.scss.d.ts
│   │   │   ├── PresentationNode.tsx
│   │   │   ├── PresentationNodeLeaf.tsx
│   │   │   ├── PresentationNodeRoot.m.scss
│   │   │   ├── PresentationNodeRoot.m.scss.d.ts
│   │   │   ├── PresentationNodeRoot.tsx
│   │   │   ├── PresentationNodeSearchResults.m.scss
│   │   │   ├── PresentationNodeSearchResults.m.scss.d.ts
│   │   │   ├── PresentationNodeSearchResults.tsx
│   │   │   ├── Record.m.scss
│   │   │   ├── Record.m.scss.d.ts
│   │   │   ├── Record.tsx
│   │   │   ├── Records.m.scss
│   │   │   ├── Records.m.scss.d.ts
│   │   │   ├── Records.tsx
│   │   │   ├── SetCard.m.scss
│   │   │   ├── SetCard.m.scss.d.ts
│   │   │   ├── SetCard.tsx
│   │   │   ├── _set-card.scss
│   │   │   ├── catalysts.ts
│   │   │   ├── collectible-matching.ts
│   │   │   ├── extra-collectibles.d.ts
│   │   │   ├── plugset-helpers.ts
│   │   │   ├── presentation-nodes.ts
│   │   │   ├── selectors.ts
│   │   │   └── universal-ornaments/
│   │   │       ├── UniversalOrnaments.m.scss
│   │   │       ├── UniversalOrnaments.m.scss.d.ts
│   │   │       ├── UniversalOrnaments.tsx
│   │   │       └── universal-ornaments.ts
│   │   ├── register-service-worker.test.ts
│   │   ├── register-service-worker.ts
│   │   ├── routes.ts
│   │   ├── safari-touch-fix.ts
│   │   ├── search/
│   │   │   ├── FilterHelp.m.scss
│   │   │   ├── FilterHelp.m.scss.d.ts
│   │   │   ├── FilterHelp.tsx
│   │   │   ├── HighlightedText.tsx
│   │   │   ├── MainSearchBarActions.m.scss
│   │   │   ├── MainSearchBarActions.m.scss.d.ts
│   │   │   ├── MainSearchBarActions.tsx
│   │   │   ├── MainSearchBarMenu.tsx
│   │   │   ├── SearchBar.m.scss
│   │   │   ├── SearchBar.m.scss.d.ts
│   │   │   ├── SearchBar.tsx
│   │   │   ├── SearchFilter.tsx
│   │   │   ├── SearchHistory.m.scss
│   │   │   ├── SearchHistory.m.scss.d.ts
│   │   │   ├── SearchHistory.tsx
│   │   │   ├── SearchInput.tsx
│   │   │   ├── SearchResults.m.scss
│   │   │   ├── SearchResults.m.scss.d.ts
│   │   │   ├── SearchResults.tsx
│   │   │   ├── __snapshots__/
│   │   │   │   ├── autocomplete.test.ts.snap
│   │   │   │   ├── query-parser.test.ts.snap
│   │   │   │   ├── search-config.test.ts.snap
│   │   │   │   └── search-filter.test.ts.snap
│   │   │   ├── armory-search.ts
│   │   │   ├── autocomplete.test.ts
│   │   │   ├── autocomplete.ts
│   │   │   ├── d1-known-values.ts
│   │   │   ├── d2-known-values.ts
│   │   │   ├── filter-description.tsx
│   │   │   ├── filter-types.ts
│   │   │   ├── items/
│   │   │   │   ├── item-filter-types.ts
│   │   │   │   ├── item-search-filter.ts
│   │   │   │   └── search-filters/
│   │   │   │       ├── advanced.ts
│   │   │   │       ├── d1-filters.ts
│   │   │   │       ├── d2-sources.ts
│   │   │   │       ├── data/
│   │   │   │       │   └── d2/
│   │   │   │       │       └── artifact-breaker-weapon-types.d.ts
│   │   │   │       ├── dupes-deprecated.ts
│   │   │   │       ├── dupes.ts
│   │   │   │       ├── freeform.ts
│   │   │   │       ├── item-infos.ts
│   │   │   │       ├── known-values.ts
│   │   │   │       ├── loadouts.ts
│   │   │   │       ├── perks-set.ts
│   │   │   │       ├── range-numeric.ts
│   │   │   │       ├── range-overload.ts
│   │   │   │       ├── simple.ts
│   │   │   │       ├── sockets.ts
│   │   │   │       ├── stats.ts
│   │   │   │       ├── stores.ts
│   │   │   │       └── wishlist.ts
│   │   │   ├── loadouts/
│   │   │   │   ├── __snapshots__/
│   │   │   │   │   └── loadout-search-filter.test.ts.snap
│   │   │   │   ├── loadout-filter-types.ts
│   │   │   │   ├── loadout-search-filter.test.ts
│   │   │   │   ├── loadout-search-filter.ts
│   │   │   │   └── search-filters/
│   │   │   │       ├── freeform.ts
│   │   │   │       ├── range-overload.ts
│   │   │   │       └── simple.ts
│   │   │   ├── plug-search.ts
│   │   │   ├── power-levels.ts
│   │   │   ├── query-parser.test.ts
│   │   │   ├── query-parser.ts
│   │   │   ├── search-config.test.ts
│   │   │   ├── search-config.ts
│   │   │   ├── search-filter-values.test.ts
│   │   │   ├── search-filter-values.ts
│   │   │   ├── search-filter.scss
│   │   │   ├── search-filter.test.ts
│   │   │   ├── search-filter.ts
│   │   │   ├── specialty-modslots.ts
│   │   │   ├── suggestions-generation.ts
│   │   │   └── text-utils.ts
│   │   ├── settings/
│   │   │   ├── CharacterOrderEditor.m.scss
│   │   │   ├── CharacterOrderEditor.m.scss.d.ts
│   │   │   ├── CharacterOrderEditor.tsx
│   │   │   ├── Checkbox.tsx
│   │   │   ├── CustomStatsSettings.m.scss
│   │   │   ├── CustomStatsSettings.m.scss.d.ts
│   │   │   ├── CustomStatsSettings.tsx
│   │   │   ├── LanguageSetting.tsx
│   │   │   ├── Select.m.scss
│   │   │   ├── Select.m.scss.d.ts
│   │   │   ├── Select.tsx
│   │   │   ├── SettingsPage.m.scss
│   │   │   ├── SettingsPage.m.scss.d.ts
│   │   │   ├── SettingsPage.tsx
│   │   │   ├── SortOrderEditor.m.scss
│   │   │   ├── SortOrderEditor.m.scss.d.ts
│   │   │   ├── SortOrderEditor.tsx
│   │   │   ├── Spreadsheets.m.scss
│   │   │   ├── Spreadsheets.m.scss.d.ts
│   │   │   ├── Spreadsheets.tsx
│   │   │   ├── Troubleshooting.tsx
│   │   │   ├── WishListSettings.m.scss
│   │   │   ├── WishListSettings.m.scss.d.ts
│   │   │   ├── WishListSettings.tsx
│   │   │   ├── actions.ts
│   │   │   ├── character-sort.ts
│   │   │   ├── hooks.ts
│   │   │   ├── initial-settings.ts
│   │   │   ├── item-sort.ts
│   │   │   ├── settings.ts
│   │   │   ├── vault-grouping.test.ts
│   │   │   └── vault-grouping.ts
│   │   ├── shell/
│   │   │   ├── About.m.scss
│   │   │   ├── About.m.scss.d.ts
│   │   │   ├── About.tsx
│   │   │   ├── AppInstallBanner.m.scss
│   │   │   ├── AppInstallBanner.m.scss.d.ts
│   │   │   ├── AppInstallBanner.tsx
│   │   │   ├── DefaultAccount.tsx
│   │   │   ├── Destiny.m.scss
│   │   │   ├── Destiny.m.scss.d.ts
│   │   │   ├── Destiny.tsx
│   │   │   ├── ErrorPanel.m.scss
│   │   │   ├── ErrorPanel.m.scss.d.ts
│   │   │   ├── ErrorPanel.tsx
│   │   │   ├── GATracker.tsx
│   │   │   ├── Header.m.scss
│   │   │   ├── Header.m.scss.d.ts
│   │   │   ├── Header.tsx
│   │   │   ├── HeaderWarningBanner.m.scss
│   │   │   ├── HeaderWarningBanner.m.scss.d.ts
│   │   │   ├── HeaderWarningBanner.tsx
│   │   │   ├── LocationSwitcher.tsx
│   │   │   ├── MenuBadge.m.scss
│   │   │   ├── MenuBadge.m.scss.d.ts
│   │   │   ├── MenuBadge.tsx
│   │   │   ├── PostmasterWarningBanner.tsx
│   │   │   ├── Privacy.m.scss
│   │   │   ├── Privacy.m.scss.d.ts
│   │   │   ├── Privacy.tsx
│   │   │   ├── RefreshButton.m.scss
│   │   │   ├── RefreshButton.m.scss.d.ts
│   │   │   ├── RefreshButton.tsx
│   │   │   ├── ScrollToTop.tsx
│   │   │   ├── SneakyUpdates.tsx
│   │   │   ├── actions.ts
│   │   │   ├── alerts.ts
│   │   │   ├── app-install.ts
│   │   │   ├── formatters.ts
│   │   │   ├── icons/
│   │   │   │   ├── AppIcon.scss
│   │   │   │   ├── AppIcon.tsx
│   │   │   │   ├── Library.js
│   │   │   │   ├── custom/
│   │   │   │   │   ├── Artifice.ts
│   │   │   │   │   ├── Engram.ts
│   │   │   │   │   ├── Enhanced.ts
│   │   │   │   │   ├── Epic.ts
│   │   │   │   │   ├── FeaturedBanner.ts
│   │   │   │   │   ├── Hunter.ts
│   │   │   │   │   ├── HunterProportional.ts
│   │   │   │   │   ├── MasterworkHammer.ts
│   │   │   │   │   ├── Power.ts
│   │   │   │   │   ├── PowerAlt.ts
│   │   │   │   │   ├── Shaped.ts
│   │   │   │   │   ├── StatBarsIcon.ts
│   │   │   │   │   ├── Titan.ts
│   │   │   │   │   ├── TitanProportional.ts
│   │   │   │   │   ├── TunedStatIcon.ts
│   │   │   │   │   ├── Warlock.ts
│   │   │   │   │   ├── WarlockProportional.ts
│   │   │   │   │   └── utils.ts
│   │   │   │   ├── font-awesome-icon-variables.scss
│   │   │   │   ├── font-awesome.scss
│   │   │   │   └── index.ts
│   │   │   ├── item-comparators.ts
│   │   │   ├── links.ts
│   │   │   ├── loading-tracker.ts
│   │   │   ├── reducer.ts
│   │   │   ├── refresh-events.ts
│   │   │   └── selectors.ts
│   │   ├── storage/
│   │   │   ├── DimApiSettings.m.scss
│   │   │   ├── DimApiSettings.m.scss.d.ts
│   │   │   ├── DimApiSettings.tsx
│   │   │   ├── DimApiWarningBanner.tsx
│   │   │   ├── ImportExport.tsx
│   │   │   ├── LocalStorageInfo.m.scss
│   │   │   ├── LocalStorageInfo.m.scss.d.ts
│   │   │   ├── LocalStorageInfo.tsx
│   │   │   ├── export-data.ts
│   │   │   ├── human-bytes.ts
│   │   │   └── idb-keyval.ts
│   │   ├── store/
│   │   │   ├── observerMiddleware.ts
│   │   │   ├── reducers.ts
│   │   │   ├── store.ts
│   │   │   ├── thunk-dispatch.ts
│   │   │   └── types.ts
│   │   ├── store-stats/
│   │   │   ├── AccountCurrencies.m.scss
│   │   │   ├── AccountCurrencies.m.scss.d.ts
│   │   │   ├── AccountCurrencies.tsx
│   │   │   ├── CharacterStats.m.scss
│   │   │   ├── CharacterStats.m.scss.d.ts
│   │   │   ├── CharacterStats.tsx
│   │   │   ├── ClarityCharacterStat.m.scss
│   │   │   ├── ClarityCharacterStat.m.scss.d.ts
│   │   │   ├── ClarityCharacterStat.tsx
│   │   │   ├── D1CharacterStats.m.scss
│   │   │   ├── D1CharacterStats.m.scss.d.ts
│   │   │   ├── D1CharacterStats.tsx
│   │   │   ├── StatTooltip.m.scss
│   │   │   ├── StatTooltip.m.scss.d.ts
│   │   │   ├── StatTooltip.tsx
│   │   │   ├── StoreStats.m.scss
│   │   │   ├── StoreStats.m.scss.d.ts
│   │   │   ├── StoreStats.tsx
│   │   │   ├── VaultCapacity.m.scss
│   │   │   ├── VaultCapacity.m.scss.d.ts
│   │   │   └── VaultCapacity.tsx
│   │   ├── stream-deck/
│   │   │   ├── OpenOnStreamDeckButton/
│   │   │   │   ├── OpenOnStreamDeckButton.m.scss
│   │   │   │   ├── OpenOnStreamDeckButton.m.scss.d.ts
│   │   │   │   └── OpenOnStreamDeckButton.tsx
│   │   │   ├── StreamDeckButton/
│   │   │   │   ├── StreamDeckButton.m.scss
│   │   │   │   ├── StreamDeckButton.m.scss.d.ts
│   │   │   │   └── StreamDeckButton.tsx
│   │   │   ├── StreamDeckSettings/
│   │   │   │   ├── StreamDeckSettings.m.scss
│   │   │   │   ├── StreamDeckSettings.m.scss.d.ts
│   │   │   │   └── StreamDeckSettings.tsx
│   │   │   ├── actions.ts
│   │   │   ├── async-module.ts
│   │   │   ├── interfaces.ts
│   │   │   ├── msg-handlers.ts
│   │   │   ├── reducer.ts
│   │   │   ├── selectors.ts
│   │   │   ├── stream-deck.ts
│   │   │   ├── useStreamDeckSelection.ts
│   │   │   └── util/
│   │   │       ├── authorization.ts
│   │   │       ├── packager.ts
│   │   │       └── version.ts
│   │   ├── strip-sockets/
│   │   │   ├── StripSockets.m.scss
│   │   │   ├── StripSockets.m.scss.d.ts
│   │   │   ├── StripSockets.tsx
│   │   │   ├── strip-sockets-actions.ts
│   │   │   └── strip-sockets.ts
│   │   ├── themes/
│   │   │   ├── _theme-classic.scss
│   │   │   ├── _theme-dimdark.scss
│   │   │   ├── _theme-europa.scss
│   │   │   ├── _theme-neomuna.scss
│   │   │   ├── _theme-pyramid.scss
│   │   │   ├── _theme-throneworld.scss
│   │   │   ├── _theme-vexnet.scss
│   │   │   └── _theme.scss
│   │   ├── utils/
│   │   │   ├── __snapshots__/
│   │   │   │   └── csv.test.ts.snap
│   │   │   ├── action-queue.ts
│   │   │   ├── app-badge.ts
│   │   │   ├── browsers.ts
│   │   │   ├── cancel.ts
│   │   │   ├── collections.test.ts
│   │   │   ├── collections.ts
│   │   │   ├── comparators.ts
│   │   │   ├── csv.test.ts
│   │   │   ├── csv.ts
│   │   │   ├── dim-error.ts
│   │   │   ├── download.ts
│   │   │   ├── empty.ts
│   │   │   ├── errors.ts
│   │   │   ├── functions.ts
│   │   │   ├── hooks.ts
│   │   │   ├── intl.test.ts
│   │   │   ├── intl.ts
│   │   │   ├── item-utils.ts
│   │   │   ├── log.ts
│   │   │   ├── measure-memory.ts
│   │   │   ├── media-queries.ts
│   │   │   ├── memoize.test.ts
│   │   │   ├── memoize.ts
│   │   │   ├── observable.ts
│   │   │   ├── parallel-cores.ts
│   │   │   ├── perk-utils.ts
│   │   │   ├── plug-descriptions.ts
│   │   │   ├── promises.test.ts
│   │   │   ├── promises.ts
│   │   │   ├── react.ts
│   │   │   ├── seasons.ts
│   │   │   ├── selectors.ts
│   │   │   ├── sentry.ts
│   │   │   ├── socket-utils.ts
│   │   │   ├── stats-set.test.ts
│   │   │   ├── stats-set.ts
│   │   │   ├── stats.ts
│   │   │   ├── system-info.ts
│   │   │   ├── temp-container.scss
│   │   │   ├── temp-container.ts
│   │   │   ├── textarea-caret.ts
│   │   │   ├── time.test.ts
│   │   │   ├── time.ts
│   │   │   ├── undo-redo-history.test.ts
│   │   │   ├── undo-redo-history.ts
│   │   │   ├── useWhatChanged.ts
│   │   │   └── util-types.ts
│   │   ├── vendors/
│   │   │   ├── Cost.m.scss
│   │   │   ├── Cost.m.scss.d.ts
│   │   │   ├── Cost.tsx
│   │   │   ├── Vendor.m.scss
│   │   │   ├── Vendor.m.scss.d.ts
│   │   │   ├── Vendor.tsx
│   │   │   ├── VendorItem.m.scss
│   │   │   ├── VendorItem.m.scss.d.ts
│   │   │   ├── VendorItemComponent.tsx
│   │   │   ├── VendorItems.m.scss
│   │   │   ├── VendorItems.m.scss.d.ts
│   │   │   ├── VendorItems.tsx
│   │   │   ├── Vendors.m.scss
│   │   │   ├── Vendors.m.scss.d.ts
│   │   │   ├── Vendors.tsx
│   │   │   ├── VendorsMenu.m.scss
│   │   │   ├── VendorsMenu.m.scss.d.ts
│   │   │   ├── VendorsMenu.tsx
│   │   │   ├── actions.ts
│   │   │   ├── d2-vendors.test.ts
│   │   │   ├── d2-vendors.ts
│   │   │   ├── focusing-item-outputs.d.ts
│   │   │   ├── hooks.ts
│   │   │   ├── reducer.ts
│   │   │   ├── selectors.ts
│   │   │   ├── single-vendor/
│   │   │   │   ├── ArtifactUnlocks.m.scss
│   │   │   │   ├── ArtifactUnlocks.m.scss.d.ts
│   │   │   │   ├── ArtifactUnlocks.tsx
│   │   │   │   ├── SingleVendor.m.scss
│   │   │   │   ├── SingleVendor.m.scss.d.ts
│   │   │   │   ├── SingleVendor.tsx
│   │   │   │   ├── SingleVendorPage.m.scss
│   │   │   │   ├── SingleVendorPage.m.scss.d.ts
│   │   │   │   ├── SingleVendorPage.tsx
│   │   │   │   ├── SingleVendorSheet.m.scss
│   │   │   │   ├── SingleVendorSheet.m.scss.d.ts
│   │   │   │   ├── SingleVendorSheet.tsx
│   │   │   │   ├── SingleVendorSheetContainer.tsx
│   │   │   │   └── single-vendor-sheet.ts
│   │   │   ├── specialVendorStrings.d.ts
│   │   │   └── vendor-item.ts
│   │   ├── whats-new/
│   │   │   ├── BungieAlerts.m.scss
│   │   │   ├── BungieAlerts.m.scss.d.ts
│   │   │   ├── BungieAlerts.tsx
│   │   │   ├── ChangeLog.scss
│   │   │   ├── ChangeLog.tsx
│   │   │   ├── WhatsNew.tsx
│   │   │   ├── WhatsNewLink.m.scss
│   │   │   ├── WhatsNewLink.m.scss.d.ts
│   │   │   ├── WhatsNewLink.tsx
│   │   │   └── versions.ts
│   │   └── wishlists/
│   │       ├── WishListPerkThumb.m.scss
│   │       ├── WishListPerkThumb.m.scss.d.ts
│   │       ├── WishListPerkThumb.tsx
│   │       ├── actions.ts
│   │       ├── observers.ts
│   │       ├── reducer.ts
│   │       ├── selectors.ts
│   │       ├── types.ts
│   │       ├── utils.ts
│   │       ├── wishlist-fetch.ts
│   │       ├── wishlist-file.test.ts
│   │       ├── wishlist-file.ts
│   │       └── wishlists.ts
│   ├── authReturn.ts
│   ├── backup.html
│   ├── backup.ts
│   ├── browsercheck-utils.js
│   ├── browsercheck.js
│   ├── browsercheck.test.ts
│   ├── browserconfig.xml
│   ├── build-browsercheck-utils.js
│   ├── bungie-api-ts.d.ts
│   ├── data/
│   │   ├── d1/
│   │   │   ├── manifests/
│   │   │   │   ├── d1-manifest-de.json
│   │   │   │   ├── d1-manifest-de.json.br
│   │   │   │   ├── d1-manifest-en.json
│   │   │   │   ├── d1-manifest-en.json.br
│   │   │   │   ├── d1-manifest-es.json
│   │   │   │   ├── d1-manifest-es.json.br
│   │   │   │   ├── d1-manifest-fr.json
│   │   │   │   ├── d1-manifest-fr.json.br
│   │   │   │   ├── d1-manifest-it.json
│   │   │   │   ├── d1-manifest-it.json.br
│   │   │   │   ├── d1-manifest-ja.json
│   │   │   │   ├── d1-manifest-ja.json.br
│   │   │   │   ├── d1-manifest-pt-br.json
│   │   │   │   └── d1-manifest-pt-br.json.br
│   │   │   └── missing_sources.json
│   │   ├── d2/
│   │   │   ├── README.md
│   │   │   ├── artifact-breaker-weapon-types.json
│   │   │   ├── bad-vendors.json
│   │   │   ├── bright-engram-bonus.json
│   │   │   ├── bright-engrams.json
│   │   │   ├── catalyst-triumph-icons.json
│   │   │   ├── craftable-hashes.json
│   │   │   ├── crafting-enhanced-intrinsics.ts
│   │   │   ├── crafting-mementos.json
│   │   │   ├── d2-event-info-v2.ts
│   │   │   ├── d2-event-info.ts
│   │   │   ├── d2-season-info.ts
│   │   │   ├── d2-trials-objectives.json
│   │   │   ├── deprecated-mods.json
│   │   │   ├── dummy-catalyst-mapping.json
│   │   │   ├── empty-plug-hashes.ts
│   │   │   ├── energy-mods-change.json
│   │   │   ├── energy-mods.json
│   │   │   ├── engram-rarity-icons.json
│   │   │   ├── events.json
│   │   │   ├── exotic-synergy.json
│   │   │   ├── exotic-to-catalyst-record.json
│   │   │   ├── exotics-with-catalysts.ts
│   │   │   ├── extended-breaker.json
│   │   │   ├── extended-foundry.json
│   │   │   ├── extended-ich.json
│   │   │   ├── focusing-item-outputs.json
│   │   │   ├── generated-enums.ts
│   │   │   ├── ghost-perks.json
│   │   │   ├── item-def-workaround-replacements.json
│   │   │   ├── legacy-triumphs.json
│   │   │   ├── lightcap-to-season.json
│   │   │   ├── masterworks-with-cond-stats.json
│   │   │   ├── missing-faction-tokens.json
│   │   │   ├── missing-source-info.ts
│   │   │   ├── mods-with-bad-descriptions.json
│   │   │   ├── mutually-exclusive-mods.json
│   │   │   ├── objective-richTexts.ts
│   │   │   ├── objective-triumph.json
│   │   │   ├── powerful-rewards.json
│   │   │   ├── pursuits.json
│   │   │   ├── raid-mod-plug-category-hashes.json
│   │   │   ├── reduced-cost-mod-mappings.ts
│   │   │   ├── season-tags.json
│   │   │   ├── season-to-source.json
│   │   │   ├── seasonal-armor-mods.json
│   │   │   ├── seasonal-challenges.json
│   │   │   ├── seasons.json
│   │   │   ├── seasons_backup.json
│   │   │   ├── source-info-v2.ts
│   │   │   ├── source-info.ts
│   │   │   ├── source-to-season-v2.json
│   │   │   ├── sources.json
│   │   │   ├── special-vendors-strings.json
│   │   │   ├── spider-mats.json
│   │   │   ├── spider-purchaseables-to-mats.json
│   │   │   ├── subclass-plug-category-hashes.json
│   │   │   ├── trait-definition-ids.json
│   │   │   ├── trait-to-enhanced-trait.json
│   │   │   ├── universal-ornament-aux-sets.json
│   │   │   ├── universal-ornament-plugset-hashes.json
│   │   │   ├── unreferenced-collections-items.json
│   │   │   ├── unstackable-mods.json
│   │   │   ├── voice-dim-valid-perks.json
│   │   │   ├── watermark-to-event.json
│   │   │   ├── watermark-to-season.json
│   │   │   └── weapon-from-quest.json
│   │   └── font/
│   │       ├── d2-font-glyphs.ts
│   │       ├── dim-custom-symbols.ts
│   │       └── symbol-name-sources.ts
│   ├── earlyErrorReport.js
│   ├── fa-subset.js
│   ├── global.d.ts
│   ├── htaccess
│   ├── images/
│   │   └── holofoil-anim.apng
│   ├── index.html
│   ├── locale/
│   │   ├── de.json
│   │   ├── en.json
│   │   ├── es.json
│   │   ├── esMX.json
│   │   ├── fr.json
│   │   ├── it.json
│   │   ├── ja.json
│   │   ├── ko.json
│   │   ├── locales.test.ts
│   │   ├── pl.json
│   │   ├── ptBR.json
│   │   ├── ru.json
│   │   ├── zhCHS.json
│   │   └── zhCHT.json
│   ├── nuke.php
│   ├── return.html
│   ├── robots.txt
│   ├── service-worker.ts
│   └── testing/
│       ├── data/
│       │   ├── d1profiles-2022-10-24.json
│       │   ├── linkedaccounts-2025-07-15.json
│       │   ├── profile-2025-12-02.json
│       │   └── vendors-2025-12-02.json
│       ├── global.d.ts
│       ├── jest-setup.cjs
│       ├── precache-manifest.test.ts
│       ├── test-item-utils.ts
│       ├── test-utils.ts
│       └── utils/
│           └── i18next.ts
└── tsconfig.json

================================================
FILE CONTENTS
================================================

================================================
FILE: .dockerignore
================================================
# Dependency directories
node_modules

# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*

# Documentation
docs/

# Misc.
.vscode/
build/


================================================
FILE: .editorconfig
================================================
# http://editorconfig.org
root = true

[*]
end_of_line = lf
insert_final_newline = true
trim_trailing_whitespace = true
charset = utf-8
indent_style = space
indent_size = 2

[*.md]
trim_trailing_whitespace = false



================================================
FILE: .git-blame-ignore-revs
================================================
# Added trailing commas everywhere
4ecced03d68e8ef1c4addd24ad32d1cde3d393e9


================================================
FILE: .gitattributes
================================================
# Default core.autocrlf on
* text=auto

CHANGELOG.md merge=union

*.png binary
*.jpg binary

# Generated files can always be collapsed in diffs
*.m.scss.d.ts linguist-generated

================================================
FILE: .github/FUNDING.yml
================================================
# These are supported funding model platforms

github: [DestinyItemManager] # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2]
patreon: # Replace with a single Patreon username
open_collective: dim # Replace with a single Open Collective username
ko_fi: # Replace with a single Ko-fi username
tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
custom: # Replace with a single custom sponsorship URL


================================================
FILE: .github/ISSUE_TEMPLATE/bug_report.yml
================================================
name: Bug
description: File a bug or report an issue
labels: [Bug]
body:
- type: markdown
  attributes:
    value: |
      Thank you for taking the time to fill out a bug report! To save both you and us time, please make sure to check the [FAQ](https://guide.dim.gg/FAQ) and [search issues](https://github.com/DestinyItemManager/DIM/issues?q=is%3Aissue) to see if this has already been reported.
- type: input
  id: DIMversion
  attributes:
    label: DIM Version
    description: Find the version in "About DIM" from the menu (the button with three bars on the upper left of the screen). Is the DIM icon orange, or blue?
    placeholder: ex. Version 6.78.0.1000630 (beta), built on 8/15/2021, 8:04:14 PM
  validations:
    required: true
- type: input
  id: BrowserVersion
  attributes:
    label: Browser Details
    description: What browser and version are you experiencing this issue on?
    placeholder: ex. Chrome 92.0.4515.131
  validations:
    required: true
- type: input
  id: OSversion
  attributes:
    label: OS Details
    description: What operating system are you experiencing this issue on?
    placeholder: ex. Windows 10
  validations:
    required: true
- type: textarea
  attributes:
    label: Describe the bug
    description: Tell us what's wrong. A great format for bug reports is "I did X, and I expected Y, but instead Z happened." If it helps illustrate the issue, please add screenshots to help explain your problem.
  validations:
    required: true
- type: textarea
  attributes:
    label: Logs
    description: If you can, open the devtools console (ctrl+shift+J on PC and cmd+option+J on Mac) and paste what you see in the window that pops up
    render: shell
  validations:
    required: false


================================================
FILE: .github/ISSUE_TEMPLATE/feature_request.yml
================================================
name: Feature Request
description: Let us know what you want to see next in DIM
labels: [Enhancement]
body:
- type: markdown
  attributes:
    value: |
      Thank you for taking the time to fill out a feature request and let us know what you'd like to see in DIM! To save both you and us time, please make sure to check the [Frequently Requested Features](https://guide.dim.gg/Frequently-Requested-Features) and [search issues](https://github.com/DestinyItemManager/DIM/issues?q=is%3Aissue) to see if this has already been reported.
- type: textarea
  id: ChangeDesc
  attributes:
    label: Proposed change
    description: Explain what you'd like to see as a new feature or enhancement to DIM.
  validations:
    required: true
- type: textarea
  id: Workflow
  attributes:
    label: How does this fit into your workflow?
    description: Tell us how you'd use this. Having this context is very helpful for us to understand how a proposed change would fit into the way you play.
  validations:
    required: true


================================================
FILE: .github/actions/setup-pnpm/action.yml
================================================
name: 'Setup PNPM Environment'
description: 'Setup Node.js with PNPM and install dependencies with proper caching'

inputs:
  install:
    description: 'Whether to install dependencies (default: true)'
    required: false
    default: 'true'

runs:
  using: 'composite'
  steps:
    - name: Setup pnpm
      uses: pnpm/action-setup@v4

    - name: Setup Node.js
      uses: actions/setup-node@v6
      with:
        node-version-file: '.nvmrc'
        cache: ${{ inputs.install == 'true' && 'pnpm' || '' }}

    - name: Install dependencies
      if: inputs.install == 'true'
      shell: bash
      run: pnpm install --frozen-lockfile --prefer-offline

================================================
FILE: .github/copilot-instructions.md
================================================
# General DIM Code Style

Always follow the [Contributing Guide](../docs/CONTRIBUTING.md).

## JS

- Pure JavaScript files should be named in lowercase kebab-case, with a .ts extension. These should not use a default export.
- Files with JSX should be named in PascalCase with a .tsx extension. In general we should have a separate file for each component. The component should be that module's default export, and the file should have the same name as the component.
- Prefer using "function" to declare functions over const arrow functions.

## CSS

- All CSS should be put in CSS modules. The CSS module file should have the same name as the file it is used from but with the extension .m.scss. The classes from the module should be imported as `styles` and referenced in JSX.
- Do not use inline styles.
- Do not use string classNames, only use CSS modules.
- Use the clsx helper to combine classNames or conditionally include classes.

## Tests

- For unit tests, prefer defining a table of inputs and expected outputs, and then looping through that to create tests. This is also called "table-style testing".
- Run `pnpm test -- -u` to update snapshots. This is especially necessary when adding new search terms.
- Run `pnpm build:beta` to make sure the code builds.
- Run `pnpm test` to run all tests.

## Localization

- Only ever add strings to `config/i18n.json`. Then run `pnpm i18n` and commit the updated `src/locale/en.json` file.


================================================
FILE: .github/dependabot.yml
================================================
version: 2
updates:
  - directory: /
    package-ecosystem: "npm"
    schedule:
      interval: "weekly"
      time: "18:00" # UTC, = ~10AM Pacific
    groups:
      major:
        update-types:
          - major
      minor:
        update-types:
          - minor
          - patch

  - directory: /
    package-ecosystem: "github-actions"
    schedule:
      interval: "weekly"
      time: "18:00" # UTC, = ~10AM Pacific
    groups:
      major:
        update-types:
          - major
      minor:
        update-types:
          - minor
          - patch

  # Dependabot doesn't support docker-compose yet
  # - directory: /
  #   package-ecosystem: "docker"
  #   schedule:
  #     interval: "weekly"
  #     time: "18:00" # UTC, = ~10AM Pacific


================================================
FILE: .github/pull_request_template.md
================================================
<!-- To add entries to the CHANGELOG.md, include lines in your commit messages that start with `Changelog:` followed by the description -->


================================================
FILE: .github/scripts/discord_changelog.py
================================================
#!/usr/bin/env python3
"""
Discord changelog helper for DIMmit.
Used by .github/workflows/notify-discord-changelog.yml

Usage:
  python3 discord_changelog.py

Environment variables:
  DISCORD_CHANGELOG_BOT_TOKEN  — required (deletes existing beta messages before posting)
  DISCORD_CHANGELOG_WEBHOOK    — required (posts the new changelog embed)
"""

import json
import os
import re
import sys
import time
import urllib.request
import urllib.error

CHANGELOG_FILE = "docs/CHANGELOG.md"
CHANNEL_ID = "894808801109245952"
BETA_AVATAR_HASH = "5153E66D003AFF489DC73FF9EE151A6F"
CHUNK_SIZE = 4000  # safely under Discord's 4096 embed limit
REQUEST_TIMEOUT = 10  # seconds

ICONS_BASE = "https://raw.githubusercontent.com/DestinyItemManager/DIM/refs/heads/master/icons"
AVATAR_BETA = f"{ICONS_BASE}/beta/favicon-96x96.png"
AVATAR_PROD = f"{ICONS_BASE}/release/favicon-96x96.png"

PROFILES = {
    "beta": {"avatar_url": AVATAR_BETA, "color": 0x68A0B7},
    "prod": {"avatar_url": AVATAR_PROD, "color": 0xF37423},
}


# ── Changelog parsing ──────────────────────────────────────────────────────────

def _sections():
    """Return a dict of {heading: body} parsed from CHANGELOG.md."""
    with open(CHANGELOG_FILE) as f:
        content = f.read()
    parts = re.split(r"^(## .*)", content, flags=re.MULTILINE)
    result = {}
    for i, part in enumerate(parts):
        if part.startswith("## ") and i + 1 < len(parts):
            result[part.strip()] = parts[i + 1].strip()
    return result


def detect_profile(sections):
    """Return 'beta', 'prod', or 'none' based on changelog content."""
    beta_body = sections.get("## Next", "")
    if re.search(r"^\*", beta_body, re.MULTILINE):
        return "beta"
    for heading, body in sections.items():
        if re.match(r"## \d", heading) and re.search(r"^\*", body, re.MULTILINE):
            return "prod"
    return "none"


def get_content(sections, profile):
    """Return formatted Discord content for the given profile."""
    if profile == "beta":
        return "### Destiny Item Manager - BETA\n" + sections.get("## Next", "")
    if profile == "prod":
        for heading, body in sections.items():
            if re.match(r"## \d", heading):
                version = re.sub(r"<.*?>", "", heading[3:]).strip()
                return f"### Destiny Item Manager v{version}\n" + body
    return ""


# ── Discord API helpers ────────────────────────────────────────────────────────

def bot_api(method, path, token, data=None):
    url = f"https://discord.com/api/v10/{path}"
    body = json.dumps(data).encode() if data else None
    req = urllib.request.Request(
        url, data=body,
        headers={"Authorization": f"Bot {token}", "Content-Type": "application/json"},
        method=method
    )
    try:
        with urllib.request.urlopen(req, timeout=REQUEST_TIMEOUT) as r:
            raw = r.read()
            return json.loads(raw) if raw else None
    except urllib.error.HTTPError as e:
        print(f"HTTP {e.code} on {method} {path}: {e.read().decode()}")
        raise


def chunk_content(content):
    """Split content into <=CHUNK_SIZE chunks on newline boundaries."""
    chunks = []
    current = ""
    for line in content.splitlines(keepends=True):
        if len(current) + len(line) > CHUNK_SIZE:
            chunks.append(current.rstrip())
            current = line
        else:
            current += line
    if current.strip():
        chunks.append(current.rstrip())
    return chunks


# ── Commands ───────────────────────────────────────────────────────────────────

LOOKBACK_DAYS = 8  # releases are weekly; 8 days covers the full beta window


def _snowflake_from_days_ago(days):
    """Return the Discord snowflake ID for a timestamp N days ago.
    Used as an `after` cursor to avoid scanning the full channel history.
    """
    ms = int((time.time() - days * 86400) * 1000)
    return str((ms - 1420070400000) << 22)


def _bot_api_with_retry(method, path, token, data=None, retries=5):
    """Call bot_api with exponential backoff on 429 rate-limit responses."""
    for attempt in range(retries):
        try:
            return bot_api(method, path, token, data)
        except urllib.error.HTTPError as e:
            if e.code == 429 and attempt < retries - 1:
                retry_after = float(json.loads(e.read()).get("retry_after", 1))
                print(f"Rate limited, retrying in {retry_after}s...")
                time.sleep(retry_after)
            else:
                raise


def delete_beta():
    """Delete beta-avatar messages from the last LOOKBACK_DAYS days."""
    token = os.environ["DISCORD_CHANGELOG_BOT_TOKEN"]
    after_id = _snowflake_from_days_ago(LOOKBACK_DAYS)

    messages = []
    last_id = None
    while True:
        path = f"channels/{CHANNEL_ID}/messages?limit=100&after={after_id}"
        if last_id:
            path += f"&before={last_id}"
        batch = _bot_api_with_retry("GET", path, token)
        if not batch:
            break
        messages.extend(batch)
        if len(batch) < 100:
            break
        last_id = batch[-1]["id"]

    deleted = 0
    for msg in messages:
        if msg.get("author", {}).get("avatar", "").upper() == BETA_AVATAR_HASH:
            _bot_api_with_retry("DELETE", f"channels/{CHANNEL_ID}/messages/{msg['id']}", token)
            deleted += 1
            time.sleep(0.5)  # stay under rate limit

    print(f"Deleted {deleted} beta message(s)")



# ── Entrypoint ─────────────────────────────────────────────────────────────────

if __name__ == "__main__":
    sections = _sections()
    profile = detect_profile(sections)

    if profile == "none":
        print("No changelog content detected, skipping Discord post.")
        sys.exit(0)

    content = get_content(sections, profile)
    delete_beta()

    webhook = os.environ["DISCORD_CHANGELOG_WEBHOOK"]
    avatar = PROFILES[profile]

    for chunk in chunk_content(content):
        payload = {
            "username": "DIMmit",
            "avatar_url": avatar["avatar_url"],
            "content": "",
            "embeds": [{"description": chunk, "color": avatar["color"]}]
        }
        data = json.dumps(payload).encode()
        req = urllib.request.Request(
            webhook, data=data,
            headers={"Content-Type": "application/json"}
        )
        urllib.request.urlopen(req, timeout=REQUEST_TIMEOUT)
        print(f"Posted chunk ({len(chunk)} chars)")


================================================
FILE: .github/scripts/i18n_discord.py
================================================
#!/usr/bin/env python3
"""
Discord i18n diff helper for DIMi18n.
Used by .github/workflows/notify-discord-i18n.yml

Usage:
  python3 i18n_discord.py

Environment variables:
  DISCORD_I18N_WEBHOOK  — required (posts the diff embed)
"""

import json
import os
import subprocess
import sys
import urllib.request
import urllib.error

LOCALE_FILE = "src/locale/en.json"
CHUNK_SIZE = 4000  # safely under Discord's 4096 embed limit
REQUEST_TIMEOUT = 10  # seconds
ROLE_MENTION = "<@&622449489008918548>"
AVATAR_URL = "https://raw.githubusercontent.com/DestinyItemManager/DIM/refs/heads/master/icons/pr/android-chrome-mask-512x512-6-2018.png"
COLOR = 0xFF64E7
CROWDIN_URL = "https://crowdin.com/project/destiny-item-manager"


# ── JSON diffing ───────────────────────────────────────────────────────────────

def flatten(obj, prefix=""):
    """Flatten a nested JSON object to dot-notation keys."""
    result = {}
    for key, value in obj.items():
        new_key = f"{prefix}.{key}" if prefix else key
        if isinstance(value, dict):
            result.update(flatten(value, new_key))
        else:
            result[new_key] = value
    return result


def compare(old_flat, new_flat):
    """Return a dict of added, modified, and removed keys."""
    old_keys = set(old_flat)
    new_keys = set(new_flat)

    added = [
        {"path": k, "new": new_flat[k]}
        for k in new_keys - old_keys
    ]
    removed = [
        {"path": k, "old": old_flat[k]}
        for k in old_keys - new_keys
    ]
    modified = [
        {"path": k, "old": old_flat[k], "new": new_flat[k]}
        for k in old_keys & new_keys
        if json.dumps(old_flat[k]) != json.dumps(new_flat[k])
    ]

    return {
        "added": sorted(added, key=lambda x: x["path"]),
        "modified": sorted(modified, key=lambda x: x["path"]),
        "removed": sorted(removed, key=lambda x: x["path"]),
    }


# ── Markdown report ────────────────────────────────────────────────────────────

MAX_VALUE_LEN = 100

def fmt(value):
    """Format a value for display, truncating if needed."""
    if value is None:
        return "`null`"
    s = f'"{value}"' if isinstance(value, str) else json.dumps(value)
    if len(s) > MAX_VALUE_LEN:
        s = s[:MAX_VALUE_LEN] + "..."
    return f"`{s}`"


def generate_report(diff, total):
    added = diff["added"]
    modified = diff["modified"]
    removed = diff["removed"]

    lines = [
        "## Summary\n",
        f"**Total Changes:** {total}\n",
        f"- **Added Translation(s):** {len(added)}",
        f"- **Modified Translation(s):** {len(modified)}",
        f"- **Removed Translation(s):** {len(removed)}",
    ]

    if added:
        lines.append(f"\n## ➕ Added Keys ({len(added)})\n")
        for i, c in enumerate(added, 1):
            lines.append(f"### {i}. `{c['path']}`\n")
            lines.append(fmt(c["new"]))

    if modified:
        lines.append(f"\n## 🔄 Modified Keys ({len(modified)})\n")
        for i, c in enumerate(modified, 1):
            lines.append(f"### {i}. `{c['path']}`\n")
            lines.append(f"<:minus:1105075710818783372> {fmt(c['old'])}")
            lines.append(f"<:plus:1105075707593371738> {fmt(c['new'])}")

    if removed:
        lines.append(f"\n## ➖ Removed Keys ({len(removed)})\n")
        for i, c in enumerate(removed, 1):
            lines.append(f"### {i}. `{c['path']}`\n")
            lines.append(f"**Previous Value:** {fmt(c['old'])}")

    return "\n".join(lines)


# ── Discord posting ────────────────────────────────────────────────────────────

def chunk_content(content):
    """Split content into <=CHUNK_SIZE chunks on newline boundaries."""
    chunks = []
    current = ""
    for line in content.splitlines(keepends=True):
        if len(current) + len(line) > CHUNK_SIZE:
            chunks.append(current.rstrip())
            current = line
        else:
            current += line
    if current.strip():
        chunks.append(current.rstrip())
    return chunks


def post_to_discord(report):
    webhook = os.environ["DISCORD_I18N_WEBHOOK"]
    chunks = chunk_content(report)

    for i, chunk in enumerate(chunks):
        payload = {
            "username": "i18n Bot",
            "avatar_url": AVATAR_URL,
            "content": ROLE_MENTION if i == 0 else "",
            "embeds": [{
                "title": "DIM - crowdin",
                "url": CROWDIN_URL,
                "description": chunk,
                "color": COLOR,
            }]
        }
        data = json.dumps(payload).encode()
        req = urllib.request.Request(
            webhook, data=data,
            headers={"Content-Type": "application/json"}
        )
        try:
            urllib.request.urlopen(req, timeout=REQUEST_TIMEOUT)
            print(f"Posted chunk {i + 1}/{len(chunks)} ({len(chunk)} chars)")
        except urllib.error.HTTPError as e:
            print(f"HTTP {e.code}: {e.read().decode()}")
            raise


# ── Entrypoint ─────────────────────────────────────────────────────────────────

if __name__ == "__main__":
    old_json = subprocess.run(
        ["git", "show", f"HEAD^:{LOCALE_FILE}"],
        capture_output=True, text=True, check=True
    ).stdout

    old = flatten(json.loads(old_json))
    with open(LOCALE_FILE) as f:
        new = flatten(json.load(f))

    diff = compare(old, new)
    total = len(diff["added"]) + len(diff["modified"]) + len(diff["removed"])

    if total == 0:
        print("No changes detected, skipping Discord post.")
        sys.exit(0)

    report = generate_report(diff, total)
    post_to_discord(report)


================================================
FILE: .github/workflows/auto-merge.yml
================================================
name: Auto-merge

on:
  pull_request_target:

permissions:
  contents: write
  pull-requests: write

jobs:
  auto-merge:
    runs-on: ubuntu-latest
    timeout-minutes: 10
    if: github.actor == 'd2ai-bot' || github.actor == 'dependabot[bot]'
    steps:
      - name: Generate token
        uses: actions/create-github-app-token@v3
        id: app-token
        with:
          app-id: ${{ secrets.AUTOMERGE_APP_ID }}
          private-key: ${{ secrets.AUTOMERGE_PRIVATE_KEY }}

      - name: Dependabot metadata
        if: github.actor == 'dependabot[bot]'
        id: metadata
        uses: dependabot/fetch-metadata@v2
        with:
          github-token: ${{ steps.app-token.outputs.token }}

      - name: Enable auto-merge for d2ai PRs
        if: github.actor == 'd2ai-bot'
        run: gh pr merge --auto --merge "${{ github.event.pull_request.html_url }}"
        env:
          GH_TOKEN: ${{ steps.app-token.outputs.token }}

      - name: Enable auto-merge for Dependabot PRs
        if: github.actor == 'dependabot[bot]' && (steps.metadata.outputs.update-type == 'version-update:semver-patch' || steps.metadata.outputs.update-type == 'version-update:semver-minor')
        run: gh pr merge --auto --merge "${{ github.event.pull_request.html_url }}"
        env:
          GH_TOKEN: ${{ steps.app-token.outputs.token }}

================================================
FILE: .github/workflows/changelog-updater.yml
================================================
name: Update Changelog

on:
  push:
    branches: [master]
    paths-ignore:
      - 'docs/CHANGELOG.md'  # Prevent infinite loops

permissions:
  contents: write

jobs:
  update-changelog:
    runs-on: ubuntu-latest
    timeout-minutes: 10
    steps:
      - uses: actions/checkout@v6
        with:
          token: ${{ secrets.I18N_PAT }}

      - uses: ./.github/actions/setup-pnpm
        with:
          install: 'false'  # Don't need dependencies for this script

      - name: Update changelog from commits
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
          GITHUB_REPOSITORY: ${{ github.repository }}
          COMMIT_SHAS: ${{ join(github.event.commits.*.id, ' ') }}
        run: |
          # Process all commits and automatically detect associated PRs using GitHub API
          node build/update-changelog.js $COMMIT_SHAS > docs/CHANGELOG.md.new
          mv docs/CHANGELOG.md.new docs/CHANGELOG.md

      - name: Commit files
        uses: stefanzweifel/git-auto-commit-action@v7
        with:
          commit_message: Apply changelog updates

================================================
FILE: .github/workflows/copilot-setup-steps.yml
================================================
name: "Copilot Setup Steps"

on:
  workflow_dispatch:
  push:
    paths:
      - .github/workflows/copilot-setup-steps.yml
  pull_request:
    paths:
      - .github/workflows/copilot-setup-steps.yml

jobs:
   copilot-setup-steps:
    runs-on: ubuntu-latest
    permissions:
      contents: read

    steps:
      - uses: actions/checkout@v6

      - uses: pnpm/action-setup@v5

      - name: Setup Node
        uses: actions/setup-node@v6
        with:
          node-version-file: '.nvmrc'
          cache: pnpm

      - name: Install
        run: pnpm install --frozen-lockfile --prefer-offline

================================================
FILE: .github/workflows/deploy-beta.yml
================================================
name: Deploy Beta

on:
  workflow_dispatch:
  push:
    branches:
      - master

# Ensures that only one deploy task per branch/environment will run at a time.
concurrency:
  group: ${{ github.workflow }}-${{ github.ref }}
  cancel-in-progress: true

jobs:
  deploy:
    runs-on: ubuntu-latest
    environment:
      name: beta
      url: https://beta.dim.gg
    steps:
      - uses: actions/checkout@v6
        with:
          fetch-depth: 2 # So sentry can get the previous commit

      - uses: ./.github/actions/setup-pnpm

      - name: Install SSH key
        uses: benoitchantre/setup-ssh-authentication-action@1.0.1
        with:
          private-key: ${{ secrets.SSH_KEY }}
          private-key-name: dim.rsa
          known-hosts: ${{ secrets.REMOTE_HOST }}

      - name: Get package version
        id: package-version
        uses: martinbeentjes/npm-get-version-action@v1.3.1

      - name: Set beta environment
        run: |
          echo "build_level='beta'" >> $GITHUB_ENV

      - name: Bump release version (beta)
        env:
          RUN_NUM: ${{ github.run_number }}
        run: |
          echo "VERSION=${{ steps.package-version.outputs.current-version }}.$(($RUN_NUM))" >> $GITHUB_ENV

      - name: Build
        run: pnpm build:beta
        env:
          NODE_OPTIONS: "--max_old_space_size=8192"
          WEB_API_KEY: ${{ secrets.BUNGIE_API_KEY }}
          WEB_OAUTH_CLIENT_ID: ${{ secrets.OAUTH_CLIENT_ID }}
          WEB_OAUTH_CLIENT_SECRET: ${{ secrets.OAUTH_SECRET }}
          DIM_API_KEY: ${{ secrets.DIM_API_KEY }}

      - name: Send bundle stats to RelativeCI
        uses: relative-ci/agent-action@v3
        with:
          key: ${{ secrets.RELATIVE_CI_KEY }}
          token: ${{ secrets.GITHUB_TOKEN }}
          webpackStatsFile: ./webpack-stats.json

      - name: Check Syntax
        run: pnpm syntax

      - name: Rsync to Server
        run: ./build/rsync-deploy.sh
        env:
          SSH_PRIVATE_KEY: ${{ secrets.SSH_KEY }}
          SOURCE: "dist/"
          REMOTE_USER: ${{ secrets.REMOTE_USER }}
          REMOTE_HOST: ${{ secrets.REMOTE_HOST }}
          REMOTE_PATH: beta.destinyitemmanager.com

      - name: Purge CloudFlare cache
        run: ./build/purge-cloudflare.sh
        env:
          CLOUDFLARE_KEY: ${{ secrets.CLOUDFLARE_KEY }}
          CLOUDFLARE_EMAIL: ${{ secrets.CLOUDFLARE_EMAIL }}
          APP_DOMAIN: beta.destinyitemmanager.com

      - name: Create Sentry release
        uses: getsentry/action-release@v3
        env:
          SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }}
          SENTRY_ORG: destiny-item-manager
          SENTRY_PROJECT: dim
        with:
          environment: beta
          release: ${{ env.VERSION }}
          ignore_missing: true


================================================
FILE: .github/workflows/deploy-prod.yml
================================================
name: Deploy Prod

on:
  workflow_dispatch:
    inputs:
      patch:
        description: 'Should this be a patch release?'
        type: boolean
        required: true
        default: true
  schedule:
    # Deploy at 5pm Sunday PST, which is 1am Monday UTC
    # * is a special character in YAML so you have to quote this string
    - cron: '0 1 * * 1'

jobs:
  deploy:
    runs-on: ubuntu-latest
    environment:
      name: release
      url: https://app.dim.gg
    steps:
      - uses: actions/checkout@v6
        with:
          fetch-depth: 2 # So sentry can get the previous commit
          # Use the dim-release-bot token rather than the default
          token: ${{ secrets.GH_TOKEN }}

      - uses: ./.github/actions/setup-pnpm

      - name: Install SSH key
        uses: benoitchantre/setup-ssh-authentication-action@1.0.1
        with:
          private-key: ${{ secrets.SSH_KEY }}
          private-key-name: dim.rsa
          known-hosts: ${{ secrets.REMOTE_HOST }}

      - name: Build and deploy
        run: ./build/deploy-prod.sh
        env:
          PATCH: ${{ github.event.inputs.patch }}
          NODE_OPTIONS: "--max_old_space_size=8192"
          WEB_API_KEY: ${{ secrets.BUNGIE_API_KEY }}
          WEB_OAUTH_CLIENT_ID: ${{ secrets.OAUTH_CLIENT_ID }}
          WEB_OAUTH_CLIENT_SECRET: ${{ secrets.OAUTH_SECRET }}
          DIM_API_KEY: ${{ secrets.DIM_API_KEY }}
          REMOTE_USER: ${{ secrets.REMOTE_USER }}
          REMOTE_HOST: ${{ secrets.REMOTE_HOST }}
          REMOTE_PATH: app.destinyitemmanager.com
          SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }}
          # Use the dim-release-bot token rather than the default
          GITHUB_TOKEN: ${{ secrets.GH_TOKEN }}

      - name: Purge CloudFlare cache
        run: ./build/purge-cloudflare.sh
        env:
          CLOUDFLARE_KEY: ${{ secrets.CLOUDFLARE_KEY }}
          CLOUDFLARE_EMAIL: ${{ secrets.CLOUDFLARE_EMAIL }}
          APP_DOMAIN: app.destinyitemmanager.com

      - name: Get package version
        id: package-version
        shell: bash
        run: |
          echo "current-version=$(node -p 'const pkg = require("./web-console/package.json"); pkg.version')" >> $GITHUB_OUTPUT

      - name: Create Sentry release
        uses: getsentry/action-release@v3
        env:
          SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }}
          SENTRY_ORG: destiny-item-manager
          SENTRY_PROJECT: dim
        with:
          environment: release
          release: ${{ steps.package-version.outputs.current-version }}
          ignore_missing: true


================================================
FILE: .github/workflows/i18n-bot-download.yml
================================================
# This workflow runs every Saturday @ 1900 UTC (NOON PST)
name: i18n download bot

on:
  workflow_dispatch:
  schedule:
    - cron: "0 19 * * 6"

jobs:
  download:
    runs-on: ubuntu-latest
    timeout-minutes: 20
    steps:
      - name: Checkout DIM
        uses: actions/checkout@v6
        with:
          ref: ${{ github.head_ref }}
          token: ${{ secrets.I18N_PAT }}

      - uses: ./.github/actions/setup-pnpm

      - name: Download updated i18n files
        uses: crowdin/github-action@v2.16.0
        with:
          upload_sources: false
          upload_translations: false
          download_translations: true
          create_pull_request: false
          push_translations: false
          project_id: ${{ secrets.CROWDIN_PROJECT_ID }}
          token: ${{ secrets.CROWDIN_PERSONAL_TOKEN }}
        env:
          CROWDIN_PROJECT_ID: ${{ secrets.CROWDIN_PROJECT_ID }}
          CROWDIN_PERSONAL_TOKEN: ${{ secrets.CROWDIN_PERSONAL_TOKEN }}
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

      - name: Sort locale JSON files
        run: |
          allLocales=("en" "de" "es" "esMX" "fr" "it" "ja" "ko" "pl" "ptBR" "ru" "zhCHS" "zhCHT")
          for lang in ${allLocales[@]}; do
            jq -S . src/locale/$lang.json > src/locale/sorted_$lang.json && mv src/locale/sorted_$lang.json src/locale/$lang.json
          done

      - name: Build browsercheck utils
        run: pnpm bcu

      - name: Check for changes
        uses: dorny/paths-filter@v4
        id: filter
        with:
          base: HEAD
          filters: |
            changed:
              - '**'

      - name: Commit files
        if: steps.filter.outputs.changed == 'true'
        uses: stefanzweifel/git-auto-commit-action@v7
        with:
          commit_message: "i18n: Update translations from Crowdin"
          commit_user_name: DIM i18n Bot
          commit_user_email: destinyitemmanager@gmail.com
          commit_author: DIM i18n Bot <destinyitemmanager@gmail.com>

================================================
FILE: .github/workflows/i18n-bot-upload.yml
================================================
# This workflow runs whenever locale/en.json is updated on the master branch
# It updates crowdin with new translation strings
name: i18n upload bot

on:
  workflow_dispatch:
  push:
    paths:
      - "src/locale/en.json"
    branches: [master]

jobs:
  upload:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout DIM
        uses: actions/checkout@v6

      - name: Sort en.json
        run: dimJSON="$(jq -S . src/locale/en.json)" && echo "${dimJSON}" > src/locale/en.json

      - name: Upload updated en.json to crowdin
        uses: crowdin/github-action@v2.16.0
        with:
          upload_sources: true
          upload_translations: false
          project_id: ${{ secrets.CROWDIN_PROJECT_ID }}
          token: ${{ secrets.CROWDIN_PERSONAL_TOKEN }}
        env:
          CROWDIN_PROJECT_ID: ${{ secrets.CROWDIN_PROJECT_ID }}
          CROWDIN_PERSONAL_TOKEN: ${{ secrets.CROWDIN_PERSONAL_TOKEN }}
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

      - name: Check for changes
        uses: dorny/paths-filter@v4
        id: filter
        with:
          base: HEAD
          filters: |
            changed:
              - 'src/locale/en.json'


================================================
FILE: .github/workflows/i18n-update.yml
================================================
name: i18n-update

on:
  push:
    branches: [master]
    paths:
      - 'config/i18n.json'
      - 'src/locale/en.json'

jobs:
  update:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v6
        with:
          fetch-depth: 3
          token: ${{ secrets.I18N_PAT }}

      - uses: ./.github/actions/setup-pnpm

      - name: Run i18n update
        run: pnpm i18n

      - name: Commit files
        uses: stefanzweifel/git-auto-commit-action@v7
        with:
          commit_message: "i18n: Apply automated updates"


================================================
FILE: .github/workflows/lint-workflows.yml
================================================
name: Lint Workflows

on:
  pull_request:
    paths:
      - '.github/workflows/**'
      - '.github/actions/**'
  push:
    branches:
      - master
    paths:
      - '.github/workflows/**'
      - '.github/actions/**'
  workflow_dispatch:

jobs:
  actionlint:
    runs-on: ubuntu-latest
    timeout-minutes: 5
    steps:
      - uses: actions/checkout@v6

      - name: Run actionlint
        uses: reviewdog/action-actionlint@v1
        with:
          github_token: ${{ secrets.GITHUB_TOKEN }}
          reporter: github-pr-review
          filter_mode: nofilter
          fail_level: error
          actionlint_flags: -color


================================================
FILE: .github/workflows/notify-discord-changelog.yml
================================================
name: Notify Discord - Changelog

on:
  workflow_dispatch:
  push:
    branches:
      - master
    paths:
      - 'docs/CHANGELOG.md'

jobs:
  post-changelog:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout
        uses: actions/checkout@v6

      - name: Post changelog to Discord
        env:
          DISCORD_CHANGELOG_BOT_TOKEN: ${{ secrets.DISCORD_CHANGELOG_BOT_TOKEN }}
          DISCORD_CHANGELOG_WEBHOOK: ${{ secrets.DISCORD_CHANGELOG_WEBHOOK }}
        run: python3 .github/scripts/discord_changelog.py


================================================
FILE: .github/workflows/notify-discord-i18n.yml
================================================
name: Notify Discord - i18n

on:
  workflow_dispatch:
  push:
    branches:
      - master
    paths:
      - 'src/locale/en.json'

jobs:
  post-i18n-diff:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout
        uses: actions/checkout@v6
        with:
          fetch-depth: 2  # needed to access HEAD^ for the previous version

      - name: Post i18n diff to Discord
        env:
          DISCORD_I18N_WEBHOOK: ${{ secrets.DISCORD_I18N_WEBHOOK }}
        run: python3 .github/scripts/i18n_discord.py


================================================
FILE: .github/workflows/pr-cleanup.yml
================================================
name: PR Cleanup
on:
  pull_request:
    types: [closed]

jobs:
  # Remove the preview build directory
  cleanup:
    runs-on: ubuntu-latest
    environment: pr
    if: ${{github.event.pull_request.head.repo.full_name == github.repository && github.actor != 'dependabot[bot]'}}
    steps:
      - name: Install SSH key
        uses: benoitchantre/setup-ssh-authentication-action@1.0.1
        with:
          private-key: ${{ secrets.SSH_KEY }}
          private-key-name: dim.rsa
          known-hosts: ${{ secrets.REMOTE_HOST }}

      - name: Delete preview build
        run: ssh -i ~/.ssh/dim.rsa -o StrictHostKeyChecking=no ${{secrets.REMOTE_USER}}@${{secrets.REMOTE_HOST}} "rm -rf pr.destinyitemmanager.com/${{ github.event.number }}"

================================================
FILE: .github/workflows/pr-reports.yml
================================================
name: PR Reports

on:
  workflow_run:
    workflows: ['PR Validation']
    types: [completed]

permissions:
  checks: write
  pull-requests: write
  actions: read

jobs:
  # Check all artifacts in a single job to reduce API calls
  check-artifacts:
    runs-on: ubuntu-latest
    timeout-minutes: 5
    if: github.event.workflow_run.event == 'pull_request' && github.event.workflow_run.conclusion != 'cancelled'
    outputs:
      has-test-results: ${{ steps.check.outputs.test-results }}
      has-eslint-results: ${{ steps.check.outputs.eslint-results }}
      has-webpack-stats: ${{ steps.check.outputs.webpack-stats }}
    steps:
      - name: Check for all artifacts
        id: check
        uses: actions/github-script@v8
        with:
          script: |
            const artifacts = await github.rest.actions.listWorkflowRunArtifacts({
              owner: context.repo.owner,
              repo: context.repo.repo,
              run_id: context.payload.workflow_run.id
            });

            const hasTestResults = artifacts.data.artifacts.some(a => a.name === 'test-results');
            const hasEslintResults = artifacts.data.artifacts.some(a => a.name === 'eslint-results');
            const hasWebpackStats = artifacts.data.artifacts.some(a => a.name === 'webpack-stats');

            console.log(`Test results: ${hasTestResults ? '✅' : '❌'}`);
            console.log(`ESLint results: ${hasEslintResults ? '✅' : '❌'}`);
            console.log(`Webpack stats: ${hasWebpackStats ? '✅' : '❌'}`);

            core.setOutput('test-results', hasTestResults);
            core.setOutput('eslint-results', hasEslintResults);
            core.setOutput('webpack-stats', hasWebpackStats);

  test-report:
    needs: check-artifacts
    runs-on: ubuntu-latest
    timeout-minutes: 10
    if: needs.check-artifacts.outputs.has-test-results == 'true'
    steps:
      - name: Download test results
        uses: actions/download-artifact@v8
        with:
          name: test-results
          github-token: ${{ secrets.GITHUB_TOKEN }}
          run-id: ${{ github.event.workflow_run.id }}

      - name: Publish test report
        uses: dorny/test-reporter@v3
        with:
          artifact: test-results
          name: JEST Tests
          path: '*.xml'
          reporter: jest-junit

  eslint-annotate:
    needs: check-artifacts
    runs-on: ubuntu-latest
    timeout-minutes: 10
    if: needs.check-artifacts.outputs.has-eslint-results == 'true'
    steps:
      - name: Download ESLint results
        uses: actions/download-artifact@v8
        with:
          name: eslint-results
          github-token: ${{ secrets.GITHUB_TOKEN }}
          run-id: ${{ github.event.workflow_run.id }}

      - name: Annotate ESLint results
        uses: ataylorme/eslint-annotate-action@v4
        with:
          report-json: eslint.results.json
          fail-on-error: false
          fail-on-warning: false

  bundle-analysis:
    needs: check-artifacts
    runs-on: ubuntu-latest
    timeout-minutes: 10
    if: needs.check-artifacts.outputs.has-webpack-stats == 'true' && github.event.workflow_run.conclusion == 'success'
    steps:
      - name: Download webpack stats
        uses: actions/download-artifact@v8
        with:
          name: webpack-stats
          run-id: ${{ github.event.workflow_run.id }}
          github-token: ${{ secrets.GITHUB_TOKEN }}

      - name: Upload to RelativeCI
        uses: relative-ci/agent-action@v3
        with:
          key: ${{ secrets.RELATIVE_CI_KEY }}
          token: ${{ secrets.GITHUB_TOKEN }}
          artifactName: webpack-stats
          webpackStatsFile: ./webpack-stats.json

================================================
FILE: .github/workflows/pr-validation.yml
================================================
name: PR Validation

on:
  pull_request:
    types: [opened, synchronize, reopened]
    paths-ignore:
      - 'docs/**'

concurrency:
  group: ${{ github.workflow }}-${{ github.ref }}
  cancel-in-progress: true

jobs:
  test:
    runs-on: ubuntu-latest
    timeout-minutes: 20
    steps:
      - uses: actions/checkout@v6

      # Inline setup - required for fork PR compatibility
      # Cannot use ./.github/actions/setup-pnpm as it won't work from forks
      - uses: pnpm/action-setup@v5

      - name: Setup Node
        uses: actions/setup-node@v6
        with:
          node-version-file: '.nvmrc'
          cache: pnpm

      - name: Install dependencies
        run: pnpm install --frozen-lockfile --prefer-offline

      - name: Cache Manifest
        uses: actions/cache@v5
        with:
          path: manifest-cache
          key: destiny-manifest-${{ github.run_number }}
          restore-keys: |
            destiny-manifest-

      - name: Run tests
        run: pnpm test
        env:
          CLEAN_MANIFEST_CACHE: true

      - name: Upload test results
        uses: actions/upload-artifact@v7
        if: success() || failure()
        with:
          name: test-results
          path: junit.xml
          retention-days: 7

  lint:
    runs-on: ubuntu-latest
    timeout-minutes: 15
    steps:
      - uses: actions/checkout@v6

      # Inline setup - required for fork PR compatibility
      - uses: pnpm/action-setup@v5

      - name: Setup Node
        uses: actions/setup-node@v6
        with:
          node-version-file: '.nvmrc'
          cache: pnpm

      - name: Install dependencies
        run: pnpm install --frozen-lockfile --prefer-offline

      # Optimized cache key: Only invalidate on config changes, not all dependencies
      - name: Cache ESLint
        uses: actions/cache@v5
        with:
          path: |
            .eslintcache
            node_modules/.cache
          key: ${{ runner.os }}-eslint-${{ hashFiles('eslint.config.js', 'tsconfig.json') }}-${{ hashFiles('src/**/*.ts', 'src/**/*.tsx', 'src/**/*.js', 'src/**/*.jsx') }}
          restore-keys: |
            ${{ runner.os }}-eslint-${{ hashFiles('eslint.config.js', 'tsconfig.json') }}-
            ${{ runner.os }}-eslint-

      - name: Prettier
        run: pnpm lint:prettier

      - name: StyleLint
        run: pnpm lint:stylelint

      - name: ESLint
        id: eslint
        run: pnpm lint-report:cached
        continue-on-error: true

      - name: Upload ESLint results
        if: always()
        uses: actions/upload-artifact@v7
        with:
          name: eslint-results
          path: eslint.results.json
          if-no-files-found: ignore
          retention-days: 7

      # Annotation happens in separate workflow (pr-reports.yml)
      # This allows annotations to work for fork PRs too

      - name: Fail if ESLint has errors
        if: steps.eslint.outcome == 'failure'
        run: |
          pnpm lintcached
          exit 1

  build:
    runs-on: ubuntu-latest
    timeout-minutes: 30
    environment:
      name: pr
      url: ${{ steps.deploy-url.outputs.url }}
    steps:
      - uses: actions/checkout@v6

      # Inline setup - required for fork PR compatibility
      - uses: pnpm/action-setup@v5

      - name: Setup Node
        uses: actions/setup-node@v6
        with:
          node-version-file: '.nvmrc'
          cache: pnpm

      - name: Install dependencies
        run: pnpm install --frozen-lockfile --prefer-offline

      - name: Get package version
        id: package-version
        uses: martinbeentjes/npm-get-version-action@v1.3.1

      - name: Set version
        run: |
          echo "VERSION=${{ steps.package-version.outputs.current-version }}.${{ github.run_number }}" >> $GITHUB_ENV

      - name: Build PR version
        run: pnpm build:pr
        env:
          NODE_OPTIONS: "--max_old_space_size=8192"
          WEB_API_KEY: ${{ secrets.BUNGIE_API_KEY }}
          WEB_OAUTH_CLIENT_ID: ${{ secrets.OAUTH_CLIENT_ID }}
          WEB_OAUTH_CLIENT_SECRET: ${{ secrets.OAUTH_SECRET }}
          DIM_API_KEY: ${{ secrets.DIM_API_KEY }}
          PUBLIC_PATH: /${{ github.event.number }}/

      - name: Check for build pipeline updates
        id: filter
        uses: dorny/paths-filter@v4
        with:
          filters: |
            build-pipeline:
              - package.json
              - pnpm-lock.yaml
              - config/webpack.ts
              - babel.config.cjs

      - name: Upload webpack stats
        if: steps.filter.outputs.build-pipeline == 'true'
        uses: actions/upload-artifact@v7
        with:
          name: webpack-stats
          path: webpack-stats.json
          retention-days: 1

      - name: Install SSH key
        if: ${{ github.event.pull_request.head.repo.full_name == github.repository && github.actor != 'dependabot[bot]' }}
        uses: benoitchantre/setup-ssh-authentication-action@1.0.1
        with:
          private-key: ${{ secrets.SSH_KEY }}
          private-key-name: dim.rsa
          known-hosts: ${{ secrets.REMOTE_HOST }}

      - name: Check Syntax
        if: ${{ github.event.pull_request.head.repo.full_name == github.repository && github.actor != 'dependabot[bot]' }}
        run: pnpm syntax

      - name: Deploy to preview
        if: ${{ github.event.pull_request.head.repo.full_name == github.repository && github.actor != 'dependabot[bot]' }}
        run: ./build/rsync-deploy.sh
        env:
          SSH_PRIVATE_KEY: ${{ secrets.SSH_KEY }}
          SOURCE: "dist/"
          REMOTE_USER: ${{ secrets.REMOTE_USER }}
          REMOTE_HOST: ${{ secrets.REMOTE_HOST }}
          REMOTE_PATH: pr.destinyitemmanager.com/${{ github.event.number }}

      - name: Purge CloudFlare cache
        if: ${{ github.event.pull_request.head.repo.full_name == github.repository && github.actor != 'dependabot[bot]' }}
        run: ./build/purge-cloudflare.sh
        env:
          CLOUDFLARE_KEY: ${{ secrets.CLOUDFLARE_KEY }}
          CLOUDFLARE_EMAIL: ${{ secrets.CLOUDFLARE_EMAIL }}
          APP_DOMAIN: pr.destinyitemmanager.com/${{ github.event.number }}

      - name: Set preview URL
        if: ${{ github.event.pull_request.head.repo.full_name == github.repository && github.actor != 'dependabot[bot]' }}
        id: deploy-url
        run: |
          echo "url=https://pr.dim.gg/${{ github.event.number }}/" >> $GITHUB_OUTPUT

================================================
FILE: .gitignore
================================================
dist/
.settings/
.idea/
node_modules/
coverage/
*.DS_Store
config/dim_travis.rsa
cert.pem
key.pem
ca.crt
ca.key
.brackets.json
npm-debug.log
yarn-error.log
.eslintcache
manifest-cache
Heap.*
eslint_report.json
webpack-stats.json
webpack-stats.json.br
junit.xml
eslint.results.json
.pnpm-store
/sonda-report.html
sonda-report/
.claude/

================================================
FILE: .gitmodules
================================================
[submodule "destiny-icons"]
	path = destiny-icons
	url = https://github.com/justrealmilk/destiny-icons
	branch = master

================================================
FILE: .husky/pre-commit
================================================
node_modules/.bin/lint-staged


================================================
FILE: .npmrc
================================================
# Tells pnpm to use a shell emulator that works the same on macOS, linux, and Windows
shell-emulator=true


================================================
FILE: .nvmrc
================================================
24

================================================
FILE: .prettierignore
================================================
Gruntfile.js
tools/
dist/
extension/
*.md
*.yml
*.m.scss.d.ts
src/data/**

================================================
FILE: .prettierrc
================================================
{
  "printWidth": 100,
  "singleQuote": true,
  "plugins": ["prettier-plugin-organize-imports"]
}


================================================
FILE: .stylelintrc
================================================
{
  "plugins": [
    "stylelint-order"
  ],
  "extends": [
    "stylelint-config-standard-scss",
    "stylelint-config-css-modules"
  ],
  "rules": {
    "alpha-value-notation": "number",
    "shorthand-property-no-redundant-values": null,
    "rule-empty-line-before": null,
    "value-keyword-case": null,
    "comment-empty-line-before": null,
    "scss/double-slash-comment-empty-line-before": null,
    "scss/dollar-variable-empty-line-before": null,
    "scss/comment-no-empty": null,
    "function-name-case": null,
    "function-calc-no-unspaced-operator": null,
    "media-feature-range-notation": null,
    "declaration-empty-line-before": null,
    "custom-property-empty-line-before": null,
    "scss/no-global-function-names": null,
    "scss/operator-no-newline-after": null,
    "color-function-notation": "legacy",
    "at-rule-no-unknown": null,
    "scss/at-rule-no-unknown": true,
    "media-feature-name-no-unknown": null,
    "selector-not-notation": null,
    "selector-pseudo-class-no-unknown": [
      true,
      {
        "ignorePseudoClasses": [
          "horizontal",
          "global"
        ]
      }
    ],
    "hue-degree-notation": "number",
    "selector-id-pattern": "(^[a-z][a-zA-Z0-9]+$|^([a-z][a-z0-9]*)(-[a-z0-9]+)*$)",
    "selector-class-pattern": "(^[a-z][a-zA-Z0-9]+$|^([a-z][a-z0-9]*)(-[A-Za-z0-9]+)*$)",
    "scss/dollar-variable-pattern": "(^[a-z][a-zA-Z0-9]+$|^([a-z][a-z0-9]*)(-[a-z0-9]+)*$)",
    "value-no-vendor-prefix": [
      true,
      {
        "ignoreValues": [
          "box"
        ]
      }
    ],
    "color-no-invalid-hex": true,
    "unit-no-unknown": true,
    "no-duplicate-selectors": true,
    "declaration-block-no-duplicate-properties": [
      true,
      {
        "ignore": [
          "consecutive-duplicates-with-different-values"
        ]
      }
    ],
    "declaration-block-no-redundant-longhand-properties": [
      true,
      {
        "ignoreShorthands": [
          "/grid-template/"
        ]
      }
    ],
    "scss/function-no-unknown": [
      true,
      {
        "ignoreFunctions": "/^dim-([a-z][a-z0-9]*)(-[a-z0-9]+)*$/"
      }
    ],
    "scss/at-function-pattern": [
      "^dim-([a-z][a-z0-9]*)(-[a-z0-9]+)*$",
      {
        "message": "Expected function name to be kebab-case and prefixed with 'dim-'"
      }
    ],
    "scss/load-partial-extension": null,
    "order/order": [
      "custom-properties",
      "dollar-variables",
      "declarations",
      {
        "type": "at-rule",
        "name": "include",
        "hasBlock": false
      },
      {
        "type": "at-rule",
        "name": "include",
        "hasBlock": true
      },
      {
        "type": "at-rule"
      },
      "rules"
    ],
    "declaration-block-no-shorthand-property-overrides": true
  }
}

================================================
FILE: .svgo.yml
================================================
plugins:
  - name: preset-default
    params:
      overrides:
        removeViewBox: false

================================================
FILE: .vscode/css.json
================================================
{
  "version": 1.1,
  "properties": [
    {
      "name": "composes",
      "description": "css modules compose"
    }
  ],
  "atDirectives": [
    {
      "name": "@value",
      "description": "css modules value import"
    }
  ],
  "pseudoClasses": [],
  "pseudoElements": []
}


================================================
FILE: .vscode/dim.code-snippets
================================================
{
  // Place your global snippets here. Each snippet is defined under a snippet name and has a scope, prefix, body and
  // description. Add comma separated ids of the languages where the snippet is applicable in the scope field. If scope
  // is left empty or omitted, the snippet gets applied to all languages. The prefix is what is
  // used to trigger the snippet and the body will be expanded and inserted. Possible variables are:
  // $1, $2 for tab stops, $0 for the final cursor position, and ${1:label}, ${2:another} for placeholders.
  // Placeholders with the same ids are connected.
  // Example:
  // "Print to console": {
  // 	"scope": "javascript,typescript",
  // 	"prefix": "log",
  // 	"body": [
  // 		"console.log('$1');",
  // 		"$2"
  // 	],
  // 	"description": "Log output to console"
  // }
  "SFC Component": {
    "prefix": "sfc",
    "body": [
      "export default function ${1:ClassName}({",
      "}: {",
      "}) {",
      "\treturn (",
      "\t\t$0",
      "\t);",
      "}",
      "",
    ],
    "description": "TypeScript Stateless Functional Component",
    "scope": "javascriptreact,typescriptreact",
  },

  "import i18next": {
    "prefix": "imt",
    "body": ["import { t } from 'app/i18next-t';"],
    "description": "Import t helper from i18next",
    "scope": "javascriptreact,typescriptreact",
  },

  "import clsx": {
    "prefix": "imc",
    "body": ["import clsx from 'clsx';"],
    "description": "Import clsx",
    "scope": "javascriptreact,typescriptreact",
  },

  "import styles": {
    "prefix": "ims",
    "body": ["import * as styles from './$TM_FILENAME_BASE.m.scss';"],
    "description": "Import CSS module",
    "scope": "javascriptreact,typescriptreact",
  },
}


================================================
FILE: .vscode/extensions.json
================================================
{
  // See http://go.microsoft.com/fwlink/?LinkId=827846
  // for the documentation about the extensions.json format
  "recommendations": [
    // Extension identifier format: ${publisher}.${name}. Example: vscode.csharp
    "Jacano.vscode-pnpm",
    "esbenp.prettier-vscode",
    "streetsidesoftware.code-spell-checker",
    "dbaeumer.vscode-eslint",
    "orta.vscode-jest",
    "stylelint.vscode-stylelint",
    "amodio.tsl-problem-matcher",
    "timonwong.shellcheck",
    "github.vscode-github-actions"
  ]
}


================================================
FILE: .vscode/launch.json
================================================
{
  // Use IntelliSense to learn about possible attributes.
  // Hover to view descriptions of existing attributes.
  // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
  "version": "0.2.0",
  "configurations": [
    {
      "type": "chrome",
      "request": "launch",
      "preLaunchTask": "start",
      "name": "Launch Chrome against localhost",
      "url": "https://localhost:8080/",
      "webRoot": "${workspaceFolder}"
    },
    {
      "type": "node",
      "request": "launch",
      "name": "Jest All",
      "program": "${workspaceFolder}/node_modules/.bin/jest",
      "args": ["--runInBand"],
      "console": "integratedTerminal",
      "internalConsoleOptions": "neverOpen",
      "disableOptimisticBPs": true,
      "windows": {
        "program": "${workspaceFolder}/node_modules/jest/bin/jest"
      }
    },
    {
      "type": "node",
      "request": "launch",
      "name": "Jest Current File",
      "program": "${workspaceFolder}/node_modules/.bin/jest",
      "args": ["${fileBasenameNoExtension}", "--config", "jest.config.js"],
      "console": "integratedTerminal",
      "internalConsoleOptions": "neverOpen",
      "disableOptimisticBPs": true,
      "windows": {
        "program": "${workspaceFolder}/node_modules/jest/bin/jest"
      }
    }
  ]
}


================================================
FILE: .vscode/settings.json
================================================
{
  "editor.tabSize": 2,
  "editor.trimAutoWhitespace": true,
  "files.trimTrailingWhitespace": true,
  "typescript.tsdk": "./node_modules/typescript/lib",
  "typescript.enablePromptUseWorkspaceTsdk": true,
  "editor.formatOnSave": true,
  "jest.runMode": "on-demand",
  "editor.defaultFormatter": "esbenp.prettier-vscode",
  "eslint.validate": ["javascript", "javascriptreact", "typescript", "typescriptreact"],
  "search.exclude": {
    "**/data/d1/manifests": true,
    "src/testing/data": true,
    "destiny-icons": true,
    "manifest-cache": true
  },
  "files.readonlyInclude": {
    "node_modules/**": true,
    "src/data/**": true,
    "destiny-icons/**": true,
    "src/locale/*": true,
    "**/*.m.scss.d.ts": true
  },
  "editor.codeActionsOnSave": {
    "source.fixAll": "explicit"
  },
  // "jest.jestCommandLine": "NODE_ENV=test LOCAL_MANIFEST=true npx jest --verbose",
  "[javascript]": {
    "editor.codeActionsOnSave": {
      "source.organizeImports": "never"
    }
  },
  "[typescript]": {
    "editor.codeActionsOnSave": {
      "source.organizeImports": "never"
    }
  },
  "[typescriptreact]": {
    "editor.codeActionsOnSave": {
      "source.organizeImports": "never"
    }
  },
  "cSpell.enabledLanguageIds": [
    "jsonc",
    "json",
    "markdown",
    "javascript",
    "scss",
    "typescript",
    "typescriptreact",
    "yaml"
  ],
  "css.customData": ["./.vscode/custom.css-data.json"],
  "css.validate": false,
  "scss.validate": false,
  "stylelint.validate": ["css", "scss"],
  "explorer.fileNesting.enabled": true,
  "explorer.fileNesting.expand": false,
  "explorer.fileNesting.patterns": {
    "*.ts": "${capture}.js, ${capture}.test.ts",
    "*.js": "${capture}.js.map, ${capture}.min.js, ${capture}.d.ts, ${capture}.test.js",
    "*.jsx": "${capture}.js, ${capture}.test.js",
    "*.tsx": "${capture}.ts, ${capture}.test.ts",
    "*.m.scss": "${capture}.m.scss.d.ts",
    "tsconfig.json": "tsconfig.*.json",
    "package.json": "package-lock.json, pnpm-lock.yaml"
  },
  "eslint.lintTask.options": "src",
  "[javascript][typescript][typescriptreact]": {
    "editor.codeActionsOnSave": {
      "source.organizeImports": "never"
    }
  }
}


================================================
FILE: .vscode/tasks.json
================================================
{
  // See https://go.microsoft.com/fwlink/?LinkId=733558
  // for the documentation about the tasks.json format
  "version": "2.0.0",
  "tasks": [
    {
      "label": "start",
      "type": "shell",
      "command": "pnpm",
      "args": ["start"],
      "isBackground": true,
      "problemMatcher": ["$ts-checker-webpack", "$ts-checker-eslint-webpack"]
    }
  ]
}


================================================
FILE: LICENSE.md
================================================
MIT License

Copyright (c) 2018 Destiny Item Manager

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.


================================================
FILE: README.md
================================================
[![Crowdin](https://badges.crowdin.net/destiny-item-manager/localized.svg)](https://crowdin.com/project/destiny-item-manager)
[![OpenCollective](https://opencollective.com/dim/backers/badge.svg)](#backers)
[![OpenCollective](https://opencollective.com/dim/sponsors/badge.svg)](#sponsors)

### [Launch DIM](https://app.destinyitemmanager.com)

## Destiny Item Manager
Destiny Item Manager (DIM) lets [Destiny](http://destinythegame.com/) game players easily move items between their Guardians and the Vault. DIM's goal is to let players equip their guardians quickly. Our Loadouts feature accomplishes this by removing manual steps needed when transferring items.

Loadouts give players the ability to define sets of items that they want on their Guardians. When a loadout is selected, DIM will move all of the items referenced by the Loadout to a Guardian. If the item was equipped by another guardian, the Loadouts feature will replace that item with a similar item, if possible, to allow the Loadout referenced item to be transferred. With a single click of a button, you can have a PVP, PVE, or Raid-ready guardian.

DIM is based on the same services used by the Destiny Companion app to move and equip items. DIM will not be able to dismantle any of your items.

Visit [Discord](https://discordapp.com/invite/UK2GWC7) for updates and more details.

## Bugs and feature requests
Have a bug or a feature request? Please first search for [existing and closed issues](https://github.com/DestinyItemManager/DIM/issues). If your problem or idea is not addressed yet, please open a new issue.

## Backers
[Support us](https://opencollective.com/dim#backer) with a one-time or monthly donation and help us continue our active development.

<a href="https://opencollective.com/dim/backer/0/website" target="_blank"><img src="https://opencollective.com/dim/backer/0/avatar.svg"></a>
<a href="https://opencollective.com/dim/backer/1/website" target="_blank"><img src="https://opencollective.com/dim/backer/1/avatar.svg"></a>
<a href="https://opencollective.com/dim/backer/2/website" target="_blank"><img src="https://opencollective.com/dim/backer/2/avatar.svg"></a>
<a href="https://opencollective.com/dim/backer/3/website" target="_blank"><img src="https://opencollective.com/dim/backer/3/avatar.svg"></a>
<a href="https://opencollective.com/dim/backer/4/website" target="_blank"><img src="https://opencollective.com/dim/backer/4/avatar.svg"></a>
<a href="https://opencollective.com/dim/backer/5/website" target="_blank"><img src="https://opencollective.com/dim/backer/5/avatar.svg"></a>
<a href="https://opencollective.com/dim/backer/6/website" target="_blank"><img src="https://opencollective.com/dim/backer/6/avatar.svg"></a>
<a href="https://opencollective.com/dim/backer/7/website" target="_blank"><img src="https://opencollective.com/dim/backer/7/avatar.svg"></a>
<a href="https://opencollective.com/dim/backer/8/website" target="_blank"><img src="https://opencollective.com/dim/backer/8/avatar.svg"></a>
<a href="https://opencollective.com/dim/backer/9/website" target="_blank"><img src="https://opencollective.com/dim/backer/9/avatar.svg"></a>
<a href="https://opencollective.com/dim/backer/10/website" target="_blank"><img src="https://opencollective.com/dim/backer/10/avatar.svg"></a>
<a href="https://opencollective.com/dim/backer/11/website" target="_blank"><img src="https://opencollective.com/dim/backer/11/avatar.svg"></a>
<a href="https://opencollective.com/dim/backer/12/website" target="_blank"><img src="https://opencollective.com/dim/backer/12/avatar.svg"></a>
<a href="https://opencollective.com/dim/backer/13/website" target="_blank"><img src="https://opencollective.com/dim/backer/13/avatar.svg"></a>
<a href="https://opencollective.com/dim/backer/14/website" target="_blank"><img src="https://opencollective.com/dim/backer/14/avatar.svg"></a>
<a href="https://opencollective.com/dim/backer/15/website" target="_blank"><img src="https://opencollective.com/dim/backer/15/avatar.svg"></a>
<a href="https://opencollective.com/dim/backer/16/website" target="_blank"><img src="https://opencollective.com/dim/backer/16/avatar.svg"></a>
<a href="https://opencollective.com/dim/backer/17/website" target="_blank"><img src="https://opencollective.com/dim/backer/17/avatar.svg"></a>
<a href="https://opencollective.com/dim/backer/18/website" target="_blank"><img src="https://opencollective.com/dim/backer/18/avatar.svg"></a>
<a href="https://opencollective.com/dim/backer/19/website" target="_blank"><img src="https://opencollective.com/dim/backer/19/avatar.svg"></a>
<a href="https://opencollective.com/dim/backer/20/website" target="_blank"><img src="https://opencollective.com/dim/backer/20/avatar.svg"></a>
<a href="https://opencollective.com/dim/backer/21/website" target="_blank"><img src="https://opencollective.com/dim/backer/21/avatar.svg"></a>
<a href="https://opencollective.com/dim/backer/22/website" target="_blank"><img src="https://opencollective.com/dim/backer/22/avatar.svg"></a>
<a href="https://opencollective.com/dim/backer/23/website" target="_blank"><img src="https://opencollective.com/dim/backer/23/avatar.svg"></a>
<a href="https://opencollective.com/dim/backer/24/website" target="_blank"><img src="https://opencollective.com/dim/backer/24/avatar.svg"></a>
<a href="https://opencollective.com/dim/backer/25/website" target="_blank"><img src="https://opencollective.com/dim/backer/25/avatar.svg"></a>
<a href="https://opencollective.com/dim/backer/26/website" target="_blank"><img src="https://opencollective.com/dim/backer/26/avatar.svg"></a>
<a href="https://opencollective.com/dim/backer/27/website" target="_blank"><img src="https://opencollective.com/dim/backer/27/avatar.svg"></a>
<a href="https://opencollective.com/dim/backer/28/website" target="_blank"><img src="https://opencollective.com/dim/backer/28/avatar.svg"></a>
<a href="https://opencollective.com/dim/backer/29/website" target="_blank"><img src="https://opencollective.com/dim/backer/29/avatar.svg"></a>
<a href="https://opencollective.com/dim/backer/30/website" target="_blank"><img src="https://opencollective.com/dim/backer/30/avatar.svg"></a>
<a href="https://opencollective.com/dim/backer/31/website" target="_blank"><img src="https://opencollective.com/dim/backer/31/avatar.svg"></a>
<a href="https://opencollective.com/dim/backer/32/website" target="_blank"><img src="https://opencollective.com/dim/backer/32/avatar.svg"></a>
<a href="https://opencollective.com/dim/backer/33/website" target="_blank"><img src="https://opencollective.com/dim/backer/33/avatar.svg"></a>
<a href="https://opencollective.com/dim/backer/34/website" target="_blank"><img src="https://opencollective.com/dim/backer/34/avatar.svg"></a>
<a href="https://opencollective.com/dim/backer/35/website" target="_blank"><img src="https://opencollective.com/dim/backer/35/avatar.svg"></a>
<a href="https://opencollective.com/dim/backer/36/website" target="_blank"><img src="https://opencollective.com/dim/backer/36/avatar.svg"></a>
<a href="https://opencollective.com/dim/backer/37/website" target="_blank"><img src="https://opencollective.com/dim/backer/37/avatar.svg"></a>
<a href="https://opencollective.com/dim/backer/38/website" target="_blank"><img src="https://opencollective.com/dim/backer/38/avatar.svg"></a>
<a href="https://opencollective.com/dim/backer/39/website" target="_blank"><img src="https://opencollective.com/dim/backer/39/avatar.svg"></a>
<a href="https://opencollective.com/dim/backer/40/website" target="_blank"><img src="https://opencollective.com/dim/backer/40/avatar.svg"></a>
<a href="https://opencollective.com/dim/backer/41/website" target="_blank"><img src="https://opencollective.com/dim/backer/41/avatar.svg"></a>
<a href="https://opencollective.com/dim/backer/42/website" target="_blank"><img src="https://opencollective.com/dim/backer/42/avatar.svg"></a>
<a href="https://opencollective.com/dim/backer/43/website" target="_blank"><img src="https://opencollective.com/dim/backer/43/avatar.svg"></a>
<a href="https://opencollective.com/dim/backer/44/website" target="_blank"><img src="https://opencollective.com/dim/backer/44/avatar.svg"></a>
<a href="https://opencollective.com/dim/backer/45/website" target="_blank"><img src="https://opencollective.com/dim/backer/45/avatar.svg"></a>
<a href="https://opencollective.com/dim/backer/46/website" target="_blank"><img src="https://opencollective.com/dim/backer/46/avatar.svg"></a>
<a href="https://opencollective.com/dim/backer/47/website" target="_blank"><img src="https://opencollective.com/dim/backer/47/avatar.svg"></a>
<a href="https://opencollective.com/dim/backer/48/website" target="_blank"><img src="https://opencollective.com/dim/backer/48/avatar.svg"></a>
<a href="https://opencollective.com/dim/backer/49/website" target="_blank"><img src="https://opencollective.com/dim/backer/49/avatar.svg"></a>
<a href="https://opencollective.com/dim/backer/50/website" target="_blank"><img src="https://opencollective.com/dim/backer/50/avatar.svg"></a>
<a href="https://opencollective.com/dim/backer/51/website" target="_blank"><img src="https://opencollective.com/dim/backer/51/avatar.svg"></a>
<a href="https://opencollective.com/dim/backer/52/website" target="_blank"><img src="https://opencollective.com/dim/backer/52/avatar.svg"></a>
<a href="https://opencollective.com/dim/backer/53/website" target="_blank"><img src="https://opencollective.com/dim/backer/53/avatar.svg"></a>
<a href="https://opencollective.com/dim/backer/54/website" target="_blank"><img src="https://opencollective.com/dim/backer/54/avatar.svg"></a>
<a href="https://opencollective.com/dim/backer/55/website" target="_blank"><img src="https://opencollective.com/dim/backer/55/avatar.svg"></a>
<a href="https://opencollective.com/dim/backer/56/website" target="_blank"><img src="https://opencollective.com/dim/backer/56/avatar.svg"></a>
<a href="https://opencollective.com/dim/backer/57/website" target="_blank"><img src="https://opencollective.com/dim/backer/57/avatar.svg"></a>
<a href="https://opencollective.com/dim/backer/58/website" target="_blank"><img src="https://opencollective.com/dim/backer/58/avatar.svg"></a>
<a href="https://opencollective.com/dim/backer/59/website" target="_blank"><img src="https://opencollective.com/dim/backer/59/avatar.svg"></a>
<a href="https://opencollective.com/dim/backer/60/website" target="_blank"><img src="https://opencollective.com/dim/backer/60/avatar.svg"></a>

## Sponsors
Become a sponsor and get your logo here with a link to your site.

<a href="https://opencollective.com/dim/sponsor/0/website" target="_blank"><img src="https://opencollective.com/dim/sponsor/0/avatar.svg"></a>
<a href="https://opencollective.com/dim/sponsor/1/website" target="_blank"><img src="https://opencollective.com/dim/sponsor/1/avatar.svg"></a>
<a href="https://opencollective.com/dim/sponsor/2/website" target="_blank"><img src="https://opencollective.com/dim/sponsor/2/avatar.svg"></a>
<a href="https://opencollective.com/dim/sponsor/3/website" target="_blank"><img src="https://opencollective.com/dim/sponsor/3/avatar.svg"></a>

## Translation
If you speak a language other than English that Destiny supports, a great way to help with DIM development is to provide translations. See [translation guide](https://github.com/DestinyItemManager/DIM/blob/master/docs/TRANSLATIONS.md) for more info on how to help.

## Contributing

See [CONTRIBUTING.md](https://github.com/DestinyItemManager/DIM/blob/master/docs/CONTRIBUTING.md) for information on how to Contribute to the development of DIM.

## License
Code released under the [MIT license](http://choosealicense.com/licenses/mit/).


================================================
FILE: babel.config.cjs
================================================
const coreJSPackage = require('core-js/package.json');

module.exports = function (api) {
  const isProduction = api.env('production');
  const isTest = api.env('test');
  const plugins = [
    // Statically optimize away clsx functions
    'babel-plugin-optimize-clsx',
    // Improve performance by turning large objects into JSON.parse
    'object-to-json-parse',
    [
      '@babel/plugin-transform-runtime',
      {
        useESModules: !isTest,
      },
    ],
  ];

  if (isProduction) {
    plugins.push(
      // Optimize React components at the cost of some memory by automatically
      // factoring out constant/inline JSX fragments
      '@babel/plugin-transform-react-constant-elements',
      // This transform is not compatible with React 19
      // '@babel/plugin-transform-react-inline-elements',
    );
  } else {
    if (!isTest) {
      plugins.push('react-refresh/babel');
    }

    // In dev, compile TS with babel
    plugins.push(['@babel/plugin-transform-typescript', { isTSX: true, optimizeConstEnums: true }]);
  }

  const corejs = { version: coreJSPackage.version };

  const presetEnvOptions = {
    bugfixes: true,
    modules: false,
    loose: true,
    useBuiltIns: 'usage',
    corejs,
    shippedProposals: true,
    // Set to true and run `pnpm build:beta` to see what plugins and polyfills are being used
    debug: false,
    // corejs includes a bunch of polyfills for behavior we don't use or bugs we don't care about
    exclude: [
      // Really edge-case bugfix for Array.prototype.push and friends
      'es.array.push',
      'es.array.unshift',
      // This fixes an obscure Webkit bug that we don't care about
      'es.map.group-by',
      // Remove this if we start using proposed set methods like .intersection
      /^es(next)?\.set/,
      // Remove this if we start using iterator-helpers (which would be nice!)
      /^es(next)?\.iterator\.(?!concat)/,
      // Not sure what exactly this is, but we have our own error-cause stuff
      'es.error.cause',
      // Only used when customizing JSON parsing w/ a "reviver"
      'esnext.json.parse',
      // Edge-case bugfixes for URLSearchParams.prototype.has, delete, and size
      /^web\.url-search-params/,
      // Unneeded mis-detected DOMException extension
      'web.dom-exception.stack',
      // Not needed in worker context
      'web.self',
      // Mis-detected by usage of Array.prototype.at
      'es.string.at-alternative',
      // We're not doing weird stuff with structured clone
      'web.structured-clone',
    ],
  };

  if (isTest) {
    presetEnvOptions.targets = { node: 'current' };
    presetEnvOptions.modules = 'auto';
  }

  return {
    presets: [
      ['@babel/preset-env', presetEnvOptions],
      [
        '@babel/preset-react',
        {
          useBuiltIns: true,
          loose: true,
          corejs,
          runtime: 'automatic',
          useSpread: true,
        },
      ],
    ],
    plugins,
    // https://babeljs.io/docs/en/assumptions
    assumptions: {
      noDocumentAll: true,
      noClassCalls: true,
      setPublicClassFields: true,
      setSpreadProperties: true,
    },
  };
};


================================================
FILE: build/deploy-prod.sh
================================================
#!/bin/sh -exu

git config --global user.email "destinyitemmanager@gmail.com"
git config --global user.name "DIM Release Bot"

if [ "$PATCH" = 'true' ]; then
  VERSION=$(npm version patch --no-git-tag-version | sed 's/v//')
else
  VERSION=$(npm version minor --no-git-tag-version | sed 's/v//')
fi

awk '/## Next/{flag=1;next}/##/{flag=0}flag' docs/CHANGELOG.md >release-notes.txt

# update changelog
OPENSPAN='\<span class="changelog-date"\>'
CLOSESPAN='\<\/span\>'
DATE=$(TZ="America/Los_Angeles" date +"%Y-%m-%d")
perl -i'' -pe"s/^## Next/## Next\n\n## $VERSION $OPENSPAN($DATE)$CLOSESPAN/" docs/CHANGELOG.md

# Add these other changes to the version commit
git add -u
git commit -m"$VERSION"
git tag "v$VERSION"

# build and check
VERSION=$VERSION pnpm build:release
pnpm syntax

# rsync the files onto the remote host using SSH keys
./build/rsync-deploy.sh

# push tags and changes
git push --tags origin master:master

# publish a release on GitHub
gh release create "v$VERSION" -F release-notes.txt -t "$VERSION"


================================================
FILE: build/purge-cloudflare.sh
================================================
#!/bin/bash -eux

set -o pipefail

# Set variables CLOUDFLARE_EMAIL, CLOUDFLARE_KEY, and APP_DOMAIN

# Purge the cache in CloudFlare for long-lived files
curl -X POST "https://api.cloudflare.com/client/v4/zones/2c34c69276ed0f6eb2b9e1518fe56f74/purge_cache" \
    -H "X-Auth-Email: $CLOUDFLARE_EMAIL" \
    -H "X-Auth-Key: $CLOUDFLARE_KEY" \
    -H "Content-Type: application/json" \
    --data '{"files":["https://'"$APP_DOMAIN"'", "https://'"$APP_DOMAIN"'/index.html", "https://'"$APP_DOMAIN"'/version.json", "https://'"$APP_DOMAIN"'/service-worker.js", "https://'"$APP_DOMAIN"'/return.html", "https://'"$APP_DOMAIN"'/.well-known/assetlinks.json", "https://'"$APP_DOMAIN"'/.well-known/apple-app-site-association", "https://'"$APP_DOMAIN"'/manifest-webapp.json"]}'


================================================
FILE: build/rsync-deploy.sh
================================================
#!/bin/sh -exu

REMOTE_SHELL="ssh -i ~/.ssh/dim.rsa -o StrictHostKeyChecking=no"

# Sync everything but the HTML first, so it's ready to go
rsync dist/ "$REMOTE_USER"@"$REMOTE_HOST":"$REMOTE_PATH" --rsh "$REMOTE_SHELL" --recursive --exclude=*.html --exclude=*.html.br --exclude=service-worker.js --exclude=service-worker.js.br --exclude=version.json --exclude=version.json.br --verbose

# Then sync the HTML which will start using the new content
rsync dist/*.html dist/*.html.br dist/service-worker.js dist/service-worker.js.br dist/version.json dist/version.json.br "$REMOTE_USER"@"$REMOTE_HOST":"$REMOTE_PATH" --rsh "$REMOTE_SHELL" --verbose


================================================
FILE: build/test-changelog.js
================================================
#!/usr/bin/env node

// Simple test for the changelog update logic
import { readFileSync, unlinkSync, writeFileSync } from 'fs';

// Test data - mock GitHub commits
const testCommits = [
  {
    id: 'abc123',
    message:
      'Fix bug in loadout optimizer\n\nChangelog: Fixed crash in Loadout Optimizer when using +Artifice option',
    author: { name: 'Test User' },
  },
  {
    id: 'def456',
    message:
      'Add new feature\n\nChangelog: Added tier-level pips to item icons\nChangelog: Fixed some engrams not looking like engrams',
    author: { name: 'Test User' },
  },
  {
    id: 'ghi789',
    message: 'Regular commit without changelog entry',
    author: { name: 'Test User' },
  },
];

// Create test commits.json
writeFileSync('commits.json', JSON.stringify(testCommits, null, 2));

// Create a test changelog
const testChangelog = `## Next

* DIMmit is back, for all your changelog notifications.

## 8.82.2 <span class="changelog-date">(2025-07-22)</span>

* Fix an item inspection crash in D1.

## 8.82.1 <span class="changelog-date">(2025-07-21)</span>

* Some other changes here.`;

// Backup the original changelog
const originalChangelog = readFileSync('docs/CHANGELOG.md', 'utf8');
writeFileSync('docs/CHANGELOG.md.backup', originalChangelog);

// Write test changelog
writeFileSync('docs/CHANGELOG.md', testChangelog);

console.log('Running changelog update test...');

// Import and run the main script
try {
  // Since we can't easily import the other script, let's just test the expected behavior
  console.log('Test commits:');
  testCommits.forEach((commit) => {
    console.log(`  - ${commit.id}: ${commit.message.split('\n')[0]}`);
  });

  console.log('\nExpected changelog entries to be extracted:');
  const expectedEntries = [
    'Fixed crash in Loadout Optimizer when using +Artifice option',
    'Added tier-level pips to item icons',
    'Fixed some engrams not looking like engrams',
  ];
  expectedEntries.forEach((entry) => {
    console.log(`  * ${entry}`);
  });

  console.log('\nTest setup complete. You can now run:');
  console.log("  echo './commits.json' | node build/update-changelog.js");
  console.log('  # or:');
  console.log('  cat commits.json | node build/update-changelog.js');
  console.log('\nTo restore original changelog:');
  console.log('  mv docs/CHANGELOG.md.backup docs/CHANGELOG.md');
} catch (error) {
  console.error('Test failed:', error.message);
} finally {
  // Restore original changelog
  writeFileSync('docs/CHANGELOG.md', originalChangelog);
  // Clean up test files
  try {
    unlinkSync('commits.json');
    unlinkSync('docs/CHANGELOG.md.backup');
  } catch (e) {
    // Ignore cleanup errors
  }
}


================================================
FILE: build/update-changelog.js
================================================
#!/usr/bin/env node

import { readFileSync } from 'fs';
import { dirname, join } from 'path';
import { fileURLToPath } from 'url';

const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename);

// GitHub API functions
async function fetchCommitFromAPI(owner, repo, sha, token) {
  const url = `https://api.github.com/repos/${owner}/${repo}/commits/${sha}`;
  const response = await fetch(url, {
    headers: {
      Accept: 'application/vnd.github+json',
      Authorization: `Bearer ${token}`,
      'X-GitHub-Api-Version': '2022-11-28',
      'User-Agent': 'DIM-Changelog-Updater',
    },
  });

  if (!response.ok) {
    throw new Error(`Failed to fetch commit ${sha}: ${response.status} ${response.statusText}`);
  }

  return await response.json();
}

async function fetchAssociatedPRsFromGraphQL(owner, repo, sha, token) {
  const query = `
    query associatedPRs($sha: String!, $repo: String!, $owner: String!) {
      repository(name: $repo, owner: $owner) {
        commit: object(expression: $sha) {
          ... on Commit {
            associatedPullRequests(first: 5) {
              edges {
                node {
                  title
                  number
                  body
                  merged
                }
              }
            }
          }
        }
      }
    }
  `;

  const variables = { sha, repo, owner };

  const response = await fetch('https://api.github.com/graphql', {
    method: 'POST',
    headers: {
      Authorization: `Bearer ${token}`,
      'Content-Type': 'application/json',
      'User-Agent': 'DIM-Changelog-Updater',
    },
    body: JSON.stringify({ query, variables }),
  });

  if (!response.ok) {
    throw new Error(`GraphQL request failed: ${response.status} ${response.statusText}`);
  }

  const result = await response.json();

  if (result.errors) {
    throw new Error(`GraphQL errors: ${JSON.stringify(result.errors)}`);
  }

  // Extract the PRs from the GraphQL response
  const commit = result.data?.repository?.commit;
  if (!commit?.associatedPullRequests?.edges) {
    return [];
  }

  return commit.associatedPullRequests.edges.map((edge) => edge.node).filter((pr) => pr.merged); // Only return merged PRs
}

function extractChangelogEntries(commits) {
  const entries = [];

  if (!Array.isArray(commits)) {
    console.error('Commits is not an array:', typeof commits);
    return entries;
  }

  for (const commit of commits) {
    if (!commit || typeof commit.commit?.message !== 'string') {
      console.error('Invalid commit object:', commit);
      continue;
    }

    // Use the full commit message from the API response
    const message = commit.commit.message;
    const lines = message.split('\n');

    for (const line of lines) {
      const trimmedLine = line.trim();
      if (trimmedLine.toLowerCase().startsWith('changelog:')) {
        // Extract text after "Changelog:" and trim whitespace
        const changelogText = trimmedLine.substring(10).trim();
        if (changelogText) {
          entries.push(changelogText);
        }
      }
    }
  }

  return entries;
}

function extractChangelogEntriesFromText(text, source = 'unknown') {
  const entries = [];

  if (typeof text !== 'string') {
    console.error(`Invalid text from ${source}:`, typeof text);
    return entries;
  }

  const lines = text.split('\n');

  for (const line of lines) {
    const trimmedLine = line.trim();
    if (trimmedLine.toLowerCase().startsWith('changelog:')) {
      // Extract text after "Changelog:" and trim whitespace
      const changelogText = trimmedLine.substring(10).trim();
      if (changelogText) {
        console.error(`Found changelog entry from ${source}: ${changelogText}`);
        entries.push(changelogText);
      }
    }
  }

  return entries;
}

function updateChangelog(entries, originalChangelog) {
  if (entries.length === 0) {
    // No entries to add, return original content unchanged
    return originalChangelog;
  }

  // Find the "## Next" section
  const nextSectionRegex = /^## Next\s*$/m;
  const nextMatch = originalChangelog.match(nextSectionRegex);

  if (!nextMatch) {
    console.error('Could not find "## Next" section in CHANGELOG.md');
    process.exit(1);
  }

  // Find the position after the "## Next" line
  const nextSectionIndex = nextMatch.index + nextMatch[0].length;

  // Look for the next section (next "##" header) or end of file
  const afterNextSection = originalChangelog.substring(nextSectionIndex);
  const nextHeaderMatch = afterNextSection.match(/^## /m);

  let insertPosition;
  let existingContent = '';

  if (nextHeaderMatch) {
    // There's another section after "## Next"
    const nextHeaderIndex = nextSectionIndex + nextHeaderMatch.index;
    existingContent = originalChangelog.substring(nextSectionIndex, nextHeaderIndex).trim();
    insertPosition = nextHeaderIndex;
  } else {
    // "## Next" is the last section
    existingContent = originalChangelog.substring(nextSectionIndex).trim();
    insertPosition = originalChangelog.length;
  }

  // Format new entries as bullet points
  const newEntries = entries.map((entry) => `* ${entry}`).join('\n');

  // Build the new content for the "## Next" section
  let newNextContent = '';
  if (existingContent) {
    // Preserve existing content and add new entries
    newNextContent = `\n${existingContent}\n${newEntries}\n\n`;
  } else {
    // No existing content, just add new entries
    newNextContent = `\n${newEntries}\n\n`;
  }

  // Construct the new changelog content
  const newChangelogContent =
    originalChangelog.substring(0, nextSectionIndex) +
    newNextContent +
    originalChangelog.substring(insertPosition);

  return newChangelogContent;
}

async function fetchCommitsFromAPI(commitShas, githubToken, githubRepository) {
  const [owner, repo] = githubRepository.split('/');
  const commits = [];

  for (const sha of commitShas) {
    if (sha.trim()) {
      try {
        const commit = await fetchCommitFromAPI(owner, repo, sha.trim(), githubToken);
        commits.push(commit);
        console.error(
          `Fetched commit ${sha.substring(0, 7)}: ${commit.commit.message.split('\n')[0]}`,
        );
      } catch (error) {
        console.error(`Failed to fetch commit ${sha}: ${error.message}`);
      }
    }
  }

  return commits;
}

async function main() {
  try {
    // Get commit SHAs from command line arguments
    const commitShas = process.argv.slice(2);

    if (commitShas.length === 0) {
      console.error('No commit SHAs provided');
      process.exit(1);
    }

    // Get GitHub token and repository from environment
    const githubToken = process.env.GITHUB_TOKEN;
    const githubRepository = process.env.GITHUB_REPOSITORY;

    if (!githubToken) {
      console.error('GITHUB_TOKEN environment variable is required');
      process.exit(1);
    }

    if (!githubRepository) {
      console.error('GITHUB_REPOSITORY environment variable is required');
      process.exit(1);
    }

    const [owner, repo] = githubRepository.split('/');

    console.error(`Processing ${commitShas.length} commit SHAs...`);

    // Fetch commits from GitHub API
    const commits = await fetchCommitsFromAPI(commitShas, githubToken, githubRepository);

    console.error(`Successfully fetched ${commits.length} commits`);

    // Extract changelog entries from commit messages
    let changelogEntries = extractChangelogEntries(commits);

    // For each commit, check for associated PRs using GraphQL
    const processedPRs = new Set(); // Avoid duplicate PR processing

    for (const sha of commitShas) {
      if (sha.trim()) {
        try {
          console.error(`Checking for associated PRs for commit ${sha.substring(0, 7)}...`);
          const associatedPRs = await fetchAssociatedPRsFromGraphQL(
            owner,
            repo,
            sha.trim(),
            githubToken,
          );

          for (const pr of associatedPRs) {
            // Only process each PR once
            if (!processedPRs.has(pr.number)) {
              processedPRs.add(pr.number);
              console.error(`Found associated PR #${pr.number}: ${pr.title}`);

              const prEntries = extractChangelogEntriesFromText(pr.body || '', `PR #${pr.number}`);
              changelogEntries = changelogEntries.concat(prEntries);
            }
          }
        } catch (error) {
          console.error(`Failed to fetch associated PRs for commit ${sha}: ${error.message}`);
        }
      }
    }

    console.error(`Processed ${processedPRs.size} unique associated PRs`);

    // Read the current changelog
    const changelogPath = join(__dirname, '..', 'docs', 'CHANGELOG.md');
    let changelog = readFileSync(changelogPath, 'utf8');

    // Update the changelog content
    if (changelogEntries.length > 0) {
      changelog = updateChangelog(changelogEntries, changelog);
    }

    // Output the updated changelog to stdout
    process.stdout.write(changelog);

    console.error(`Successfully processed ${changelogEntries.length} changelog entries:`);
    changelogEntries.forEach((entry) => console.error(`  * ${entry}`));
  } catch (error) {
    console.error('Error processing commits:', error.message);
    process.exit(1);
  }
}

main();


================================================
FILE: config/.well-known/android-config.beta.json
================================================
[
  {
    "relation": [
      "delegate_permission/common.handle_all_urls"
    ],
    "target": {
      "namespace": "android_app",
      "package_name": "com.destinyitemmanager.beta.twa",
      "sha256_cert_fingerprints": [
        "2C:73:F4:D4:FB:D3:48:87:73:D0:34:54:82:D8:4F:32:0E:F7:37:71:23:6C:F1:4E:AC:0F:7A:83:71:E5:11:55"
      ]
    }
  }
]

================================================
FILE: config/.well-known/android-config.json
================================================
[
  {
    "relation": [
      "delegate_permission/common.handle_all_urls"
    ],
    "target": {
      "namespace": "android_app",
      "package_name": "com.destinyitemmanager.app",
      "sha256_cert_fingerprints": [
        "48:9B:BD:A6:8F:4C:DE:F3:35:83:2F:4B:3A:BC:85:0A:F1:D8:FE:6D:62:E7:53:83:B5:E1:86:11:89:50:E4:B6",
        "E8:7B:18:E2:6E:24:12:1C:A3:D3:3D:1A:C2:7C:39:3A:D9:9B:33:95:8D:42:AD:79:B7:80:F5:24:05:69:F1:7D",
        "1E:4C:58:AD:FF:D6:3A:E1:BD:89:C1:39:46:8C:1B:C0:06:19:0A:EE:67:0D:BB:85:F3:DE:1E:3D:6B:C6:DC:59",
        "B6:43:A6:AD:81:A3:42:E0:F5:39:D2:C8:AF:79:08:1A:4D:80:B5:85:B1:A3:95:37:0F:37:42:FE:BD:AE:AE:4A"
      ]
    }
  },
  {
    "relation": [
      "delegate_permission/common.handle_all_urls"
    ],
    "target": {
      "namespace": "android_app",
      "package_name": "gg.dim.app",
      "sha256_cert_fingerprints": [
        "45:1D:42:60:22:60:32:8B:71:61:99:28:EF:BE:D3:EC:19:D8:24:E0:B6:81:11:85:CA:24:68:C3:BF:74:A4:B5"
      ]
    }
  }
]

================================================
FILE: config/.well-known/apple-config.json
================================================
{
  "applinks": {
    "details": [
      {
        "appIDs": ["P7G764E7RR.com.destinyitemmanager.app"],
        "components": [
          {
            "#": "no_universal_links",
            "exclude": true,
            "comment": "Matches any URL with a fragment that equals no_universal_links and instructs the system not to open it as a universal link."
          },
          {
            "/": "*",
            "comment": "Matches any URL."
          }
        ]
      }
    ]
  }
}


================================================
FILE: config/content-security-policy.ts
================================================
import builder from 'content-security-policy-builder';
import { type FeatureFlags } from './feature-flags.ts';

const SELF = "'self'";

/**
 * Generate a Content Security Policy directive for a particular DIM environment (beta, release)
 */
export default function csp(
  env: 'release' | 'beta' | 'dev' | 'pr',
  featureFlags: FeatureFlags,
  version: string | undefined,
) {
  const baseCSP: Record<string, string[] | string | boolean> = {
    defaultSrc: ["'none'"],
    scriptSrc: [
      SELF,
      'https://*.googletagmanager.com',
      'https://*.google-analytics.com',
      // OpenCollective backers
      'https://opencollective.com',
    ],
    workerSrc: [SELF],
    styleSrc: [
      SELF,
      // For our inline styles
      "'unsafe-inline'",
      // Google Fonts
      'https://fonts.googleapis.com/',
    ],
    connectSrc: [
      SELF,
      // Google Analytics
      'https://*.google-analytics.com',
      'https://*.analytics.google.com',
      'https://*.googletagmanager.com',
      // Bungie.net API
      'https://www.bungie.net',
      // Sentry
      featureFlags.sentry && 'https://sentry.io/api/279673/',
      // Wishlists
      featureFlags.wishLists && 'https://raw.githubusercontent.com',
      featureFlags.wishLists && 'https://gist.githubusercontent.com',
      // DIM Sync
      'https://api.destinyitemmanager.com',
      // Clarity
      featureFlags.clarityDescriptions && 'https://database-clarity.github.io',
      // Stream Deck Plugin
      featureFlags.elgatoStreamDeck && 'ws://localhost:9120',
      featureFlags.elgatoStreamDeck && 'http://localhost:9120',
      // Game2Give
      featureFlags.issueBanner && 'https://bungiefoundation.donordrive.com',
    ].filter((s) => s !== false),
    imgSrc: [
      SELF,
      // Webpack inlines some images
      'data:',
      // Bungie.net images
      'https://www.bungie.net',
      // Google analytics tracking
      'https://*.google-analytics.com',
      'https://*.googletagmanager.com',
      // OpenCollective backers
      'https://opencollective.com',
    ],
    fontSrc: [
      SELF,
      'data:',
      // Google Fonts
      'https://fonts.gstatic.com',
    ],
    childSrc: [SELF],
    frameSrc: [
      // OpenCollective backers
      'https://opencollective.com',
      // Mastodon feed
      'https://www.mastofeed.com/apiv2/feed',
    ],
    prefetchSrc: [SELF],
    objectSrc: SELF,
    // Web app manifest
    manifestSrc: SELF,
  };

  // Turn on CSP reporting to sentry.io on beta only
  if (featureFlags.sentry && env === 'beta') {
    baseCSP.reportUri = `https://sentry.io/api/279673/csp-report/?sentry_key=1367619d45da481b8148dd345c1a1330&sentry_environment=${env}`;
    if (version) {
      baseCSP.reportUri += `&sentry_release=${version}`;
    }
  }

  return builder({
    directives: baseCSP,
  });
}


================================================
FILE: config/cspell/bungie-dict.txt
================================================
+s
bnet
Bungie
Calus
cooldown
Crota*
crownofsorrow
cryptarchs
daito
España
Eververse
exlusive
Felwinter*
fotl
Fynch
Gahlran
gardenofsalvation
Gjallarhorn
grimoire
Hadium
hakke
Ikora
infusable*
Intrinsics
Italiano
Karn
LFR*
mechanica
México
Mida
Nessus
omolon
PGCR
Português
Rahool
reforgeable
Shaxx
suros
Ticuu
Tyra
Variks
vaultofglass
veist
vowofthedisciple
wotm
wrathofthemachine
Xur
Zavala
Русский
Telesto
Neomuna


================================================
FILE: config/cspell/dim-dict.txt
================================================
ARGH
bois
curations
dedupe
deduping
deduplicating
dequip
dequipped
dequipping
dequips
DIM
DTR
dupelower
elgato
equippability
equippable
favorited
hashta
holofoil
ICHs
indimloadout
iningameloadout
inleftchar
inloadout
inloadouts
inmiddlechar
inpostmaster
inrightchar
invault
itemname
itemtype
janky
lightgg
loadout
merch
misdetection
needsxp
notexample
notransfer
onwrongclass
reacquirable
recalc
recents
regen
reimplemented
Repurchasable
reqs
reusables
showxp
stackable
swappable
tshirt
unacquired
Uncollectible
unequip
unequippable
unequipped
unexclude
unfavorited
uninstanced
unselectable
untrack
untracked
wayyyyy
Xbox
xpcomplete
xpincomplete


================================================
FILE: config/cspell/dim-username-dict.txt
================================================
48klocs
bhollis
delphiactual
iihavetoes
JFLAY
lowlines
Mercules
pandapaxxy
tehdaw
vthorn


================================================
FILE: config/cspell/programming-dict.txt
================================================
asyncs
brotli
caniuse
canonicalization
canonicalize
ceaser
clsx
Cruver
destructurable
divs
Dont
falsyness
frecency
gstatic
immer
indexeddb
initi18n
Interp
keyi18n
KHTML
klass
lngs
Metadatas
mkcert
mkdir
msapplication
mstile
nums
oanimationend
Ofint32
Ofint64
onbeforeinstallprompt
onoffswitch
outl
pmmmwh
popperjs
rbpage
React's
reauth
rsync
Scroller
Spawnfx
SVGs
swipable
tappable
UniFFFD
unmount
unparse
upgradeiOS
uuidv4
vpadding
vxvy
wasm
xxhash


================================================
FILE: config/dim_travis.rsa.pub
================================================
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQCiwgjtkq2QrAjJnK2EYfbkSGYTLIaJfQ2ILZ79ntBIti2ZXIvagbabOjjiirfIJrtN2j4zT0/UExGsUwUZMVsHU04jeLlg9xNioRfRw1NrMz/cVR29W8nYKnkxQhdMjN8Ss7iOcYULZHoC1g77IeHLih79+t5Utc0dWU9CSHDQ4hFk7ImkWsLvnLw43PuzJ0/rhe1966o1H4kTsxGNs6GkjB2b/3EVyO6h5w6Y2AMQ/BHRR2/FHW8PFkH+UFJ1UfLVhfXG4dl5JQP57TGlIckB7pI9QkfV6f6lmmJlMDlnV+krfSJ4E7rLClU3V+KJlNLe/qFfmXiLIEyqAA+A7Uw0Zz5tc2v0AXjusZ+IweadZeApqS+jykU5ZvpGlPNpeTaA2T/D3lQ8DqNFV9YQ2NBIajexMEQpe0j777Va88mNVhOdcnpSfHwTuX+kQgfgmngiJ2YpXcI5G5ZyfGWgEug569XNw4d7CdO3iVEE3cS14XUSrA074B4g9rI/0Raew8q1L7tdaJwHtftkVP+vszM0b3CnkKGb9VLtecXHq7O6qOGNQnmDnN9zErFa2yG0RJtkfmfhf65NZsoCMJJjnYVsVQr135XKrQn9QAoxXR/4CKDwC3QLG4eEKVdljhCllA2xhWhOPOE9c0aVtjTphI21KKG3P0fAQgCzRa9mJSPtUw== brh@legion.local


================================================
FILE: config/feature-flags.ts
================================================
/**
 * Return a set of compile time feature flags. These values will be inlined into
 * the code at build time, based on the version of the app being built. This
 * will then allow Webpack/Terser to fully remove code if the feature flag is
 * off. We build features behind these feature flags so we can easily remove
 * them from the app, or keep them in beta/dev for a longer time without
 * releasing to app.
 */
export function makeFeatureFlags(env: {
  release: boolean;
  beta: boolean;
  dev: boolean;
  pr: boolean;
}) {
  return {
    // Print debug info to console about item moves
    debugMoves: !env.release,
    // Debug Service Worker
    debugSW: !env.release,
    // Send exception reports to Sentry.io on beta/prod only
    sentry: !env.dev && !env.pr,
    // Community-curated wish lists
    wishLists: true,
    // Show a banner for supporting a charitable cause
    issueBanner: false,
    // Show the triage tab in the item popup
    triage: true,
    // Advanced Write Actions (inserting mods)
    awa: process.env.USER === 'brh', // Only Ben has the keys...
    // Item feed sidebar
    itemFeed: true,
    // Clarity perk descriptions
    clarityDescriptions: true,
    // Elgato Stream Deck integration
    elgatoStreamDeck: true,
    // Warn when DIM Sync is off and you save some DIM-specific data
    warnNoSync: true,
    // Expose the "Automatically add stat mods" Loadout Optimizer toggle
    loAutoStatMods: true,
    // Pretend that Bungie.net is down for maintenance
    simulateBungieMaintenance: false,
    // Pretend that Bungie.net is not returning sockets info
    simulateMissingSockets: false,
    // Request the PresentationNodes component only needed during
    // Solstice to associate each character with a set of triumphs.
    // Solstice 2022 had a set of challenges for each character,
    // while Solstice 2023 had shared progress/challenges, so maybe
    // this won't be needed going forward?
    solsticePresentationNodes: false,
    // not ready to turn these on but the code is there
    customStatWeights: false,
    // On the Loadouts page, run Loadout Optimizer to find better tiers for loadouts.
    runLoInBackground: true,
    // Whether to allow setting in-game loadout identifiers on DIM loadouts.
    editInGameLoadoutIdentifiers: false,
    // Whether to sync DIM API data instead of loading everything
    dimApiSync: true,
    // Whether to show the "New Items" dot
    newItems: false,
  };
}

export type FeatureFlags = ReturnType<typeof makeFeatureFlags>;


================================================
FILE: config/i18n.json
================================================
{
  "AWA": {
    "ConfirmDescription": "Please use the Destiny 2 Companion App to approve DIM to modify your items.",
    "ConfirmTitle": "Confirm Action",
    "Error": "Error changing mods or perks",
    "ErrorMessage": "We couldn't equip {{plug}} into {{item}}.\n\n{{error}}",
    "FailedToken": "Couldn't get permission to change item",
    "IrreversiblePlugging": "You don't own {{plug}}, so we won't overwrite it.",
    "NotSupported": "We cannot change this type of mod or perk"
  },
  "Accounts": {
    "Choose": "Profiles for {{bungieName}}",
    "Title": "Accounts",
    "NoCharacters": "You have no Destiny characters associated with this Bungie.net account. Try logging into a different account.",
    "ErrorLoading": "Unable to load Destiny accounts from Bungie.net",
    "MissingAccountWarning": "If you don't see your account here, you may not have logged in to the right Bungie.net account, or Bungie.net may be down for maintenance.",
    "MissingTitle": "Account Not Found",
    "MissingDescription": "The account you're trying to view is not an account linked to your Bungie.net profile. Select one of your accounts below.",
    "ErrorLoadInventory": "Unable to load your Destiny {{version}} characters and inventory",
    "ErrorLoadManifest": "Unable to load Destiny info database from Bungie",
    "SwitchAccounts": "You can switch accounts later from the menu in the header.",
    "NoCharactersTitle": "No Characters Found"
  },
  "Activities": {
    "Activities": "Activities",
    "Hard": "Hard",
    "Nightfall": "Nightfall Strike",
    "Normal": "Normal",
    "WeeklyHeroic": "Weekly Heroic Strike"
  },
  "Armory": {
    "AlternateItems": "Alternate Versions",
    "Armory": "Armory",
    "DifferentSeason": "Reissue from a different season",
    "OpenInArmory": "view in Armory",
    "WishlistedRolls_one": "Wishlisted Roll",
    "WishlistedRolls_other": "{{count, number}} Wishlisted Rolls",
    "TrashlistedRolls_one": "Trashlisted Roll",
    "TrashlistedRolls_other": "{{count, number}} Trashlisted Rolls",
    "NoNotes": "No Notes",
    "YourItems": "Your Items",
    "Unknown": "Unknown Item",
    "Season": "Season {{season}}, Year {{year}}",
    "UnknownPerkHash": "The perk hash {{hash}} ({{perkName}}) does not appear on this item, so this wish list roll is invalid. Please contact the wish list author to correct this. Note that wish lists should always specify the non-enhanced version of perks."
  },
  "Browsercheck": {
    "Unsupported": "The DIM team does not support using this browser. Some or all DIM features may not work.",
    "Steam": "The Steam overlay browser is very old and some or all DIM features may not work. We cannot provide support for it.",
    "Samsung": "Samsung Internet can make sites look too dark when dark mode is on. Enable Settings > Labs > Use website dark theme or switch to another browser."
  },
  "Bucket": {
    "Armor": "Armor",
    "Class": "Subclass",
    "General": "General",
    "Ghost": "Ghost",
    "Inventory": "Inventory",
    "Postmaster": "Postmaster",
    "Progress": "Progress",
    "Reputation": "Reputation",
    "Unknown": "Unknown",
    "Vault": "Vault",
    "Weapons": "Weapons"
  },
  "BulkNote": {
    "Title_one": "Change notes for 1 item",
    "Title_other": "Change notes for {{count}} items",
    "Replace": "Replace notes",
    "Append": "Append to notes / add #hashtags",
    "Remove": "Remove from notes / remove #hashtags",
    "Confirm": "Update Notes"
  },
  "BungieAlert": {
    "Title": "A message from Bungie:"
  },
  "BungieService": {
    "AppNotPermitted": "DIM does not have permission to perform this action.",
    "DestinyLegacyPlatform": "Bungie's services currently have a bug that prevents DIM from loading info for your Destiny 2 account if you played Destiny 1 on a last-gen console. Bungie will fix this soon, but until then you must play Destiny 1 on a current-gen console to be able to access your info.",
    "DevVersion": "Are you running a development version of DIM? You must register your chrome extension with Bungie.net.",
    "Difficulties": "Bungie.net is currently experiencing difficulties.",
    "ErrorTitle": "Bungie.net Error",
    "ItemUniquenessExplanation": "A character can only have one of '{{name}}' on it.",
    "Maintenance": "Bungie.net servers are down for maintenance.",
    "MissingInventory": "Bungie.net did not return your inventory, possibly because your privacy settings prevent it. Try logging out and logging back in.",
    "DestinyCannotPerformActionAtThisLocation": "You cannot equip items or change mods while in an activity. Try heading to orbit or a social area. This is a limitation of the Bungie.net API, not DIM.",
    "DestinyItemUnequippable": "You cannot equip this item. If this character's last activity locked their equipment, try logging into the character again.",
    "NetworkError": "Network error - {{status}} {{statusText}}",
    "NoAccount": "No Destiny account was found. Do you have the right platform selected?",
    "NoAccountForPlatform": "Failed to find a Destiny account for you on {{platform}}.",
    "NotConnected": "You may not be connected to the internet.",
    "NotConnectedOrBlocked": "You may not be connected to the internet, or an ad blocking or privacy extension may be blocking Bungie.net.",
    "NotLoggedIn": "Please authorize DIM in order to use this app.",
    "SlowResponse": "Bungie.net was too slow to respond.",
    "Slow": "Bungie.net is slow right now",
    "SlowDetails": "Bungie.net is taking a long time to return your information. This can happen when a lot of players are in the game at once, or if Bungie.net is having issues. You also might be having an internet connection issue. We'll keep waiting for a response.",
    "Throttled": "Bungie.net is limiting how many requests DIM can make.",
    "Twitter": "Get status updates on:",
    "UnknownError": "Bungie.net message: {{message}}",
    "VendorNotFound": "Vendor data is unavailable."
  },
  "Compare": {
    "NoModArmor": "Pre-mods",
    "Button": "Compare",
    "Archetype": "Archetype",
    "ButtonHelp": "Compare Items",
    "CompareBaseStats": "Show Base Stats",
    "BaseStatsDescription": "Base stats, without Masterwork or Mods",
    "AssumeMasterworked": "Assume Masterworked",
    "AssumeMasterworkedDescription": "Stats if fully Masterworked, without current Mods",
    "CurrentStats": "Current Stats",
    "CurrentStatsDescription": "Current stats, including Mods and Masterwork level",
    "InitialItem": "This is the item the Compare tool was launched from",
    "IsVendorItem": "This item is not in your inventory, but {{vendorName}} sells it.",
    "Error": {
      "Unmatched": "This item doesn't match the type of items being compared.",
      "Invalid": "There are no valid items for comparison."
    }
  },
  "Cooldown": {
    "Grenade": "Grenade cooldown: {{cooldown}}",
    "Melee": "Melee cooldown: {{cooldown}}",
    "Super": "Super cooldown: {{cooldown}}"
  },
  "Countdown": {
    "Days_one": "1 Day",
    "Days_compact_one": "{{count}}d",
    "Days_compact_other": "{{count}}d",
    "Days_other": "{{count}} Days"
  },
  "Csv": {
    "EmptyFile": "There were no rows in the file.",
    "ImportConfirm": "Are you sure you want to import tags/notes from CSV? This will overwrite tags/notes for all items contained in your spreadsheet.",
    "ImportFailed": "Failed to import tags/notes from CSV: {{error}}",
    "ImportSuccess_one": "Tags/notes loaded for one item.",
    "ImportSuccess_other": "Tags/notes loaded for {{count}} items.",
    "ImportWrongFileType": "File is not a CSV file.",
    "WrongFields": "CSV must have 'Id', 'Notes', 'Tag', and 'Hash' columns."
  },
  "Dialog": {
    "Cancel": "Cancel",
    "OK": "OK"
  },
  "EnergyMeter": {
    "Energy": "Energy",
    "Used": "Used",
    "Unused": "Unused",
    "UpgradeNeeded": "This item's current energy capacity is {{energyCapacity}}. To fit the selected mods, its energy capacity must be {{energyUsed}}."
  },
  "ErrorBoundary": {
    "Title": "Something went wrong"
  },
  "ErrorPanel": {
    "BrowserTooOldTitle": "Incompatible browser",
    "BrowserTooOld": "Your browser is too old to use DIM. Please update your browser to the latest version.",
    "Description": "Try loading your inventory in the Destiny 2 Companion App to see if Bungie.net is down.",
    "Troubleshooting": "Troubleshooting Guide",
    "SystemDown": "This affects all Destiny apps, and the DIM team cannot fix or bypass it.",
    "ReadTheGuide": "Read our User Guide (linked from the menu) for troubleshooting steps."
  },
  "FarmingMode": {
    "Vault": "It will move items to the vault to make room.",
    "D2Desc_one": "DIM is preventing items from going to the Postmaster by making sure there's always one empty space per item type on {{store}}.",
    "D2Desc_female_one": "DIM is preventing items from going to the Postmaster by making sure there's always one empty space per item type on {{store}}.",
    "D2Desc_male_one": "DIM is preventing items from going to the Postmaster by making sure there's always one empty space per item type on {{store}}.",
    "D2Desc_other": "DIM is preventing items from going to the Postmaster by making sure there's always {{count}} empty spaces per item type on {{store}}.",
    "D2Desc_female_other": "DIM is preventing items from going to the Postmaster by making sure there's always {{count}} empty spaces per item type on {{store}}.",
    "D2Desc_male_other": "DIM is preventing items from going to the Postmaster by making sure there's always {{count}} empty spaces per item type on {{store}}.",
    "Desc_one": "DIM is moving Engram and Glimmer items from {{store}} to the vault and keeping one empty space open per item type to prevent anything from going to the Postmaster.",
    "Desc_female_one": "DIM is moving Engram and Glimmer items from {{store}} to the vault and keeping one empty space open per item type to prevent anything from going to the Postmaster.",
    "Desc_male_one": "DIM is moving Engram and Glimmer items from {{store}} to the vault and keeping one empty space open per item type to prevent anything from going to the Postmaster.",
    "Desc_other": "DIM is moving Engram and Glimmer items from {{store}} to the vault and keeping {{count}} spaces open per item type to prevent anything from going to the Postmaster.",
    "Desc_female_other": "DIM is moving Engram and Glimmer items from {{store}} to the vault and keeping {{count}} spaces open per item type to prevent anything from going to the Postmaster.",
    "Desc_male_other": "DIM is moving Engram and Glimmer items from {{store}} to the vault and keeping {{count}} spaces open per item type to prevent anything from going to the Postmaster.",
    "FarmingMode": "Farming Mode",
    "FarmingModeNote": "(maintain space for drops)",
    "MakeRoom": {
      "Desc": "DIM is moving only Engram and Glimmer items from {{store}} to the vault or other characters to prevent anything from going to the Postmaster.",
      "Desc_female": "DIM is moving only Engram and Glimmer items from {{store}} to the vault or other characters to prevent anything from going to the Postmaster.",
      "Desc_male": "DIM is moving only Engram and Glimmer items from {{store}} to the vault or other characters to prevent anything from going to the Postmaster.",
      "MakeRoom": "Make room to pick up items by moving equipment",
      "Tooltip": "If checked, DIM will move weapons and armor around to make space in the vault for engrams."
    },
    "OutOfRoom": "You're out of space to move items off of {{character}}. Time to clear out the trash!",
    "OutOfRoomTitle": "Out of Room",
    "Stop": "Stop"
  },
  "FashionDrawer": {
    "Accept": "Save fashion",
    "CannotFitOrnament": "This item does not have an ornament socket or you have no ornaments for it.",
    "CannotFitShader": "This item cannot fit a shader",
    "ClearOrnaments": "Clear Ornaments",
    "ClearOrnamentsTitle": "Reset all ornaments to \"no preference\"",
    "ClearShaders": "Clear Shaders",
    "ClearShadersTitle": "Reset all shaders to \"no preference\"",
    "NoPreference": "No preference - this socket won't be changed",
    "Reset": "Clear fashion",
    "Sync": "Sync",
    "SyncOrnaments": "Sync Ornaments",
    "SyncOrnamentsTitle": "Use ornaments from the same set on all items, if they're unlocked",
    "SyncShaders": "Sync Shaders",
    "SyncShadersTitle": "Use the same shader on all items",
    "Title": "Choose shaders and ornaments",
    "UseEquipped": "Use equipped fashion"
  },
  "FileUpload": {
    "Instructions": "Click or drag files"
  },
  "LoadoutFilter": {
    "Contains": "Shows loadouts which have an item or a mod matching the filter text. Search for items with spaces in their name using quotes.",
    "Name": "Shows loadouts whose name matches (exactname:) or partially matches (name:) the filter text. Search for entire phrases using quotes.",
    "Notes": "Search for loadouts by their notes field.",
    "PartialMatch": "Shows loadouts where their name or notes has a partial match to the filter text. Search for entire phrases using quotes.",
    "Season": "Shows loadouts by which season of Destiny 2 they were last modified in.",
    "FashionOnly": "Shows loadouts that contain only fashion (shaders or ornaments).",
    "ModsOnly": "Shows loadouts that only contain armor mods.",
    "Subclass": "Shows loadouts whose subclass name or damage type partially matches the filter text.",
    "LoadoutLight": "Shows loadouts based on their calculated light level. Use the pinnaclecap or softcap keyword instead of a number to refer to the current season's power limits."
  },
  "Filter": {
    "Adept": "\\(Adept\\)",
    "AmmoType": "Shows items based on their ammo type.",
    "ArmorCategory": "Shows armors based on their category.",
    "ArmorIntrinsic": "Shows legendary armor which has an intrinsic perk, such as Artifice Armor.",
    "Artifice": "Shows Artifice armor.",
    "Ascended": "Shows items that have an ascend node which have been ascended.",
    "Unascended": "Shows items that have an ascend node which have not been ascended.",
    "Breaker": "Filter by breaker type or corresponding champion type. breaker:instrinsic shows items with intrinsic breaker ability.",
    "BulkClear_one": "Removed tag from 1 item.",
    "BulkClear_other": "Removed tags from {{count}} items.",
    "BulkRevert_one": "Reverted tag on 1 item.",
    "BulkRevert_other": "Reverted tags on {{count}} items.",
    "BulkTag_one": "Tagged selected item as {{tag}}.",
    "BulkTag_other": "Tagged {{count}} selected items as {{tag}}.",
    "Catalyst": "Shows catalysts based on their status. catalyst:complete shows catalysts you have completed and applied, catalyst:incomplete shows catalysts you have unlocked but either not completed the objective or applied the catalyst, and catalyst:missing shows items that can have a catalyst but you haven't found it yet.",
    "Class": "Shows items based on their class affinity.",
    "Combine": "Filters can be combined or grouped with parentheses, \"or\" and \"and\" to narrow down your search, for example \"{{example}}\".",
    "ContributePower": "Shows items that have power and can contribute to your power level.",
    "Craftable": "Shows items that are craftable.",
    "CraftedDupe": "Shows duplicate weapons where at least one of the duplicates is crafted.",
    "Curated": "Shows items that are a curated roll.",
    "CurrentClass": "Shows items that are equippable on the currently logged in guardian.",
    "DamageType": "Shows items based on their damage type.",
    "Deepsight": "Shows weapons with Deepsight Resonance, which can have their pattern extracted, or which can have Deepsight Resonance enabled using a Deepsight Harmonizer.",
    "Deprecated": "This filter is no longer supported.",
    "Description": "Description",
    "DescriptionFilter": "Shows items whose description has a partial match to the filter text. Search for entire phrases using quotes.",
    "RetiredPerk": "Shows weapons with perks that no longer obtainable.",
    "Dupe": "Shows duplicate items, including reissues",
    "DupeCount": "Items that have the specified number of duplicates.",
    "DupeLower": "Duplicate items, including reissues, that are not the highest power dupe. Only one duplicate is chosen as the highest, and the rest are considered lower.",
    "DupePerks": "Shows items whose perks are either a duplicate of, or a subset of, another item of the same type.",
    "DupeTraits": "Weapons whose traits are either a duplicate of, or a subset of, another weapon of the same type.",
    "DupeStats": "Shows armor with identical base stats, and matching stat adjustment mods like Artifice or Tuners.",
    "DupeUntunedStats": "Groups armor with identical base stats, ignoring stat adjustment mods.",
    "DupeTunedStat": "Groups armor with the same Tuned stat.",
    "DupeArchetype": "Groups armor with the same stat Archetype.",
    "DupeTertiary": "Groups armor with the same tertiary stat.",
    "DupeSetBonus": "Groups armor with the same set bonus.",
    "DupeZeroStats": "Groups armor with the same 3 non-zero base stats.",
    "Energy": "Shows items that use the Armor 2.0 mod system introduced in Shadowkeep.",
    "EnergyCapacity": "Shows items based on their current energy capacity.",
    "Armor3": "Shows items that use the Armor 3.0 stat system introduced in Edge of Fate.",
    "Engrams": "Shows engrams.",
    "Enhanceable": "Shows weapons that can be enhanced.",
    "Enhanced": "Shows weapons based on their enhancement tier.",
    "EnhancedPerk": "Shows weapons that have the specified number of enhanced perk columns.",
    "EnhancementReady": "Shows weapons that have reached level thresholds for perk enhancement.",
    "Equipment": "Items that can be equipped.",
    "Equipped": "Items that are currently equipped on a character.",
    "Event": "Shows items from which event in Destiny 2 they appeared in.",
    "ExtraPerk": "Shows random-rolled Legendary weapons with an additional selectable perk.",
    "Featured": "Items that count as one of the \"New Gear\" or \"Featured Items\" in the current season.",
    "Filter": "Filter",
    "FilterWith": "Filter with:",
    "Focusable": "Shows items that can be focused at a vendor",
    "Foundry": "Shows items by which foundry created them.",
    "Glimmer": "Shows items that are consumables that are related to gaining glimmer.",
    "Memento": "Shows weapons that have a memento socket.",
    "InfusionFodder": "Shows items that could be infused into lower-power versions of the same item for only glimmer.",
    "HasNotes": "Show items that have notes applied.",
    "HasShader": "Shows items that have a shader applied.",
    "HasOrnament": "Shows items that have an ornament applied.",
    "Harrowed": "\\(Harrowed\\)",
    "InLoadout": "is:inloadout shows items that are included in any loadout. Searching with inloadout: shows items that are included in loadouts with matching titles. When used with a hashtag, inloadout: shows items whose loadouts have the hashtag in the title or notes. When used with a range, it shows items that are in that many loadouts.",
    "InInGameLoadout": "is:iningameloadout shows items that are included in any in-game loadout.",
    "InDimLoadout": "is:indimloadout shows items that are included in any DIM loadout.",
    "Infusable": "Shows items that can be infused.",
    "IsAdept": "Shows weapons compatible with Adept mods.",
    "IsCrafted": "Shows weapons that have been crafted.",
    "ItemId": "Shows the item with the given inventory item ID. For advanced users.",
    "ItemHash": "Shows the items with the given inventory item hash. For advanced users.",
    "Leveling": {
      "Complete": "{{term}} - shows items that are totally complete - every upgrade unlocked.",
      "Incomplete": "{{term}} - shows items that are not complete - there's still at least one upgrade to unlock.",
      "NeedsXP": "{{term}} - shows items that can still have XP put into them.",
      "Upgraded": "{{term}} - shows items that have enough XP to unlock all their nodes, but not all the nodes have been unlocked.",
      "XPComplete": "{{term}} - shows items that cannot have XP put into them (whether or not their upgrades have been unlocked)."
    },
    "Location": "Shows items based on their location within the app. left/middle/right are the visual location of the char, and while inleftchar will always work, the other two are based on how many characters you have. current is your last/current logged char (that is marked with a yellow triangle).",
    "LockAllFailed": "Failed to lock items",
    "LockAllSuccess": "Locked {{num}} items",
    "Locked": "Shows items based on their locked status.",
    "Masterwork": "Shows items based on their masterwork stat or masterwork level.",
    "MasterworkKills": "Shows items based on their masterwork kill tracker count.",
    "MaxPowerLoadout": "Shows the items in the loadout that would maximize your Power Level for each character class.",
    "MaxPower": "Shows the items at the highest power per slot.",
    "Mods": {
      "Y3": "Shows items with any mods applied."
    },
    "DisabledModSlot": "Shows items with a disabled mod.",
    "ModSlot": "Shows armor with a specific mod type slot.",
    "Name": "Shows items whose name matches (exactname:) or partially matches (name:) the filter text. Search for entire phrases using quotes.",
    "NamedStat": "Shows armor that has points in the named stat.",
    "Negate": "To negate a search, prefix that search term with a minus sign or the word \"not\", for example \"{{notexample}}\" or \"{{notexample2}}\".",
    "NewItems": "Shows new items.",
    "Notes": "Search for items that you have tagged with custom notes.",
    "OriginTrait": "Shows weapons that have an origin trait perk.",
    "Ornament": "Shows items with ornaments and filters for their status.",
    "InInventory": "Shows items that you have at least one copy of in your inventory. Only really useful in the Vendors and Records screens.",
    "PartialMatch": "Shows items where their name, description, any perk, or any mod has a partial match to the filter text. Search for entire phrases using quotes.",
    "PatternUnlocked": "Shows items that have a crafting pattern unlocked, even if the item itself isn't crafted.",
    "Perk": "Shows items where one of their perks or mods has a partial match to the filter text in their name or description. Search for entire phrases using quotes.",
    "PerkName": "Shows items with a perk or mod whose name matches (exactperk:) or partially matches (perkname:) the filter text. Search for entire phrases using quotes.",
    "Postmaster": "Items that are currently in the Postmaster.",
    "PowerLevel": "Shows items based on their power level. $t(Filter.PowerKeywords)",
    "PowerKeywords": "Use the pinnaclecap or softcap keyword instead of a number to refer to the current season's power limits.",
    "PowerfulReward": "Shows pursuits which produce a powerful reward.",
    "PinnacleReward": "Shows pursuits which produce a pinnacle reward.",
    "PrismaticDamageType": "Shows items based on if they are a light or darkness damage type. Light types are arc, solar, and void. Darkness types are stasis and strand.",
    "Quality": "Shows items based on their total stat quality percentage. '{{percentage}}' is an alias for '{{quality}}'.",
    "RandomRoll": "Shows items that drop with random rolls.",
    "RarityTier": "Shows items based on their rarity tier.",
    "Reforgeable": "Shows items that can be reforged at the Gunsmith.",
    "Release": "Shows items available from a specific release or event.",
    "Holofoil": "Shows holofoil weapons.",
    "Weapon": "Shows items that are weapons.",
    "Armor": "Shows items that are armor.",
    "Cosmetic": "Shows items that are flair or cosmetic.",
    "RequiredLevel": "Shows items based on their required level.",
    "SearchPrompt": "Search available filter commands",
    "Season": "Shows items from which season of Destiny 2 they appeared in.",
    "StackLevel": "Shows items based on the quantity of items in its stack.",
    "Stackable": "Shows items that can stack (ammo synths, strange coin, etc)",
    "StackFull": "Show items which are at-capacity for their stack (Enhancement Cores, Strange Coins, Gunsmith Materials etc)",
    "StatLower": "Shows armor whose stats are strictly lower than another of the same type of armor.",
    "CustomStatLower": "Shows armor whose stats are strictly lower than another of the same type of armor, only taking into account stats that are in any of that class' custom stat total list.",
    "Stats": "Shows items based on a specific stat value. $t(Filter.StatsExtras)",
    "StatsBase": "Filters armor based on its base stat value, not including attached mods or masterworking. $t(Filter.StatsExtras)",
    "StatsExtras": "Supports stat addition by connecting multiple stat names with the + or & symbol.  There are also special keywords highest, secondhighest, thirdhighest, etc. which match stats based on their rank within an item's stats. Each custom stats also has its own search term, shown in the Custom Stats settings.",
    "StatsLoadout": "Finds a set of items to equip for the maximum total value of a specific stat.",
    "StatsOrdinal": "Finds armor 3.0 with the specified stat focusing.",
    "StatsMax": "Finds armor with the highest number for a specific stat. Includes all items with the highest stat.",
    "Tags": {
      "Tag": "Shows items that have a specific tag.",
      "Tagged": "Shows items that have any tag."
    },
    "Tier": "Shows items based on their tier from 0-5.",
    "Timelost": "\\(Timelost\\)",
    "Tracked": "Shows quests/bounties based on their tracked status.",
    "Transferable": "Items that can be moved between characters.",
    "Trashlist": "Shows items that match your wish list's trash list.",
    "TunedStat": "Shows items with tuning mods for the specified stat.",
    "Undo": "Undo",
    "UnlockAllFailed": "Failed to unlock items",
    "UnlockAllSuccess": "Unlocked {{num}} items",
    "Vendor": "Item is available from a specific vendor.",
    "VendorItem": "Item is from a vendor, not in your inventory. Useful for excluding vendor items from Loadout Optimizer.",
    "WeaponType": "Shows weapons based on their weapon type.",
    "WeaponLevel": "Shows weapons based on their Weapon Level.",
    "Wishlist": "Shows items that match your wish list.",
    "WishlistDupe": "Shows duplicate items where at least one of the duplicates is on your wish list.",
    "WishlistNotes": "Shows wish listed items whose notes match the search.",
    "WishlistUnknown": "Shows items with no roll recommendations in the loaded wish lists.",
    "WishlistEnabled": "Shows items that are eligible to have wish list rolls.",
    "Year": "Shows items from which year of Destiny they appeared in."
  },
  "General": {
    "ClickForDetails": "Click for details",
    "Confirm": "Confirm?",
    "UserGuideLink": "User guide",
    "Close": "Close"
  },
  "Glyphs": {
    "Missing": "Missing",
    "Axe": "Axe",
    "DarkAbility": "Darkness Ability",
    "LightAbility": "Light Ability",
    "Gilded": "Gilded",
    "Harmonic": "Harmonic",
    "HiveSword": "Hive Sword",
    "LightLevel": "Light Level",
    "Prismatic": "Prismatic",
    "RespawnRestricted": "Respawn Restricted",
    "Smoke": "Smoke",
    "Misadventure": "Misadventure",
    "Quickfall": "Quickfall",
    "ScorchCannon": "Scorch Cannon",
    "OpenSymbolsPicker": "Open Symbols Picker",
    "SearchSymbols": "Search Symbols..."
  },
  "Header": {
    "About": "About DIM",
    "AutoRefresh": "DIM will automatically reload as long as you are still playing.",
    "BulkTag": "Bulk tag items",
    "BungieNetAlert": "Bungie Alert",
    "Clear": "Clear search filter",
    "TagAs": "Tag as '{{tag}}'",
    "CompareMatching": "Compare Items",
    "DeleteSearch": "Delete Search",
    "FilterHelp": "Search item/perk, {{example}}, and more",
    "FilterHelpBrief": "Search items",
    "FilterHelpRecords": "Search triumphs and collections",
    "FilterHelpProgress": "Search milestones and bounties",
    "FilterHelpOptimizer": "Filter armor included in builds, e.g.: {{example}}",
    "FilterHelpLoadouts": "Search loadout names and notes",
    "FilterMatchCount_one": "1 item",
    "FilterMatchCount_other": "{{count}} items",
    "Filters": "Filters",
    "FilterHelpMenuItem": "Filters Help...",
    "LaunchDIMAlone": "Separate Window",
    "InstallDIM": "Install as an App",
    "InstallDIMBanner": "Install DIM as an app on your home screen",
    "Inventory": "Inventory",
    "IosPwaPrompt": "In Safari, click the share icon (middle button on the bottom) and select \"Add to Home Screen\".",
    "KeyboardShortcuts": "Keyboard Shortcuts",
    "MaterialCounts": "Material Counts",
    "Menu": "Menu",
    "ProfileAge": "Destiny servers last sent updated data {{age}} ago.\nRefreshing from DIM may get newer data, but Bungie.net may also repeat cached information.",
    "Refresh": "Refresh Destiny Data [R]",
    "ReloadApp": "Reload App",
    "ReportBug": "Report a Bug",
    "SaveSearch": "Save Search",
    "SearchResults": "Show Items",
    "SearchActions": "Open Search Actions",
    "Shop": "Shop",
    "UpgradeDIM": "Update DIM",
    "WhatsNew": "What's New"
  },
  "Help": {
    "CannotMove": "Cannot move that item off this character.",
    "NoStorage": "DIM can't store data",
    "NoStorageMessage": "DIM can't store data in your browser. This can be caused by browsing in private or incognito mode, or when you have low disk space, or a browser bug. Try restarting your computer! You won't be able to log in to or use DIM until you fix this."
  },
  "Hotkey": {
    "Armory": "Show Armory for an item",
    "CheatSheetTitle": "Keyboard Shortcuts:",
    "ClearDialog": "Dismiss dialog",
    "ClearNewItems": "Clear new items",
    "Enter": "ENTER",
    "ItemPopupTab": "Switch item details tab",
    "LockUnlock": "Lock or unlock an item",
    "MarkItemAs": "Mark item as '{{tag}}'",
    "Menu": "Toggle menu",
    "Note": "Enter notes",
    "Pull": "Pull item to active character",
    "RefreshInventory": "Refresh inventory",
    "ShowHotkeys": "Show keyboard shortcuts",
    "StartSearch": "Start a search",
    "StartSearchClear": "Start a fresh search",
    "Tab": "TAB",
    "Vault": "Send item to vault"
  },
  "Infusion": {
    "Filter": "Filter items",
    "InfuseSource": "Select item to infuse {{name}} into",
    "InfuseTarget": "Select item to infuse into {{name}}",
    "InfusionMaterials": "Infusion Materials",
    "NoItems": "No infusable items available.",
    "NoTransfer": "Transfer infusion material\n {{target}} cannot be moved.",
    "SwitchDirection": "Switch",
    "TransferItems": "Transfer"
  },
  "InGameLoadout": {
    "ClearSlot": "Clear Slot {{index}}",
    "Create": "Create Loadout",
    "CreateTitle": "Create In-Game Loadout From Current Equipment",
    "CurrentlyEquipped": "Currently Equipped",
    "PrepareEquip": "Prepare Equip",
    "EditIdentifiers": "Edit Identifiers",
    "EditTitle": "Edit Loadout Name and Icon",
    "EditFailed": "Failed to update loadout",
    "EquipReady": "In-game Equip Ready",
    "EquipNotReady": "In-game Equip Not Ready",
    "LoadoutDetails": "Loadout Details",
    "LoadoutSlotNum": "Slot {{index}}",
    "MatchingLoadouts": "Matching Loadouts:",
    "Deleted": "Loadout Deleted",
    "DeletedBody": "Cleared the in-game loadout at slot {{index}}",
    "DeleteFailed": "Failed to delete loadout",
    "Save": "Update Loadout",
    "SaveIdentifiers": "Update Identifiers",
    "SaveToDimLoadout": "Save as DIM Loadout",
    "Replace": "Replace Loadout {{index}}",
    "SnapshotFailed": "Failed to snapshot equipped loadout"
  },
  "Inventory": {
    "ClickToExpand": "(Click to expand)",
    "MissingSilver": "Your Silver balance is only available while you are playing the game."
  },
  "Item": {
    "ThumbsUp": "Thumbs Up",
    "ThumbsDown": "Thumbs Down",
    "SetBonus": {
      "NPiece_one": "{{count}} Piece",
      "NPiece_other": "{{count}} Piece"
    }
  },
  "ItemFeed": {
    "Description": "Item Feed",
    "HideTagged": "Hide Tagged",
    "ClearFeed": "Clear Feed",
    "ShowOlderItems": "Show older items",
    "NoNewItems": "No new items"
  },
  "ItemMove": {
    "Consolidate": "Consolidated {{name}}",
    "Distributed": "Distributed {{name}}\n {{name}} is now equally divided between characters.",
    "MovingItem": "Transfer to vault",
    "MovingItem_male": "Transfer to {{target}}",
    "MovingItem_female": "Transfer to {{target}}",
    "ToStore": "All {{name}} are now on your {{store}}.",
    "ToVault": "All {{name}} are now in your vault."
  },
  "ItemPicker": {
    "ChooseItem": "Choose an item:",
    "SearchPlaceholder": "Search items"
  },
  "ItemService": {
    "BucketFull": {
      "Guardian": "There are too many '{{itemtype}}' items on your {{store}}.",
      "Guardian_female": "There are too many '{{itemtype}}' items on your {{store}}.",
      "Guardian_male": "There are too many '{{itemtype}}' items on your {{store}}.",
      "Vault": "There are too many '{{itemtype}}' items in the {{store}}."
    },
    "Classified": "This item is classified and cannot be transferred at this time.",
    "Classified2": "Classified item. Bungie does not yet provide information about this item. Add notes to this item and use the \"notes:\" search filter to find it.",
    "Deequip": "Cannot find another item to equip in order to deequip {{itemname}}",
    "ExoticError": "'{{itemname}}' cannot be equipped because the exotic in the {{slot}} slot cannot be unequipped. ({{error}})",
    "NotEnoughRoom": "There's nothing we can move out of {{store}} to make room for {{itemname}}",
    "NotEnoughRoomGeneral": "There's not enough room to move this item.",
    "OnlyEquippedClassLevel": "This can only be equipped on a {{class}} at or above level {{level}}.",
    "OnlyEquippedLevel": "This can only be equipped on characters at or above level {{level}}.",
    "PostmasterAlmostFull": "Almost full!",
    "PostmasterFull": "Full!",
    "PreviewVendor": "Preview {{type}} contents",
    "StackFull": "You already have a full stack of {{name}}",
    "StoreName": "{{genderRace}} {{className}}"
  },
  "KillType": {
    "Melee": "Melee",
    "Super": "Super",
    "Grenade": "Grenade",
    "Finisher": "Finisher",
    "Precision": "Precision",
    "ClassAbilities": "Class Ability"
  },
  "PostmasterWarningBanner": {
    "PostmasterAlmostFull": "The postmaster is almost full! ({{number}}/{{postmasterSize}})",
    "PostmasterFull": "The postmaster is full! ({{number}}/{{postmasterSize}})"
  },
  "LB": {
    "AdvancedOptions": "Advanced Options",
    "ChooseAMod": "Choose your mods",
    "ChooseAnExotic": "Choose your exotic",
    "ChooseASetBonus": "Choose your set bonuses",
    "ClearLocked": "Clear Locked",
    "ContainsVendorItems": "This loadout contains vendor items",
    "Current": "Current",
    "Equip": "Equip on {{character}}",
    "Exclude": "Excluded Items",
    "ExcludeHelp": "Shift + click an item (or drag and drop into this bucket) to build sets without specific gear.",
    "ExistingBuildStats": "Existing Build Stats",
    "ExistingBuildStatsNote": "Only showing builds with strictly higher stats.",
    "FilterSets": "Filter sets",
    "Help": {
      "And": "Armor with all of these perks will be used (\"and\")",
      "ChangeNodes": "Change the Intellect, Discipline, or Strength nodes in game to what is displayed to create each loadout.",
      "Discipline": "Discipline speeds up Grenade recharge time",
      "DragAndDrop": "Drag and drop items into the locked buckets to build sets with only that gear",
      "Help": "Need help?",
      "HigherTiers": "Higher Tiers are better",
      "Intellect": "Intellect speeds up Super recharge time",
      "Lock": "Lock a set of perks by clicking a lock bucket and selecting perks",
      "MultiPerk": "To use armor with multiple perks together shift+click the desired perks",
      "NoPerk": "If a perk doesn't appear it means that you own no armor with that perk",
      "Or": "Armor with any of these perks will be used (\"or\")",
      "ShiftClick": "Shift click an item to build sets without that gear",
      "StatsIncrease": "As an items defense level increases, the stats on that item (int/dis/str) also increase.",
      "Strength": "Strength speeds up Melee recharge time",
      "Synergy": "Try to find armor that has ammo increasing perks for weapon types that you use.",
      "Tier11Example": "4/5/2 (a Tier 11 build) is 4 Intellect, 5 Discipline, 2 Strength (4+5+2 = Tier 11)"
    },
    "HideAllConfigs": "Hide all configurations",
    "HideConfigs": "Hide configurations",
    "IncompatibleWithOptimizer": "This item is incompatible with the Optimizer. Please reacquire a new version from Collections.",
    "LB": "Loadout Optimizer",
    "LightMode": {
      "HelpCurrent": "Calculates loadouts at current defense levels.",
      "HelpScaled": "Calculates loadouts as if all items were 350 defense.",
      "LightMode": "Light mode"
    },
    "Loading": "Loading best sets",
    "LockEquipped": "Lock Equipped",
    "LockPerk": "Lock perk",
    "Locked": "Locked Items",
    "LockedHelp": "Drag and drop any item into its bucket to build set with that specific gear. Shift + click to exclude items.",
    "Missing2": "Missing rare, legendary, or exotic pieces to build a full set!",
    "ProcessingMode": {
      "Fast": "Fast",
      "Full": "Full",
      "HelpFast": "Only looks at your best gear.",
      "HelpFull": "Looks at more gear, but takes longer.",
      "ProcessingMode": "Processing mode"
    },
    "Scaled": "Scaled",
    "SearchAMod": "Search for mod name or description",
    "SearchAnExotic": "Search for exotic name or description",
    "SelectModsCount": "{{selected}}/{{maxSelectable}}",
    "SelectModsCountActivityMods": "{{selected}}/{{maxSelectable}} Activity Mods",
    "SelectExotic": "Select exotic",
    "SelectMods": "Select Mods",
    "SelectSetBonus": "Select Set Bonuses",
    "AddStack": "Add another copy of this mod",
    "RemoveStack": "Remove a copy of this mod",
    "SelectSubclassOptions": "Customize subclass",
    "ShowAllConfigs": "Show all configurations",
    "ShowConfigs": "Show configurations",
    "ShowGear": "{{class}} Armor",
    "Vendor": "Include Vendor items"
  },
  "Loading": {
    "Code": "Loading DIM code...",
    "Profile": "Loading Destiny profile...",
    "Accounts": "Loading Destiny accounts...",
    "FilterHelp": "Loading search help...",
    "Vendors": "Loading Destiny vendors..."
  },
  "LoadoutBuilder": {
    "AutomaticallyPicked": "This mod was added automatically to improve build stats.",
    "AlwaysAutoMods": "Artifice and Tuning mods will always be chosen automatically.",
    "DisabledByAutoStatMods": "Stat mods are being chosen automatically by Loadout Optimizer.",
    "AutoStatMods": "Automatically add stat mods",
    "All": "All",
    "AnyExotic": "Any Exotic",
    "AnyExoticDescription": "Sets must contain an exotic, but any exotic will do.",
    "Artifice": "Artifice",
    "AssumeMasterwork": "Assume Masterwork",
    "AssumeMasterworkOptions": {
      "All": "All Armor: $t(LoadoutBuilder.AssumeMasterworkOptions.Masterworked)",
      "AllWithArtificeExotic": "All Armor: $t(LoadoutBuilder.AssumeMasterworkOptions.Masterworked)\nArmor 2.0 Exotics: $t(LoadoutBuilder.AssumeMasterworkOptions.ArtificeExotic)",
      "ArtificeExotic": "Enhanced to accept Artifice stat mods.",
      "Legendary": "Legendary: $t(LoadoutBuilder.AssumeMasterworkOptions.Masterworked)\nExotic: $t(LoadoutBuilder.AssumeMasterworkOptions.Current)",
      "None": "All armor: $t(LoadoutBuilder.AssumeMasterworkOptions.Current)",
      "Current": "Current stats, assumed energy level at least {{minLoItemEnergy}}.",
      "Masterworked": "Full masterwork stat bonuses, assumed energy level at least 10."
    },
    "ChooseAlternateTitle": "Choose another item",
    "CompareLoadout": "Compare Loadout",
    "ConfirmOverwrite": "Are you sure you want to replace the armor in the loadout \"{{name}}\" with this new set of armor?",
    "DisabledDueToMaintenance": "The Loadout Optimizer is currently disabled due to Bungie API maintenance.",
    "EquipItems": "Equip",
    "ExcludeItem": "Exclude Item",
    "ExcludedItems": "Excluded Items",
    "Exotic": "Exotic Armor",
    "MwExotic": "Exotic",
    "ExcludeVendors": "Search \"not:vendor\" to exclude vendor items from Loadout Optimizer.",
    "ExistingLoadout": "Existing Loadout",
    "FOTLWildcardWarning": "This set contains a Festival of the Lost mask. Manually apply the correct mod to activate desired set bonuses.",
    "ExoticClassItemPerks": "If you want specific perks, use searches like exactperk:\"spirit of verity\". Click perks in the Optimizer results to add or remove them from the item filter.",
    "ExoticSpecialCategory": "Special",
    "Filter": "Settings",
    "Legendary": "Legendary",
    "LockItem": "Pin item",
    "PinnedItems": "Pinned Items",
    "PinnedItemsFinePrint": "Search filters are saved with Loadout Optimizer settings, but pinned and excluded items are not. Pins and exclusions will be ignored when DIM checks existing Loadouts for better stat builds.",
    "MissingClass": "Build is for: {{className}}",
    "MissingClassDescription": "The build you're trying to view is for a character class you don't have.",
    "NoBuildsFoundExplainer": {
      "Header": "No builds were found. Here are possible reasons DIM couldn't find any builds:",
      "AlwaysInvalidMods": "These mods don't fit into any of your owned items:",
      "RemoveMods": "Remove these mods",
      "MaybeRemoveMods": "Consider removing some mods:",
      "AssumptionsRestricted": "DIM cannot recommend armor energy changes:",
      "AssumeMasterworked": "Allow DIM to recommend masterworking armor",
      "ActiveSearchQuery": "An active search query is restricting the items DIM can include in builds",
      "MaybeRemoveSearchQuery": "Consider clearing or changing the filter in the search bar",
      "ExoticDoesNotExist": "You don't have any of the selected exotic armor in your inventory.",
      "MaybeAllowMoreItems": "Consider allowing other items:",
      "BadSlot": "In the {{bucketName}} slot, none of the allowed items could accommodate these mods:",
      "LowerBoundsFailed": "Many sets did not meet minimum stat requirements",
      "ModAssignmentFailed": "Many sets could not accommodate all requested mods",
      "MaybeDecreaseLowerBounds": "Consider reducing minimum stat requirements",
      "AllowAutoStatMods": "Allow DIM to automatically include additional stat mods",
      "SetBonuses": "You have chosen some set bonuses, maybe you don't have the right items to use them.",
      "RemoveSetBonuses": "Consider removing some set bonuses"
    },
    "NoExotic": "No Exotic",
    "NoExoticDescription": "Equivalent to searching \"not:exotic\" in the search bar - sets will not use any exotic armor.",
    "NoExoticPreference": "No Exotic Selected",
    "NoExoticPreferenceDescription": "Exotic armor will be used if it maximizes stats.",
    "NoLoadoutsToCompare": "No loadouts to compare",
    "None": "None",
    "OptimizerExplanationStats": "Drag the most important stats to the top, and uncheck stats you don't want to maximize.",
    "OptimizerExplanationMods": "Choose an exotic, mods, and a subclass. These will contribute stats to the build, while any mods already on the armor are ignored.",
    "OptimizerExplanationSearch": "Use the search bar to narrow down which armor to consider, e.g. {{example}}. If no armor in a slot matches the search, all items will be considered for that slot.",
    "OptimizerExplanationGuide": "Read the User Guide for more info and a video tutorial.",
    "OptimizerSet": "Optimizer Set",
    "ProcessingSets": "Finding highest stat sets...",
    "SaveAs": "Save as",
    "SetBonus": "Set Bonuses",
    "SpeedReport": "Evaluated {{combos, number}} combinations in {{time}} seconds using {{cpus}} CPU cores.",
    "StatConstraints": "Stat Priorities & Ranges",
    "StatMax": "Max",
    "StatMin": "Min",
    "StatRangeTooltip": "With the current min/max setting, loadouts exist which have {{min}} to {{max}} points in this stat. Double-click to set min to {{max}}.",
    "StatTotal": "Total: {{total}}",
    "TierNumber": "T{{tier}}",
    "UnableToAddAllMods": "Unable to add all mods.",
    "UnableToAddAllModsBody": "There weren't enough mod slots available to fit {{mods}}.",
    "UnlockItem": "Unpin Item",
    "IncreaseStatPriority": "Increase stat priority",
    "DecreaseStatPriority": "Decrease stat priority",
    "IgnoreStat": "If unchecked, Loadout Optimizer will pretend this stat doesn't exist when building sets",
    "LimitToNewFeaturedGear": "Limit to new/featured gear"
  },
  "Loadouts": {
    "Abilities": "Abilities",
    "Actions": "Actions for {{title}}",
    "AddEquippedItems": "Add Equipped",
    "AddNotes": "Add Notes",
    "AddUnequippedItems": "Add Unequipped",
    "Any": "Any class",
    "ArmorStats": "Armor Stats",
    "ArtifactUnlocks": "Artifact Unlocks",
    "ArtifactUnlocksWithSeason": "Artifact Unlocks – S{{seasonNumber}}",
    "ArtifactUnlocksDesc": "Due to Bungie.net limitations, DIM cannot automatically configure your artifact. You need to perform these unlocks in-game before applying the Loadout.",
    "Apply": "Apply",
    "ApplySearch": "Transfer search \"{{query}}\"",
    "BadLoadoutShare": "Unable to load shared loadout",
    "BadLoadoutShareBody": "The loadout you're trying to load is invalid: {{error}}",
    "Before": "Before '{{name}}'",
    "CannotCustomizeSubclass": "This subclass cannot be configured",
    "ChooseItem": "Add {{name}}",
    "Classified": "Some of your items are classified, and cannot be included in the max power calculation.",
    "ClassType": "Any class loadout",
    "ClassType_male": "{{className}} loadout",
    "ClassType_female": "{{className}} loadout",
    "ClassTypeMismatch": "A {{className}} item cannot be added to this loadout",
    "ClassTypeMissing": "You do not have a {{className}} to create a loadout for",
    "ClearSection": "Remove all",
    "ClearLoadoutParameters": "Remove Loadout Optimizer settings",
    "ClearSpace": "Move others away",
    "ClearSpaceWeapons": "Move other weapons away",
    "ClearSpaceArmor": "Move other armor away",
    "ClearUnsetMods": "Remove other mods",
    "CopyAndEdit": "Edit Copy",
    "Create": "Create Loadout",
    "CurrentlyEquipped": "Currently Equipped",
    "Delete": "Delete",
    "DimLoadouts": "DIM Loadouts",
    "Edit": "Edit Loadout",
    "EditBrief": "Edit",
    "EquippableDifferent1": "Multiple Exotic items were used to calculate your Maximum Power, so the number shown may not be achievable when equipping your items in-game.",
    "EquippableDifferent2": "Maximum Power isn't limited by the \"One Exotic\" rule when determining the Power of your drops, powerful, and pinnacle rewards.",
    "Equipped": "Equipped",
    "Fashion": "Choose fashion",
    "FashionOnly": "Fashion-only",
    "ModsOnly": "Mods-only",
    "Filters": "Loadout Filters",
    "FilteredItems": "Filtered Items",
    "FindAnother": "Find another {{name}}",
    "FromEquipped": "Equipped",
    "Generated": "{{statTotal}} Stat Point Loadout",
    "HashtagTip": "Tip: Use #hashtags in your loadout names or notes and they'll show up here.",
    "ImportLoadout": "Import Loadout",
    "Import": {
      "PasteHere": "Paste a loadout link to open the loadout.",
      "BadURL": "Not a valid loadout share URL.",
      "Error404": "This loadout doesn't exist.",
      "Error": "Error getting loadout:"
    },
    "IncludeRuntimeStatBenefits": "Include Font mod stats",
    "IncludeRuntimeStatBenefitsDesc": "\"Font of ...\" armor mods provide a flat boost to character stats while you have Armor Charges.\n\nWith this setting, DIM considers these mods active and adds their benefits to this Loadout's stats in calculations and optimizations.",
    "InGameLoadouts": "In-Game Loadouts",
    "SetBonusesDesc": "Required set bonuses",
    "InGameActions": "In-Game Loadout Actions",
    "ItemLeveling": "Item Leveling",
    "LoadoutName": "Loadout name",
    "Loadouts": "Loadouts",
    "LoadoutParameters": "Loadout Optimizer settings",
    "LoadoutParametersExotic": "Loadout must include this exotic: {{exoticName}}",
    "LoadoutParametersQuery": "Items must match this search filter",
    "LoadoutParametersStats": "Stat priorities and minimum/maximum stat ranges",
    "MakeRoom": "Make Room for Postmaster",
    "MakeRoomDone_one": "Finished making room for 1 Postmaster item by moving 1 item off of {{store}}.",
    "MakeRoomDone_female_one": "Finished making room for 1 Postmaster item by moving 1 item off of {{store}}.",
    "MakeRoomDone_male_one": "Finished making room for 1 Postmaster item by moving 1 item off of {{store}}.",
    "MakeRoomDone_other": "Finished making room for {{count}} Postmaster items by moving {{movedNum}} items off of {{store}}.",
    "MakeRoomDone_female_other": "Finished making room for {{count}} Postmaster items by moving {{movedNum}} items off of {{store}}.",
    "MakeRoomDone_male_other": "Finished making room for {{count}} Postmaster items by moving {{movedNum}} items off of {{store}}.",
    "MakeRoomError": "Unable to make room for all Postmaster items: {{error}}.",
    "ManageLoadouts": "Manage Loadouts",
    "MaxSlots": "You can only have {{slots}} {{bucketName}} in a loadout.",
    "MaximizeLight": "Max Light",
    "MaximizePower": "Max Power",
    "MaximizeStat": "Maximize Stat",
    "ModPlacement": {
      "InvalidMods": "Invalid Mods",
      "InvalidModsDesc_one": "1 mod cannot fit into any armor piece.",
      "InvalidModsDesc_other": "{{count}} mods cannot fit into any armor piece.",
      "ModPlacement": "Mod Placement",
      "UnassignedMods": "Unassigned Mods",
      "UnassignedModsDesc_one": "1 mod did not fit due to insufficient energy capacity or mod slots. Energy upgrades to the selected armor will not fix the issue.",
      "UnassignedModsDesc_other": "{{count}} mods did not fit due to insufficient energy capacity or mod slots. Energy upgrades to the selected armor will not fix the issue.",
      "UpgradeCosts": "Upgrade Costs",
      "UpgradeCostsDesc": "Some armor needs energy capacity upgrades to fit the requested mods. In total, these upgrades cost:",
      "UnstackableMod": "Not Stackable",
      "StackableMod": "Stackable"
    },
    "MissingItemsWarning": "Some of the items in this loadout are no longer in your inventory.",
    "MissingItems": "Missing Items",
    "ModErrorSummary_one": "1 mod error:",
    "ModErrorSummary_other": "{{count}} mod errors:",
    "ItemErrorSummary_one": "1 item error:",
    "ItemErrorSummary_other": "{{count}} item errors:",
    "Mods": "Mods",
    "NoneMatch": "None of your loadouts matched the filters.",
    "NotesPlaceholder": "Write some notes about this loadout, or use #hashtags to categorize it",
    "NotificationTitle": "Loadout: {{name}}",
    "OnlyItems": "Only equippable items, materials, and consumables can be added to a loadout.",
    "OnWrongCharacterWarning": "This character's most powerful armor is on another character. To count toward the Power of drops, powerful, and pinnacle rewards, armor must be on this character or in the Vault.",
    "OnWrongCharacterAdvice": "Click here to find this character's highest Power items.",
    "OpenInOptimizer": "Optimize Armor",
    "PickArmor": "Pick Armor",
    "PickMods": "Add armor mods",
    "PullFromPostmaster": "Collect Postmaster",
    "PullFromPostmasterNotification_one": "Pulling 1 Postmaster item to {{store}}.",
    "PullFromPostmasterNotification_female_one": "Pulling 1 Postmaster item to {{store}}.",
    "PullFromPostmasterNotification_male_one": "Pulling 1 Postmaster item to {{store}}.",
    "PullFromPostmasterNotification_other": "Pulling {{count}} Postmaster items to {{store}}.",
    "PullFromPostmasterNotification_female_other": "Pulling {{count}} Postmaster items to {{store}}.",
    "PullFromPostmasterNotification_male_other": "Pulling {{count}} Postmaster items to {{store}}.",
    "PullFromPostmasterError": "Unable to pull from Postmaster: {{error}}.",
    "PullFromPostmasterGeneralError": "Unable to pull all items from Postmaster.",
    "PullFromPostmasterPopupTitle": "Pull from Postmaster",
    "NoSpace": "You're out of space in the vault and any other characters.",
    "Prismatic": {
      "Aspect": "Prismatic Aspect",
      "Grenade": "Prismatic Grenade",
      "Melee": "Prismatic Melee",
      "Super": "Super Ability"
    },
    "Random": "Random",
    "Randomize": "Randomize Loadout",
    "RandomizeNew": "Create Random",
    "RandomizeButton": "Randomize",
    "RandomizePrompt": "Randomize your equipped weapons, armor and ghost?",
    "RandomizeQueryHint": "Tip: Search for items first to restrict what items can be randomly chosen.",
    "RandomizeSearch": "Randomize from Search",
    "RandomizeSearchPrompt": "Randomize your equipped items from search \"{{query}}\"?",
    "RandomizeWeapons": "Randomize your equipped weapons?",
    "Redo": "Redo",
    "RestoreAllItems": "All Items",
    "Save": "Save",
    "OpenOnStreamDeck": "Open on Stream Deck",
    "SaveLoadout": "Save Loadout",
    "UpdateLoadout": "Update Loadout",
    "SaveAsDIM": "Save as DIM Loadout",
    "SaveAsNew": "Save as New",
    "SaveAsNewTooltip": "Keep the original loadout and save this as a new loadout",
    "SaveDisabled": {
      "AlreadyExists": "Choose a new name for the loadout.",
      "Empty": "The loadout is empty.",
      "NoName": "The loadout needs a name."
    },
    "Season": "Season {{season}}",
    "Snapshot": "Save As In-Game Loadout",
    "SortByName": "Sort by name",
    "SortByEditTime": "Sort by last edited",
    "Share": {
      "Title": "Share \"{{name}}\"",
      "Placeholder": "Loading share link",
      "Error": "Error getting share link",
      "Copied": "Copied loadout link to clipboard",
      "CopyButton": "Copy Link",
      "NativeShare": "Share Link",
      "Summary": "Share this loadout containing:",
      "NumItems_one": "{{count}} item - recipients will be prompted to select a comparable item from their inventory",
      "NumItems_other": "{{count}} items - recipients will be prompted to select comparable items from their inventory",
      "NumMods_one": "{{count}} mod",
      "NumMods_other": "{{count}} mods",
      "Fashion": "Fashion (shaders & ornaments)",
      "Subclass": "Subclass customization",
      "LoadoutOptimizer": "Loadout Optimizer settings",
      "Notes": "Notes"
    },
    "ShareLoadout": "Share",
    "ShowModPlacement": "Show Mod Placement",
    "SubclassOptions": "{{subclass}} options",
    "SubclassOptionsSearch": "Search {{subclass}} options",
    "SyncFromEquipped": "Sync from equipped",
    "FillFromEquipped": "Fill in using equipped",
    "FillFromInventory": "Fill in using non-equipped",
    "TooManyRequested": "You have {{total}} {{itemname}} but your loadout asks for {{requested}}. We transferred all you had.",
    "UnassignedModError": "Mod didn't fit on your current armor",
    "Undo": "Undo",
    "Unequipped": "Unequipped",
    "VendorsCannotEquip": "You don't have these items. Tap to pick a replacement or click the X to remove:",
    "WeaponsOnly": "Weapons Only",
    "NotStarted": "Waiting for other actions to complete, or an inventory refresh to finish loading",
    "Deequip": "De-equipping items from other characters",
    "MoveItems": "Moving items",
    "EquipItems": "Equipping items",
    "EquipInGameLoadout": "Equipping in-game loadout",
    "ApplyInGameLoadoutInGame": "Your loadout is ready to equip but since you're in an activity you need to equip it in-game.",
    "SocketOverrides": "Changing subclass options",
    "ApplyMods": "Applying mods",
    "ClearingSpace": "Moving other items away",
    "Succeeded": "Loadout succeeded",
    "Failed": "Loadout failed to apply completely",
    "Update": "Save Changes",
    "TuningMods": "Tuning Mods",
    "SalvationsEdgeMods": "Salvation's Edge Mods",
    "CancelEditing": "Cancel Editing"
  },
  "LoadoutAnalysis": {
    "Analyzing": "Analyzing {{numAnalyzed}}/{{numLoadouts}} Loadouts",
    "Analyzed": "Analyzed {{numLoadouts}} Loadouts",
    "BetterStatsAvailableFontNote": "Note: This Loadout uses \"Font of ...\" mods that cause a stat to exceed 200. DIM may identify better stats by reducing the amount of excess stats. If this is undesired, disable \"$t(Loadouts.IncludeRuntimeStatBenefits)\" in the Loadout.",
    "MissingItems": {
      "Name": "Missing Items",
      "Description": "Some of the items in this loadout are no longer in your inventory."
    },
    "InvalidMods": {
      "Name": "Deprecated Mods",
      "Description": "Some mods in this loadout are deprecated or do not otherwise fit into any of your armor pieces."
    },
    "EmptyFragmentSlots": {
      "Name": "Empty Fragment Slots",
      "Description": "There are empty fragment slots in this subclass."
    },
    "TooManyFragments": {
      "Name": "Too Many Fragments",
      "Description": "There are more fragments configured on the subclass than granted by aspects."
    },
    "NeedsArmorUpgrades": {
      "Name": "Needs Armor Upgrades",
      "Description": "Armor in this loadout needs to be upgraded to accommodate all mods or reach specified stats."
    },
    "BetterStatsAvailable": {
      "Name": "Better Stats Available",
      "Description": "Choosing different armor or mods for this loadout will allow reaching higher stats. Choose \"$t(Loadouts.OpenInOptimizer)\" to view better builds."
    },
    "NotAFullArmorSet": {
      "Name": "Not A Full Armor Set",
      "Description": "This loadout could not be analyzed further because it does not include a full set of armor."
    },
    "DoesNotRespectExotic": {
      "Name": "Wrong Exotic",
      "Description": "This loadout's Loadout Optimizer settings specify an exotic choice, but the loadout does not match that exotic."
    },
    "ModsDontFit": {
      "Name": "Unassigned Mods",
      "Description": "Armor in this loadout cannot accommodate all loadout mods, even if the armor was upgraded."
    },
    "UsesSeasonalMods": {
      "Name": "Uses Seasonal Mods",
      "Description": "This loadout relies on mods that are only available in some seasons. When the season ends, some mods will be unavailable or exceed armor energy capacity."
    },
    "DoesNotSatisfyStatConstraints": {
      "Name": "Wrong Stat Minimums",
      "Description": "Loadout Optimizer settings for this Loadout specify stat minimums, but the Loadout does not reach them."
    },
    "InvalidSearchQuery": {
      "Name": "Invalid Search Query",
      "Description": "This loadout was created with a search query in Loadout Optimizer that is not valid."
    },
    "ItemsDoNotMatchSearchQuery": {
      "Name": "Search Excludes Items",
      "Description": "This loadout was created with a search query in Loadout Optimizer, and that search query excludes at least one of the items in the loadout."
    }
  },
  "Manifest": {
    "Download": "Downloading latest Destiny info database from Bungie...",
    "Error": "Error loading Destiny info database:\n{{error}}\nReload to retry.",
    "Load": "Loading Destiny info database..."
  },
  "Milestone": {
    "Daily": "Daily Challenge",
    "OneTime": "One Time Challenge",
    "SeasonalRank": "Seasonal Rank {{rank}}",
    "SeasonEnds": "Season ends in ",
    "Special": "Special Event Challenge",
    "Tutorial": "Tutorial Challenge",
    "Unknown": "Challenge",
    "Weekly": "Weekly Challenge"
  },
  "Mods": {
    "HarmonicModDescription": "This mod's effect comes at a reduced cost and changes element depending on the equipped subclass."
  },
  "MoveAmount": {
    "Amount": "Amount:"
  },
  "MovePopup": {
    "Acquired": "This item is unlocked in collections.",
    "AcquiredMod": "This mod is unlocked in collections.",
    "AddToLoadout": "Loadout",
    "AddToLoadoutTitle": "Add this to a loadout",
    "AddNote": "Add notes",
    "All": "All",
    "CantPullFromPostmaster": "You must visit the postmaster in game to retrieve this item.",
    "CannotCurrentlyRoll": "This perk cannot be rolled on the current version of this item.",
    "UnreliablePerkOption": "This perk appears only in the collections view. It might not roll randomly on this item.",
    "Consolidate": "Consolidate",
    "CommunityData": "Community Insight",
    "DistributeEvenly": "Distribute Evenly",
    "EnhancementTier": "Tier {{tier}}",
    "Equip": "Equip on:",
    "EquipWithName": "Equip on {{character}}",
    "FavoriteUnFavorite": {
      "Favorite": "Favorite {{itemType}}",
      "Unfavorite": "Unfavorite {{itemType}}",
      "Favorited": "Favorited",
      "Unfavorited": "Unfavorited"
    },
    "Infuse": "Infuse",
    "InfuseTitle": "Open the infusion fuel finder",
    "LoadingSockets": "Perk and stat details have not loaded yet for this item.",
    "LockUnlock": {
      "Lock": "Lock {{itemType}}",
      "Unlock": "Unlock {{itemType}}",
      "Locked": "Locked",
      "Unlocked": "Unlocked",
      "AutoLock": "Lock state is synced to this item's tag"
    },
    "MissingSockets": "Perk and mod details are unavailable while Bungie is updating their services. It will return when they are done, usually in a few hours.",
    "Notes": "Notes:",
    "OverviewTab": "Overview",
    "Owned": "This item is in your inventory.",
    "OwnedMod": "This mod is in your modifications inventory.",
    "PullItem": "Pull from {{bucket}} to {{store}}",
    "PullPostmaster": "Pull from Postmaster",
    "ReadLore": "Read lore on Ishtar Collective",
    "ReadLoreLink": "Read lore",
    "Rewards": "Rewards:",
    "SendToVault": "Send to Vault",
    "Store": "Pull to:",
    "OpenOnStreamDeck": "Open on Stream Deck",
    "StoreWithName": "Pull to {{character}}",
    "Subtitle": {
      "Type": "{{classType}} {{typeName}}",
      "QuestProgress": "Step {{questStepNum}} of {{questStepsTotal}}"
    },
    "TabList": "Item detail tabs",
    "ToggleSidecar": "Expand or collapse item actions",
    "TrackUntrack": {
      "Track": "Track {{itemType}}",
      "Untrack": "Untrack {{itemType}}",
      "Tracked": "Tracked",
      "Untracked": "Untracked"
    },
    "TriageTab": "Triage",
    "Vault": "Vault",
    "WeaponLevel": "Weapon Level {{level}}",
    "CatalystProgress": "Catalyst Progress",
    "ArtifactBreaker": "This weapon has {{breaker}} because of an unlocked artifact perk.",
    "IntrinsicBreaker": "This weapon intrinsically has {{breaker}}."
  },
  "Notes": {
    "Error": "Error! Max 120 characters for notes.",
    "Help": "Add notes, #hashtags, and :symbols:"
  },
  "Notification": {
    "Cancel": "Cancel",
    "OK": "Dismiss"
  },
  "Objectives": {
    "Complete": "Complete",
    "Incomplete": "Incomplete"
  },
  "Organizer": {
    "Organizer": "Organizer",
    "OpenIn": "Show in Organizer",
    "EnabledColumns": "Enabled Columns",
    "BulkMove": "Move To",
    "BulkTag": "Tag",
    "BulkMoveLoadoutName": "Selected in Organizer",
    "SelectItem": "Select or unselect {{name}}",
    "SelectAll": "Select All",
    "Lock": "Lock",
    "Unlock": "Unlock",
    "ShiftTip": "Tip: Hold the Shift key and click on a cell to filter items",
    "NoMobile": "Turn your phone sideways to use the Organizer.",
    "NoItems": "No items match the filters. If you have a search query, try clearing it.",
    "Note": "Set Notes",
    "Columns": {
      "Stats": "Stats",
      "BaseStats": "Base Stats",
      "Breaker": "Breaker",
      "Icon": "Icon",
      "Name": "Name",
      "Power": "Power",
      "Damage": "Damage",
      "Ammo": "Ammo",
      "Foundry": "Foundry",
      "Featured": "New Gear",
      "Holofoil": "Holofoil",
      "OriginTraits": "Origin Trait",
      "Shaders": "Cosmetics",
      "Locked": "Locked",
      "Energy": "Energy",
      "Location": "Location",
      "Tag": "Tag",
      "WishList": "Wish List",
      "PercentComplete": "% Complete",
      "StatQuality": "Stat Quality",
      "StatQualityStat": "{{stat}}%",
      "Perks": "Perks",
      "PerksGrid": "Perks Grid",
      "Mods": "Mods",
      "Quality": "Quality %",
      "ItemTier": "Tier",
      "Tier": "Rarity",
      "Source": "Source",
      "Year": "Year",
      "Season": "Season",
      "Event": "Event",
      "ModSlot": "Mod Slot",
      "Archetype": "Archetype",
      "Frame": "Frame",
      "PerksMods": "Perks & Mods",
      "OtherPerks": "Weapon Components",
      "Traits": "Weapon Traits",
      "TertiaryStat": "3rd Stat",
      "TuningStat": "Tuner",
      "CustomTotal": "Custom Total",
      "MasterworkTier": "MW Tier",
      "MasterworkStat": "MW Stat",
      "Level": "Level",
      "Harmonizable": "Harmonizable",
      "KillTracker": "Kills",
      "Loadouts": "Loadouts",
      "Notes": "Notes",
      "WishListNotes": "Wish List Notes",
      "New": "New",
      "Recency": "Recency",
      "Crafted": "Shaped Date"
    },
    "Stats": {
      "RPM": "RPM",
      "Reload": "Reload",
      "Aim": "Aim",
      "Recoil": "Recoil",
      "Power": "Power",
      "Airborne": "Airborne",
      "AmmoGeneration": "Ammo Gen"
    }
  },
  "Progress": {
    "Bounties": "Bounties",
    "CrucibleRank": "Ranks",
    "RewardPassPrestigeRank": "Prestige Rank {{rank}}",
    "RewardPassEndsIn": "Reward Pass ends in ",
    "Items": "Quest Items",
    "Milestones": "Milestones & Challenges",
    "PaleHeartPathfinder": "Pale Heart Pathfinder",
    "PercentPrestige": "{{pct}}% to reset",
    "PercentMax": "{{pct}}% to maximum",
    "PointsUsed_one": "1 point used",
    "PointsUsed_other": "{{count}} points used",
    "PowerBonusHeader": "+{{powerBonus}} Power Rewards",
    "PowerBonusHeaderUndefined": "Other Rewards",
    "Progress": "Progress",
    "QuestExpired": "Expired",
    "QuestExpires": "Expires in ",
    "Quests": "Quests",
    "Rank": "{{name}} {{rank}}",
    "RecordValue": "{{value}}pts",
    "Resets_one": "1 reset",
    "Resets_other": "{{count}} resets",
    "GambitPathfinder": "Gambit Pathfinder",
    "CruciblePathfinder": "Crucible Pathfinder",
    "VanguardPathfinder": "Vanguard Pathfinder",
    "SeasonalHub": "Seasonal Hub",
    "SecretTriumph": "Secret Triumph",
    "StatTrackers": "Stat Trackers",
    "TrackedTriumphs": "Tracked Triumphs",
    "QueryFilteredTrackedTriumphs": "None of your tracked triumphs matched the search",
    "NoTrackedTriumph": "You have no tracked triumphs. Track as many as you like in DIM.",
    "NoEventChallenges": "You have completed all event challenges",
    "CatalystSource": "Source: {{source}}"
  },
  "RecordBooks": {
    "HideCompleted": "Hide completed records",
    "RecordBooks": "Record Books"
  },
  "Records": {
    "Title": "Records",
    "UniversalOrnamentSetOther": "Other"
  },
  "SearchHistory": {
    "Description": "These are all your past and saved searches. You can delete them from here.",
    "DeleteAll": "Delete all non-starred searches",
    "Date": "Last Used",
    "UsageCount": "# Used",
    "Query": "Search",
    "Link": "View and edit search history",
    "Title": "Search History",
    "Item": "Item Searches",
    "Loadout": "Loadout Searches"
  },
  "Settings": {
    "Appearance": "Appearance",
    "ArmorArchetypeModslot": "Armor Archetype / Modslot",
    "AutoLockTagged": "Sync item lock state with tag",
    "AutoLockTaggedExplanation": "DIM will automatically lock and unlock items to match their tag. Crafted items will remain unlocked to allow reshaping. When this setting is enabled, the lock icon will not be shown on the item tile for tagged items.",
    "BadgePostmaster": "Show the number of postmaster items for the current character on app icon",
    "BadgePostmasterExplanation": "For this to work you must install DIM as an app and your OS must support displaying badges",
    "BungieDescriptionOnly": "Bungie Descriptions",
    "CommunityDescriptionOnly": "Community Descriptions",
    "BothDescriptions": "Both Descriptions",
    "CharacterOrder": "Sort characters by",
    "CharacterOrderFixed": "Character age (buggy on PC)",
    "CharacterOrderRecent": "Most recent character",
    "CharacterOrderReversed": "Most recent character (reversed)",
    "ColumnSize": "{{num}} items",
    "ColumnSizeAuto": "Auto",
    "CommunityData": "Community Perk Insights",
    "CsvImport": "Import CSV",
    "CustomStatTitle": "Custom Stat Total",
    "CustomStatDesc1": "Choose desired armor stats to make a custom total stat.",
    "CustomStatDesc3": "Custom stats will appear in the Item Popup, Organizer, and Compare.",
    "CustomDesc": "Custom total of selected base stats, ignoring mods or masterworks. Visit Settings to configure which stats are included.",
    "CustomStatDelete": "Delete this Custom Stat",
    "CustomStatDeleteConfirm": "Delete this Custom Stat?",
    "CustomStatCreate": "Create a new custom stat",
    "CustomStatChooseName": "Choose a Custom Stat name",
    "CustomErrorValues": "Stat weights must be positive numbers.\nAt least 2 stat weights must be above zero.",
    "CustomErrorLabel": "A stat name must contain word characters, and be different from other stat names for this Guardian class.",
    "Data": "Spreadsheets",
    "DefaultItemSizeNote": "An item size of 50px will look the sharpest, without blurring the item picture or text.",
    "DontForgetDupes": "Don't forget you can search is:dupe to quickly find duplicate items, and you can use the comparison tool or organizer to evaluate related items.",
    "EnableAdvancedStats": "Show stat quality rating on armor (D1)",
    "ExportProfile": "Export API profile response",
    "ExportSS": "Inventory spreadsheets",
    "ExportSSHelp": "Download a CSV list of your items that can be easily viewed in the spreadsheet app of your choice.",
    "ExportLoadoutSS": "Loadout spreadsheets",
    "ExportLoadoutSSHelp": "Download a CSV list of your DIM Loadouts that can be easily viewed in the spreadsheet app of your choice.",
    "ExportSSNoStores": "You need to load your inventory once before clicking this button.",
    "HidePullFromPostmaster": "Hide the \"$t(Loadouts.PullFromPostmaster)\" button",
    "Inventory": "Inventory Display",
    "InventoryColumns": "Character inventory width",
    "InventoryColumnsMobile": "Character inventory width on mobile portrait",
    "InventoryColumnsMobileLine2": "The items will be resized to accommodate the new setting",
    "InventoryNumberOfSpacesToClear": "Number of empty spaces to make when using Farming Mode",
    "Items": "Item Display",
    "Language": "Language",
    "LogOut": "Log out",
    "Masterworked": "Masterworked",
    "MaxParallelCores": "Maximum cores for parallel tasks",
    "MaxParallelCoresExplanation": "Controls how many CPU cores DIM can use for intensive tasks like Loadout Optimizer and Loadout Analyzer. Higher values may improve performance but use more system resources.",
    "OrnamentDisplay": "Show Ornaments on item tiles",
    "OrnamentDisplayExplanationDisabled": "Items will never display their ornaments",
    "OrnamentDisplayExplanationEnabled": "Hovering or long-pressing armor will hide its ornament",
    "OrnamentDisplayExplanationHide": "Hovering or long-pressing an item will hide its ornament",
    "OrnamentDisplayExplanationShow": "Hovering or long-pressing an item will show its ornament",
    "ResetToDefault": "Reset",
    "ReverseSort": "Toggle forward/reverse sort",
    "SetSort": "Sort items by:",
    "SetVaultWeaponGrouping": "Group vault weapons by:",
    "VaultArmorGroupingStyle": "Separate armor on different lines by class",
    "VaultWeaponGroupingStyle": "Separate weapon groups on different lines",
    "Settings": "Settings",
    "ShowNewItems": "Show a red dot on new items",
    "ExpandSingleCharacter": "Show all characters",
    "SingleCharacter": "Single-Character View",
    "SingleCharacterExplanation": "DIM will show only the most recently played character.\nItems held by hidden characters will appear in the vault, if they can be used by the current character.\nItems specific to other classes will be hidden entirely.",
    "SizeItem": "Item size",
    "SortByAmmoType": "Ammo Type",
    "SortByAmount": "Stack Size",
    "SortByClassType": "Required Class",
    "SortByCrafted": "Crafted (D2)",
    "SortByDeepsight": "Deepsight (D2)",
    "SortByFeatured": "New Gear / Featured (D2)",
    "SortByPrimary": "Power level",
    "SortByRarity": "Rarity",
    "SortByRating": "Armor Quality (D1)",
    "SortByRecent": "Recently Acquired (D2)",
    "SortByTag": "Tag ({{taglist}})",
    "SortByTier": "Tier (D2)",
    "SortByType": "Type",
    "SortBySeason": "Season (D2)",
    "SortByWeaponElement": "Damage Type",
    "SortCustom": "Custom Sort",
    "SortName": "Name",
    "SpacesSize_one": "{{count}} space",
    "SpacesSize_other": "{{count}} spaces",
    "Theme": "Theme",
    "Troubleshooting": "Troubleshooting",
    "VaultGroupingNone": "None",
    "VaultUnder": "Show vaulted items under equipped items",
    "RestoreVaultSide": "Show vaulted items in their own column",
    "WeaponFrame": "Weapon Frame",
    "WishlistRefreshNotificationBody": "If you do not see any updates, be sure the source (such as GitHub) reflects them!",
    "WishlistRefreshNotificationTitle": "Wishlists Reloaded"
  },
  "Sockets": {
    "ApplyPerks": "Apply Perks",
    "Search": "Search names or descriptions",
    "SelectWishlistPerks": "Preview Wishlist Perks",
    "Insert": {
      "Mod": "Insert Mod",
      "Shader": "Apply Shader",
      "Ornament": "Apply Ornament",
      "Ability": "Equip Ability",
      "Fragment": "Insert Fragment",
      "Aspect": "Insert Aspect",
      "Transmat": "Apply Transmat Effect",
      "Projection": "Apply Ghost Projection",
      "Super": "Equip Super"
    },
    "Select": {
      "Mod": "Preview Mod",
      "Shader": "Preview Shader",
      "Ornament": "Preview Ornament",
      "Ability": "Preview Ability",
      "Fragment": "Preview Fragment",
      "Aspect": "Preview Aspect",
      "Transmat": "Preview Transmat Effect",
      "Projection": "Preview Ghost Projection",
      "Super": "Preview Super"
    },
    "ListStyle": "Display perks as a list",
    "GridStyle": "Display perks as a grid"
  },
  "Stats": {
    "Custom": "Custom Total",
    "CustomDesc": "Custom total of selected base stats, ignoring mods or masterworks. Visit Settings to configure which stats are included.",
    "Discipline": "Discipline",
    "Intellect": "Intellect",
    "MaxGearPower": "Maximum Power of equippable gear",
    "DropLevel": "Account Power",
    "DropLevelExplanation1": "Account Power is the base power level when calculating the increased level of rewards.",
    "DropLevelExplanation2": "Account Power uses the highest level item in each slot, regardless of required Class or the \"One Exotic\" rule.",
    "EquippableGear": "Equippable Gear",
    "MaxGearPowerOneExoticRule": "Maximum Power of equippable gear\n(only one Exotic armor piece equipped)",
    "MaxGearPowerAll": "Maximum Power of all gear",
    "PowerModifier": "Power granted by seasonal experience progression",
    "MaxTotalPower": "Maximum total Power",
    "Milliseconds": "ms",
    "NoBonus": "No Bonus",
    "NotApplicable": "N/A",
    "OfMaxRoll": "{{range}} of max roll",
    "PercentHelp": "Click for more information about what Stats Quality is.",
    "Prestige": "Prestige Level: {{level}}\n{{exp}}xp until 5 motes of light.",
    "Quality": "Stats quality",
    "Strength": "Strength",
    "TierProgress": "T{{tier}} {{statName}} ({{progress}}/60 for T{{nextTier}})\n",
    "TierProgress_Max": "T{{tier}} {{statName}} ({{progress}}/300)\n",
    "Total": "Total",
    "MetersPerSecond": "m/s",
    "Percentage": "%",
    "HP": "HP",
    "TimeToFullHP": "Time to Full HP",
    "WalkingSpeed": "Walking",
    "StrafingSpeed": "Strafing",
    "CrouchingSpeed": "Crouching",
    "TotalHP": "Total HP",
    "ShieldHP": "Shield HP",
    "DamageResistance": "PvE Damage Resist",
    "FlinchResistance": "Flinch Resist",
    "WeaponPart": "Weapon Part"
  },
  "Storage": {
    "ApiPermissionPrompt": {
      "Title": "Enable DIM Sync?",
      "Description": "DIM can now store your tags, loadouts, and settings on our own servers and sync that data between different versions of DIM, with no separate login. You can import your existing data from the Settings page if you haven't enabled DIM Sync before. This was made possible by the support of our OpenCollective backers!",
      "Yes": "Enable Sync",
      "No": "Not right now"
    },
    "AutoBackup": "We've backed up your data to a file in your downloads folder called dim-data.json, just in case.",
    "BackUpFirst": "You MUST back up your data first, before you delete it all. Just in case.",
    "BrowserMayClearData": "The browser may delete this information if you run out of space or don't visit DIM frequently.",
    "DataIsLocal": "Tag and notes data is local only",
    "DeleteAllData": "Delete ALL Data from DIM Sync Servers",
    "DeleteAllDataConfirm": "Are you sure you want to delete ALL your data, for all accounts, from DIM Sync? You can't undo this.",
    "DeleteAllDataLabel": "Wipe DIM Sync Data",
    "Details": {
      "IndexedDBStorage": "Local storage will save your information only on this browser. Clearing your browsing data will delete this information."
    },
    "DimApiFinePrint": "DIM will save your tags, loadouts, and settings to the DIM servers and sync them between different versions of DIM.",
    "DimSyncEnabled": "DIM Sync Enabled",
    "DimSyncDown": "DIM Sync is not connected due to a problem talking to the server.",
    "UpdateQueueLength_one": "{{count}} new change will be saved when we can reconnect.",
    "DimSyncNotEnabled": "DIM Sync is not enabled, so your settings, tags, loadouts, and searches are only stored locally and will be lost if you clear your browser storage. Enable DIM Sync in Settings to back up your data automatically, or regularly back up your data manually.",
    "UpdateQueueLength_other": "{{count}} new changes will be saved when we can reconnect.",
    "EnableDimApi": "Enable DIM Sync (recommended)",
    "Export": "Download Data Backup",
    "ExportError": "Failed to download backup from DIM Sync",
    "ExportErrorBody": "DIM Sync may be down, or you are having trouble with your connection. We will download a copy of your locally saved data instead.",
    "Import": "Import Data Backup",
    "ImportConfirmDimApi": "Are you sure you want to overwrite your current tags, loadouts, and settings with this version? It will completely replace what you had.",
    "ImportNotification": {
      "SuccessTitle": "Import Successful",
      "SuccessBodyForced": "Imported settings, {{loadouts}} loadouts, and {{tags}} tagged items from your backup into DIM Sync, replacing what was already there.",
      "SuccessBodyLocal": "Imported settings, {{loadouts}} loadouts, and {{tags}} tagged items from your backup into local storage, replacing what was already there. We cannot guarantee that local storage won't be lost - consider enabling DIM Sync.",
      "FailedTitle": "Import Failed",
      "FailedBody": "Unable to import data. {{error}}",
      "NoData": "No loadouts or tags found in the backup"
    },
    "ImportExport": "Backup & Import",
    "ImportFailed": "Import Failed! {{error}}",
    "ImportNoFile": "No file selected!",
    "ImportTooManyFiles": "Please only select one file to import.",
    "ImportWrongFileType": "File is not a JSON file. It may not be a DIM backup.",
    "IndexedDBStorage": "Local Browser Storage",
    "LearnMore": "Learn more about DIM Sync",
    "MenuTitle": "Sync & Backups",
    "ProfileErrorTitle": "DIM Sync Download Error",
    "ProfileErrorBody": "We had a problem communicating with DIM Sync. Your latest settings, tags, loadouts, and searches may not be shown. Your data is still on our servers, and any updates you make locally will be saved when we can reconnect. We'll keep retrying while DIM is open.",
    "RefreshDimSync": "Reload remote data from DIM Sync",
    "UpdateInvalid": "Failed to save data to DIM Sync",
    "UpdateInvalidBody": "Data sent to DIM Sync was invalid and will not be saved.",
    "UpdateInvalidBodyLoadout": "The loadout \"{{name}}\" is invalid and will not be saved. If you imported it from another site, please let them know that they are exporting invalid loadouts.",
    "UpdateErrorTitle": "DIM Sync Save Error",
    "UpdateErrorBody": "We had a problem saving your data to DIM Sync. We'll keep retrying while DIM is open.",
    "Usage": "DIM is using {{usage, humanBytes}} out of {{quota, humanBytes}} available to it on this device. This includes the downloaded Destiny item databases from Bungie.net."
  },
  "StripSockets": {
    "Action": "Strip Sockets",
    "Button": "Strip {{numSockets}} Sockets",
    "Choose": "Choose Sockets to strip",
    "Running": "Stripping Sockets",
    "Done": "Stripped Sockets",
    "Ok": "Ok",
    "Cancel": "Cancel",
    "NoSockets": "No Sockets to clear",
    "Shaders": "{{count}}x Shader",
    "Ornaments": "{{count}}x Ornament",
    "WeaponMods": "{{count}}x Weapon Mod",
    "DiscountedMods": "{{count}}x Discounted Mod",
    "ArmorMods": "{{count}}x Armor Mod",
    "Subclass": "{{count}}x Subclass Option",
    "Others": "{{count}}x Ghost Projection"
  },
  "StreamDeck": {
    "name": "Stream Deck",
    "Tooltip": {
      "Title": "DIM Stream Deck Plugin",
      "Version": "Version:",
      "Application": "Stream Deck Application",
      "Plugin": "Plugin",
      "Error": "Your Stream Deck plugin is no longer supported. Please update to the latest version. This plugin requires at least:",
      "AuthRequired": "Click this button or go to settings and click \"Connect application\".",
      "ExtensionIssue": "Extensions Issue",
      "ErrorConnection": "if you're already using the latest version, check if some browser extension is blocking the connection."
    },
    "Error": {
      "Title": "Stream Deck Plugin Error",
      "Body": "There was an error sending data to the Stream Deck plugin. Please contact the plugin developer. {{error}}"
    },
    "Enable": "Stream Deck Plugin",
    "FinePrint": "Enable the connection with the DIM Stream Deck plugin. This plugin is a separate project that is neither written by nor supported by the DIM team.",
    "Install": "Install plugin",
    "Authorize": "Connect application",
    "MissingAuthorization": "You must authorize the Stream Deck application to connect to DIM. Go to settings and click \"Connect application\"."
  },
  "Tags": {
    "Archive": "Archive",
    "ClearTag": "Clear Tag",
    "Favorite": "Favorite",
    "Infuse": "Infuse",
    "Junk": "Junk",
    "Keep": "Keep",
    "LockAll": "Lock Items",
    "TagItem": "Tag Item",
    "UnlockAll": "Unlock Items"
  },
  "Triage": {
    "BetterWorseArmor": "Better/Worse Armor",
    "BetterWorseIncludes": "Identifies armor pieces with:",
    "WorseArmor": "Strictly Worse Armor",
    "WorseStatArmor": "Worse Stat Armor",
    "WorseArtificeArmor": "Worse Non-Artifice Armor",
    "WorseStatArtificeArmor": "Worse Stat Non-Artifice Armor",
    "StatWorseArmorDesc": "No better stats, and at least one worse stat.",
    "PerkWorseArmorDesc": "The same intrinsic perk, or none.",
    "BetterArmor": "Strictly Better Armor",
    "BetterStatArmor": "Better Stats Armor",
    "BetterArtificeArmor": "Better Artifice Armor",
    "BetterStatArtificeArmor": "Better Stat Artifice Armor",
    "StatBetterArmorDesc": "All stats at least as high, and at least one stat better.",
    "PerkBetterArmorDesc": "The same, or more, intrinsic perks or special mod slots.",
    "AccountsForArtifice": "This tests whether an Artifice armor piece could be better, if a +3 stat mod were used.",
    "StatNotPerkArmorDesc": "This tests only stats. A lower piece may still have special mod slots or intrinsic perks.",
    "YourBestItem": "Your best item",
    "ThisItem": "This item",
    "SimilarItems": "Similar Items",
    "InLoadouts": "In Loadouts",
    "HighStats": "High Stats",
    "OwnedCount": "# Owned"
  },
  "Triumphs": {
    "HideCompleted": "Hide completed triumphs",
    "RevealRedacted": "Reveal redacted triumphs",
    "SortRecords": "Sort triumphs by completion",
    "GildingTriumph": "Gilding Triumph"
  },
  "Vendors": {
    "Collections": "Collections",
    "Engram": "Rank",
    "FilterToUnacquired": "Only show uncollected items",
    "HideSilverItems": "Hide Silver items",
    "NoItems": "This Vendor is currently not offering any items.",
    "Vendors": "Vendors",
    "RefreshTime": "Inventory refreshes in:"
  },
  "Views": {
    "About": {
      "APIHistory": "View the history of all actions taken by DIM (and other Destiny apps)",
      "BungieCopyright": "All images and content are property of Bungie.",
      "CommunityInsight": "Community Insights for Perks and Character Stats courtesy of {{clarityLink}}. If you notice inaccuracies or have questions, join the {{clarityDiscordLink}}.",
      "Discord": "Discord",
      "DiscordHelp": "Ask questions, give feedback, and get support in our Discord channels.",
      "FAQ": "Frequently Asked Questions",
      "FAQAccess": "How does DIM get access to my Destiny data?",
      "FAQAccessAnswer": "We use Bungie's app authentication to grant access to DIM to see and move your items. DIM never sees your username or password. This is the same way the Companion app works.",
      "FAQKeyboard": "Does DIM support keyboard shortcuts?",
      "FAQKeyboardAnswer": "Yes! Press \"?\" to see a list of available shortcuts.",
      "FAQLogout": "How can I log out of DIM?",
      "FAQLogoutAnswer": "Open the menu from the top left icon and choose \"Log Out\"",
      "FAQLostItem": "I lost my item using your tool!",
      "FAQLostItemAnswer": "Bungie doesn't allow apps to delete items (even their own app!). More than likely a transfer failed, leaving your item in the vault or on another character. You could search for the item. If that doesn't turn it up, reload the page. Check {{link}} or in game to see if your item still exists. We're sure it's still there.",
      "FAQMobile": "Does DIM support mobile? Will there be an app?",
      "FAQMobileAnswer": "The DIM website can be loaded on phones and tablets today, and you can add it to your home screen for an app-like experience.",
      "GitHub": "GitHub",
      "GitHubHelp": "If you're interested in contributing to the project, visit us at our project page on {{link}}.",
      "Header": "DIM (Destiny Item Manager)",
      "HowItsMade": "DIM is a free, open source app built by community developers upon the same services used by Bungie.net and the Destiny Companion App.",
      "Schedule": {
        "beta": "This beta version of DIM is updated every time we change the code - it gets the latest features and fixes, but also the latest bugs!",
        "release": "This version of DIM is updated once a week, at approximately midnight on Sundays, US Pacific time."
      },
      "Translation": "Join the Translation Team!",
      "TranslationText": "We use {{link}} for ease of translation. If you want to improve one of DIM's translations, join the team.",
      "Version": "Version {{version}} ({{flavor}}), built on {{date}}",
      "Wiki": "DIM User Guide",
      "WikiHelp": "Learn how to use DIM's features."
    },
    "Login": {
      "Auth": "Authorize with Bungie.net",
      "BackupPrompt": "Are you sure you want to enable DIM Sync without a backup?",
      "EnableDimSyncWarning": "You had previously disabled DIM Sync and were only using local data storage. Enabling DIM Sync will replace any local data with the data from DIM Sync. You should back up your data before enabling DIM Sync. You can restore from that backup in Settings.",
      "DisabledDimSyncWarning": "You had previously enabled DIM Sync and were only using local data storage. Enabling DIM Sync will replace any local data with the data from DIM Sync. You should back up your data before enabling DIM Sync. You can restore from that backup in Settings.",
      "Explanation": "Allow DIM to view and modify your Destiny characters, vault, and progression.",
      "LearnMore": "Learn more about accounts and login",
      "NewAccount": "Log in with a different Bungie.net account",
      "Permission": "We need your permission..."
    },
    "Support": {
      "BackersDetail": "Support us with a one-time or monthly donation and help us continue our active development.",
      "FreeToDownload": "DIM is a product that is free to download and use. The source code for DIM is open source and free for anyone to enhance. You will never see an ad in DIM. That is our commitment.",
      "OpenCollective": "We are using {{link}} as a service to provide compensation to our developers for their dedication and time spent on this project.",
      "Store": "We have merch with our logo and other designs for sale on {{link}}",
      "Support": "Support DIM"
    }
  },
  "WishListRoll": {
    "BestRatedTip_one": "This perk exactly matches a weapon roll on your wishlist.",
    "BestRatedTip_other": "These perks exactly match a weapon roll on your wishlist.",
    "WorstRatedTip_one": "This perk exactly matches a weapon roll on your trashlist.",
    "WorstRatedTip_other": "These perks exactly match a weapon roll on your trashlist.",
    "Clear": "Clear Wish List",
    "ExternalSource": "Add another wish list",
    "ExternalSourcePlaceholder": "Paste wish list URL here",
    "Header": "Wish List",
    "Import": "Load Wish List Rolls",
    "ImportFailed": "None of your wish lists contained any valid rolls.",
    "ImportError": "Error loading wish list from \"{{url}}\": {{error}}",
    "ImportNoFile": "No file selected.",
    "InvalidExternalSource": "Please enter a valid URL for your external wish list source. The URL must start with one of the following:",
    "JustAnotherTeam": "Just Another Team",
    "LastUpdated": "Last updated: {{lastUpdatedDate}} at {{lastUpdatedTime}}",
    "Num": "{{num, number}} rolls in your wish list",
    "NumRolls": "{{num, number}} rolls",
    "DupeRolls": " (+{{num, number}} ignored dupes)",
    "PreMadeFiles": "Use A Pre-Made Wish List",
    "Refresh": "Refresh Wishlist",
    "SourceAlreadyAdded": "Wish List already added",
    "UpdateExternalSource": "Add Wish List",
    "Untitled": "Untitled Wish List",
    "Voltron": "voltron (default)",
    "WishListNotes": "Wish List Notes:",
    "CopyLine": "Copy Selected Perks as Wish List Roll",
    "CopiedLine": "Wish List roll copied to clipboard"
  },
  "wrong-level": "wrong-level",
  "no-space": "no-space"
}

================================================
FILE: config/manifest-webapp.ts
================================================
export default function createWebAppManifest(publicPath: string) {
  return {
    name: 'Destiny Item Manager',
    short_name: 'DIM',
    description: 'An item and loadout manager for Destiny.',
    icons: [
      {
        src: `${publicPath}android-chrome-192x192-6-2018.png`,
        sizes: '192x192',
        type: 'image/png',
      },
      {
        src: `${publicPath}android-chrome-512x512-6-2018.png`,
        sizes: '512x512',
        type: 'image/png',
      },
      {
        src: `${publicPath}android-chrome-mask-512x512-6-2018.png`,
        sizes: '512x512',
        type: 'image/png',
        purpose: 'maskable',
      },
    ],
    shortcuts: [
      {
        name: 'Vendors',
        url: `${publicPath}vendors`,
        description: "View vendors' wares",
      },
      {
        name: 'Loadouts',
        url: `${publicPath}loadouts`,
        description: 'Create & share loadouts',
      },
      {
        name: 'Settings',
        url: `${publicPath}settings`,
      },
    ],
    screenshots: [
      {
        src: `${publicPath}screenshots/inventory.jpg`,
        sizes: '1902x1080',
        type: 'image/jpeg',
        form_factor: 'wide',
        label: 'DIM Inventory Screen',
      },
      {
        src: `${publicPath}screenshots/mobile.jpg`,
        sizes: '390x770',
        type: 'image/jpeg',
        form_factor: 'narrow',
        label: 'DIM on Mobile',
      },
    ],
    theme_color: '#000000',
    background_color: '#000000',
    display: 'standalone',
    display_override: ['window-controls-overlay'],
    categories: ['games', 'entertainment', 'productivity', 'utilities'],
    start_url: `${publicPath}?utm_source=homescreen`,
    launch_handler: {
      client_mode: ['navigate-existing'],
    },
  };
}


================================================
FILE: config/notify-webpack-plugin.ts
================================================
// Originally from https://github.com/joshhunt/notify-webpack-plugin/, converted to TypeScript

import { type Compiler, type Stats } from '@rspack/core';

import chalk from 'chalk';

export default class NotifyPlugin {
  name: string;
  firstRun: boolean;
  hideChildren: boolean;

  constructor(name: string, isProd?: boolean) {
    this.name = name;
    this.firstRun = true;
    this.hideChildren = !isProd;
  }

  apply(compiler: Compiler) {
    // Hack to get rid of the 'Child extract-text...' log spam
    compiler.hooks.done.tap('NotifyPlugin', (stat) => {
      stat.compilation.children = this.hideChildren ? [] : stat.compilation.children;
    });

    compiler.hooks.compile.tap('NotifyPlugin', () => {
      const action = this.firstRun ? 'starting to build' : 'updating';
      console.log('==> ' + chalk.cyan(`Webpack is ${action} ${this.name}...`));
    });

    compiler.hooks.done.tap('NotifyPlugin', this.onDone.bind(this));
  }

  onDone(rawWebpackStats: Stats) {
    const { time } = rawWebpackStats.toJson({ timings: true });
    const action = this.firstRun ? 'building' : 'updating';
    console.log('==> ' + chalk.green(`Webpack finished ${action} ${this.name} in ${time}ms`));

    this.firstRun = false;
  }
}


================================================
FILE: config/webpack.ts
================================================
import { InjectManifest } from '@aaroon/workbox-rspack-plugin';
import filterWebpackStats from '@bundle-stats/plugin-webpack-filter';
import { type Configuration, rspack } from '@rspack/core';
import ReactRefreshPlugin from '@rspack/plugin-react-refresh';
import { CleanWebpackPlugin } from 'clean-webpack-plugin';
import CompressionPlugin from 'compression-webpack-plugin';
import GenerateJsonPlugin from 'generate-json-webpack-plugin';
import HtmlWebpackPlugin from 'html-webpack-plugin';
import SondaWebpackPlugin from 'sonda/webpack';
import { TsCheckerRspackPlugin } from 'ts-checker-rspack-plugin';
import { StatsWriterPlugin } from 'webpack-stats-plugin';
import NotifyPlugin from './notify-webpack-plugin.ts';

import browserslist from 'browserslist';
import { execSync } from 'child_process';
import fs from 'fs';
import svgToMiniDataURI from 'mini-svg-data-uri';
import { resolve } from 'node:path';
import zlib from 'zlib';
import csp from './content-security-policy.ts';
import { makeFeatureFlags } from './feature-flags.ts';

const ASSET_NAME_PATTERN = 'static/[name]-[contenthash:6][ext]';

import packageJson from '../package.json' with { type: 'json' };
import createWebAppManifest from './manifest-webapp.ts';

import splash from '../icons/splash.json' with { type: 'json' };

// https://stackoverflow.com/questions/69584268/what-is-the-type-of-the-webpack-config-function-when-it-comes-to-typescript
type CLIValues = boolean | string;
type EnvValues = Record<string, CLIValues | Record<string, Env>>;
interface Env extends EnvValues {
  release: boolean;
  beta: boolean;
  dev: boolean;
  pr: boolean;
  name: 'release' | 'beta' | 'dev' | 'pr';
}
type Argv = Record<string, CLIValues>;
export interface WebpackConfigurationGenerator {
  (env?: Env, argv?: Argv): Configuration | Promise<Configuration>;
}

export default (env: Env) => {
  env.name = Object.keys(env)[0] as Env['name'];
  (['release', 'beta', 'dev', 'pr'] as const).forEach((e) => {
    // set booleans based on env
    env[e] = Boolean(env[e]);
    if (env[e]) {
      env.name = e;
    }
  });

  if (env.dev && env.WEBPACK_SERVE && (!fs.existsSync('key.pem') || !fs.existsSync('cert.pem'))) {
    console.log('Generating certificate');
    execSync('mkcert create-ca --validity 825');
    execSync('mkcert create-cert --validity 825 --key key.pem --cert cert.pem');
  }

  let version = env.dev ? packageJson.version.toString() : process.env.VERSION;

  if (!env.dev) {
    console.log('Building DIM version ' + version);
  }

  const buildTime = Date.now();
  const publicPath = process.env.PUBLIC_PATH ?? '/';

  const featureFlags = makeFeatureFlags(env);
  const contentSecurityPolicy = csp(env.name, featureFlags, version);

  const analyticsProperty = env.release ? 'G-1PW23SGMHN' : 'G-MYWW38Z3LR';
  const jsFilenamePattern = env.dev ? '[name]-[fullhash].js' : '[name]-[contenthash:8].js';
  const cssFilenamePattern = env.dev ? '[name]-[fullhash].css' : '[name]-[contenthash:8].css';

  const lightningCssLoader = {
    loader: 'builtin:lightningcss-loader',
    /** @type {import('@rspack/core').LightningcssLoaderOptions} */
    options: {
      targets: packageJson.browserslist,
    },
  };

  const config: Configuration = {
    mode: env.dev ? ('development' as const) : ('production' as const),

    entry: {
      main: './src/Index.tsx',
      browsercheck: './src/browsercheck.js',
      earlyErrorReport: './src/earlyErrorReport.js',
      authReturn: './src/authReturn.ts',
      backup: './src/backup.ts',
    },

    // https://github.com/webpack/webpack-dev-server/issues/2758
    // target: env.dev ? 'web' : 'browserslist',
    target: 'browserslist',

    output: {
      path: resolve('./dist'),
      publicPath,
      filename: jsFilenamePattern,
      chunkFilename: jsFilenamePattern,
      assetModuleFilename: ASSET_NAME_PATTERN,
      hashFunction: 'xxhash64',
    },

    // Dev server
    devServer: env.dev
      ? {
          host: process.env.DOCKER ? '0.0.0.0' : 'localhost',
          allowedHosts: 'all',
          server: {
            type: 'https',
            options: {
              key: fs.readFileSync('key.pem'), // Private keys in PEM format.
              cert: fs.readFileSync('cert.pem'), // Cert chains in PEM format.
            },
          },
          devMiddleware: {
            stats: 'errors-only',
          },
          client: {
            overlay: false,
            logging: 'none', // we don't need to see build errors in the console log
          },
          historyApiFallback: true,
          hot: 'only',
          liveReload: false,
          headers: (req) => {
            // This mirrors what's in .htaccess - headers for html paths, COEP for JS.
            const headers: Record<string, string | string[]> = req.url?.match
Download .txt
gitextract_c6q93roc/

├── .dockerignore
├── .editorconfig
├── .git-blame-ignore-revs
├── .gitattributes
├── .github/
│   ├── FUNDING.yml
│   ├── ISSUE_TEMPLATE/
│   │   ├── bug_report.yml
│   │   └── feature_request.yml
│   ├── actions/
│   │   └── setup-pnpm/
│   │       └── action.yml
│   ├── copilot-instructions.md
│   ├── dependabot.yml
│   ├── pull_request_template.md
│   ├── scripts/
│   │   ├── discord_changelog.py
│   │   └── i18n_discord.py
│   └── workflows/
│       ├── auto-merge.yml
│       ├── changelog-updater.yml
│       ├── copilot-setup-steps.yml
│       ├── deploy-beta.yml
│       ├── deploy-prod.yml
│       ├── i18n-bot-download.yml
│       ├── i18n-bot-upload.yml
│       ├── i18n-update.yml
│       ├── lint-workflows.yml
│       ├── notify-discord-changelog.yml
│       ├── notify-discord-i18n.yml
│       ├── pr-cleanup.yml
│       ├── pr-reports.yml
│       └── pr-validation.yml
├── .gitignore
├── .gitmodules
├── .husky/
│   └── pre-commit
├── .npmrc
├── .nvmrc
├── .prettierignore
├── .prettierrc
├── .stylelintrc
├── .svgo.yml
├── .vscode/
│   ├── css.json
│   ├── dim.code-snippets
│   ├── extensions.json
│   ├── launch.json
│   ├── settings.json
│   └── tasks.json
├── LICENSE.md
├── README.md
├── babel.config.cjs
├── build/
│   ├── deploy-prod.sh
│   ├── purge-cloudflare.sh
│   ├── rsync-deploy.sh
│   ├── test-changelog.js
│   └── update-changelog.js
├── config/
│   ├── .well-known/
│   │   ├── android-config.beta.json
│   │   ├── android-config.json
│   │   └── apple-config.json
│   ├── content-security-policy.ts
│   ├── cspell/
│   │   ├── bungie-dict.txt
│   │   ├── dim-dict.txt
│   │   ├── dim-username-dict.txt
│   │   └── programming-dict.txt
│   ├── dim_travis.rsa.enc
│   ├── dim_travis.rsa.pub
│   ├── feature-flags.ts
│   ├── i18n.json
│   ├── manifest-webapp.ts
│   ├── notify-webpack-plugin.ts
│   └── webpack.ts
├── crowdin.yml
├── cspell.json
├── docker-compose.yml
├── docs/
│   ├── CHANGELOG.md
│   ├── CODE_OF_CONDUCT.md
│   ├── COMMUNITY_CURATIONS.md
│   ├── CONTRIBUTING.md
│   ├── Docker.md
│   ├── OLD_CHANGELOG/
│   │   ├── OLD_CHANGELOG_3.X.X.md
│   │   ├── OLD_CHANGELOG_4.X.X.md
│   │   ├── OLD_CHANGELOG_5.X.X.md
│   │   └── OLD_CHANGELOG_6.X.X.md
│   ├── TRANSLATIONS.md
│   └── clean-changelog.rb
├── eslint.config.js
├── i18next-scanner.config.cjs
├── icons/
│   ├── build_icons.cjs
│   └── splash.json
├── jest.config.js
├── package.json
├── src/
│   ├── 404.html
│   ├── @types/
│   │   └── i18next.d.ts
│   ├── Index.tsx
│   ├── StorageTest.tsx
│   ├── __mocks__/
│   │   └── fileMock.js
│   ├── app/
│   │   ├── App.m.scss
│   │   ├── App.m.scss.d.ts
│   │   ├── App.tsx
│   │   ├── Root.tsx
│   │   ├── _variables.scss
│   │   ├── accounts/
│   │   │   ├── Account.m.scss
│   │   │   ├── Account.m.scss.d.ts
│   │   │   ├── Account.tsx
│   │   │   ├── MenuAccounts.m.scss
│   │   │   ├── MenuAccounts.m.scss.d.ts
│   │   │   ├── MenuAccounts.tsx
│   │   │   ├── SelectAccount.m.scss
│   │   │   ├── SelectAccount.m.scss.d.ts
│   │   │   ├── SelectAccount.tsx
│   │   │   ├── actions.ts
│   │   │   ├── bungie-account.ts
│   │   │   ├── destiny-account.test.ts
│   │   │   ├── destiny-account.ts
│   │   │   ├── observers.ts
│   │   │   ├── platforms.ts
│   │   │   ├── reducer.ts
│   │   │   └── selectors.ts
│   │   ├── armory/
│   │   │   ├── AllWishlistRolls.m.scss
│   │   │   ├── AllWishlistRolls.m.scss.d.ts
│   │   │   ├── AllWishlistRolls.tsx
│   │   │   ├── Armory.m.scss
│   │   │   ├── Armory.m.scss.d.ts
│   │   │   ├── Armory.tsx
│   │   │   ├── ArmoryPage.tsx
│   │   │   ├── ArmorySheet.m.scss
│   │   │   ├── ArmorySheet.m.scss.d.ts
│   │   │   ├── ArmorySheet.tsx
│   │   │   ├── ItemGrid.tsx
│   │   │   ├── LazyArmory.ts
│   │   │   ├── Links.m.scss
│   │   │   ├── Links.m.scss.d.ts
│   │   │   ├── Links.tsx
│   │   │   ├── WishListEntry.m.scss
│   │   │   ├── WishListEntry.m.scss.d.ts
│   │   │   ├── WishListEntry.tsx
│   │   │   ├── crafting-utils.ts
│   │   │   ├── trait-to-enhanced-trait.d.ts
│   │   │   ├── wishlist-collapser.test.ts
│   │   │   └── wishlist-collapser.ts
│   │   ├── bungie-api/
│   │   │   ├── README.md
│   │   │   ├── __snapshots__/
│   │   │   │   └── http-client.test.ts.snap
│   │   │   ├── authenticated-fetch.ts
│   │   │   ├── bungie-api-utils.ts
│   │   │   ├── bungie-core-api.ts
│   │   │   ├── bungie-service-helper.ts
│   │   │   ├── destiny1-api.ts
│   │   │   ├── destiny2-api.ts
│   │   │   ├── error-toaster.tsx
│   │   │   ├── http-client.test.ts
│   │   │   ├── http-client.ts
│   │   │   ├── oauth-tokens.ts
│   │   │   ├── oauth.ts
│   │   │   ├── rate-limit-config.ts
│   │   │   └── rate-limiter.ts
│   │   ├── character-tile/
│   │   │   ├── CharacterHeaderXP.m.scss
│   │   │   ├── CharacterHeaderXP.m.scss.d.ts
│   │   │   ├── CharacterHeaderXP.tsx
│   │   │   ├── CharacterTile.m.scss
│   │   │   ├── CharacterTile.m.scss.d.ts
│   │   │   ├── CharacterTile.tsx
│   │   │   ├── CharacterTileButton.m.scss
│   │   │   ├── CharacterTileButton.m.scss.d.ts
│   │   │   ├── CharacterTileButton.tsx
│   │   │   ├── StoreHeading.m.scss
│   │   │   ├── StoreHeading.m.scss.d.ts
│   │   │   ├── StoreHeading.tsx
│   │   │   ├── StoreIcon.m.scss
│   │   │   ├── StoreIcon.m.scss.d.ts
│   │   │   └── StoreIcon.tsx
│   │   ├── clarity/
│   │   │   ├── about.ts
│   │   │   ├── actions.ts
│   │   │   ├── descriptions/
│   │   │   │   ├── ClarityDescriptions.tsx
│   │   │   │   ├── Description.m.scss
│   │   │   │   ├── Description.m.scss.d.ts
│   │   │   │   ├── character-stats.ts
│   │   │   │   ├── descriptionInterface.ts
│   │   │   │   └── loadDescriptions.ts
│   │   │   ├── reducer.ts
│   │   │   └── selectors.ts
│   │   ├── compare/
│   │   │   ├── Compare.m.scss
│   │   │   ├── Compare.m.scss.d.ts
│   │   │   ├── Compare.tsx
│   │   │   ├── CompareButtons.m.scss
│   │   │   ├── CompareButtons.m.scss.d.ts
│   │   │   ├── CompareColumns.m.scss
│   │   │   ├── CompareColumns.m.scss.d.ts
│   │   │   ├── CompareColumns.tsx
│   │   │   ├── CompareContainer.tsx
│   │   │   ├── CompareItem.m.scss
│   │   │   ├── CompareItem.m.scss.d.ts
│   │   │   ├── CompareItem.tsx
│   │   │   ├── CompareStat.m.scss
│   │   │   ├── CompareStat.m.scss.d.ts
│   │   │   ├── CompareStat.tsx
│   │   │   ├── CompareSuggestions.tsx
│   │   │   ├── actions.ts
│   │   │   ├── compare-buttons.tsx
│   │   │   ├── compare-utils.ts
│   │   │   ├── reducer.ts
│   │   │   ├── selectors.ts
│   │   │   └── types.ts
│   │   ├── css-variables.ts
│   │   ├── debug/
│   │   │   ├── Debug.m.scss
│   │   │   ├── Debug.m.scss.d.ts
│   │   │   └── Debug.tsx
│   │   ├── destiny1/
│   │   │   ├── activities/
│   │   │   │   ├── Activities.m.scss
│   │   │   │   ├── Activities.m.scss.d.ts
│   │   │   │   └── Activities.tsx
│   │   │   ├── d1-bucket-categories.ts
│   │   │   ├── d1-buckets.ts
│   │   │   ├── d1-definitions.ts
│   │   │   ├── d1-factions.ts
│   │   │   ├── d1-manifest-types.ts
│   │   │   ├── loadout-builder/
│   │   │   │   ├── D1LoadoutBuilder.m.scss
│   │   │   │   ├── D1LoadoutBuilder.m.scss.d.ts
│   │   │   │   ├── D1LoadoutBuilder.tsx
│   │   │   │   ├── ExcludeItemsDropTarget.tsx
│   │   │   │   ├── GeneratedSet.m.scss
│   │   │   │   ├── GeneratedSet.m.scss.d.ts
│   │   │   │   ├── GeneratedSet.tsx
│   │   │   │   ├── LoadoutBuilderDropTarget.m.scss
│   │   │   │   ├── LoadoutBuilderDropTarget.m.scss.d.ts
│   │   │   │   ├── LoadoutBuilderDropTarget.tsx
│   │   │   │   ├── LoadoutBuilderItem.m.scss
│   │   │   │   ├── LoadoutBuilderItem.m.scss.d.ts
│   │   │   │   ├── LoadoutBuilderItem.tsx
│   │   │   │   ├── LoadoutBuilderLockPerk.m.scss
│   │   │   │   ├── LoadoutBuilderLockPerk.m.scss.d.ts
│   │   │   │   ├── LoadoutBuilderLockPerk.tsx
│   │   │   │   ├── LoadoutBuilderLocksDialog.m.scss
│   │   │   │   ├── LoadoutBuilderLocksDialog.m.scss.d.ts
│   │   │   │   ├── LoadoutBuilderLocksDialog.tsx
│   │   │   │   ├── calculate.ts
│   │   │   │   ├── types.ts
│   │   │   │   └── utils.ts
│   │   │   ├── loadout-drawer/
│   │   │   │   ├── Buttons.m.scss
│   │   │   │   ├── Buttons.m.scss.d.ts
│   │   │   │   ├── Buttons.tsx
│   │   │   │   ├── D1LoadoutDrawer.m.scss
│   │   │   │   ├── D1LoadoutDrawer.m.scss.d.ts
│   │   │   │   ├── D1LoadoutDrawer.tsx
│   │   │   │   ├── LoadoutDrawerBucket.m.scss
│   │   │   │   ├── LoadoutDrawerBucket.m.scss.d.ts
│   │   │   │   ├── LoadoutDrawerBucket.tsx
│   │   │   │   ├── LoadoutDrawerContents.m.scss
│   │   │   │   ├── LoadoutDrawerContents.m.scss.d.ts
│   │   │   │   ├── LoadoutDrawerContents.tsx
│   │   │   │   ├── LoadoutDrawerItem.m.scss
│   │   │   │   ├── LoadoutDrawerItem.m.scss.d.ts
│   │   │   │   ├── LoadoutDrawerItem.tsx
│   │   │   │   ├── LoadoutDrawerOptions.m.scss
│   │   │   │   ├── LoadoutDrawerOptions.m.scss.d.ts
│   │   │   │   └── LoadoutDrawerOptions.tsx
│   │   │   ├── record-books/
│   │   │   │   ├── RecordBooks.m.scss
│   │   │   │   ├── RecordBooks.m.scss.d.ts
│   │   │   │   └── RecordBooks.tsx
│   │   │   └── vendors/
│   │   │       ├── D1Vendor.tsx
│   │   │       ├── D1VendorItem.m.scss
│   │   │       ├── D1VendorItem.m.scss.d.ts
│   │   │       ├── D1VendorItem.tsx
│   │   │       ├── D1VendorItems.tsx
│   │   │       ├── D1Vendors.m.scss
│   │   │       ├── D1Vendors.m.scss.d.ts
│   │   │       ├── D1Vendors.tsx
│   │   │       └── vendor.service.ts
│   │   ├── destiny2/
│   │   │   ├── d2-bucket-categories.ts
│   │   │   ├── d2-buckets.ts
│   │   │   ├── d2-definitions.test.ts
│   │   │   ├── d2-definitions.ts
│   │   │   └── definitions.ts
│   │   ├── developer/
│   │   │   └── Developer.tsx
│   │   ├── dim-api/
│   │   │   ├── actions.ts
│   │   │   ├── api-permission-prompt.m.scss
│   │   │   ├── api-permission-prompt.m.scss.d.ts
│   │   │   ├── api-permission-prompt.tsx
│   │   │   ├── api-types.ts
│   │   │   ├── basic-actions.ts
│   │   │   ├── dim-api-helper.ts
│   │   │   ├── dim-api.ts
│   │   │   ├── import.ts
│   │   │   ├── reducer.test.ts
│   │   │   ├── reducer.ts
│   │   │   ├── register-app.ts
│   │   │   └── selectors.ts
│   │   ├── dim-ui/
│   │   │   ├── AlertIcon.m.scss
│   │   │   ├── AlertIcon.m.scss.d.ts
│   │   │   ├── AlertIcon.tsx
│   │   │   ├── AnimatedNumber.tsx
│   │   │   ├── AutoRefresh.tsx
│   │   │   ├── BungieImage.tsx
│   │   │   ├── CharacterSelect.m.scss
│   │   │   ├── CharacterSelect.m.scss.d.ts
│   │   │   ├── CharacterSelect.tsx
│   │   │   ├── CheckButton.m.scss
│   │   │   ├── CheckButton.m.scss.d.ts
│   │   │   ├── CheckButton.tsx
│   │   │   ├── ClassIcon.tsx
│   │   │   ├── ClickOutside.tsx
│   │   │   ├── ClickOutsideRoot.tsx
│   │   │   ├── ClosableContainer.m.scss
│   │   │   ├── ClosableContainer.m.scss.d.ts
│   │   │   ├── ClosableContainer.tsx
│   │   │   ├── CollapsibleTitle.m.scss
│   │   │   ├── CollapsibleTitle.m.scss.d.ts
│   │   │   ├── CollapsibleTitle.tsx
│   │   │   ├── ConfirmButton.m.scss
│   │   │   ├── ConfirmButton.m.scss.d.ts
│   │   │   ├── ConfirmButton.tsx
│   │   │   ├── Countdown.tsx
│   │   │   ├── CustomStatTotal.m.scss
│   │   │   ├── CustomStatTotal.m.scss.d.ts
│   │   │   ├── CustomStatTotal.tsx
│   │   │   ├── CustomStatWeights.m.scss
│   │   │   ├── CustomStatWeights.m.scss.d.ts
│   │   │   ├── CustomStatWeights.tsx
│   │   │   ├── DestinyTooltipText.m.scss
│   │   │   ├── DestinyTooltipText.m.scss.d.ts
│   │   │   ├── DestinyTooltipText.tsx
│   │   │   ├── DiamondProgress.m.scss
│   │   │   ├── DiamondProgress.m.scss.d.ts
│   │   │   ├── DiamondProgress.tsx
│   │   │   ├── Dropdown.m.scss
│   │   │   ├── Dropdown.m.scss.d.ts
│   │   │   ├── Dropdown.tsx
│   │   │   ├── ElementIcon.m.scss
│   │   │   ├── ElementIcon.m.scss.d.ts
│   │   │   ├── ElementIcon.tsx
│   │   │   ├── EnergyIncrements.m.scss
│   │   │   ├── EnergyIncrements.m.scss.d.ts
│   │   │   ├── EnergyIncrements.tsx
│   │   │   ├── ErrorBoundary.tsx
│   │   │   ├── ExpandableTextBlock.m.scss
│   │   │   ├── ExpandableTextBlock.m.scss.d.ts
│   │   │   ├── ExpandableTextBlock.tsx
│   │   │   ├── ExternalLink.tsx
│   │   │   ├── FileUpload.m.scss
│   │   │   ├── FileUpload.m.scss.d.ts
│   │   │   ├── FileUpload.tsx
│   │   │   ├── FilterPills.m.scss
│   │   │   ├── FilterPills.m.scss.d.ts
│   │   │   ├── FilterPills.tsx
│   │   │   ├── FractionalPowerLevel.m.scss
│   │   │   ├── FractionalPowerLevel.m.scss.d.ts
│   │   │   ├── FractionalPowerLevel.tsx
│   │   │   ├── HelpLink.m.scss
│   │   │   ├── HelpLink.m.scss.d.ts
│   │   │   ├── HelpLink.tsx
│   │   │   ├── ItemCategoryIcon.m.scss
│   │   │   ├── ItemCategoryIcon.m.scss.d.ts
│   │   │   ├── ItemCategoryIcon.tsx
│   │   │   ├── ItemPop.m.scss
│   │   │   ├── ItemPop.m.scss.d.ts
│   │   │   ├── KeyHelp.m.scss
│   │   │   ├── KeyHelp.m.scss.d.ts
│   │   │   ├── KeyHelp.tsx
│   │   │   ├── Loading.m.scss
│   │   │   ├── Loading.m.scss.d.ts
│   │   │   ├── Loading.tsx
│   │   │   ├── PageLoading.m.scss
│   │   │   ├── PageLoading.m.scss.d.ts
│   │   │   ├── PageLoading.tsx
│   │   │   ├── PageWithMenu.m.scss
│   │   │   ├── PageWithMenu.m.scss.d.ts
│   │   │   ├── PageWithMenu.tsx
│   │   │   ├── PressTip.m.scss
│   │   │   ├── PressTip.m.scss.d.ts
│   │   │   ├── PressTip.tsx
│   │   │   ├── README.md
│   │   │   ├── RadioButtons.m.scss
│   │   │   ├── RadioButtons.m.scss.d.ts
│   │   │   ├── RadioButtons.tsx
│   │   │   ├── Select.m.scss
│   │   │   ├── Select.m.scss.d.ts
│   │   │   ├── Select.tsx
│   │   │   ├── SetFilterButton.m.scss
│   │   │   ├── SetFilterButton.m.scss.d.ts
│   │   │   ├── SetFilterButton.tsx
│   │   │   ├── Sheet.m.scss
│   │   │   ├── Sheet.m.scss.d.ts
│   │   │   ├── Sheet.tsx
│   │   │   ├── SheetHorizontalScrollContainer.m.scss
│   │   │   ├── SheetHorizontalScrollContainer.m.scss.d.ts
│   │   │   ├── SheetHorizontalScrollContainer.tsx
│   │   │   ├── ShowPageLoading.tsx
│   │   │   ├── SpecialtyModSlotIcon.m.scss
│   │   │   ├── SpecialtyModSlotIcon.m.scss.d.ts
│   │   │   ├── SpecialtyModSlotIcon.tsx
│   │   │   ├── StaticPage.m.scss
│   │   │   ├── StaticPage.m.scss.d.ts
│   │   │   ├── StaticPage.tsx
│   │   │   ├── Switch.m.scss
│   │   │   ├── Switch.m.scss.d.ts
│   │   │   ├── Switch.tsx
│   │   │   ├── TileGrid.m.scss
│   │   │   ├── TileGrid.m.scss.d.ts
│   │   │   ├── TileGrid.tsx
│   │   │   ├── UserGuideLink.tsx
│   │   │   ├── VirtualList.m.scss
│   │   │   ├── VirtualList.m.scss.d.ts
│   │   │   ├── VirtualList.tsx
│   │   │   ├── WeaponGroupingIcon.m.scss
│   │   │   ├── WeaponGroupingIcon.m.scss.d.ts
│   │   │   ├── WeaponGroupingIcon.tsx
│   │   │   ├── _tooltip-mixins.scss
│   │   │   ├── common.m.scss
│   │   │   ├── destiny-symbols/
│   │   │   │   ├── ColorDestinySymbols.m.scss
│   │   │   │   ├── ColorDestinySymbols.m.scss.d.ts
│   │   │   │   ├── ColorDestinySymbols.tsx
│   │   │   │   ├── RichDestinyText.tsx
│   │   │   │   ├── SymbolsPicker.m.scss
│   │   │   │   ├── SymbolsPicker.m.scss.d.ts
│   │   │   │   ├── SymbolsPicker.tsx
│   │   │   │   ├── destiny-symbols.test.ts
│   │   │   │   ├── destiny-symbols.ts
│   │   │   │   └── rich-destiny-text.ts
│   │   │   ├── dim-button.scss
│   │   │   ├── scroll.ts
│   │   │   ├── sheets-open.ts
│   │   │   ├── svgs/
│   │   │   │   ├── BucketIcon.tsx
│   │   │   │   └── itemCategory.ts
│   │   │   ├── table-columns.test.ts
│   │   │   ├── table-columns.ts
│   │   │   ├── text-complete/
│   │   │   │   ├── text-complete.m.scss
│   │   │   │   ├── text-complete.m.scss.d.ts
│   │   │   │   └── text-complete.ts
│   │   │   ├── useBulkNote.m.scss
│   │   │   ├── useBulkNote.m.scss.d.ts
│   │   │   ├── useBulkNote.tsx
│   │   │   ├── useConfirm.tsx
│   │   │   ├── useDialog.m.scss
│   │   │   ├── useDialog.m.scss.d.ts
│   │   │   ├── useDialog.tsx
│   │   │   ├── useFixOverscrollBehavior.ts
│   │   │   ├── usePopper.ts
│   │   │   ├── usePrompt.m.scss
│   │   │   ├── usePrompt.m.scss.d.ts
│   │   │   └── usePrompt.tsx
│   │   ├── farming/
│   │   │   ├── Farming.m.scss
│   │   │   ├── Farming.m.scss.d.ts
│   │   │   ├── Farming.tsx
│   │   │   ├── actions.ts
│   │   │   ├── basic-actions.ts
│   │   │   ├── reducer.ts
│   │   │   └── selectors.ts
│   │   ├── gear-power/
│   │   │   ├── GearPower.m.scss
│   │   │   ├── GearPower.m.scss.d.ts
│   │   │   ├── GearPower.tsx
│   │   │   └── gear-power.ts
│   │   ├── google.ts
│   │   ├── hotkeys/
│   │   │   ├── GlobalHotkeys.tsx
│   │   │   ├── HotkeysCheatSheet.m.scss
│   │   │   ├── HotkeysCheatSheet.m.scss.d.ts
│   │   │   ├── HotkeysCheatSheet.tsx
│   │   │   ├── hotkeys.test.ts
│   │   │   ├── hotkeys.ts
│   │   │   └── useHotkey.ts
│   │   ├── i18n.ts
│   │   ├── i18next-t.ts
│   │   ├── infuse/
│   │   │   ├── InfusionFinder.m.scss
│   │   │   ├── InfusionFinder.m.scss.d.ts
│   │   │   ├── InfusionFinder.tsx
│   │   │   └── infuse.ts
│   │   ├── inventory/
│   │   │   ├── ArtifactXP.m.scss
│   │   │   ├── ArtifactXP.m.scss.d.ts
│   │   │   ├── ArtifactXP.tsx
│   │   │   ├── BadgeInfo.m.scss
│   │   │   ├── BadgeInfo.m.scss.d.ts
│   │   │   ├── BadgeInfo.tsx
│   │   │   ├── ConnectedInventoryItem.tsx
│   │   │   ├── DragPerformanceFix.m.scss
│   │   │   ├── DragPerformanceFix.m.scss.d.ts
│   │   │   ├── DragPerformanceFix.tsx
│   │   │   ├── DraggableInventoryItem.m.scss
│   │   │   ├── DraggableInventoryItem.m.scss.d.ts
│   │   │   ├── DraggableInventoryItem.tsx
│   │   │   ├── InventoryItem.m.scss
│   │   │   ├── InventoryItem.m.scss.d.ts
│   │   │   ├── InventoryItem.tsx
│   │   │   ├── ItemDragPreview.tsx
│   │   │   ├── ItemIcon.m.scss
│   │   │   ├── ItemIcon.m.scss.d.ts
│   │   │   ├── ItemIcon.tsx
│   │   │   ├── ItemIconPlaceholder.m.scss
│   │   │   ├── ItemIconPlaceholder.m.scss.d.ts
│   │   │   ├── ItemIconPlaceholder.tsx
│   │   │   ├── ItemPopupTrigger.tsx
│   │   │   ├── ItemPowerSet.m.scss
│   │   │   ├── ItemPowerSet.m.scss.d.ts
│   │   │   ├── ItemPowerSet.tsx
│   │   │   ├── MoveNotifications.m.scss
│   │   │   ├── MoveNotifications.m.scss.d.ts
│   │   │   ├── MoveNotifications.tsx
│   │   │   ├── NewItemIndicator.m.scss
│   │   │   ├── NewItemIndicator.m.scss.d.ts
│   │   │   ├── NewItemIndicator.tsx
│   │   │   ├── PullFromPostmaster.m.scss
│   │   │   ├── PullFromPostmaster.m.scss.d.ts
│   │   │   ├── PullFromPostmaster.tsx
│   │   │   ├── RatingIcon.m.scss
│   │   │   ├── RatingIcon.m.scss.d.ts
│   │   │   ├── RatingIcon.tsx
│   │   │   ├── SyncTagLock.tsx
│   │   │   ├── TagIcon.tsx
│   │   │   ├── __snapshots__/
│   │   │   │   └── d2-stores.test.ts.snap
│   │   │   ├── actions.ts
│   │   │   ├── advanced-write-actions.ts
│   │   │   ├── bulk-actions.tsx
│   │   │   ├── cross-tab.ts
│   │   │   ├── d1-stores.ts
│   │   │   ├── d2-stores.test.ts
│   │   │   ├── d2-stores.ts
│   │   │   ├── dim-item-info.ts
│   │   │   ├── drag-events.ts
│   │   │   ├── inventory-buckets.ts
│   │   │   ├── item-move-service.ts
│   │   │   ├── item-types.ts
│   │   │   ├── locate-item.ts
│   │   │   ├── manual-moves.ts
│   │   │   ├── move-item.ts
│   │   │   ├── note-hashtags.ts
│   │   │   ├── notes-hashtags.test.ts
│   │   │   ├── observers.ts
│   │   │   ├── reducer.ts
│   │   │   ├── rewards.ts
│   │   │   ├── selectors.ts
│   │   │   ├── spreadsheets.ts
│   │   │   ├── store/
│   │   │   │   ├── armor-quality.ts
│   │   │   │   ├── catalyst.ts
│   │   │   │   ├── character-utils.ts
│   │   │   │   ├── crafted.ts
│   │   │   │   ├── d1-item-factory.ts
│   │   │   │   ├── d1-store-factory.ts
│   │   │   │   ├── d2-item-factory.ts
│   │   │   │   ├── d2-store-factory.ts
│   │   │   │   ├── deepsight.ts
│   │   │   │   ├── energy.ts
│   │   │   │   ├── enhanced-info.d.ts
│   │   │   │   ├── exotic-class-item.ts
│   │   │   │   ├── exotic-to-catalyst-record.d.ts
│   │   │   │   ├── hooks.ts
│   │   │   │   ├── item-index.ts
│   │   │   │   ├── masterwork.ts
│   │   │   │   ├── missing-sources.d.ts
│   │   │   │   ├── objectives.ts
│   │   │   │   ├── override-sockets.ts
│   │   │   │   ├── patterns.ts
│   │   │   │   ├── season-d2ai.d.ts
│   │   │   │   ├── season.ts
│   │   │   │   ├── selectors.ts
│   │   │   │   ├── sockets.ts
│   │   │   │   ├── stats-conditional.ts
│   │   │   │   ├── stats-custom.ts
│   │   │   │   ├── stats.ts
│   │   │   │   └── well-rested.ts
│   │   │   ├── store-types.ts
│   │   │   ├── stores-helpers.ts
│   │   │   └── subclass.ts
│   │   ├── inventory-page/
│   │   │   ├── CategoryStrip.m.scss
│   │   │   ├── CategoryStrip.m.scss.d.ts
│   │   │   ├── CategoryStrip.tsx
│   │   │   ├── D1Reputation.m.scss
│   │   │   ├── D1Reputation.m.scss.d.ts
│   │   │   ├── D1Reputation.tsx
│   │   │   ├── D1ReputationSection.tsx
│   │   │   ├── DesktopStores.m.scss
│   │   │   ├── DesktopStores.m.scss.d.ts
│   │   │   ├── DesktopStores.tsx
│   │   │   ├── HeaderShadowDiv.m.scss
│   │   │   ├── HeaderShadowDiv.m.scss.d.ts
│   │   │   ├── HeaderShadowDiv.tsx
│   │   │   ├── Inventory.tsx
│   │   │   ├── InventoryCollapsibleTitle.m.scss
│   │   │   ├── InventoryCollapsibleTitle.m.scss.d.ts
│   │   │   ├── InventoryCollapsibleTitle.tsx
│   │   │   ├── PhoneStores.m.scss
│   │   │   ├── PhoneStores.m.scss.d.ts
│   │   │   ├── PhoneStores.tsx
│   │   │   ├── PhoneStoresHeader.m.scss
│   │   │   ├── PhoneStoresHeader.m.scss.d.ts
│   │   │   ├── PhoneStoresHeader.tsx
│   │   │   ├── StoreBucket.m.scss
│   │   │   ├── StoreBucket.m.scss.d.ts
│   │   │   ├── StoreBucket.scss
│   │   │   ├── StoreBucket.tsx
│   │   │   ├── StoreBucketDropTarget.m.scss
│   │   │   ├── StoreBucketDropTarget.m.scss.d.ts
│   │   │   ├── StoreBucketDropTarget.tsx
│   │   │   ├── StoreBuckets.m.scss
│   │   │   ├── StoreBuckets.m.scss.d.ts
│   │   │   ├── StoreBuckets.tsx
│   │   │   ├── StoreInventoryItem.tsx
│   │   │   ├── Stores.scss
│   │   │   └── Stores.tsx
│   │   ├── issue-awareness-banner/
│   │   │   ├── Game2Give.m.scss
│   │   │   ├── Game2Give.m.scss.d.ts
│   │   │   ├── Game2Give.tsx
│   │   │   ├── IssueAwarenessBanner.tsx
│   │   │   └── useGame2GiveData.tsx
│   │   ├── item-actions/
│   │   │   ├── ActionButton.m.scss
│   │   │   ├── ActionButton.m.scss.d.ts
│   │   │   ├── ActionButton.tsx
│   │   │   ├── ActionButtons.m.scss
│   │   │   ├── ActionButtons.m.scss.d.ts
│   │   │   ├── ActionButtons.tsx
│   │   │   ├── ItemAccessoryButtons.tsx
│   │   │   ├── ItemActionsDropdown.m.scss
│   │   │   ├── ItemActionsDropdown.m.scss.d.ts
│   │   │   ├── ItemActionsDropdown.tsx
│   │   │   ├── ItemMoveLocations.m.scss
│   │   │   ├── ItemMoveLocations.m.scss.d.ts
│   │   │   ├── ItemMoveLocations.tsx
│   │   │   ├── LockButton.m.scss
│   │   │   ├── LockButton.m.scss.d.ts
│   │   │   └── LockButton.tsx
│   │   ├── item-feed/
│   │   │   ├── Highlights.m.scss
│   │   │   ├── Highlights.m.scss.d.ts
│   │   │   ├── Highlights.tsx
│   │   │   ├── ItemFeed.m.scss
│   │   │   ├── ItemFeed.m.scss.d.ts
│   │   │   ├── ItemFeed.tsx
│   │   │   ├── ItemFeedPage.m.scss
│   │   │   ├── ItemFeedPage.m.scss.d.ts
│   │   │   ├── ItemFeedPage.tsx
│   │   │   ├── ItemFeedSidebar.m.scss
│   │   │   ├── ItemFeedSidebar.m.scss.d.ts
│   │   │   ├── ItemFeedSidebar.tsx
│   │   │   ├── TagButtons.m.scss
│   │   │   ├── TagButtons.m.scss.d.ts
│   │   │   └── TagButtons.tsx
│   │   ├── item-picker/
│   │   │   ├── ItemPicker.m.scss
│   │   │   ├── ItemPicker.m.scss.d.ts
│   │   │   ├── ItemPicker.tsx
│   │   │   ├── ItemPickerContainer.tsx
│   │   │   └── item-picker.ts
│   │   ├── item-popup/
│   │   │   ├── AmmoIcon.m.scss
│   │   │   ├── AmmoIcon.m.scss.d.ts
│   │   │   ├── AmmoIcon.tsx
│   │   │   ├── ApplyPerkSelection.m.scss
│   │   │   ├── ApplyPerkSelection.m.scss.d.ts
│   │   │   ├── ApplyPerkSelection.tsx
│   │   │   ├── ArchetypeSocket.m.scss
│   │   │   ├── ArchetypeSocket.m.scss.d.ts
│   │   │   ├── ArchetypeSocket.tsx
│   │   │   ├── BreakerType.m.scss
│   │   │   ├── BreakerType.m.scss.d.ts
│   │   │   ├── BreakerType.tsx
│   │   │   ├── DeepSightHarmonizerIcon.m.scss
│   │   │   ├── DeepSightHarmonizerIcon.m.scss.d.ts
│   │   │   ├── DeepsightHarmonizerIcon.tsx
│   │   │   ├── DesktopItemActions.m.scss
│   │   │   ├── DesktopItemActions.m.scss.d.ts
│   │   │   ├── DesktopItemActions.tsx
│   │   │   ├── EmblemPreview.m.scss
│   │   │   ├── EmblemPreview.m.scss.d.ts
│   │   │   ├── EmblemPreview.tsx
│   │   │   ├── EmoteSockets.m.scss
│   │   │   ├── EmoteSockets.m.scss.d.ts
│   │   │   ├── EmoteSockets.tsx
│   │   │   ├── EnergyMeter.m.scss
│   │   │   ├── EnergyMeter.m.scss.d.ts
│   │   │   ├── EnergyMeter.tsx
│   │   │   ├── ItemDescription.m.scss
│   │   │   ├── ItemDescription.m.scss.d.ts
│   │   │   ├── ItemDescription.tsx
│   │   │   ├── ItemDetails.m.scss
│   │   │   ├── ItemDetails.m.scss.d.ts
│   │   │   ├── ItemDetails.tsx
│   │   │   ├── ItemExpiration.tsx
│   │   │   ├── ItemMoveAmount.m.scss
│   │   │   ├── ItemMoveAmount.m.scss.d.ts
│   │   │   ├── ItemMoveAmount.tsx
│   │   │   ├── ItemPerks.m.scss
│   │   │   ├── ItemPerks.m.scss.d.ts
│   │   │   ├── ItemPerks.tsx
│   │   │   ├── ItemPerksList.m.scss
│   │   │   ├── ItemPerksList.m.scss.d.ts
│   │   │   ├── ItemPerksList.tsx
│   │   │   ├── ItemPopup.m.scss
│   │   │   ├── ItemPopup.m.scss.d.ts
│   │   │   ├── ItemPopup.tsx
│   │   │   ├── ItemPopupBody.scss
│   │   │   ├── ItemPopupContainer.tsx
│   │   │   ├── ItemPopupHeader.m.scss
│   │   │   ├── ItemPopupHeader.m.scss.d.ts
│   │   │   ├── ItemPopupHeader.tsx
│   │   │   ├── ItemPopupTabs.m.scss
│   │   │   ├── ItemPopupTabs.m.scss.d.ts
│   │   │   ├── ItemPopupTabs.tsx
│   │   │   ├── ItemSockets.m.scss
│   │   │   ├── ItemSockets.m.scss.d.ts
│   │   │   ├── ItemSockets.tsx
│   │   │   ├── ItemSocketsGeneral.m.scss
│   │   │   ├── ItemSocketsGeneral.m.scss.d.ts
│   │   │   ├── ItemSocketsGeneral.tsx
│   │   │   ├── ItemSocketsWeapons.m.scss
│   │   │   ├── ItemSocketsWeapons.m.scss.d.ts
│   │   │   ├── ItemSocketsWeapons.tsx
│   │   │   ├── ItemStat.m.scss
│   │   │   ├── ItemStat.m.scss.d.ts
│   │   │   ├── ItemStat.tsx
│   │   │   ├── ItemStats.m.scss
│   │   │   ├── ItemStats.m.scss.d.ts
│   │   │   ├── ItemStats.tsx
│   │   │   ├── ItemTagHotkeys.tsx
│   │   │   ├── ItemTagSelector.m.scss
│   │   │   ├── ItemTagSelector.m.scss.d.ts
│   │   │   ├── ItemTagSelector.tsx
│   │   │   ├── ItemTalentGrid.m.scss
│   │   │   ├── ItemTalentGrid.m.scss.d.ts
│   │   │   ├── ItemTalentGrid.tsx
│   │   │   ├── KillTracker.tsx
│   │   │   ├── MetricCategories.m.scss
│   │   │   ├── MetricCategories.m.scss.d.ts
│   │   │   ├── MetricCategories.tsx
│   │   │   ├── NotesArea.m.scss
│   │   │   ├── NotesArea.m.scss.d.ts
│   │   │   ├── NotesArea.tsx
│   │   │   ├── Plug.m.scss
│   │   │   ├── Plug.m.scss.d.ts
│   │   │   ├── Plug.tsx
│   │   │   ├── PlugTooltip.m.scss
│   │   │   ├── PlugTooltip.m.scss.d.ts
│   │   │   ├── PlugTooltip.tsx
│   │   │   ├── RecoilStat.tsx
│   │   │   ├── SetBonus.m.scss
│   │   │   ├── SetBonus.m.scss.d.ts
│   │   │   ├── SetBonus.tsx
│   │   │   ├── Socket.m.scss
│   │   │   ├── Socket.m.scss.d.ts
│   │   │   ├── Socket.tsx
│   │   │   ├── SocketDetails.m.scss
│   │   │   ├── SocketDetails.m.scss.d.ts
│   │   │   ├── SocketDetails.tsx
│   │   │   ├── SocketDetailsSelectedPlug.m.scss
│   │   │   ├── SocketDetailsSelectedPlug.m.scss.d.ts
│   │   │   ├── SocketDetailsSelectedPlug.tsx
│   │   │   ├── WeaponCatalystInfo.m.scss
│   │   │   ├── WeaponCatalystInfo.m.scss.d.ts
│   │   │   ├── WeaponCatalystInfo.tsx
│   │   │   ├── WeaponCraftedInfo.m.scss
│   │   │   ├── WeaponCraftedInfo.m.scss.d.ts
│   │   │   ├── WeaponCraftedInfo.tsx
│   │   │   ├── WeaponDeepsightInfo.m.scss
│   │   │   ├── WeaponDeepsightInfo.m.scss.d.ts
│   │   │   ├── WeaponDeepsightInfo.tsx
│   │   │   ├── item-popup-actions.test.ts
│   │   │   ├── item-popup-actions.ts
│   │   │   ├── item-popup.ts
│   │   │   └── sidecar-popper-modifier.ts
│   │   ├── item-triage/
│   │   │   ├── ItemTriage.m.scss
│   │   │   ├── ItemTriage.m.scss.d.ts
│   │   │   ├── ItemTriage.tsx
│   │   │   ├── TriageFactors.m.scss
│   │   │   ├── TriageFactors.m.scss.d.ts
│   │   │   ├── triage-factors.tsx
│   │   │   ├── triage-utils.test.ts
│   │   │   └── triage-utils.ts
│   │   ├── loadout/
│   │   │   ├── LoadoutView.m.scss
│   │   │   ├── LoadoutView.m.scss.d.ts
│   │   │   ├── LoadoutView.tsx
│   │   │   ├── Loadouts.m.scss
│   │   │   ├── Loadouts.m.scss.d.ts
│   │   │   ├── Loadouts.tsx
│   │   │   ├── LoadoutsRow.m.scss
│   │   │   ├── LoadoutsRow.tsx
│   │   │   ├── ModPicker.tsx
│   │   │   ├── SubclassPlugDrawer.tsx
│   │   │   ├── actions.ts
│   │   │   ├── armor-upgrade-utils.ts
│   │   │   ├── fashion/
│   │   │   │   ├── FashionDrawer.m.scss
│   │   │   │   ├── FashionDrawer.m.scss.d.ts
│   │   │   │   └── FashionDrawer.tsx
│   │   │   ├── ingame/
│   │   │   │   ├── EditInGameLoadout.m.scss
│   │   │   │   ├── EditInGameLoadout.m.scss.d.ts
│   │   │   │   ├── EditInGameLoadout.tsx
│   │   │   │   ├── EditInGameLoadoutIdentifiers.m.scss
│   │   │   │   ├── EditInGameLoadoutIdentifiers.m.scss.d.ts
│   │   │   │   ├── EditInGameLoadoutIdentifiers.tsx
│   │   │   │   ├── InGameLoadoutDetailsSheet.m.scss
│   │   │   │   ├── InGameLoadoutDetailsSheet.m.scss.d.ts
│   │   │   │   ├── InGameLoadoutDetailsSheet.tsx
│   │   │   │   ├── InGameLoadoutIcon.m.scss
│   │   │   │   ├── InGameLoadoutIcon.m.scss.d.ts
│   │   │   │   ├── InGameLoadoutIcon.tsx
│   │   │   │   ├── InGameLoadoutIdentifiersSelectButton.m.scss
│   │   │   │   ├── InGameLoadoutIdentifiersSelectButton.m.scss.d.ts
│   │   │   │   ├── InGameLoadoutIdentifiersSelectButton.tsx
│   │   │   │   ├── InGameLoadoutStrip.m.scss
│   │   │   │   ├── InGameLoadoutStrip.m.scss.d.ts
│   │   │   │   ├── InGameLoadoutStrip.tsx
│   │   │   │   ├── RadioButton.m.scss
│   │   │   │   ├── RadioButton.m.scss.d.ts
│   │   │   │   ├── RadioButton.tsx
│   │   │   │   ├── SelectInGameLoadoutIdentifiers.m.scss
│   │   │   │   ├── SelectInGameLoadoutIdentifiers.m.scss.d.ts
│   │   │   │   ├── SelectInGameLoadoutIdentifiers.tsx
│   │   │   │   ├── actions.ts
│   │   │   │   ├── ingame-loadout-apply.ts
│   │   │   │   ├── ingame-loadout-utils.ts
│   │   │   │   ├── reducer.ts
│   │   │   │   └── selectors.ts
│   │   │   ├── known-values.ts
│   │   │   ├── loadout-edit/
│   │   │   │   ├── LoadoutEdit.m.scss
│   │   │   │   ├── LoadoutEdit.m.scss.d.ts
│   │   │   │   ├── LoadoutEdit.tsx
│   │   │   │   ├── LoadoutEditBucket.m.scss
│   │   │   │   ├── LoadoutEditBucket.m.scss.d.ts
│   │   │   │   ├── LoadoutEditBucket.tsx
│   │   │   │   ├── LoadoutEditSection.m.scss
│   │   │   │   ├── LoadoutEditSection.m.scss.d.ts
│   │   │   │   ├── LoadoutEditSection.tsx
│   │   │   │   ├── LoadoutEditSubclass.m.scss
│   │   │   │   ├── LoadoutEditSubclass.m.scss.d.ts
│   │   │   │   ├── LoadoutEditSubclass.tsx
│   │   │   │   └── useEquipDropTargets.tsx
│   │   │   ├── loadout-item-utils.ts
│   │   │   ├── loadout-menu/
│   │   │   │   ├── LoadoutPopup.m.scss
│   │   │   │   ├── LoadoutPopup.m.scss.d.ts
│   │   │   │   ├── LoadoutPopup.tsx
│   │   │   │   ├── LoadoutPopupRandomize.m.scss
│   │   │   │   ├── LoadoutPopupRandomize.m.scss.d.ts
│   │   │   │   ├── LoadoutPopupRandomize.tsx
│   │   │   │   ├── MaxlightButton.m.scss
│   │   │   │   ├── MaxlightButton.m.scss.d.ts
│   │   │   │   └── MaxlightButton.tsx
│   │   │   ├── loadout-share/
│   │   │   │   ├── LoadoutImportSheet.m.scss
│   │   │   │   ├── LoadoutImportSheet.m.scss.d.ts
│   │   │   │   ├── LoadoutImportSheet.tsx
│   │   │   │   ├── LoadoutShareSheet.m.scss
│   │   │   │   ├── LoadoutShareSheet.m.scss.d.ts
│   │   │   │   ├── LoadoutShareSheet.tsx
│   │   │   │   ├── loadout-import.test.ts
│   │   │   │   └── loadout-import.ts
│   │   │   ├── loadout-type-converters.ts
│   │   │   ├── loadout-types.ts
│   │   │   ├── loadout-ui/
│   │   │   │   ├── BucketPlaceholder.m.scss
│   │   │   │   ├── BucketPlaceholder.m.scss.d.ts
│   │   │   │   ├── BucketPlaceholder.tsx
│   │   │   │   ├── EmptySubclass.tsx
│   │   │   │   ├── FashionMods.m.scss
│   │   │   │   ├── FashionMods.m.scss.d.ts
│   │   │   │   ├── FashionMods.tsx
│   │   │   │   ├── LoadoutItemCategorySection.m.scss
│   │   │   │   ├── LoadoutItemCategorySection.m.scss.d.ts
│   │   │   │   ├── LoadoutItemCategorySection.tsx
│   │   │   │   ├── LoadoutMods.m.scss
│   │   │   │   ├── LoadoutMods.m.scss.d.ts
│   │   │   │   ├── LoadoutMods.tsx
│   │   │   │   ├── LoadoutParametersDisplay.m.scss
│   │   │   │   ├── LoadoutParametersDisplay.m.scss.d.ts
│   │   │   │   ├── LoadoutParametersDisplay.tsx
│   │   │   │   ├── LoadoutSubclassSection.m.scss
│   │   │   │   ├── LoadoutSubclassSection.m.scss.d.ts
│   │   │   │   ├── LoadoutSubclassSection.tsx
│   │   │   │   ├── OptimizerButton.tsx
│   │   │   │   ├── PlugDef.tsx
│   │   │   │   ├── Sockets.m.scss
│   │   │   │   ├── Sockets.m.scss.d.ts
│   │   │   │   ├── Sockets.tsx
│   │   │   │   ├── menu-hooks.m.scss
│   │   │   │   ├── menu-hooks.m.scss.d.ts
│   │   │   │   └── menu-hooks.tsx
│   │   │   ├── loadouts-selector.ts
│   │   │   ├── mod-assignment-drawer/
│   │   │   │   ├── ModAssignmentDrawer.m.scss
│   │   │   │   ├── ModAssignmentDrawer.m.scss.d.ts
│   │   │   │   ├── ModAssignmentDrawer.tsx
│   │   │   │   └── selectors.ts
│   │   │   ├── mod-assignment-utils.test.ts
│   │   │   ├── mod-assignment-utils.ts
│   │   │   ├── mod-permutations.ts
│   │   │   ├── mod-utils.ts
│   │   │   ├── mutually-exclusive-mods.d.ts
│   │   │   ├── plug-drawer/
│   │   │   │   ├── Footer.m.scss
│   │   │   │   ├── Footer.m.scss.d.ts
│   │   │   │   ├── Footer.tsx
│   │   │   │   ├── PlugDrawer.tsx
│   │   │   │   ├── PlugSection.m.scss
│   │   │   │   ├── PlugSection.m.scss.d.ts
│   │   │   │   ├── PlugSection.tsx
│   │   │   │   ├── PlugStackableIcon.m.scss
│   │   │   │   ├── PlugStackableIcon.m.scss.d.ts
│   │   │   │   ├── PlugStackableIcon.tsx
│   │   │   │   ├── SelectablePlug.m.scss
│   │   │   │   ├── SelectablePlug.m.scss.d.ts
│   │   │   │   ├── SelectablePlug.tsx
│   │   │   │   └── types.ts
│   │   │   ├── reducer.ts
│   │   │   ├── selectors.ts
│   │   │   ├── spreadsheets.ts
│   │   │   └── stats.ts
│   │   ├── loadout-analyzer/
│   │   │   ├── analysis.test.ts
│   │   │   ├── analysis.ts
│   │   │   ├── finding-display.ts
│   │   │   ├── hooks.tsx
│   │   │   ├── store.ts
│   │   │   ├── types.ts
│   │   │   └── utils.ts
│   │   ├── loadout-builder/
│   │   │   ├── LoadoutBucketDropTarget.m.scss
│   │   │   ├── LoadoutBucketDropTarget.m.scss.d.ts
│   │   │   ├── LoadoutBucketDropTarget.tsx
│   │   │   ├── LoadoutBuilder.m.scss
│   │   │   ├── LoadoutBuilder.m.scss.d.ts
│   │   │   ├── LoadoutBuilder.tsx
│   │   │   ├── LoadoutBuilderContainer.tsx
│   │   │   ├── LoadoutBuilderItem.tsx
│   │   │   ├── NoBuildsFoundExplainer.m.scss
│   │   │   ├── NoBuildsFoundExplainer.m.scss.d.ts
│   │   │   ├── NoBuildsFoundExplainer.tsx
│   │   │   ├── README.md
│   │   │   ├── example-search.ts
│   │   │   ├── filter/
│   │   │   │   ├── EnergyOptions.m.scss
│   │   │   │   ├── EnergyOptions.m.scss.d.ts
│   │   │   │   ├── EnergyOptions.tsx
│   │   │   │   ├── ExoticArmorChoice.m.scss
│   │   │   │   ├── ExoticArmorChoice.m.scss.d.ts
│   │   │   │   ├── ExoticArmorChoice.tsx
│   │   │   │   ├── ExoticPicker.m.scss
│   │   │   │   ├── ExoticPicker.m.scss.d.ts
│   │   │   │   ├── ExoticPicker.tsx
│   │   │   │   ├── ExoticTile.m.scss
│   │   │   │   ├── ExoticTile.m.scss.d.ts
│   │   │   │   ├── ExoticTile.tsx
│   │   │   │   ├── LoadoutOptimizerExotic.m.scss
│   │   │   │   ├── LoadoutOptimizerExotic.m.scss.d.ts
│   │   │   │   ├── LoadoutOptimizerExotic.tsx
│   │   │   │   ├── LoadoutOptimizerMenuItems.m.scss
│   │   │   │   ├── LoadoutOptimizerMenuItems.m.scss.d.ts
│   │   │   │   ├── LoadoutOptimizerMenuItems.tsx
│   │   │   │   ├── LoadoutOptimizerSetBonus.m.scss
│   │   │   │   ├── LoadoutOptimizerSetBonus.m.scss.d.ts
│   │   │   │   ├── LoadoutOptimizerSetBonus.tsx
│   │   │   │   ├── LockedItem.tsx
│   │   │   │   ├── NewFeaturedGearFilter.m.scss
│   │   │   │   ├── NewFeaturedGearFilter.m.scss.d.ts
│   │   │   │   ├── NewFeaturedGearFilter.tsx
│   │   │   │   ├── TierlessStatConstraintEditor.m.scss
│   │   │   │   ├── TierlessStatConstraintEditor.m.scss.d.ts
│   │   │   │   └── TierlessStatConstraintEditor.tsx
│   │   │   ├── generated-sets/
│   │   │   │   ├── CompareLoadoutsDrawer.m.scss
│   │   │   │   ├── CompareLoadoutsDrawer.m.scss.d.ts
│   │   │   │   ├── CompareLoadoutsDrawer.tsx
│   │   │   │   ├── GeneratedSet.m.scss
│   │   │   │   ├── GeneratedSet.m.scss.d.ts
│   │   │   │   ├── GeneratedSet.tsx
│   │   │   │   ├── GeneratedSetButtons.m.scss
│   │   │   │   ├── GeneratedSetButtons.m.scss.d.ts
│   │   │   │   ├── GeneratedSetButtons.tsx
│   │   │   │   ├── GeneratedSetItem.m.scss
│   │   │   │   ├── GeneratedSetItem.m.scss.d.ts
│   │   │   │   ├── GeneratedSetItem.tsx
│   │   │   │   ├── GeneratedSets.tsx
│   │   │   │   ├── SetStats.m.scss
│   │   │   │   ├── SetStats.m.scss.d.ts
│   │   │   │   ├── SetStats.tsx
│   │   │   │   └── utils.ts
│   │   │   ├── item-filter.test.ts
│   │   │   ├── item-filter.ts
│   │   │   ├── loadout-builder-reducer.ts
│   │   │   ├── loadout-builder-vendors.ts
│   │   │   ├── loadout-params.test.ts
│   │   │   ├── loadout-params.ts
│   │   │   ├── process/
│   │   │   │   ├── mappers.test.ts
│   │   │   │   ├── mappers.ts
│   │   │   │   ├── process-wrapper.ts
│   │   │   │   └── useProcess.ts
│   │   │   ├── process-worker/
│   │   │   │   ├── ProcessWorker.ts
│   │   │   │   ├── __snapshots__/
│   │   │   │   │   ├── auto-stat-mod-utils.test.ts.snap
│   │   │   │   │   └── process-utils.test.ts.snap
│   │   │   │   ├── auto-stat-mod-utils.test.ts
│   │   │   │   ├── auto-stat-mod-utils.ts
│   │   │   │   ├── process-utils.test.ts
│   │   │   │   ├── process-utils.ts
│   │   │   │   ├── process.ts
│   │   │   │   ├── set-tracker.test.ts
│   │   │   │   ├── set-tracker.ts
│   │   │   │   ├── tsconfig.json
│   │   │   │   └── types.ts
│   │   │   ├── types.ts
│   │   │   ├── updated-loadout.ts
│   │   │   ├── useEquippedHashes.ts
│   │   │   └── utils.ts
│   │   ├── loadout-drawer/
│   │   │   ├── LoadoutDrawer.m.scss
│   │   │   ├── LoadoutDrawer.m.scss.d.ts
│   │   │   ├── LoadoutDrawer.tsx
│   │   │   ├── LoadoutDrawerContainer.tsx
│   │   │   ├── LoadoutDrawerDropTarget.m.scss
│   │   │   ├── LoadoutDrawerDropTarget.m.scss.d.ts
│   │   │   ├── LoadoutDrawerDropTarget.tsx
│   │   │   ├── LoadoutDrawerFooter.m.scss
│   │   │   ├── LoadoutDrawerFooter.m.scss.d.ts
│   │   │   ├── LoadoutDrawerFooter.tsx
│   │   │   ├── LoadoutDrawerHeader.m.scss
│   │   │   ├── LoadoutDrawerHeader.m.scss.d.ts
│   │   │   ├── LoadoutDrawerHeader.tsx
│   │   │   ├── auto-loadouts.ts
│   │   │   ├── loadout-apply-state.ts
│   │   │   ├── loadout-apply.ts
│   │   │   ├── loadout-drawer-reducer.test.ts
│   │   │   ├── loadout-drawer-reducer.ts
│   │   │   ├── loadout-events.ts
│   │   │   ├── loadout-item-conversion.ts
│   │   │   ├── loadout-utils.ts
│   │   │   └── postmaster.ts
│   │   ├── login/
│   │   │   ├── Login.m.scss
│   │   │   ├── Login.m.scss.d.ts
│   │   │   └── Login.tsx
│   │   ├── main.scss
│   │   ├── manifest/
│   │   │   ├── actions.ts
│   │   │   ├── d1-manifest-service.ts
│   │   │   ├── manifest-service-json.ts
│   │   │   ├── reducer.ts
│   │   │   └── selectors.ts
│   │   ├── material-counts/
│   │   │   ├── MaterialCounts.m.scss
│   │   │   ├── MaterialCounts.m.scss.d.ts
│   │   │   ├── MaterialCounts.tsx
│   │   │   ├── MaterialCountsWrappers.m.scss
│   │   │   ├── MaterialCountsWrappers.m.scss.d.ts
│   │   │   └── MaterialCountsWrappers.tsx
│   │   ├── notifications/
│   │   │   ├── Notification.m.scss
│   │   │   ├── Notification.m.scss.d.ts
│   │   │   ├── Notification.tsx
│   │   │   ├── NotificationButton.m.scss
│   │   │   ├── NotificationButton.m.scss.d.ts
│   │   │   ├── NotificationButton.tsx
│   │   │   ├── NotificationsContainer.m.scss
│   │   │   ├── NotificationsContainer.m.scss.d.ts
│   │   │   ├── NotificationsContainer.tsx
│   │   │   └── notifications.ts
│   │   ├── organizer/
│   │   │   ├── Columns.m.scss
│   │   │   ├── Columns.m.scss.d.ts
│   │   │   ├── Columns.tsx
│   │   │   ├── CustomStatColumns.tsx
│   │   │   ├── DropDown.m.scss
│   │   │   ├── DropDown.m.scss.d.ts
│   │   │   ├── DropDown.tsx
│   │   │   ├── EnabledColumnsSelector.tsx
│   │   │   ├── ItemActions.m.scss
│   │   │   ├── ItemActions.m.scss.d.ts
│   │   │   ├── ItemActions.tsx
│   │   │   ├── ItemTable.m.scss
│   │   │   ├── ItemTable.m.scss.d.ts
│   │   │   ├── ItemTable.tsx
│   │   │   ├── ItemTypeSelector.m.scss
│   │   │   ├── ItemTypeSelector.m.scss.d.ts
│   │   │   ├── ItemTypeSelector.tsx
│   │   │   ├── Organizer.m.scss
│   │   │   ├── Organizer.m.scss.d.ts
│   │   │   ├── Organizer.tsx
│   │   │   └── table-types.ts
│   │   ├── progress/
│   │   │   ├── ActivityModifier.m.scss
│   │   │   ├── ActivityModifier.m.scss.d.ts
│   │   │   ├── ActivityModifier.tsx
│   │   │   ├── BountyGuide.m.scss
│   │   │   ├── BountyGuide.m.scss.d.ts
│   │   │   ├── BountyGuide.tsx
│   │   │   ├── Event.m.scss
│   │   │   ├── Event.m.scss.d.ts
│   │   │   ├── Event.tsx
│   │   │   ├── FactionIcon.m.scss
│   │   │   ├── FactionIcon.m.scss.d.ts
│   │   │   ├── FactionIcon.tsx
│   │   │   ├── Milestones.m.scss
│   │   │   ├── Milestones.m.scss.d.ts
│   │   │   ├── Milestones.tsx
│   │   │   ├── Objective.m.scss
│   │   │   ├── Objective.m.scss.d.ts
│   │   │   ├── Objective.tsx
│   │   │   ├── Pathfinder.m.scss
│   │   │   ├── Pathfinder.m.scss.d.ts
│   │   │   ├── Pathfinder.tsx
│   │   │   ├── Progress.m.scss
│   │   │   ├── Progress.m.scss.d.ts
│   │   │   ├── Progress.tsx
│   │   │   ├── Pursuit.tsx
│   │   │   ├── PursuitGrid.m.scss
│   │   │   ├── PursuitGrid.m.scss.d.ts
│   │   │   ├── PursuitGrid.tsx
│   │   │   ├── PursuitItem.m.scss
│   │   │   ├── PursuitItem.m.scss.d.ts
│   │   │   ├── PursuitItem.tsx
│   │   │   ├── Pursuits.tsx
│   │   │   ├── Raid.tsx
│   │   │   ├── RaidDisplay.m.scss
│   │   │   ├── RaidDisplay.m.scss.d.ts
│   │   │   ├── RaidDisplay.tsx
│   │   │   ├── Raids.tsx
│   │   │   ├── Ranks.tsx
│   │   │   ├── ReputationRank.m.scss
│   │   │   ├── ReputationRank.m.scss.d.ts
│   │   │   ├── ReputationRank.tsx
│   │   │   ├── Reward.m.scss
│   │   │   ├── Reward.m.scss.d.ts
│   │   │   ├── Reward.tsx
│   │   │   ├── SeasonalChallenges.tsx
│   │   │   ├── SeasonalRank.m.scss
│   │   │   ├── SeasonalRank.m.scss.d.ts
│   │   │   ├── SeasonalRank.tsx
│   │   │   ├── TrackedTriumphs.m.scss
│   │   │   ├── TrackedTriumphs.m.scss.d.ts
│   │   │   ├── TrackedTriumphs.tsx
│   │   │   ├── WellRestedPerkIcon.tsx
│   │   │   ├── engrams.ts
│   │   │   ├── milestone-items.ts
│   │   │   ├── milestone.scss
│   │   │   ├── selectors.ts
│   │   │   └── xp.ts
│   │   ├── records/
│   │   │   ├── Collectible.tsx
│   │   │   ├── CollectiblesGrid.m.scss
│   │   │   ├── CollectiblesGrid.m.scss.d.ts
│   │   │   ├── CollectiblesGrid.tsx
│   │   │   ├── Craftable.tsx
│   │   │   ├── Metric.m.scss
│   │   │   ├── Metric.m.scss.d.ts
│   │   │   ├── Metric.tsx
│   │   │   ├── MetricBanner.m.scss
│   │   │   ├── MetricBanner.m.scss.d.ts
│   │   │   ├── MetricBanner.tsx
│   │   │   ├── Metrics.m.scss
│   │   │   ├── Metrics.m.scss.d.ts
│   │   │   ├── Metrics.tsx
│   │   │   ├── PresentationNode.m.scss
│   │   │   ├── PresentationNode.m.scss.d.ts
│   │   │   ├── PresentationNode.tsx
│   │   │   ├── PresentationNodeLeaf.tsx
│   │   │   ├── PresentationNodeRoot.m.scss
│   │   │   ├── PresentationNodeRoot.m.scss.d.ts
│   │   │   ├── PresentationNodeRoot.tsx
│   │   │   ├── PresentationNodeSearchResults.m.scss
│   │   │   ├── PresentationNodeSearchResults.m.scss.d.ts
│   │   │   ├── PresentationNodeSearchResults.tsx
│   │   │   ├── Record.m.scss
│   │   │   ├── Record.m.scss.d.ts
│   │   │   ├── Record.tsx
│   │   │   ├── Records.m.scss
│   │   │   ├── Records.m.scss.d.ts
│   │   │   ├── Records.tsx
│   │   │   ├── SetCard.m.scss
│   │   │   ├── SetCard.m.scss.d.ts
│   │   │   ├── SetCard.tsx
│   │   │   ├── _set-card.scss
│   │   │   ├── catalysts.ts
│   │   │   ├── collectible-matching.ts
│   │   │   ├── extra-collectibles.d.ts
│   │   │   ├── plugset-helpers.ts
│   │   │   ├── presentation-nodes.ts
│   │   │   ├── selectors.ts
│   │   │   └── universal-ornaments/
│   │   │       ├── UniversalOrnaments.m.scss
│   │   │       ├── UniversalOrnaments.m.scss.d.ts
│   │   │       ├── UniversalOrnaments.tsx
│   │   │       └── universal-ornaments.ts
│   │   ├── register-service-worker.test.ts
│   │   ├── register-service-worker.ts
│   │   ├── routes.ts
│   │   ├── safari-touch-fix.ts
│   │   ├── search/
│   │   │   ├── FilterHelp.m.scss
│   │   │   ├── FilterHelp.m.scss.d.ts
│   │   │   ├── FilterHelp.tsx
│   │   │   ├── HighlightedText.tsx
│   │   │   ├── MainSearchBarActions.m.scss
│   │   │   ├── MainSearchBarActions.m.scss.d.ts
│   │   │   ├── MainSearchBarActions.tsx
│   │   │   ├── MainSearchBarMenu.tsx
│   │   │   ├── SearchBar.m.scss
│   │   │   ├── SearchBar.m.scss.d.ts
│   │   │   ├── SearchBar.tsx
│   │   │   ├── SearchFilter.tsx
│   │   │   ├── SearchHistory.m.scss
│   │   │   ├── SearchHistory.m.scss.d.ts
│   │   │   ├── SearchHistory.tsx
│   │   │   ├── SearchInput.tsx
│   │   │   ├── SearchResults.m.scss
│   │   │   ├── SearchResults.m.scss.d.ts
│   │   │   ├── SearchResults.tsx
│   │   │   ├── __snapshots__/
│   │   │   │   ├── autocomplete.test.ts.snap
│   │   │   │   ├── query-parser.test.ts.snap
│   │   │   │   ├── search-config.test.ts.snap
│   │   │   │   └── search-filter.test.ts.snap
│   │   │   ├── armory-search.ts
│   │   │   ├── autocomplete.test.ts
│   │   │   ├── autocomplete.ts
│   │   │   ├── d1-known-values.ts
│   │   │   ├── d2-known-values.ts
│   │   │   ├── filter-description.tsx
│   │   │   ├── filter-types.ts
│   │   │   ├── items/
│   │   │   │   ├── item-filter-types.ts
│   │   │   │   ├── item-search-filter.ts
│   │   │   │   └── search-filters/
│   │   │   │       ├── advanced.ts
│   │   │   │       ├── d1-filters.ts
│   │   │   │       ├── d2-sources.ts
│   │   │   │       ├── data/
│   │   │   │       │   └── d2/
│   │   │   │       │       └── artifact-breaker-weapon-types.d.ts
│   │   │   │       ├── dupes-deprecated.ts
│   │   │   │       ├── dupes.ts
│   │   │   │       ├── freeform.ts
│   │   │   │       ├── item-infos.ts
│   │   │   │       ├── known-values.ts
│   │   │   │       ├── loadouts.ts
│   │   │   │       ├── perks-set.ts
│   │   │   │       ├── range-numeric.ts
│   │   │   │       ├── range-overload.ts
│   │   │   │       ├── simple.ts
│   │   │   │       ├── sockets.ts
│   │   │   │       ├── stats.ts
│   │   │   │       ├── stores.ts
│   │   │   │       └── wishlist.ts
│   │   │   ├── loadouts/
│   │   │   │   ├── __snapshots__/
│   │   │   │   │   └── loadout-search-filter.test.ts.snap
│   │   │   │   ├── loadout-filter-types.ts
│   │   │   │   ├── loadout-search-filter.test.ts
│   │   │   │   ├── loadout-search-filter.ts
│   │   │   │   └── search-filters/
│   │   │   │       ├── freeform.ts
│   │   │   │       ├── range-overload.ts
│   │   │   │       └── simple.ts
│   │   │   ├── plug-search.ts
│   │   │   ├── power-levels.ts
│   │   │   ├── query-parser.test.ts
│   │   │   ├── query-parser.ts
│   │   │   ├── search-config.test.ts
│   │   │   ├── search-config.ts
│   │   │   ├── search-filter-values.test.ts
│   │   │   ├── search-filter-values.ts
│   │   │   ├── search-filter.scss
│   │   │   ├── search-filter.test.ts
│   │   │   ├── search-filter.ts
│   │   │   ├── specialty-modslots.ts
│   │   │   ├── suggestions-generation.ts
│   │   │   └── text-utils.ts
│   │   ├── settings/
│   │   │   ├── CharacterOrderEditor.m.scss
│   │   │   ├── CharacterOrderEditor.m.scss.d.ts
│   │   │   ├── CharacterOrderEditor.tsx
│   │   │   ├── Checkbox.tsx
│   │   │   ├── CustomStatsSettings.m.scss
│   │   │   ├── CustomStatsSettings.m.scss.d.ts
│   │   │   ├── CustomStatsSettings.tsx
│   │   │   ├── LanguageSetting.tsx
│   │   │   ├── Select.m.scss
│   │   │   ├── Select.m.scss.d.ts
│   │   │   ├── Select.tsx
│   │   │   ├── SettingsPage.m.scss
│   │   │   ├── SettingsPage.m.scss.d.ts
│   │   │   ├── SettingsPage.tsx
│   │   │   ├── SortOrderEditor.m.scss
│   │   │   ├── SortOrderEditor.m.scss.d.ts
│   │   │   ├── SortOrderEditor.tsx
│   │   │   ├── Spreadsheets.m.scss
│   │   │   ├── Spreadsheets.m.scss.d.ts
│   │   │   ├── Spreadsheets.tsx
│   │   │   ├── Troubleshooting.tsx
│   │   │   ├── WishListSettings.m.scss
│   │   │   ├── WishListSettings.m.scss.d.ts
│   │   │   ├── WishListSettings.tsx
│   │   │   ├── actions.ts
│   │   │   ├── character-sort.ts
│   │   │   ├── hooks.ts
│   │   │   ├── initial-settings.ts
│   │   │   ├── item-sort.ts
│   │   │   ├── settings.ts
│   │   │   ├── vault-grouping.test.ts
│   │   │   └── vault-grouping.ts
│   │   ├── shell/
│   │   │   ├── About.m.scss
│   │   │   ├── About.m.scss.d.ts
│   │   │   ├── About.tsx
│   │   │   ├── AppInstallBanner.m.scss
│   │   │   ├── AppInstallBanner.m.scss.d.ts
│   │   │   ├── AppInstallBanner.tsx
│   │   │   ├── DefaultAccount.tsx
│   │   │   ├── Destiny.m.scss
│   │   │   ├── Destiny.m.scss.d.ts
│   │   │   ├── Destiny.tsx
│   │   │   ├── ErrorPanel.m.scss
│   │   │   ├── ErrorPanel.m.scss.d.ts
│   │   │   ├── ErrorPanel.tsx
│   │   │   ├── GATracker.tsx
│   │   │   ├── Header.m.scss
│   │   │   ├── Header.m.scss.d.ts
│   │   │   ├── Header.tsx
│   │   │   ├── HeaderWarningBanner.m.scss
│   │   │   ├── HeaderWarningBanner.m.scss.d.ts
│   │   │   ├── HeaderWarningBanner.tsx
│   │   │   ├── LocationSwitcher.tsx
│   │   │   ├── MenuBadge.m.scss
│   │   │   ├── MenuBadge.m.scss.d.ts
│   │   │   ├── MenuBadge.tsx
│   │   │   ├── PostmasterWarningBanner.tsx
│   │   │   ├── Privacy.m.scss
│   │   │   ├── Privacy.m.scss.d.ts
│   │   │   ├── Privacy.tsx
│   │   │   ├── RefreshButton.m.scss
│   │   │   ├── RefreshButton.m.scss.d.ts
│   │   │   ├── RefreshButton.tsx
│   │   │   ├── ScrollToTop.tsx
│   │   │   ├── SneakyUpdates.tsx
│   │   │   ├── actions.ts
│   │   │   ├── alerts.ts
│   │   │   ├── app-install.ts
│   │   │   ├── formatters.ts
│   │   │   ├── icons/
│   │   │   │   ├── AppIcon.scss
│   │   │   │   ├── AppIcon.tsx
│   │   │   │   ├── Library.js
│   │   │   │   ├── custom/
│   │   │   │   │   ├── Artifice.ts
│   │   │   │   │   ├── Engram.ts
│   │   │   │   │   ├── Enhanced.ts
│   │   │   │   │   ├── Epic.ts
│   │   │   │   │   ├── FeaturedBanner.ts
│   │   │   │   │   ├── Hunter.ts
│   │   │   │   │   ├── HunterProportional.ts
│   │   │   │   │   ├── MasterworkHammer.ts
│   │   │   │   │   ├── Power.ts
│   │   │   │   │   ├── PowerAlt.ts
│   │   │   │   │   ├── Shaped.ts
│   │   │   │   │   ├── StatBarsIcon.ts
│   │   │   │   │   ├── Titan.ts
│   │   │   │   │   ├── TitanProportional.ts
│   │   │   │   │   ├── TunedStatIcon.ts
│   │   │   │   │   ├── Warlock.ts
│   │   │   │   │   ├── WarlockProportional.ts
│   │   │   │   │   └── utils.ts
│   │   │   │   ├── font-awesome-icon-variables.scss
│   │   │   │   ├── font-awesome.scss
│   │   │   │   └── index.ts
│   │   │   ├── item-comparators.ts
│   │   │   ├── links.ts
│   │   │   ├── loading-tracker.ts
│   │   │   ├── reducer.ts
│   │   │   ├── refresh-events.ts
│   │   │   └── selectors.ts
│   │   ├── storage/
│   │   │   ├── DimApiSettings.m.scss
│   │   │   ├── DimApiSettings.m.scss.d.ts
│   │   │   ├── DimApiSettings.tsx
│   │   │   ├── DimApiWarningBanner.tsx
│   │   │   ├── ImportExport.tsx
│   │   │   ├── LocalStorageInfo.m.scss
│   │   │   ├── LocalStorageInfo.m.scss.d.ts
│   │   │   ├── LocalStorageInfo.tsx
│   │   │   ├── export-data.ts
│   │   │   ├── human-bytes.ts
│   │   │   └── idb-keyval.ts
│   │   ├── store/
│   │   │   ├── observerMiddleware.ts
│   │   │   ├── reducers.ts
│   │   │   ├── store.ts
│   │   │   ├── thunk-dispatch.ts
│   │   │   └── types.ts
│   │   ├── store-stats/
│   │   │   ├── AccountCurrencies.m.scss
│   │   │   ├── AccountCurrencies.m.scss.d.ts
│   │   │   ├── AccountCurrencies.tsx
│   │   │   ├── CharacterStats.m.scss
│   │   │   ├── CharacterStats.m.scss.d.ts
│   │   │   ├── CharacterStats.tsx
│   │   │   ├── ClarityCharacterStat.m.scss
│   │   │   ├── ClarityCharacterStat.m.scss.d.ts
│   │   │   ├── ClarityCharacterStat.tsx
│   │   │   ├── D1CharacterStats.m.scss
│   │   │   ├── D1CharacterStats.m.scss.d.ts
│   │   │   ├── D1CharacterStats.tsx
│   │   │   ├── StatTooltip.m.scss
│   │   │   ├── StatTooltip.m.scss.d.ts
│   │   │   ├── StatTooltip.tsx
│   │   │   ├── StoreStats.m.scss
│   │   │   ├── StoreStats.m.scss.d.ts
│   │   │   ├── StoreStats.tsx
│   │   │   ├── VaultCapacity.m.scss
│   │   │   ├── VaultCapacity.m.scss.d.ts
│   │   │   └── VaultCapacity.tsx
│   │   ├── stream-deck/
│   │   │   ├── OpenOnStreamDeckButton/
│   │   │   │   ├── OpenOnStreamDeckButton.m.scss
│   │   │   │   ├── OpenOnStreamDeckButton.m.scss.d.ts
│   │   │   │   └── OpenOnStreamDeckButton.tsx
│   │   │   ├── StreamDeckButton/
│   │   │   │   ├── StreamDeckButton.m.scss
│   │   │   │   ├── StreamDeckButton.m.scss.d.ts
│   │   │   │   └── StreamDeckButton.tsx
│   │   │   ├── StreamDeckSettings/
│   │   │   │   ├── StreamDeckSettings.m.scss
│   │   │   │   ├── StreamDeckSettings.m.scss.d.ts
│   │   │   │   └── StreamDeckSettings.tsx
│   │   │   ├── actions.ts
│   │   │   ├── async-module.ts
│   │   │   ├── interfaces.ts
│   │   │   ├── msg-handlers.ts
│   │   │   ├── reducer.ts
│   │   │   ├── selectors.ts
│   │   │   ├── stream-deck.ts
│   │   │   ├── useStreamDeckSelection.ts
│   │   │   └── util/
│   │   │       ├── authorization.ts
│   │   │       ├── packager.ts
│   │   │       └── version.ts
│   │   ├── strip-sockets/
│   │   │   ├── StripSockets.m.scss
│   │   │   ├── StripSockets.m.scss.d.ts
│   │   │   ├── StripSockets.tsx
│   │   │   ├── strip-sockets-actions.ts
│   │   │   └── strip-sockets.ts
│   │   ├── themes/
│   │   │   ├── _theme-classic.scss
│   │   │   ├── _theme-dimdark.scss
│   │   │   ├── _theme-europa.scss
│   │   │   ├── _theme-neomuna.scss
│   │   │   ├── _theme-pyramid.scss
│   │   │   ├── _theme-throneworld.scss
│   │   │   ├── _theme-vexnet.scss
│   │   │   └── _theme.scss
│   │   ├── utils/
│   │   │   ├── __snapshots__/
│   │   │   │   └── csv.test.ts.snap
│   │   │   ├── action-queue.ts
│   │   │   ├── app-badge.ts
│   │   │   ├── browsers.ts
│   │   │   ├── cancel.ts
│   │   │   ├── collections.test.ts
│   │   │   ├── collections.ts
│   │   │   ├── comparators.ts
│   │   │   ├── csv.test.ts
│   │   │   ├── csv.ts
│   │   │   ├── dim-error.ts
│   │   │   ├── download.ts
│   │   │   ├── empty.ts
│   │   │   ├── errors.ts
│   │   │   ├── functions.ts
│   │   │   ├── hooks.ts
│   │   │   ├── intl.test.ts
│   │   │   ├── intl.ts
│   │   │   ├── item-utils.ts
│   │   │   ├── log.ts
│   │   │   ├── measure-memory.ts
│   │   │   ├── media-queries.ts
│   │   │   ├── memoize.test.ts
│   │   │   ├── memoize.ts
│   │   │   ├── observable.ts
│   │   │   ├── parallel-cores.ts
│   │   │   ├── perk-utils.ts
│   │   │   ├── plug-descriptions.ts
│   │   │   ├── promises.test.ts
│   │   │   ├── promises.ts
│   │   │   ├── react.ts
│   │   │   ├── seasons.ts
│   │   │   ├── selectors.ts
│   │   │   ├── sentry.ts
│   │   │   ├── socket-utils.ts
│   │   │   ├── stats-set.test.ts
│   │   │   ├── stats-set.ts
│   │   │   ├── stats.ts
│   │   │   ├── system-info.ts
│   │   │   ├── temp-container.scss
│   │   │   ├── temp-container.ts
│   │   │   ├── textarea-caret.ts
│   │   │   ├── time.test.ts
│   │   │   ├── time.ts
│   │   │   ├── undo-redo-history.test.ts
│   │   │   ├── undo-redo-history.ts
│   │   │   ├── useWhatChanged.ts
│   │   │   └── util-types.ts
│   │   ├── vendors/
│   │   │   ├── Cost.m.scss
│   │   │   ├── Cost.m.scss.d.ts
│   │   │   ├── Cost.tsx
│   │   │   ├── Vendor.m.scss
│   │   │   ├── Vendor.m.scss.d.ts
│   │   │   ├── Vendor.tsx
│   │   │   ├── VendorItem.m.scss
│   │   │   ├── VendorItem.m.scss.d.ts
│   │   │   ├── VendorItemComponent.tsx
│   │   │   ├── VendorItems.m.scss
│   │   │   ├── VendorItems.m.scss.d.ts
│   │   │   ├── VendorItems.tsx
│   │   │   ├── Vendors.m.scss
│   │   │   ├── Vendors.m.scss.d.ts
│   │   │   ├── Vendors.tsx
│   │   │   ├── VendorsMenu.m.scss
│   │   │   ├── VendorsMenu.m.scss.d.ts
│   │   │   ├── VendorsMenu.tsx
│   │   │   ├── actions.ts
│   │   │   ├── d2-vendors.test.ts
│   │   │   ├── d2-vendors.ts
│   │   │   ├── focusing-item-outputs.d.ts
│   │   │   ├── hooks.ts
│   │   │   ├── reducer.ts
│   │   │   ├── selectors.ts
│   │   │   ├── single-vendor/
│   │   │   │   ├── ArtifactUnlocks.m.scss
│   │   │   │   ├── ArtifactUnlocks.m.scss.d.ts
│   │   │   │   ├── ArtifactUnlocks.tsx
│   │   │   │   ├── SingleVendor.m.scss
│   │   │   │   ├── SingleVendor.m.scss.d.ts
│   │   │   │   ├── SingleVendor.tsx
│   │   │   │   ├── SingleVendorPage.m.scss
│   │   │   │   ├── SingleVendorPage.m.scss.d.ts
│   │   │   │   ├── SingleVendorPage.tsx
│   │   │   │   ├── SingleVendorSheet.m.scss
│   │   │   │   ├── SingleVendorSheet.m.scss.d.ts
│   │   │   │   ├── SingleVendorSheet.tsx
│   │   │   │   ├── SingleVendorSheetContainer.tsx
│   │   │   │   └── single-vendor-sheet.ts
│   │   │   ├── specialVendorStrings.d.ts
│   │   │   └── vendor-item.ts
│   │   ├── whats-new/
│   │   │   ├── BungieAlerts.m.scss
│   │   │   ├── BungieAlerts.m.scss.d.ts
│   │   │   ├── BungieAlerts.tsx
│   │   │   ├── ChangeLog.scss
│   │   │   ├── ChangeLog.tsx
│   │   │   ├── WhatsNew.tsx
│   │   │   ├── WhatsNewLink.m.scss
│   │   │   ├── WhatsNewLink.m.scss.d.ts
│   │   │   ├── WhatsNewLink.tsx
│   │   │   └── versions.ts
│   │   └── wishlists/
│   │       ├── WishListPerkThumb.m.scss
│   │       ├── WishListPerkThumb.m.scss.d.ts
│   │       ├── WishListPerkThumb.tsx
│   │       ├── actions.ts
│   │       ├── observers.ts
│   │       ├── reducer.ts
│   │       ├── selectors.ts
│   │       ├── types.ts
│   │       ├── utils.ts
│   │       ├── wishlist-fetch.ts
│   │       ├── wishlist-file.test.ts
│   │       ├── wishlist-file.ts
│   │       └── wishlists.ts
│   ├── authReturn.ts
│   ├── backup.html
│   ├── backup.ts
│   ├── browsercheck-utils.js
│   ├── browsercheck.js
│   ├── browsercheck.test.ts
│   ├── browserconfig.xml
│   ├── build-browsercheck-utils.js
│   ├── bungie-api-ts.d.ts
│   ├── data/
│   │   ├── d1/
│   │   │   ├── manifests/
│   │   │   │   ├── d1-manifest-de.json
│   │   │   │   ├── d1-manifest-de.json.br
│   │   │   │   ├── d1-manifest-en.json
│   │   │   │   ├── d1-manifest-en.json.br
│   │   │   │   ├── d1-manifest-es.json
│   │   │   │   ├── d1-manifest-es.json.br
│   │   │   │   ├── d1-manifest-fr.json
│   │   │   │   ├── d1-manifest-fr.json.br
│   │   │   │   ├── d1-manifest-it.json
│   │   │   │   ├── d1-manifest-it.json.br
│   │   │   │   ├── d1-manifest-ja.json
│   │   │   │   ├── d1-manifest-ja.json.br
│   │   │   │   ├── d1-manifest-pt-br.json
│   │   │   │   └── d1-manifest-pt-br.json.br
│   │   │   └── missing_sources.json
│   │   ├── d2/
│   │   │   ├── README.md
│   │   │   ├── artifact-breaker-weapon-types.json
│   │   │   ├── bad-vendors.json
│   │   │   ├── bright-engram-bonus.json
│   │   │   ├── bright-engrams.json
│   │   │   ├── catalyst-triumph-icons.json
│   │   │   ├── craftable-hashes.json
│   │   │   ├── crafting-enhanced-intrinsics.ts
│   │   │   ├── crafting-mementos.json
│   │   │   ├── d2-event-info-v2.ts
│   │   │   ├── d2-event-info.ts
│   │   │   ├── d2-season-info.ts
│   │   │   ├── d2-trials-objectives.json
│   │   │   ├── deprecated-mods.json
│   │   │   ├── dummy-catalyst-mapping.json
│   │   │   ├── empty-plug-hashes.ts
│   │   │   ├── energy-mods-change.json
│   │   │   ├── energy-mods.json
│   │   │   ├── engram-rarity-icons.json
│   │   │   ├── events.json
│   │   │   ├── exotic-synergy.json
│   │   │   ├── exotic-to-catalyst-record.json
│   │   │   ├── exotics-with-catalysts.ts
│   │   │   ├── extended-breaker.json
│   │   │   ├── extended-foundry.json
│   │   │   ├── extended-ich.json
│   │   │   ├── focusing-item-outputs.json
│   │   │   ├── generated-enums.ts
│   │   │   ├── ghost-perks.json
│   │   │   ├── item-def-workaround-replacements.json
│   │   │   ├── legacy-triumphs.json
│   │   │   ├── lightcap-to-season.json
│   │   │   ├── masterworks-with-cond-stats.json
│   │   │   ├── missing-faction-tokens.json
│   │   │   ├── missing-source-info.ts
│   │   │   ├── mods-with-bad-descriptions.json
│   │   │   ├── mutually-exclusive-mods.json
│   │   │   ├── objective-richTexts.ts
│   │   │   ├── objective-triumph.json
│   │   │   ├── powerful-rewards.json
│   │   │   ├── pursuits.json
│   │   │   ├── raid-mod-plug-category-hashes.json
│   │   │   ├── reduced-cost-mod-mappings.ts
│   │   │   ├── season-tags.json
│   │   │   ├── season-to-source.json
│   │   │   ├── seasonal-armor-mods.json
│   │   │   ├── seasonal-challenges.json
│   │   │   ├── seasons.json
│   │   │   ├── seasons_backup.json
│   │   │   ├── source-info-v2.ts
│   │   │   ├── source-info.ts
│   │   │   ├── source-to-season-v2.json
│   │   │   ├── sources.json
│   │   │   ├── special-vendors-strings.json
│   │   │   ├── spider-mats.json
│   │   │   ├── spider-purchaseables-to-mats.json
│   │   │   ├── subclass-plug-category-hashes.json
│   │   │   ├── trait-definition-ids.json
│   │   │   ├── trait-to-enhanced-trait.json
│   │   │   ├── universal-ornament-aux-sets.json
│   │   │   ├── universal-ornament-plugset-hashes.json
│   │   │   ├── unreferenced-collections-items.json
│   │   │   ├── unstackable-mods.json
│   │   │   ├── voice-dim-valid-perks.json
│   │   │   ├── watermark-to-event.json
│   │   │   ├── watermark-to-season.json
│   │   │   └── weapon-from-quest.json
│   │   └── font/
│   │       ├── d2-font-glyphs.ts
│   │       ├── dim-custom-symbols.ts
│   │       └── symbol-name-sources.ts
│   ├── earlyErrorReport.js
│   ├── fa-subset.js
│   ├── global.d.ts
│   ├── htaccess
│   ├── images/
│   │   └── holofoil-anim.apng
│   ├── index.html
│   ├── locale/
│   │   ├── de.json
│   │   ├── en.json
│   │   ├── es.json
│   │   ├── esMX.json
│   │   ├── fr.json
│   │   ├── it.json
│   │   ├── ja.json
│   │   ├── ko.json
│   │   ├── locales.test.ts
│   │   ├── pl.json
│   │   ├── ptBR.json
│   │   ├── ru.json
│   │   ├── zhCHS.json
│   │   └── zhCHT.json
│   ├── nuke.php
│   ├── return.html
│   ├── robots.txt
│   ├── service-worker.ts
│   └── testing/
│       ├── data/
│       │   ├── d1profiles-2022-10-24.json
│       │   ├── linkedaccounts-2025-07-15.json
│       │   ├── profile-2025-12-02.json
│       │   └── vendors-2025-12-02.json
│       ├── global.d.ts
│       ├── jest-setup.cjs
│       ├── precache-manifest.test.ts
│       ├── test-item-utils.ts
│       ├── test-utils.ts
│       └── utils/
│           └── i18next.ts
└── tsconfig.json
Download .txt
Showing preview only (279K chars total). Download the full file or copy to clipboard to get everything.
SYMBOL INDEX (2947 symbols across 992 files)

FILE: .github/scripts/discord_changelog.py
  function _sections (line 40) | def _sections():
  function detect_profile (line 52) | def detect_profile(sections):
  function get_content (line 63) | def get_content(sections, profile):
  function bot_api (line 77) | def bot_api(method, path, token, data=None):
  function chunk_content (line 94) | def chunk_content(content):
  function _snowflake_from_days_ago (line 114) | def _snowflake_from_days_ago(days):
  function _bot_api_with_retry (line 122) | def _bot_api_with_retry(method, path, token, data=None, retries=5):
  function delete_beta (line 136) | def delete_beta():

FILE: .github/scripts/i18n_discord.py
  function flatten (line 31) | def flatten(obj, prefix=""):
  function compare (line 43) | def compare(old_flat, new_flat):
  function fmt (line 73) | def fmt(value):
  function generate_report (line 83) | def generate_report(diff, total):
  function chunk_content (line 120) | def chunk_content(content):
  function post_to_discord (line 135) | def post_to_discord(report):

FILE: build/update-changelog.js
  function fetchCommitFromAPI (line 11) | async function fetchCommitFromAPI(owner, repo, sha, token) {
  function fetchAssociatedPRsFromGraphQL (line 29) | async function fetchAssociatedPRsFromGraphQL(owner, repo, sha, token) {
  function extractChangelogEntries (line 82) | function extractChangelogEntries(commits) {
  function extractChangelogEntriesFromText (line 115) | function extractChangelogEntriesFromText(text, source = 'unknown') {
  function updateChangelog (line 140) | function updateChangelog(entries, originalChangelog) {
  function fetchCommitsFromAPI (line 198) | async function fetchCommitsFromAPI(commitShas, githubToken, githubReposi...
  function main (line 219) | async function main() {

FILE: config/content-security-policy.ts
  constant SELF (line 4) | const SELF = "'self'";
  function csp (line 9) | function csp(

FILE: config/feature-flags.ts
  function makeFeatureFlags (line 9) | function makeFeatureFlags(env: {
  type FeatureFlags (line 63) | type FeatureFlags = ReturnType<typeof makeFeatureFlags>;

FILE: config/manifest-webapp.ts
  function createWebAppManifest (line 1) | function createWebAppManifest(publicPath: string) {

FILE: config/notify-webpack-plugin.ts
  class NotifyPlugin (line 7) | class NotifyPlugin {
    method constructor (line 12) | constructor(name: string, isProd?: boolean) {
    method apply (line 18) | apply(compiler: Compiler) {
    method onDone (line 32) | onDone(rawWebpackStats: Stats) {

FILE: config/webpack.ts
  constant ASSET_NAME_PATTERN (line 23) | const ASSET_NAME_PATTERN = 'static/[name]-[contenthash:6][ext]';
  type CLIValues (line 31) | type CLIValues = boolean | string;
  type EnvValues (line 32) | type EnvValues = Record<string, CLIValues | Record<string, Env>>;
  type Env (line 33) | interface Env extends EnvValues {
  type Argv (line 40) | type Argv = Record<string, CLIValues>;
  type WebpackConfigurationGenerator (line 41) | interface WebpackConfigurationGenerator {
  method chunks (line 171) | chunks(chunk) {

FILE: icons/build_icons.cjs
  constant CACHEBREAKER (line 8) | const CACHEBREAKER = '6-2018';

FILE: src/@types/i18next.d.ts
  type CustomTypeOptions (line 6) | interface CustomTypeOptions {

FILE: src/StorageTest.tsx
  constant TAG (line 7) | const TAG = 'storage';
  function StorageBroken (line 9) | function StorageBroken() {
  function storageTest (line 21) | async function storageTest() {

FILE: src/app/App.m.scss.d.ts
  type CssExports (line 3) | interface CssExports {

FILE: src/app/App.tsx
  function App (line 41) | function App() {

FILE: src/app/Root.tsx
  function Root (line 20) | function Root() {

FILE: src/app/accounts/Account.m.scss.d.ts
  type CssExports (line 3) | interface CssExports {

FILE: src/app/accounts/Account.tsx
  function Account (line 11) | function Account({

FILE: src/app/accounts/MenuAccounts.m.scss.d.ts
  type CssExports (line 3) | interface CssExports {

FILE: src/app/accounts/MenuAccounts.tsx
  function MenuAccounts (line 17) | function MenuAccounts({

FILE: src/app/accounts/SelectAccount.m.scss.d.ts
  type CssExports (line 3) | interface CssExports {

FILE: src/app/accounts/SelectAccount.tsx
  function SelectAccount (line 16) | function SelectAccount({ path }: { path?: string }) {

FILE: src/app/accounts/actions.ts
  function handleAuthErrors (line 21) | function handleAuthErrors(e: unknown): ThunkResult {

FILE: src/app/accounts/bungie-account.ts
  type BungieAccount (line 7) | interface BungieAccount {
  function getBungieAccount (line 19) | function getBungieAccount(): BungieAccount | undefined {

FILE: src/app/accounts/destiny-account.ts
  constant PLATFORM_LABELS (line 30) | const PLATFORM_LABELS: Record<BungieMembershipType, string> = {
  constant PLATFORM_ICONS (line 44) | const PLATFORM_ICONS: LookupTable<BungieMembershipType, string | IconDef...
  type DestinyAccount (line 52) | interface DestinyAccount {
  function getDestinyAccountsForBungieAccount (line 82) | function getDestinyAccountsForBungieAccount(
  function couldBeD1Account (line 108) | function couldBeD1Account(destinyAccount: DestinyProfileUserInfoCard | U...
  function formatBungieName (line 116) | function formatBungieName(destinyAccount: DestinyProfileUserInfoCard | U...
  function generatePlatforms (line 128) | async function generatePlatforms(
  function findD1Characters (line 186) | async function findD1Characters(account: DestinyAccount): Promise<Destin...
  function getLastPlayedD1Character (line 224) | function getLastPlayedD1Character(characters: D1Character[]): Date {
  function compareAccounts (line 235) | function compareAccounts(

FILE: src/app/accounts/observers.ts
  function createSaveAccountsObserver (line 6) | function createSaveAccountsObserver(): StoreObserver<

FILE: src/app/accounts/platforms.ts
  function loadAccountsFromBungieNet (line 67) | function loadAccountsFromBungieNet(): ThunkResult<readonly DestinyAccoun...
  function setActivePlatform (line 76) | function setActivePlatform(
  function loadPlatforms (line 93) | function loadPlatforms(membershipId: string): ThunkResult<readonly Desti...
  function logOut (line 108) | function logOut(): ThunkResult {

FILE: src/app/accounts/reducer.ts
  type AccountsState (line 11) | interface AccountsState {
  type AccountsAction (line 39) | type AccountsAction = ActionType<typeof actions>;
  function getLastAccountFromLocalStorage (line 41) | function getLastAccountFromLocalStorage() {

FILE: src/app/armory/AllWishlistRolls.m.scss.d.ts
  type CssExports (line 3) | interface CssExports {

FILE: src/app/armory/AllWishlistRolls.tsx
  function AllWishlistRolls (line 27) | function AllWishlistRolls({
  function WishlistRolls (line 67) | function WishlistRolls({
  function InvalidPlug (line 219) | function InvalidPlug({ hash }: { hash: number }) {

FILE: src/app/armory/Armory.m.scss.d.ts
  type CssExports (line 3) | interface CssExports {

FILE: src/app/armory/Armory.tsx
  function Armory (line 51) | function Armory({
  function getAlternateItems (line 314) | function getAlternateItems(
  function AlternatePerkDiffs (line 346) | function AlternatePerkDiffs({
  function compareItemPerks (line 393) | function compareItemPerks(
  function SeasonInfo (line 436) | function SeasonInfo({

FILE: src/app/armory/ArmoryPage.tsx
  function ArmoryPage (line 9) | function ArmoryPage({ account }: { account: DestinyAccount }) {

FILE: src/app/armory/ArmorySheet.m.scss.d.ts
  type CssExports (line 3) | interface CssExports {

FILE: src/app/armory/ArmorySheet.tsx
  function ArmorySheet (line 10) | function ArmorySheet({

FILE: src/app/armory/ItemGrid.tsx
  type PopupState (line 11) | interface PopupState {
  function ItemGrid (line 16) | function ItemGrid({
  function BasicItemTrigger (line 45) | function BasicItemTrigger({

FILE: src/app/armory/Links.m.scss.d.ts
  type CssExports (line 3) | interface CssExports {

FILE: src/app/armory/Links.tsx
  function Links (line 19) | function Links({ item }: { item: DimItem }) {
  function buildSocketParam (line 68) | function buildSocketParam(item: DimItem): string {
  function buildLightGGSockets (line 88) | function buildLightGGSockets(item: DimItem) {
  function buildFoundrySockets (line 101) | function buildFoundrySockets(item: DimItem) {
  function getWeaponSocketInfo (line 119) | function getWeaponSocketInfo(item: DimItem): null | {

FILE: src/app/armory/WishListEntry.m.scss.d.ts
  type CssExports (line 3) | interface CssExports {

FILE: src/app/armory/WishListEntry.tsx
  function WishListEntry (line 15) | function WishListEntry({ item }: { item: DimItem }) {
  function createWishListRollString (line 38) | function createWishListRollString(item: DimItem) {

FILE: src/app/armory/crafting-utils.ts
  function getCraftingTemplate (line 26) | function getCraftingTemplate(defs: D2ManifestDefinitions, itemHash: numb...

FILE: src/app/armory/wishlist-collapser.ts
  type Roll (line 10) | interface Roll {
  function consolidateRollsForOneWeapon (line 28) | function consolidateRollsForOneWeapon(
  function isMajorPerk (line 176) | function isMajorPerk(item?: DestinyInventoryItemDefinition) {
  function consolidateSecondaryPerks (line 197) | function consolidateSecondaryPerks(initialRolls: Roll[]) {
  type PerkMeta (line 253) | interface PerkMeta {
  type PerkColumnsMeta (line 257) | type PerkColumnsMeta = PerkMeta[][];
  function getBaseEnhancedPerkPair (line 259) | function getBaseEnhancedPerkPair(perkHash: number) {
  function normalizePerkKey (line 278) | function normalizePerkKey(perkHash: number) {
  function combineColumns (line 283) | function combineColumns(

FILE: src/app/bungie-api/authenticated-fetch.ts
  class FatalTokenError (line 11) | class FatalTokenError extends Error {
    method constructor (line 12) | constructor(msg: string) {
  function fetchWithBungieOAuth (line 23) | async function fetchWithBungieOAuth(
  function responseIndicatesBadToken (line 61) | async function responseIndicatesBadToken(response: Response) {
  function getActiveToken (line 82) | async function getActiveToken(): Promise<Tokens> {
  function handleRefreshTokenError (line 106) | function handleRefreshTokenError(error: unknown): Promise<Tokens> {

FILE: src/app/bungie-api/bungie-api-utils.ts
  constant API_KEY (line 3) | const API_KEY = $DIM_FLAVOR !== 'dev' ? $DIM_WEB_API_KEY : localStorage....
  function bungieApiUpdate (line 5) | function bungieApiUpdate(path: string, data?: Record<string, any>): Http...
  function bungieApiQuery (line 13) | function bungieApiQuery(path: string, params?: HttpQueryParams): HttpCli...
  function oauthClientId (line 21) | function oauthClientId(): string {
  function oauthClientSecret (line 25) | function oauthClientSecret(): string {

FILE: src/app/bungie-api/bungie-core-api.ts
  function getGlobalAlerts (line 12) | async function getGlobalAlerts(): Promise<GlobalAlert[]> {
  function getBungieNetSettings (line 20) | async function getBungieNetSettings(): Promise<CoreSettingsConfiguration> {

FILE: src/app/bungie-api/bungie-service-helper.ts
  constant TIMEOUT (line 20) | const TIMEOUT = 15000;
  function dimErrorHandledHttpClient (line 74) | function dimErrorHandledHttpClient(httpClient: HttpClient): HttpClient {
  function handleErrors (line 87) | function handleErrors(error: unknown): never {
  function handleUniquenessViolation (line 211) | function handleUniquenessViolation(error: unknown, item: DimItem): never {

FILE: src/app/bungie-api/destiny1-api.ts
  function getCharacters (line 31) | async function getCharacters(account: DestinyAccount) {
  function getStores (line 49) | async function getStores(account: DestinyAccount): Promise<D1StoresData> {
  function getDestinyInventories (line 85) | function getDestinyInventories(account: DestinyAccount, characterIds: st...
  function getVaultInventory (line 100) | async function getVaultInventory(account: DestinyAccount) {
  function getDestinyProgression (line 108) | async function getDestinyProgression(account: DestinyAccount, characterI...
  function getDestinyAdvisors (line 121) | async function getDestinyAdvisors(account: DestinyAccount, characterIds:...
  function getVendorForCharacter (line 134) | async function getVendorForCharacter(
  function transfer (line 147) | async function transfer(
  function equip (line 169) | function equip(account: DestinyAccount, item: DimItem) {
  function equipItems (line 182) | async function equipItems(
  function setItemState (line 202) | function setItemState(

FILE: src/app/bungie-api/destiny2-api.ts
  function getManifest (line 55) | async function getManifest(): Promise<DestinyManifest> {
  function getLinkedAccounts (line 60) | async function getLinkedAccounts(
  function getStores (line 74) | function getStores(platform: DestinyAccount): Promise<DestinyProfileResp...
  function getCharacters (line 112) | function getCharacters(platform: DestinyAccount): Promise<DestinyProfile...
  function getProfile (line 120) | async function getProfile(
  function getVendors (line 141) | async function getVendors(
  function getVendorSaleComponents (line 160) | async function getVendorSaleComponents(
  function transfer (line 186) | async function transfer(
  function equip (line 211) | function equip(account: DestinyAccount, item: DimItem): Promise<ServerRe...
  function equipItems (line 229) | async function equipItems(
  function setLockState (line 251) | function setLockState(
  function setTrackedState (line 268) | function setTrackedState(
  function requestAdvancedWriteActionToken (line 286) | async function requestAdvancedWriteActionToken(
  function equipInGameLoadout (line 304) | async function equipInGameLoadout(account: DestinyAccount, loadout: InGa...
  function snapshotInGameLoadout (line 313) | async function snapshotInGameLoadout(account: DestinyAccount, loadout: I...
  function clearInGameLoadout (line 325) | async function clearInGameLoadout(account: DestinyAccount, loadout: InGa...
  function editInGameLoadout (line 334) | async function editInGameLoadout(account: DestinyAccount, loadout: InGam...

FILE: src/app/bungie-api/error-toaster.tsx
  function bungieErrorToaster (line 12) | function bungieErrorToaster(errorMessage: string | undefined): NotifyInp...
  function dimErrorToaster (line 33) | function dimErrorToaster(title: string, message: string, errorMessage: s...

FILE: src/app/bungie-api/http-client.test.ts
  type TroubleshootingResponse (line 30) | interface TroubleshootingResponse {

FILE: src/app/bungie-api/http-client.ts
  class HttpStatusError (line 9) | class HttpStatusError extends Error {
    method constructor (line 13) | constructor(response: Response, responseBody?: string) {
  function toHttpStatusError (line 20) | async function toHttpStatusError(response: Response) {
  class BungieError (line 33) | class BungieError extends Error {
    method constructor (line 37) | constructor(
  function throwHttpError (line 53) | async function throwHttpError(response: Response) {
  function throwBungieError (line 65) | function throwBungieError<T>(serverResponse: T | undefined, request: Req...
  function createFetchWithNonStoppingTimeout (line 105) | function createFetchWithNonStoppingTimeout(
  function createHttpClient (line 128) | function createHttpClient(fetchFunction: typeof fetch, apiKey: string): ...
  function responsivelyThrottleHttpClient (line 185) | function responsivelyThrottleHttpClient(

FILE: src/app/bungie-api/oauth-tokens.ts
  type Token (line 6) | interface Token {
  type Tokens (line 16) | interface Tokens {
  function getToken (line 35) | function getToken(): Tokens | null {
  function setToken (line 43) | function setToken(token: Tokens) {
  function removeToken (line 50) | function removeToken() {
  function hasValidAuthTokens (line 57) | function hasValidAuthTokens() {
  function removeAccessToken (line 71) | function removeAccessToken() {
  function getTokenExpiration (line 85) | function getTokenExpiration(token?: Token): number {
  function hasTokenExpired (line 97) | function hasTokenExpired(token?: Token) {

FILE: src/app/bungie-api/oauth.ts
  constant TOKEN_URL (line 9) | const TOKEN_URL = 'https://www.bungie.net/platform/app/oauth/token/';
  function getAccessTokenFromCode (line 41) | async function getAccessTokenFromCode(code: string): Promise<Tokens> {
  type OauthTokenResponse (line 63) | interface OauthTokenResponse {
  function handleAccessToken (line 71) | function handleAccessToken(response: OauthTokenResponse | undefined): To...

FILE: src/app/bungie-api/rate-limit-config.ts
  function setupRateLimiter (line 3) | function setupRateLimiter() {

FILE: src/app/bungie-api/rate-limiter.ts
  class RateLimiterQueue (line 8) | class RateLimiterQueue {
    method constructor (line 25) | constructor(pattern: RegExp, timeLimit: number) {
    method matches (line 30) | matches(url: string) {
    method add (line 35) | add<T>(fetcher: typeof fetch, request: RequestInfo | URL, options?: Re...
    method scheduleProcessing (line 56) | scheduleProcessing() {
    method processQueue (line 69) | processQueue() {
    method canProcess (line 89) | canProcess() {
  function addLimiter (line 98) | function addLimiter(queue: RateLimiterQueue) {
  function rateLimitedFetch (line 105) | function rateLimitedFetch(fetcher: typeof fetch): typeof fetch {

FILE: src/app/character-tile/CharacterHeaderXP.m.scss.d.ts
  type CssExports (line 3) | interface CssExports {

FILE: src/app/character-tile/CharacterHeaderXP.tsx
  function getLevelBar (line 9) | function getLevelBar(store: D1Store) {
  function CharacterHeaderXPBar (line 29) | function CharacterHeaderXPBar({ store }: { store: D1Store }) {

FILE: src/app/character-tile/CharacterTile.m.scss.d.ts
  type CssExports (line 3) | interface CssExports {

FILE: src/app/character-tile/CharacterTile.tsx
  function VaultTile (line 57) | function VaultTile({ store }: { store: DimStore }) {
  function MaxTotalPower (line 86) | function MaxTotalPower({ store }: { store: DimStore }) {
  function Title (line 95) | function Title({ titleInfo }: { titleInfo: DimTitle }) {

FILE: src/app/character-tile/CharacterTileButton.m.scss.d.ts
  type CssExports (line 3) | interface CssExports {

FILE: src/app/character-tile/CharacterTileButton.tsx
  function CharacterTileButton (line 7) | function CharacterTileButton({

FILE: src/app/character-tile/StoreHeading.m.scss.d.ts
  type CssExports (line 3) | interface CssExports {

FILE: src/app/character-tile/StoreHeading.tsx
  function CharacterHeader (line 16) | function CharacterHeader({
  function StoreHeading (line 44) | function StoreHeading({
  function LoadoutMenuContents (line 91) | function LoadoutMenuContents({

FILE: src/app/character-tile/StoreIcon.m.scss.d.ts
  type CssExports (line 3) | interface CssExports {

FILE: src/app/character-tile/StoreIcon.tsx
  function StoreIcon (line 15) | function StoreIcon({

FILE: src/app/clarity/descriptions/ClarityDescriptions.tsx
  function applyFormatting (line 29) | function applyFormatting(text: string | undefined) {
  function ClarityDescriptions (line 62) | function ClarityDescriptions({

FILE: src/app/clarity/descriptions/Description.m.scss.d.ts
  type CssExports (line 3) | interface CssExports {

FILE: src/app/clarity/descriptions/character-stats.ts
  type ClarityCharacterStats (line 1) | interface ClarityCharacterStats {
  type ClarityStatsVersion (line 10) | interface ClarityStatsVersion {
  type Ability (line 15) | interface Ability {
  type Description (line 29) | type Description = string;
  type SuperAbility (line 31) | interface SuperAbility {
  type Override (line 38) | interface Override {
  type StatAbilities (line 58) | interface StatAbilities {
  type DescriptionArray (line 64) | interface DescriptionArray {
  type Mobility (line 69) | interface Mobility extends StatAbilities {
  type Recovery (line 78) | interface Recovery extends StatAbilities {
  type Resilience (line 91) | interface Resilience extends StatAbilities {
  type Intellect (line 100) | interface Intellect {

FILE: src/app/clarity/descriptions/descriptionInterface.ts
  type DescriptionClassNames (line 3) | type DescriptionClassNames =
  type LinesContent (line 21) | interface LinesContent {
  type Line (line 26) | interface Line {
  type Perk (line 34) | interface Perk {
  type ClarityDescription (line 58) | interface ClarityDescription {
  type ClarityVersions (line 65) | interface ClarityVersions {

FILE: src/app/clarity/descriptions/loadDescriptions.ts
  constant CLARITY_BASE (line 10) | const CLARITY_BASE = 'https://database-clarity.github.io/';
  constant CLARITY_STATS_SUPPORTED_SCHEMA (line 19) | const CLARITY_STATS_SUPPORTED_SCHEMA = '1.9';
  function loadClarity (line 125) | function loadClarity(): ThunkResult {

FILE: src/app/clarity/reducer.ts
  type ClarityAction (line 7) | type ClarityAction = ActionType<typeof actions>;
  type ClarityState (line 9) | interface ClarityState {

FILE: src/app/compare/Compare.m.scss.d.ts
  type CssExports (line 3) | interface CssExports {

FILE: src/app/compare/Compare.tsx
  function Compare (line 47) | function Compare({ session }: { session: CompareSession }) {
  function CompareItems (line 341) | function CompareItems({
  function masterworkWeapon (line 375) | function masterworkWeapon(i: DimItem, itemCreationContext: ItemCreationC...

FILE: src/app/compare/CompareButtons.m.scss.d.ts
  type CssExports (line 3) | interface CssExports {

FILE: src/app/compare/CompareColumns.m.scss.d.ts
  type CssExports (line 3) | interface CssExports {

FILE: src/app/compare/CompareColumns.tsx
  function c (line 39) | function c<V extends Value>(columnDef: ColumnDefinition<V>): ColumnDefin...
  function getColumns (line 47) | function getColumns(

FILE: src/app/compare/CompareContainer.tsx
  function CompareContainer (line 12) | function CompareContainer({ destinyVersion }: { destinyVersion: DestinyV...

FILE: src/app/compare/CompareItem.m.scss.d.ts
  type CssExports (line 3) | interface CssExports {

FILE: src/app/compare/CompareItem.tsx
  function VendorItemWarning (line 128) | function VendorItemWarning({ item }: { item: DimItem }) {
  function CompareHeaders (line 148) | function CompareHeaders({

FILE: src/app/compare/CompareStat.m.scss.d.ts
  type CssExports (line 3) | interface CssExports {

FILE: src/app/compare/CompareStat.tsx
  function CompareStat (line 12) | function CompareStat({
  function statRange (line 91) | function statRange(stat: DimStat | D1Stat | undefined, min: number, max:...

FILE: src/app/compare/compare-buttons.tsx
  type CompareButton (line 33) | interface CompareButton {
  function findSimilarArmors (line 43) | function findSimilarArmors(exampleItem: DimItem): CompareButton[] {
  function findSimilarWeapons (line 223) | function findSimilarWeapons(exampleItem: DimItem): CompareButton[] {
  function defaultComparisons (line 300) | function defaultComparisons(exampleItem: DimItem): CompareButton[] {

FILE: src/app/compare/compare-utils.ts
  function compareNameQuery (line 20) | function compareNameQuery(item: DimItem) {

FILE: src/app/compare/reducer.ts
  type CompareSession (line 13) | interface CompareSession {
  type CompareState (line 39) | interface CompareState {
  type CompareAction (line 47) | type CompareAction = ActionType<typeof actions>;
  function addCompareItem (line 101) | function addCompareItem(state: CompareState, item: DimItem): CompareState {
  function initialCompareQuery (line 160) | function initialCompareQuery(item: DimItem) {
  function removeCompareItem (line 193) | function removeCompareItem(state: CompareState, item: DimItem): CompareS...
  function compareFilteredItems (line 219) | function compareFilteredItems(
  function compareSelectedItems (line 243) | function compareSelectedItems(state: CompareState, items: DimItem[]) {
  function getItemCategoryHashesFromExampleItem (line 259) | function getItemCategoryHashesFromExampleItem(item: DimItem) {

FILE: src/app/compare/types.ts
  type DimAdjustedItemPlug (line 3) | interface DimAdjustedItemPlug {
  type DimAdjustedPlugs (line 8) | interface DimAdjustedPlugs {
  type DimAdjustedItemStat (line 13) | interface DimAdjustedItemStat {
  type DimAdjustedStats (line 19) | interface DimAdjustedStats {

FILE: src/app/css-variables.ts
  constant KEYBOARD_THRESHOLD (line 12) | const KEYBOARD_THRESHOLD = 50;
  function setCSSVariable (line 14) | function setCSSVariable(property: string, value: { toString: () => strin...
  function createItemSizeObserver (line 20) | function createItemSizeObserver(): StoreObserver<number> {
  function createOrnamentDisplayObserver (line 30) | function createOrnamentDisplayObserver(): StoreObserver<OrnamentDisplay> {
  function createThemeObserver (line 48) | function createThemeObserver(): StoreObserver<{ theme: string; isPhonePo...
  function createTilesPerCharColumnObserver (line 65) | function createTilesPerCharColumnObserver(): StoreObserver<number> {
  function setCssVariableEventListeners (line 82) | function setCssVariableEventListeners() {
  function syncThemeColor (line 142) | function syncThemeColor(isPhonePortrait: boolean) {

FILE: src/app/debug/Debug.m.scss.d.ts
  type CssExports (line 3) | interface CssExports {

FILE: src/app/debug/Debug.tsx
  function Debug (line 38) | function Debug() {
  function BungieTokenState (line 296) | function BungieTokenState({ token }: { token: Token }) {
  function DIMTokenState (line 318) | function DIMTokenState({ token }: { token: DimAuthToken }) {
  function ErrorInfo (line 337) | function ErrorInfo({ error }: { error: Error | DimError }) {

FILE: src/app/destiny1/activities/Activities.m.scss.d.ts
  type CssExports (line 3) | interface CssExports {

FILE: src/app/destiny1/activities/Activities.tsx
  type Skull (line 26) | interface Skull {
  type Activity (line 32) | interface Activity {
  type ActivityTier (line 43) | interface ActivityTier {
  function Activities (line 58) | function Activities({ account }: { account: DestinyAccount }) {
  function useActivities (line 173) | function useActivities(defs: D1ManifestDefinitions | undefined, characte...
  function i18nActivitySkulls (line 328) | function i18nActivitySkulls(skulls: Skull[], defs: D1ManifestDefinitions...

FILE: src/app/destiny1/d1-buckets.ts
  function getBuckets (line 31) | function getBuckets(defs: D1ManifestDefinitions) {

FILE: src/app/destiny1/d1-definitions.ts
  type DefinitionTable (line 46) | interface DefinitionTable<T> {
  type D1ManifestDefinitions (line 51) | interface D1ManifestDefinitions {
  function getDefinitions (line 78) | function getDefinitions(force = false): ThunkResult<D1ManifestDefinition...

FILE: src/app/destiny1/d1-factions.ts
  function factionAlignment (line 32) | function factionAlignment(store: DimStore): string | null {
  function factionItemAligns (line 46) | function factionItemAligns(store: DimStore, item: D1Item) {
  function factionAligned (line 62) | function factionAligned(store: DimStore, factionHash: number) {

FILE: src/app/destiny1/d1-manifest-types.ts
  type D1StatHashes (line 27) | const enum D1StatHashes {
  type AllD1DestinyManifestComponents (line 36) | interface AllD1DestinyManifestComponents {
  type D1TalentNode (line 56) | interface D1TalentNode {
  type D1Perk (line 64) | interface D1Perk {
  type D1ItemSourceDefinition (line 70) | interface D1ItemSourceDefinition {
  type D1Stat (line 82) | interface D1Stat extends DestinyStat {
  type D1ItemComponent (line 86) | interface D1ItemComponent {
  type D1InventoryItemDefinition (line 120) | interface D1InventoryItemDefinition {
  type D1DamageTypeDefinition (line 174) | interface D1DamageTypeDefinition {
  type D1TalentGridNodeStepDefinition (line 188) | interface D1TalentGridNodeStepDefinition {
  type D1TalentGridNodeDefinition (line 215) | interface D1TalentGridNodeDefinition {
  type D1TalentGridDefinition (line 240) | interface D1TalentGridDefinition {
  type D1ClassDefinition (line 258) | interface D1ClassDefinition {
  type D1StatDefinition (line 271) | interface D1StatDefinition {
  type D1ProgressionDefinition (line 285) | interface D1ProgressionDefinition {
  type D1ObjectiveDefinition (line 298) | interface D1ObjectiveDefinition {
  type D1ObjectiveProgress (line 316) | interface D1ObjectiveProgress {
  type D1RecordComponent (line 326) | interface D1RecordComponent {
  type D1RecordDefinition (line 333) | interface D1RecordDefinition {
  type D1ProgressionStep (line 348) | interface D1ProgressionStep {
  type D1RecordBook (line 353) | interface D1RecordBook {
  type D1RecordBookPageDefinition (line 366) | interface D1RecordBookPageDefinition {
  type D1RecordBookDefinition (line 386) | interface D1RecordBookDefinition {
  type D1ItemCategoryDefinition (line 414) | interface D1ItemCategoryDefinition {
  type D1VendorCategoryDefinition (line 429) | interface D1VendorCategoryDefinition {
  type D1ActivityTier (line 440) | interface D1ActivityTier {
  type D1SkullCategory (line 467) | interface D1SkullCategory {
  type D1ActivityComponent (line 476) | interface D1ActivityComponent {
  type D1ActivityDefinition (line 505) | interface D1ActivityDefinition {
  type D1ActivityTypeDefinition (line 532) | interface D1ActivityTypeDefinition {
  type D1InventoryBucketDefinition (line 551) | interface D1InventoryBucketDefinition {
  type D1RaceDefinition (line 569) | interface D1RaceDefinition {
  type D1FactionDefinition (line 581) | interface D1FactionDefinition {
  type D1VendorDefinition (line 592) | interface D1VendorDefinition {
  type D1StoresData (line 680) | interface D1StoresData {
  type D1CharacterData (line 686) | interface D1CharacterData {
  type D1GetAccountResponse (line 694) | interface D1GetAccountResponse {
  type D1GetInventoryResponse (line 706) | interface D1GetInventoryResponse {
  type D1GetVaultInventoryResponse (line 710) | interface D1GetVaultInventoryResponse {
  type D1Character (line 714) | interface D1Character {
  type D1CharacterBase (line 726) | interface D1CharacterBase {
  type D1LevelProgression (line 747) | interface D1LevelProgression {
  type D1Inventory (line 758) | interface D1Inventory {
  type D1VaultInventory (line 763) | interface D1VaultInventory {
  type D1BucketLabel (line 767) | type D1BucketLabel = 'Invisible' | 'Item' | 'Currency';
  type D1Bucket (line 769) | interface D1Bucket {
  type D1GetProgressionResponse (line 774) | interface D1GetProgressionResponse {
  type D1GetAdvisorsResponse (line 785) | interface D1GetAdvisorsResponse {
  type D1Pursuit (line 796) | interface D1Pursuit {
  type D1StatLabel (line 807) | type D1StatLabel =
  type D1Stats (line 819) | type D1Stats = { [stat in D1StatLabel]: D1Stat | undefined };

FILE: src/app/destiny1/loadout-builder/D1LoadoutBuilder.m.scss.d.ts
  type CssExports (line 3) | interface CssExports {

FILE: src/app/destiny1/loadout-builder/D1LoadoutBuilder.tsx
  type State (line 47) | interface State {
  function D1LoadoutBuilder (line 117) | function D1LoadoutBuilder({ account }: { account: DestinyAccount }) {
  function SetControls (line 517) | function SetControls({
  function ArmorForClass (line 634) | function ArmorForClass({
  function filterPerks (line 720) | function filterPerks(perks: D1GridNode[], item: D1Item) {
  function useActivePerks (line 729) | function useActivePerks({

FILE: src/app/destiny1/loadout-builder/ExcludeItemsDropTarget.tsx
  type Props (line 7) | interface Props {
  function ExcludeItemsDropTarget (line 13) | function ExcludeItemsDropTarget({ className, children, onExcluded }: Pro...

FILE: src/app/destiny1/loadout-builder/GeneratedSet.m.scss.d.ts
  type CssExports (line 3) | interface CssExports {

FILE: src/app/destiny1/loadout-builder/GeneratedSet.tsx
  type Props (line 21) | interface Props {
  function GeneratedSet (line 28) | function GeneratedSet({ setType, store, activesets, excludeItem }: Props) {

FILE: src/app/destiny1/loadout-builder/LoadoutBuilderDropTarget.m.scss.d.ts
  type CssExports (line 3) | interface CssExports {

FILE: src/app/destiny1/loadout-builder/LoadoutBuilderDropTarget.tsx
  function LoadoutBucketDropTarget (line 7) | function LoadoutBucketDropTarget({
  function dropClasses (line 43) | function dropClasses(isOver: boolean, canDrop: boolean, className?: stri...

FILE: src/app/destiny1/loadout-builder/LoadoutBuilderItem.m.scss.d.ts
  type CssExports (line 3) | interface CssExports {

FILE: src/app/destiny1/loadout-builder/LoadoutBuilderItem.tsx
  type Props (line 9) | interface Props {
  function LoadoutBuilderItem (line 14) | function LoadoutBuilderItem({ item, shiftClickCallback }: Props) {

FILE: src/app/destiny1/loadout-builder/LoadoutBuilderLockPerk.m.scss.d.ts
  type CssExports (line 3) | interface CssExports {

FILE: src/app/destiny1/loadout-builder/LoadoutBuilderLockPerk.tsx
  function LoadoutBuilderLockPerk (line 13) | function LoadoutBuilderLockPerk({

FILE: src/app/destiny1/loadout-builder/LoadoutBuilderLocksDialog.m.scss.d.ts
  type CssExports (line 3) | interface CssExports {

FILE: src/app/destiny1/loadout-builder/LoadoutBuilderLocksDialog.tsx
  type Props (line 10) | interface Props {
  function LoadoutBuilderLocksDialog (line 18) | function LoadoutBuilderLocksDialog({

FILE: src/app/destiny1/loadout-builder/calculate.ts
  constant TAG (line 20) | const TAG = 'loadout optimizer';
  function getSetBucketsStep (line 22) | async function getSetBucketsStep(
  function tierValue (line 232) | function tierValue(value: number) {

FILE: src/app/destiny1/loadout-builder/types.ts
  type D1ItemWithNormalStats (line 7) | interface D1ItemWithNormalStats extends D1Item {
  type ArmorTypes (line 21) | type ArmorTypes =
  type ClassTypes (line 30) | type ClassTypes = DestinyClass.Titan | DestinyClass.Warlock | DestinyCla...
  type ArmorSet (line 32) | interface ArmorSet {
  type LockedPerk (line 46) | interface LockedPerk {
  type ItemBucket (line 52) | type ItemBucket = { [armorType in ArmorTypes]: D1ItemWithNormalStats[] };
  type PerkCombination (line 53) | type PerkCombination = { [armorType in ArmorTypes]: D1GridNode[] };
  type LockedPerkHash (line 55) | interface LockedPerkHash {
  type SetType (line 59) | interface SetType {

FILE: src/app/destiny1/loadout-builder/utils.ts
  type ItemWithBonus (line 19) | interface ItemWithBonus {
  function getBonusType (line 24) | function getBonusType(armorpiece: D1ItemWithNormalStats): string {
  function getBestItem (line 35) | function getBestItem(
  function calcArmorStats (line 64) | function calcArmorStats(
  function getBonusConfig (line 101) | function getBonusConfig(armor: ArmorSet['armor']): { [armorType in Armor...
  function genSetHash (line 105) | function genSetHash(armorPieces: ItemWithBonus[]) {
  function getBestArmor (line 113) | function getBestArmor(
  function getActiveHighestSets (line 218) | function getActiveHighestSets(
  function mergeBuckets (line 237) | function mergeBuckets<T extends any[]>(
  function loadVendorsBucket (line 250) | function loadVendorsBucket(
  function loadBucket (line 283) | function loadBucket(currentStore: DimStore, stores: D1Store[]): ItemBuck...
  function getBuckets (line 298) | function getBuckets(items: D1Item[]): ItemBucket {
  function normalizeStats (line 324) | function normalizeStats(item: D1ItemWithNormalStats) {

FILE: src/app/destiny1/loadout-drawer/Buttons.m.scss.d.ts
  type CssExports (line 3) | interface CssExports {

FILE: src/app/destiny1/loadout-drawer/Buttons.tsx
  type AddButtonProps (line 5) | interface AddButtonProps {
  function AddButton (line 14) | function AddButton({ className, onClick }: AddButtonProps) {

FILE: src/app/destiny1/loadout-drawer/D1LoadoutDrawer.m.scss.d.ts
  type CssExports (line 3) | interface CssExports {

FILE: src/app/destiny1/loadout-drawer/D1LoadoutDrawer.tsx
  function D1LoadoutDrawer (line 36) | function D1LoadoutDrawer({
  function LoadoutDrawerBody (line 133) | function LoadoutDrawerBody({

FILE: src/app/destiny1/loadout-drawer/LoadoutDrawerBucket.m.scss.d.ts
  type CssExports (line 3) | interface CssExports {

FILE: src/app/destiny1/loadout-drawer/LoadoutDrawerBucket.tsx
  function LoadoutDrawerBucket (line 12) | function LoadoutDrawerBucket({

FILE: src/app/destiny1/loadout-drawer/LoadoutDrawerContents.m.scss.d.ts
  type CssExports (line 3) | interface CssExports {

FILE: src/app/destiny1/loadout-drawer/LoadoutDrawerContents.tsx
  function LoadoutDrawerContents (line 50) | function LoadoutDrawerContents({
  function pickLoadoutItem (line 129) | async function pickLoadoutItem(

FILE: src/app/destiny1/loadout-drawer/LoadoutDrawerItem.m.scss.d.ts
  type CssExports (line 3) | interface CssExports {

FILE: src/app/destiny1/loadout-drawer/LoadoutDrawerItem.tsx
  function LoadoutDrawerItem (line 9) | function LoadoutDrawerItem({

FILE: src/app/destiny1/loadout-drawer/LoadoutDrawerOptions.m.scss.d.ts
  type CssExports (line 3) | interface CssExports {

FILE: src/app/destiny1/loadout-drawer/LoadoutDrawerOptions.tsx
  function LoadoutDrawerOptions (line 30) | function LoadoutDrawerOptions({

FILE: src/app/destiny1/record-books/RecordBooks.m.scss.d.ts
  type CssExports (line 3) | interface CssExports {

FILE: src/app/destiny1/record-books/RecordBooks.tsx
  type RecordBook (line 23) | interface RecordBook {
  type RecordBookPage (line 37) | interface RecordBookPage {
  function RecordBooks (line 54) | function RecordBooks({ account }: { account: DestinyAccount }) {

FILE: src/app/destiny1/vendors/D1Vendor.tsx
  function D1Vendor (line 10) | function D1Vendor({

FILE: src/app/destiny1/vendors/D1VendorItem.m.scss.d.ts
  type CssExports (line 3) | interface CssExports {

FILE: src/app/destiny1/vendors/D1VendorItem.tsx
  type Props (line 7) | interface Props {
  function D1VendorItem (line 15) | function D1VendorItem({ saleItem, owned, totalCoins }: Props) {
  function D1VendorItemCost (line 34) | function D1VendorItemCost({

FILE: src/app/destiny1/vendors/D1VendorItems.tsx
  function D1VendorItems (line 13) | function D1VendorItems({

FILE: src/app/destiny1/vendors/D1Vendors.m.scss.d.ts
  type CssExports (line 3) | interface CssExports {

FILE: src/app/destiny1/vendors/D1Vendors.tsx
  function D1Vendors (line 18) | function D1Vendors({ account }: { account: DestinyAccount }) {

FILE: src/app/destiny1/vendors/vendor.service.ts
  type VendorCost (line 72) | interface VendorCost {
  type VendorSaleItem (line 81) | interface VendorSaleItem {
  type Vendor (line 90) | interface Vendor {
  function loadVendors (line 136) | function loadVendors(): ThunkResult<{ [vendorHash: number]: Vendor }> {
  function fetchVendor (line 162) | async function fetchVendor(
  function mergeVendors (line 184) | function mergeVendors([firstVendor, ...otherVendors]: Vendor[]) {
  function mergeCategory (line 205) | function mergeCategory(
  function loadVendorForCharacter (line 230) | async function loadVendorForCharacter(
  function factionLevel (line 255) | function factionLevel(store: D1Store, factionHash: number) {
  function cachedVendorUpToDate (line 265) | function cachedVendorUpToDate(vendor: Vendor, store: D1Store, vendorDef:...
  function loadVendor (line 274) | function loadVendor(
  function vendorKey (line 330) | function vendorKey(store: D1Store, vendorHash: number) {
  function calculateExpiration (line 334) | function calculateExpiration(nextRefreshDate: string, vendorHash: number...
  function processVendor (line 352) | async function processVendor(
  function isSaleItemUnlocked (line 444) | function isSaleItemUnlocked(saleItem: { unlockStatuses: { isSet: boolean...
  function countCurrencies (line 453) | function countCurrencies(

FILE: src/app/destiny2/d2-buckets.ts
  function getBuckets (line 19) | function getBuckets(defs: D2ManifestDefinitions) {

FILE: src/app/destiny2/d2-definitions.ts
  type ManifestTablesShort (line 54) | type ManifestTablesShort = Exclude<keyof D2ManifestDefinitions, 'isDesti...
  type DefinitionTable (line 99) | interface DefinitionTable<T> {
  type D2ManifestDefinitions (line 111) | interface D2ManifestDefinitions {
  function getDefinitions (line 162) | function getDefinitions(force = false): ThunkResult<D2ManifestDefinition...
  function buildDefinitionsFromManifest (line 187) | function buildDefinitionsFromManifest(db: AllDestinyManifestComponents) {
  function enhanceDBWithFakeEntries (line 240) | function enhanceDBWithFakeEntries(db: AllDestinyManifestComponents) {

FILE: src/app/destiny2/definitions.ts
  class HashLookupFailure (line 1) | class HashLookupFailure extends Error {
    method constructor (line 5) | constructor(table: string, id: number) {

FILE: src/app/developer/Developer.tsx
  function Developer (line 7) | function Developer(this: never) {

FILE: src/app/dim-api/actions.ts
  constant TAG (line 47) | const TAG = 'dim sync';
  function loadGlobalSettings (line 132) | function loadGlobalSettings(): ThunkResult {
  function getBackoffWaitTime (line 151) | function getBackoffWaitTime(backoff: number) {
  function loadDimApiData (line 176) | function loadDimApiData(
  function profileLastLoaded (line 305) | function profileLastLoaded(dimApi: DimApiState, account: DestinyAccount ...
  function flushUpdates (line 320) | function flushUpdates(): ThunkResult {
  function loadProfileFromIndexedDB (line 398) | function loadProfileFromIndexedDB(): ThunkResult {
  function subtractObject (line 410) | function subtractObject<T>(obj: T | undefined, defaults: T): Partial<T> {
  function deleteAllApiData (line 425) | function deleteAllApiData(): ThunkResult<DeleteAllResponse['deleted']> {
  function showProfileLoadErrorNotification (line 438) | function showProfileLoadErrorNotification(e: unknown) {
  function showUpdateErrorNotification (line 444) | function showUpdateErrorNotification(e: unknown) {

FILE: src/app/dim-api/api-permission-prompt.m.scss.d.ts
  type CssExports (line 3) | interface CssExports {

FILE: src/app/dim-api/api-permission-prompt.tsx
  function promptForApiPermission (line 12) | function promptForApiPermission() {

FILE: src/app/dim-api/api-types.ts
  type AddUpdateInfo (line 11) | type AddUpdateInfo<U> = U extends ProfileUpdate
  type DeleteLoadoutUpdateWithRollback (line 21) | interface DeleteLoadoutUpdateWithRollback extends DeleteLoadoutUpdate {
  type DeleteSearchUpdateWithRollback (line 27) | interface DeleteSearchUpdateWithRollback extends DeleteSearchUpdate {
  type ProfileUpdateWithRollback (line 40) | type ProfileUpdateWithRollback =

FILE: src/app/dim-api/basic-actions.ts
  type ProfileIndexedDBState (line 29) | type ProfileIndexedDBState = Pick<

FILE: src/app/dim-api/dim-api-helper.ts
  constant DIM_API_HOST (line 8) | const DIM_API_HOST = 'https://api.destinyitemmanager.com';
  constant API_KEY (line 9) | const API_KEY = $DIM_FLAVOR !== 'dev' ? $DIM_API_KEY : localStorage.getI...
  function unauthenticatedApi (line 16) | async function unauthenticatedApi<T>(
  function authenticatedApi (line 70) | async function authenticatedApi<T>(config: HttpClientConfig): Promise<T> {
  type DimAuthToken (line 119) | interface DimAuthToken {
  function getToken (line 131) | function getToken(): DimAuthToken | undefined {
  function setToken (line 139) | function setToken(token: DimAuthToken) {
  function deleteDimApiToken (line 143) | function deleteDimApiToken() {
  type AuthTokenRequest (line 147) | interface AuthTokenRequest {
  function getAuthToken (line 179) | async function getAuthToken(): Promise<DimAuthToken> {
  function hasTokenExpired (line 191) | function hasTokenExpired(token?: DimAuthToken) {

FILE: src/app/dim-api/dim-api.ts
  function getGlobalSettings (line 20) | async function getGlobalSettings() {
  function getDimApiProfile (line 32) | async function getDimApiProfile(account?: DestinyAccount, syncToken?: st...
  function importData (line 52) | async function importData(data: ExportResponse) {
  function postUpdates (line 60) | async function postUpdates(
  function createLoadoutShare (line 86) | async function createLoadoutShare(platformMembershipId: string, loadout:...
  function getSharedLoadout (line 99) | async function getSharedLoadout(shareId: string) {
  function deleteAllData (line 111) | async function deleteAllData() {
  function exportDimApiData (line 119) | async function exportDimApiData() {

FILE: src/app/dim-api/import.ts
  constant TAG (line 23) | const TAG = 'importData';
  function importDataBackup (line 29) | function importDataBackup(data: ExportResponse, silent = false): ThunkRe...
  function importBackupIntoLocalState (line 70) | function importBackupIntoLocalState(data: ExportResponse, silent = false...
  function waitForProfileLoad (line 175) | function waitForProfileLoad<D extends Dispatch>(dispatch: D) {
  function showImportSuccessNotification (line 194) | function showImportSuccessNotification(
  function showImportFailedNotification (line 208) | function showImportFailedNotification(message: string) {
  type PlatformLoadout (line 217) | type PlatformLoadout = Loadout & {
  function extractLoadouts (line 225) | function extractLoadouts(importData: ExportResponse): PlatformLoadout[] {
  type PlatformItemAnnotation (line 236) | type PlatformItemAnnotation = ItemAnnotation & {
  function extractItemAnnotations (line 244) | function extractItemAnnotations(importData: ExportResponse): PlatformIte...

FILE: src/app/dim-api/reducer.ts
  constant MAX_SEARCH_HISTORY (line 45) | const MAX_SEARCH_HISTORY = 300;
  type DimApiState (line 47) | interface DimApiState {
  function getInitialApiPermissionSetting (line 119) | function getInitialApiPermissionSetting() {
  type DimApiAction (line 160) | type DimApiAction =
  function profileLoaded (line 391) | function profileLoaded(
  function migrateSettings (line 519) | function migrateSettings(state: DimApiState) {
  function changeSetting (line 604) | function changeSetting<V extends keyof Settings>(state: DimApiState, pro...
  function prepareUpdateQueue (line 632) | function prepareUpdateQueue(state: DimApiState) {
  function compactUpdate (line 696) | function compactUpdate(
  function applyFinishedUpdatesToQueue (line 907) | function applyFinishedUpdatesToQueue(state: DimApiState, results: Profil...
  function deleteLoadout (line 982) | function deleteLoadout(state: DimApiState, loadoutId: string) {
  function updateLoadout (line 1014) | function updateLoadout(state: DimApiState, loadout: DimLoadout, account:...
  function setTag (line 1035) | function setTag(
  function setItemHashTag (line 1075) | function setItemHashTag(
  function setNote (line 1108) | function setNote(
  function setItemHashNote (line 1141) | function setItemHashNote(
  function tagCleanup (line 1166) | function tagCleanup(state: DimApiState, itemIdsToRemove: string[], accou...
  function trackTriumph (line 1185) | function trackTriumph(
  function searchUsed (line 1208) | function searchUsed(
  function saveSearch (line 1261) | function saveSearch(
  function deleteSearch (line 1336) | function deleteSearch(
  function cleanupInvalidSearches (line 1375) | function cleanupInvalidSearches(draft: Draft<DimApiState>, account: Dest...
  function parseProfileKey (line 1401) | function parseProfileKey(profileKey: string): [string, DestinyVersion] {
  function ensureProfile (line 1409) | function ensureProfile(draft: Draft<DimApiState>, profileKey: string) {
  function applyUpdateLocally (line 1421) | function applyUpdateLocally(draft: Draft<DimApiState>, update: ProfileUp...
  function reverseUpdateLocally (line 1570) | function reverseUpdateLocally(draft: Draft<DimApiState>, update: Profile...

FILE: src/app/dim-api/register-app.ts
  function registerApp (line 4) | async function registerApp(dimAppName: string, bungieApiKey: string) {

FILE: src/app/dim-api/selectors.ts
  function makeProfileKeyFromAccount (line 12) | function makeProfileKeyFromAccount(account: DestinyAccount) {
  function makeProfileKey (line 15) | function makeProfileKey(platformMembershipId: string, destinyVersion: De...

FILE: src/app/dim-ui/AlertIcon.m.scss.d.ts
  type CssExports (line 3) | interface CssExports {

FILE: src/app/dim-ui/AlertIcon.tsx
  function AlertIcon (line 5) | function AlertIcon({ className, title }: { className?: string; title?: s...

FILE: src/app/dim-ui/AnimatedNumber.tsx
  function AnimatedNumber (line 13) | function AnimatedNumber({

FILE: src/app/dim-ui/AutoRefresh.tsx
  function triggerTryRefresh (line 21) | function triggerTryRefresh() {
  function AutoRefresh (line 30) | function AutoRefresh() {
  function useAutoRefresh (line 40) | function useAutoRefresh() {
  function useScheduledAutoRefresh (line 106) | function useScheduledAutoRefresh() {
  function useThrottledRefresh (line 142) | function useThrottledRefresh() {
  function useOnlineRefresh (line 160) | function useOnlineRefresh() {
  function useVisibilityRefresh (line 181) | function useVisibilityRefresh() {

FILE: src/app/dim-ui/BungieImage.tsx
  type BungieImagePath (line 7) | type BungieImagePath = string;
  type BungieImageProps (line 9) | type BungieImageProps = Omit<React.ImgHTMLAttributes<HTMLImageElement>, ...
  function bungieBackgroundStyle (line 31) | function bungieBackgroundStyle(src: BungieImagePath) {
  function bungieBackgroundStyles (line 40) | function bungieBackgroundStyles(src: BungieImagePath[]) {
  function bungieBackgroundStyleAdvanced (line 54) | function bungieBackgroundStyleAdvanced(src: BungieImagePath, stacks = 1) {
  function bungieNetPath (line 65) | function bungieNetPath(src: BungieImagePath): string {

FILE: src/app/dim-ui/CharacterSelect.m.scss.d.ts
  type CssExports (line 3) | interface CssExports {

FILE: src/app/dim-ui/CharacterSelect.tsx
  function CharacterSelect (line 26) | function CharacterSelect({
  function ListCharacterSelect (line 57) | function ListCharacterSelect({
  function SwipableCharacterSelect (line 82) | function SwipableCharacterSelect({

FILE: src/app/dim-ui/CheckButton.m.scss.d.ts
  type CssExports (line 3) | interface CssExports {

FILE: src/app/dim-ui/CheckButton.tsx
  function CheckButton (line 6) | function CheckButton({

FILE: src/app/dim-ui/ClassIcon.tsx
  function ClassIcon (line 26) | function ClassIcon({

FILE: src/app/dim-ui/ClickOutside.tsx
  function ClickOutside (line 14) | function ClickOutside({

FILE: src/app/dim-ui/ClickOutsideRoot.tsx
  function ClickOutsideRoot (line 13) | function ClickOutsideRoot({

FILE: src/app/dim-ui/ClosableContainer.m.scss.d.ts
  type CssExports (line 3) | interface CssExports {

FILE: src/app/dim-ui/ClosableContainer.tsx
  function ClosableContainer (line 10) | function ClosableContainer({

FILE: src/app/dim-ui/CollapsibleTitle.m.scss.d.ts
  type CssExports (line 3) | interface CssExports {

FILE: src/app/dim-ui/CollapsibleTitle.tsx
  function Title (line 12) | function Title({
  function CollapsibleTitle (line 65) | function CollapsibleTitle({
  function CollapseIcon (line 125) | function CollapseIcon({ collapsed }: { collapsed: boolean }) {
  function CollapsedSection (line 145) | function CollapsedSection({

FILE: src/app/dim-ui/ConfirmButton.m.scss.d.ts
  type CssExports (line 3) | interface CssExports {

FILE: src/app/dim-ui/ConfirmButton.tsx
  function ConfirmButton (line 14) | function ConfirmButton({

FILE: src/app/dim-ui/Countdown.tsx
  function Countdown (line 7) | function Countdown({

FILE: src/app/dim-ui/CustomStatTotal.m.scss.d.ts
  type CssExports (line 3) | interface CssExports {

FILE: src/app/dim-ui/CustomStatTotal.tsx
  type StatHashListsKeyedByDestinyClass (line 10) | type StatHashListsKeyedByDestinyClass = Record<number, number[]>;
  function StatTotalToggle (line 12) | function StatTotalToggle({
  function StatToggleButton (line 74) | function StatToggleButton({
  function toggleArrayElement (line 107) | function toggleArrayElement<T>(element: T, arr: T[]) {

FILE: src/app/dim-ui/CustomStatWeights.m.scss.d.ts
  type CssExports (line 3) | interface CssExports {

FILE: src/app/dim-ui/CustomStatWeights.tsx
  function CustomStatWeightsFromHash (line 12) | function CustomStatWeightsFromHash({
  function CustomStatWeightsDisplay (line 32) | function CustomStatWeightsDisplay({

FILE: src/app/dim-ui/DestinyTooltipText.m.scss.d.ts
  type CssExports (line 3) | interface CssExports {

FILE: src/app/dim-ui/DestinyTooltipText.tsx
  function DestinyTooltipText (line 9) | function DestinyTooltipText({ item }: { item: DimItem }) {
  function isExpirationTooltip (line 36) | function isExpirationTooltip(tip: DestinyItemTooltipNotification) {
  function isPatternTooltip (line 40) | function isPatternTooltip(tip: DestinyItemTooltipNotification) {
  function isEnhancementTooltip (line 44) | function isEnhancementTooltip(item: DimItem, tip: DestinyItemTooltipNoti...

FILE: src/app/dim-ui/DiamondProgress.m.scss.d.ts
  type CssExports (line 3) | interface CssExports {

FILE: src/app/dim-ui/DiamondProgress.tsx
  type Props (line 3) | interface Props {
  function DiamondProgress (line 16) | function DiamondProgress({ progress, level, icon, className }: Props) {

FILE: src/app/dim-ui/Dropdown.m.scss.d.ts
  type CssExports (line 3) | interface CssExports {

FILE: src/app/dim-ui/Dropdown.tsx
  type Separator (line 10) | interface Separator {
  type DropdownOption (line 14) | interface DropdownOption {
  type Option (line 21) | type Option = Separator | DropdownOption;
  type Props (line 23) | interface Props {
  function isDropdownOption (line 37) | function isDropdownOption(option: Option): option is DropdownOption {
  function Dropdown (line 49) | function Dropdown({

FILE: src/app/dim-ui/ElementIcon.m.scss.d.ts
  type CssExports (line 3) | interface CssExports {

FILE: src/app/dim-ui/ElementIcon.tsx
  function ElementIcon (line 7) | function ElementIcon({
  function EnergyCostIcon (line 36) | function EnergyCostIcon({ className }: { className?: string }) {

FILE: src/app/dim-ui/EnergyIncrements.m.scss.d.ts
  type CssExports (line 3) | interface CssExports {

FILE: src/app/dim-ui/EnergyIncrements.tsx
  function EnergyIncrements (line 15) | function EnergyIncrements({
  function EnergyMeterIncrements (line 37) | function EnergyMeterIncrements({
  function EnergyIncrementsWithPresstip (line 71) | function EnergyIncrementsWithPresstip({

FILE: src/app/dim-ui/ErrorBoundary.tsx
  type Props (line 6) | interface Props {
  type State (line 11) | interface State {
  class ErrorBoundary (line 15) | class ErrorBoundary extends Component<Props, State> {
    method constructor (line 16) | constructor(props: Props) {
    method componentDidCatch (line 21) | componentDidCatch(error: Error, errorInfo: { componentStack: string }) {
    method componentDidUpdate (line 29) | componentDidUpdate(prevProps: Readonly<Props>): void {
    method render (line 35) | render() {

FILE: src/app/dim-ui/ExpandableTextBlock.m.scss.d.ts
  type CssExports (line 3) | interface CssExports {

FILE: src/app/dim-ui/ExpandableTextBlock.tsx
  function ExpandableTextBlock (line 12) | function ExpandableTextBlock({

FILE: src/app/dim-ui/ExternalLink.tsx
  function ExternalLink (line 3) | function ExternalLink({

FILE: src/app/dim-ui/FileUpload.m.scss.d.ts
  type CssExports (line 3) | interface CssExports {

FILE: src/app/dim-ui/FileUpload.tsx
  function FileUpload (line 7) | function FileUpload({

FILE: src/app/dim-ui/FilterPills.m.scss.d.ts
  type CssExports (line 3) | interface CssExports {

FILE: src/app/dim-ui/FilterPills.tsx
  type Option (line 5) | interface Option<T> {
  function FilterPills (line 15) | function FilterPills<T>({

FILE: src/app/dim-ui/FractionalPowerLevel.m.scss.d.ts
  type CssExports (line 3) | interface CssExports {

FILE: src/app/dim-ui/FractionalPowerLevel.tsx
  function FractionalPowerLevel (line 3) | function FractionalPowerLevel({ power }: { power: number }) {

FILE: src/app/dim-ui/HelpLink.m.scss.d.ts
  type CssExports (line 3) | interface CssExports {

FILE: src/app/dim-ui/HelpLink.tsx
  function HelpLink (line 6) | function HelpLink({ helpLink }: { helpLink?: string }) {

FILE: src/app/dim-ui/ItemCategoryIcon.m.scss.d.ts
  type CssExports (line 3) | interface CssExports {

FILE: src/app/dim-ui/ItemCategoryIcon.tsx
  function ArmorSlotIcon (line 11) | function ArmorSlotIcon({ item, className }: { item: DimItem; className?:...
  function WeaponSlotIcon (line 22) | function WeaponSlotIcon({ item, className }: { item: DimItem; className?...
  function WeaponTypeIcon (line 33) | function WeaponTypeIcon({ item, className }: { item: DimItem; className?...

FILE: src/app/dim-ui/ItemPop.m.scss.d.ts
  type CssExports (line 3) | interface CssExports {

FILE: src/app/dim-ui/KeyHelp.m.scss.d.ts
  type CssExports (line 3) | interface CssExports {

FILE: src/app/dim-ui/KeyHelp.tsx
  function KeyHelp (line 8) | function KeyHelp({ combo, className }: { combo: string; className?: stri...

FILE: src/app/dim-ui/Loading.m.scss.d.ts
  type CssExports (line 3) | interface CssExports {

FILE: src/app/dim-ui/Loading.tsx
  function Loading (line 23) | function Loading({ message }: { message?: string }) {

FILE: src/app/dim-ui/PageLoading.m.scss.d.ts
  type CssExports (line 3) | interface CssExports {

FILE: src/app/dim-ui/PageLoading.tsx
  function PageLoading (line 24) | function PageLoading() {

FILE: src/app/dim-ui/PageWithMenu.m.scss.d.ts
  type CssExports (line 3) | interface CssExports {

FILE: src/app/dim-ui/PageWithMenu.tsx
  function PageWithMenu (line 7) | function PageWithMenu({ children, className }: { children: React.ReactNo...
  function useHasScrollbars (line 12) | function useHasScrollbars(ref: React.RefObject<HTMLDivElement | null>) {

FILE: src/app/dim-ui/PressTip.m.scss.d.ts
  type CssExports (line 3) | interface CssExports {

FILE: src/app/dim-ui/PressTip.tsx
  type Props (line 27) | interface Props {
  type ControlProps (line 49) | type ControlProps = Props &
  type TooltipCustomization (line 55) | interface TooltipCustomization {
  function Control (line 81) | function Control({
  function containsContentStyle (line 159) | function containsContentStyle(tooltip: unknown): tooltip is React.ReactN...
  function useTooltipCustomization (line 180) | function useTooltipCustomization({
  function PressTip (line 286) | function PressTip(props: Props) {

FILE: src/app/dim-ui/RadioButtons.m.scss.d.ts
  type CssExports (line 3) | interface CssExports {

FILE: src/app/dim-ui/RadioButtons.tsx
  type Option (line 5) | interface Option<T extends string | number> {
  function RadioButtons (line 16) | function RadioButtons<T extends string | number>({
  function RadioButton (line 43) | function RadioButton<T extends string | number>({

FILE: src/app/dim-ui/Select.m.scss.d.ts
  type CssExports (line 3) | interface CssExports {

FILE: src/app/dim-ui/Select.tsx
  type Option (line 11) | interface Option<T> {
  type Props (line 18) | interface Props<T> {
  function Select (line 49) | function Select<T>({

FILE: src/app/dim-ui/SetFilterButton.m.scss.d.ts
  type CssExports (line 3) | interface CssExports {

FILE: src/app/dim-ui/SetFilterButton.tsx
  function SetFilterButton (line 7) | function SetFilterButton({ filter }: { filter: string }) {

FILE: src/app/dim-ui/Sheet.m.scss.d.ts
  type CssExports (line 3) | interface CssExports {

FILE: src/app/dim-ui/Sheet.tsx
  type SheetContent (line 45) | type SheetContent = React.ReactNode | ((args: { onClose: () => void }) =...
  function useDisableParent (line 81) | function useDisableParent(
  function Sheet (line 101) | function Sheet({
  function tryRepeatedlyWithLimit (line 333) | function tryRepeatedlyWithLimit(callback: () => boolean, timeout = 500, ...

FILE: src/app/dim-ui/SheetHorizontalScrollContainer.m.scss.d.ts
  type CssExports (line 3) | interface CssExports {

FILE: src/app/dim-ui/SheetHorizontalScrollContainer.tsx
  constant HORIZ_SCROLL_DRAG_THRESHOLD (line 6) | const HORIZ_SCROLL_DRAG_THRESHOLD = 20;
  function SheetHorizontalScrollContainer (line 14) | function SheetHorizontalScrollContainer({

FILE: src/app/dim-ui/ShowPageLoading.tsx
  function ShowPageLoading (line 8) | function ShowPageLoading({ message }: { message: string }) {

FILE: src/app/dim-ui/SpecialtyModSlotIcon.m.scss.d.ts
  type CssExports (line 3) | interface CssExports {

FILE: src/app/dim-ui/SpecialtyModSlotIcon.tsx
  function SpecialtyModSlotIcon (line 15) | function SpecialtyModSlotIcon({ item, className }: { item: DimItem; clas...

FILE: src/app/dim-ui/StaticPage.m.scss.d.ts
  type CssExports (line 3) | interface CssExports {

FILE: src/app/dim-ui/StaticPage.tsx
  function StaticPage (line 8) | function StaticPage({

FILE: src/app/dim-ui/Switch.m.scss.d.ts
  type CssExports (line 3) | interface CssExports {

FILE: src/app/dim-ui/Switch.tsx
  function Switch (line 5) | function Switch<K extends string>({

FILE: src/app/dim-ui/TileGrid.m.scss.d.ts
  type CssExports (line 3) | interface CssExports {

FILE: src/app/dim-ui/TileGrid.tsx
  function TileGrid (line 10) | function TileGrid({
  function TileGridTile (line 30) | function TileGridTile({

FILE: src/app/dim-ui/UserGuideLink.tsx
  function UserGuideLink (line 10) | function UserGuideLink({

FILE: src/app/dim-ui/VirtualList.m.scss.d.ts
  type CssExports (line 3) | interface CssExports {

FILE: src/app/dim-ui/VirtualList.tsx
  type VirtualListProps (line 6) | interface VirtualListProps {
  type VirtualListRef (line 23) | interface VirtualListRef {
  function VirtualList (line 32) | function VirtualList({
  function WindowVirtualList (line 98) | function WindowVirtualList({

FILE: src/app/dim-ui/WeaponGroupingIcon.m.scss.d.ts
  type CssExports (line 3) | interface CssExports {

FILE: src/app/dim-ui/WeaponGroupingIcon.tsx
  function WeaponGroupingIcon (line 8) | function WeaponGroupingIcon({

FILE: src/app/dim-ui/destiny-symbols/ColorDestinySymbols.m.scss.d.ts
  type CssExports (line 3) | interface CssExports {

FILE: src/app/dim-ui/destiny-symbols/ColorDestinySymbols.tsx
  function ColorDestinySymbols (line 16) | function ColorDestinySymbols({
  function replaceWithIcon (line 31) | function replaceWithIcon(textSegment: string, index: number) {

FILE: src/app/dim-ui/destiny-symbols/RichDestinyText.tsx
  function RichDestinyText (line 25) | function RichDestinyText({
  function replaceWithIcon (line 47) | function replaceWithIcon(
  function useDynamicStringReplacer (line 62) | function useDynamicStringReplacer(ownerId = '') {

FILE: src/app/dim-ui/destiny-symbols/SymbolsPicker.m.scss.d.ts
  type CssExports (line 3) | interface CssExports {

FILE: src/app/dim-ui/destiny-symbols/SymbolsPicker.tsx
  function WithSymbolsPicker (line 21) | function WithSymbolsPicker<T extends HTMLTextAreaElement | HTMLInputElem...
  function SymbolsPickerButton (line 99) | function SymbolsPickerButton<T extends HTMLTextAreaElement | HTMLInputEl...

FILE: src/app/dim-ui/destiny-symbols/destiny-symbols.ts
  type SymbolsMap (line 26) | type SymbolsMap = { glyph: string; name: string; fullName: string }[];

FILE: src/app/dim-ui/destiny-symbols/rich-destiny-text.ts
  type RichTextConversionTable (line 18) | type RichTextConversionTable = NodeJS.Dict<{

FILE: src/app/dim-ui/scroll.ts
  function scrollToPosition (line 7) | function scrollToPosition(options: ScrollToOptions) {

FILE: src/app/dim-ui/svgs/BucketIcon.tsx
  type BucketIconProps (line 8) | type BucketIconProps = React.SVGProps<SVGSVGElement> &
  function resolveIcon (line 22) | function resolveIcon(props: BucketIconProps) {
  function BucketIcon (line 45) | function BucketIcon(props: BucketIconProps) {

FILE: src/app/dim-ui/svgs/itemCategory.ts
  type ItemCategoryIcon (line 39) | interface ItemCategoryIcon {
  function monochrome (line 43) | function monochrome(svg: React.FC<React.SVGProps<SVGSVGElement>>): ItemC...
  function colorized (line 46) | function colorized(svg: React.FC<React.SVGProps<SVGSVGElement>>): ItemCa...
  function getWeaponTypeSvgIconFromCategoryHashes (line 121) | function getWeaponTypeSvgIconFromCategoryHashes(itemCategoryHashes: Item...
  function getWeaponTypeSvgIcon (line 133) | function getWeaponTypeSvgIcon(item: DimItem) {
  function getWeaponSlotSvgIcon (line 138) | function getWeaponSlotSvgIcon(item: DimItem) {
  function getArmorSlotSvgIcon (line 148) | function getArmorSlotSvgIcon(item: DimItem) {
  function getBucketSvgIcon (line 158) | function getBucketSvgIcon(bucketHash: BucketHashes) {

FILE: src/app/dim-ui/table-columns.ts
  type ColumnSort (line 3) | interface ColumnSort {
  type SortDirection (line 8) | const enum SortDirection {
  function useTableColumnSorts (line 13) | function useTableColumnSorts(defaultSorts: ColumnSort[]) {

FILE: src/app/dim-ui/text-complete/text-complete.m.scss.d.ts
  type CssExports (line 3) | interface CssExports {

FILE: src/app/dim-ui/text-complete/text-complete.ts
  function createTagsCompleter (line 12) | function createTagsCompleter(
  function createSymbolsAutocompleter (line 48) | function createSymbolsAutocompleter(symbols: SymbolsMap): StrategyProps {
  function useAutocomplete (line 78) | function useAutocomplete(

FILE: src/app/dim-ui/useBulkNote.m.scss.d.ts
  type CssExports (line 3) | interface CssExports {

FILE: src/app/dim-ui/useBulkNote.tsx
  type BulkNoteResult (line 21) | interface BulkNoteResult {
  function useBulkNote (line 31) | function useBulkNote(): [
  function BulkNoteDialog (line 67) | function BulkNoteDialog({
  function NotesEditor (line 164) | function NotesEditor({

FILE: src/app/dim-ui/useConfirm.tsx
  type ConfirmOpts (line 6) | interface ConfirmOpts {
  function useConfirm (line 15) | function useConfirm(): [
  function ConfirmDialog (line 39) | function ConfirmDialog({

FILE: src/app/dim-ui/useDialog.m.scss.d.ts
  type CssExports (line 3) | interface CssExports {

FILE: src/app/dim-ui/useDialog.tsx
  class DialogError (line 8) | class DialogError extends Error {
    method constructor (line 9) | constructor(reason: string) {
  type DialogRef (line 15) | interface DialogRef<Args, Result> {
  function Dialog (line 22) | function Dialog<Args = [], Result = void>({
  function useDialog (line 102) | function useDialog<Args = [], Result = void>(
  function Title (line 114) | function Title({ children }: { children: React.ReactNode }) {
  function Buttons (line 121) | function Buttons({ children }: { children: React.ReactNode }) {
  function Body (line 128) | function Body({ children, className }: { children: React.ReactNode; clas...

FILE: src/app/dim-ui/useFixOverscrollBehavior.ts
  function useFixOverscrollBehavior (line 19) | function useFixOverscrollBehavior(ref: React.RefObject<HTMLElement | nul...

FILE: src/app/dim-ui/usePopper.ts
  function usePopper (line 100) | function usePopper(

FILE: src/app/dim-ui/usePrompt.m.scss.d.ts
  type CssExports (line 3) | interface CssExports {

FILE: src/app/dim-ui/usePrompt.tsx
  type PromptOpts (line 7) | interface PromptOpts {
  function usePrompt (line 17) | function usePrompt(): [
  function PromptDialog (line 38) | function PromptDialog({

FILE: src/app/farming/Farming.m.scss.d.ts
  type CssExports (line 3) | interface CssExports {

FILE: src/app/farming/Farming.tsx
  function Farming (line 18) | function Farming() {

FILE: src/app/farming/actions.ts
  constant FARMING_OBSERVER_ID (line 31) | const FARMING_OBSERVER_ID = 'farming-observer';
  constant FARMING_REFRESH_RATE (line 48) | const FARMING_REFRESH_RATE = 30_000;
  function startFarming (line 56) | function startFarming(storeId: string): ThunkResult {
  function stopFarming (line 107) | function stopFarming(): ThunkResult {
  function makeRoomForItems (line 116) | function makeRoomForItems(store: DimStore, cancelToken: CancelToken): Th...
  function farmD1 (line 128) | function farmD1(store: D1Store, cancelToken: CancelToken): ThunkResult {
  function farmItems (line 137) | function farmItems(store: D1Store, cancelToken: CancelToken): ThunkResult {
  function makeRoomForD1Items (line 156) | function makeRoomForD1Items(store: D1Store, cancelToken: CancelToken): T...
  function makeRoomForItemsInBuckets (line 166) | function makeRoomForItemsInBuckets(
  function moveItemsToVault (line 209) | function moveItemsToVault(

FILE: src/app/farming/reducer.ts
  type FarmingState (line 5) | interface FarmingState {
  type FarmingAction (line 12) | type FarmingAction = ActionType<typeof actions>;

FILE: src/app/gear-power/GearPower.m.scss.d.ts
  type CssExports (line 3) | interface CssExports {

FILE: src/app/gear-power/GearPower.tsx
  function GearPower (line 33) | function GearPower() {

FILE: src/app/gear-power/gear-power.ts
  function showGearPower (line 11) | function showGearPower(selectedStoreId: string) {

FILE: src/app/google.ts
  type Window (line 5) | interface Window {
  function ga (line 12) | function ga(..._args: any[]) {
  function gaPageView (line 18) | function gaPageView(path: string, title?: string) {
  function gaEvent (line 26) | function gaEvent(type: string, params: Record<string, string>) {
  function initGoogleAnalytics (line 30) | function initGoogleAnalytics() {

FILE: src/app/hotkeys/GlobalHotkeys.tsx
  function GlobalHotkeys (line 8) | function GlobalHotkeys({ hotkeys: hotkeyDefs }: { hotkeys: Hotkey[] }) {

FILE: src/app/hotkeys/HotkeysCheatSheet.m.scss.d.ts
  type CssExports (line 3) | interface CssExports {

FILE: src/app/hotkeys/hotkeys.ts
  function symbolize (line 28) | function symbolize(combo: string) {
  type Hotkey (line 43) | interface Hotkey {
  function clearAllHotkeysForTest (line 56) | function clearAllHotkeysForTest() {
  function registerHotkeys (line 68) | function registerHotkeys(id: string, hotkeys: Hotkey[]) {
  function removeHotkeysById (line 81) | function removeHotkeysById(id: string, combo?: string) {
  function getAllHotkeys (line 92) | function getAllHotkeys() {
  function normalizeCombo (line 104) | function normalizeCombo(combo: string) {
  function bind (line 112) | function bind(id: string, hotkey: Hotkey) {
  function unbind (line 124) | function unbind(id: string, combo: string) {
  function handleKeyEvent (line 193) | function handleKeyEvent(e: KeyboardEvent) {
  function trigger (line 241) | function trigger(comboStr: string, e: KeyboardEvent) {

FILE: src/app/hotkeys/useHotkey.ts
  function useHotkey (line 17) | function useHotkey(
  function useHotkeys (line 49) | function useHotkeys(hotkeyDefs: Hotkey[]) {

FILE: src/app/i18n.ts
  constant DIM_LANG_INFOS (line 24) | const DIM_LANG_INFOS = {
  type DimLanguage (line 40) | type DimLanguage = keyof typeof DIM_LANG_INFOS;
  constant DIM_LANGS (line 42) | const DIM_LANGS = Object.keys(DIM_LANG_INFOS) as DimLanguage[];
  function browserLanguage (line 62) | function browserLanguage(): DimLanguage {
  function defaultLanguage (line 74) | function defaultLanguage(): DimLanguage {
  function initi18n (line 82) | function initi18n(): Promise<unknown> {
  function createLanguageObserver (line 150) | function createLanguageObserver(): StoreObserver<DimLanguage> {

FILE: src/app/i18next-t.ts
  type I18nKey (line 5) | type I18nKey = ParseKeys;
  function tl (line 22) | function tl<T extends I18nKey>(key: T): T {

FILE: src/app/infuse/InfusionFinder.m.scss.d.ts
  type CssExports (line 3) | interface CssExports {

FILE: src/app/infuse/InfusionFinder.tsx
  type State (line 39) | interface State {
  type Action (line 51) | type Action =
  function stateReducer (line 65) | function stateReducer(state: State, action: Action): State {
  function InfusionFinder (line 127) | function InfusionFinder() {
  function isInfusable (line 312) | function isInfusable(target: DimItem, source: DimItem) {
  function transferItems (line 328) | async function transferItems(

FILE: src/app/infuse/infuse.ts
  function showInfuse (line 9) | function showInfuse(item: DimItem) {

FILE: src/app/inventory-page/CategoryStrip.m.scss.d.ts
  type CssExports (line 3) | interface CssExports {

FILE: src/app/inventory-page/CategoryStrip.tsx
  function CategoryStrip (line 9) | function CategoryStrip({

FILE: src/app/inventory-page/D1Reputation.m.scss.d.ts
  type CssExports (line 3) | interface CssExports {

FILE: src/app/inventory-page/D1Reputation.tsx
  function D1Reputation (line 8) | function D1Reputation({ store }: { store: D1Store }) {

FILE: src/app/inventory-page/D1ReputationSection.tsx
  function D1ReputationSection (line 6) | function D1ReputationSection({ stores }: { stores: DimStore[] }) {

FILE: src/app/inventory-page/DesktopStores.m.scss.d.ts
  type CssExports (line 3) | interface CssExports {

FILE: src/app/inventory-page/DesktopStores.tsx
  type Props (line 24) | interface Props {
  function DesktopStores (line 34) | function DesktopStores({ stores, buckets, singleCharacter }: Props) {
  function categoryHasItems (line 125) | function categoryHasItems(
  type InventoryContainerProps (line 144) | interface InventoryContainerProps {
  function CollapsibleContainer (line 153) | function CollapsibleContainer({
  function StoresInventory (line 191) | function StoresInventory({

FILE: src/app/inventory-page/HeaderShadowDiv.m.scss.d.ts
  type CssExports (line 3) | interface CssExports {

FILE: src/app/inventory-page/Inventory.tsx
  function Inventory (line 11) | function Inventory({ account }: { account: DestinyAccount }) {

FILE: src/app/inventory-page/InventoryCollapsibleTitle.m.scss.d.ts
  type CssExports (line 3) | interface CssExports {

FILE: src/app/inventory-page/InventoryCollapsibleTitle.tsx
  function InventoryCollapsibleTitle (line 17) | function InventoryCollapsibleTitle({

FILE: src/app/inventory-page/PhoneStores.m.scss.d.ts
  type CssExports (line 3) | interface CssExports {

FILE: src/app/inventory-page/PhoneStores.tsx
  function PhoneStores (line 25) | function PhoneStores({
  function StoresInventory (line 141) | function StoresInventory({

FILE: src/app/inventory-page/PhoneStoresHeader.m.scss.d.ts
  type CssExports (line 3) | interface CssExports {

FILE: src/app/inventory-page/PhoneStoresHeader.tsx
  function PhoneStoresHeader (line 21) | function PhoneStoresHeader({

FILE: src/app/inventory-page/StoreBucket.m.scss.d.ts
  type CssExports (line 3) | interface CssExports {

FILE: src/app/inventory-page/StoreBucket.tsx
  function useStableArray (line 50) | function useStableArray<T>(arr: T[]) {
  function StoreBucket (line 256) | function StoreBucket({

FILE: src/app/inventory-page/StoreBucketDropTarget.m.scss.d.ts
  type CssExports (line 3) | interface CssExports {

FILE: src/app/inventory-page/StoreBucketDropTarget.tsx
  type Props (line 14) | interface Props {
  function StoreBucketDropTarget (line 24) | function StoreBucketDropTarget({

FILE: src/app/inventory-page/StoreBuckets.m.scss.d.ts
  type CssExports (line 3) | interface CssExports {

FILE: src/app/inventory-page/StoreBuckets.tsx
  function StoreBuckets (line 17) | function StoreBuckets({

FILE: src/app/inventory-page/Stores.tsx
  function Stores (line 11) | function Stores() {

FILE: src/app/inventory/ArtifactXP.m.scss.d.ts
  type CssExports (line 3) | interface CssExports {

FILE: src/app/inventory/ArtifactXP.tsx
  function ArtifactXP (line 11) | function ArtifactXP({

FILE: src/app/inventory/BadgeInfo.m.scss.d.ts
  type CssExports (line 3) | interface CssExports {

FILE: src/app/inventory/BadgeInfo.tsx
  type Props (line 15) | interface Props {
  function shouldShowBadge (line 21) | function shouldShowBadge(item: DimItem) {
  function BadgeInfo (line 37) | function BadgeInfo({ item, isCapped, wishlistRoll }: Props) {
  function ClassifiedNotes (line 115) | function ClassifiedNotes({ item }: { item: DimItem }) {

FILE: src/app/inventory/ConnectedInventoryItem.tsx
  function ConnectedInventoryItem (line 17) | function ConnectedInventoryItem({

FILE: src/app/inventory/DragPerformanceFix.m.scss.d.ts
  type CssExports (line 3) | interface CssExports {

FILE: src/app/inventory/DragPerformanceFix.tsx
  function DragPerformanceFix (line 15) | function DragPerformanceFix() {
  function showDragFixOverlay (line 21) | function showDragFixOverlay() {
  function hideDragFixOverlay (line 25) | function hideDragFixOverlay() {

FILE: src/app/inventory/DraggableInventoryItem.m.scss.d.ts
  type CssExports (line 3) | interface CssExports {

FILE: src/app/inventory/DraggableInventoryItem.tsx
  function DraggableInventoryItem (line 12) | function DraggableInventoryItem({

FILE: src/app/inventory/InventoryItem.m.scss.d.ts
  type CssExports (line 3) | interface CssExports {

FILE: src/app/inventory/InventoryItem.tsx
  function InventoryItem (line 31) | function InventoryItem({
  function StatFocus (line 175) | function StatFocus({ statHash }: { statHash: number }) {
  function WeaponFrame (line 190) | function WeaponFrame({ item }: { item: DimItem }) {

FILE: src/app/inventory/ItemDragPreview.tsx
  function ItemDragPreview (line 11) | function ItemDragPreview() {

FILE: src/app/inventory/ItemIcon.m.scss.d.ts
  type CssExports (line 3) | interface CssExports {

FILE: src/app/inventory/ItemIcon.tsx
  function getItemImageStyles (line 43) | function getItemImageStyles(item: DimItem, className?: string) {
  function ItemIcon (line 73) | function ItemIcon({ item, className }: { item: DimItem; className?: stri...
  function DefItemIcon (line 229) | function DefItemIcon({
  function getModCostInfo (line 372) | function getModCostInfo(mod: DestinyInventoryItemDefinition) {

FILE: src/app/inventory/ItemIconPlaceholder.m.scss.d.ts
  type CssExports (line 3) | interface CssExports {

FILE: src/app/inventory/ItemIconPlaceholder.tsx
  function ItemIconPlaceholder (line 47) | function ItemIconPlaceholder({

FILE: src/app/inventory/ItemPopupTrigger.tsx
  function ItemPopupTrigger (line 18) | function ItemPopupTrigger({
  function itemPopupTriggerClicked (line 57) | function itemPopupTriggerClicked(

FILE: src/app/inventory/ItemPowerSet.m.scss.d.ts
  type CssExports (line 3) | interface CssExports {

FILE: src/app/inventory/ItemPowerSet.tsx
  function ItemPowerSet (line 7) | function ItemPowerSet({ items, powerFloor }: { items: DimItem[]; powerFl...

FILE: src/app/inventory/MoveNotifications.m.scss.d.ts
  type CssExports (line 3) | interface CssExports {

FILE: src/app/inventory/MoveNotifications.tsx
  function moveItemNotification (line 35) | function moveItemNotification(
  function loadoutNotification (line 59) | function loadoutNotification(
  function ApplyLoadoutProgressBody (line 93) | function ApplyLoadoutProgressBody({
  function postmasterNotification (line 243) | function postmasterNotification(
  type MoveState (line 265) | const enum MoveState {
  function MoveItemNotificationIcon (line 276) | function MoveItemNotificationIcon({ completion }: { completion: Promise<...

FILE: src/app/inventory/NewItemIndicator.m.scss.d.ts
  type CssExports (line 3) | interface CssExports {

FILE: src/app/inventory/NewItemIndicator.tsx
  function NewItemIndicator (line 4) | function NewItemIndicator({ className }: { className?: string }) {

FILE: src/app/inventory/PullFromPostmaster.m.scss.d.ts
  type CssExports (line 3) | interface CssExports {

FILE: src/app/inventory/PullFromPostmaster.tsx
  function PullFromPostmaster (line 14) | function PullFromPostmaster({ store }: { store: DimStore }) {

FILE: src/app/inventory/RatingIcon.m.scss.d.ts
  type CssExports (line 3) | interface CssExports {

FILE: src/app/inventory/RatingIcon.tsx
  function RatingIcon (line 6) | function RatingIcon({ uiWishListRoll }: { uiWishListRoll: UiWishListRoll...

FILE: src/app/inventory/SyncTagLock.tsx
  function canSyncLockState (line 12) | function canSyncLockState(item: DimItem) {
  function getNextItemToChangeLockState (line 25) | function getNextItemToChangeLockState(

FILE: src/app/inventory/TagIcon.tsx
  function TagIcon (line 13) | function TagIcon({ className, tag }: { className?: string; tag: TagValue...

FILE: src/app/inventory/actions.ts
  type CharacterInfo (line 43) | interface CharacterInfo {
  function loadNewItems (line 107) | function loadNewItems(account: DestinyAccount): ThunkResult {
  function setTag (line 164) | function setTag(item: DimItem, tag: TagCommand | undefined): ThunkResult {
  function setNote (line 191) | function setNote(item: DimItem, note: string | undefined): ThunkResult {
  function appendNote (line 218) | function appendNote(item: DimItem, note: string | undefined): ThunkResult {
  function removeFromNote (line 232) | function removeFromNote(item: DimItem, note: string | undefined): ThunkR...
  function warnNoSync (line 246) | function warnNoSync(): ThunkResult {

FILE: src/app/inventory/advanced-write-actions.ts
  function canInsertPlug (line 41) | function canInsertPlug(
  function hasInsertionCost (line 50) | function hasInsertionCost(defs: D2ManifestDefinitions, plug: DestinyInve...
  function canInsertForFree (line 61) | function canInsertForFree(
  function checkIrreversiblePlugging (line 105) | function checkIrreversiblePlugging(
  function insertPlug (line 138) | function insertPlug(item: DimItem, socket: DimSocket, plugItemHash: numb...
  function awaInsertSocketPlugFree (line 188) | async function awaInsertSocketPlugFree(
  function awaInsertSocketPlug (line 211) | async function awaInsertSocketPlug(
  function refreshItemAfterAWA (line 243) | function refreshItemAfterAWA(changes: DestinyItemChangeResponse): ThunkR...
  function getAwaToken (line 267) | async function getAwaToken(
  function tokenValid (line 321) | function tokenValid(info: AwaAuthorizationResult & { used: number }) {

FILE: src/app/inventory/bulk-actions.tsx
  function bulkTagItems (line 19) | function bulkTagItems(
  function bulkLockItems (line 111) | function bulkLockItems(items: DimItem[], locked: boolean): ThunkResult {

FILE: src/app/inventory/cross-tab.ts
  type StoreUpdatedMessage (line 8) | interface StoreUpdatedMessage {
  type ItemMovedMessage (line 12) | interface ItemMovedMessage {
  type CrossTabMessage (line 25) | type CrossTabMessage = StoreUpdatedMessage | ItemMovedMessage;
  function useCrossTabUpdates (line 27) | function useCrossTabUpdates(callback: (m: CrossTabMessage) => void) {
  function notifyOtherTabsStoreUpdated (line 44) | function notifyOtherTabsStoreUpdated() {
  function notifyOtherTabsItemMoved (line 51) | function notifyOtherTabsItemMoved(args: Omit<ItemMovedMessage, 'type'>) {

FILE: src/app/inventory/d1-stores.ts
  function loadStores (line 33) | function loadStores(): ThunkResult<D1Store[] | undefined> {
  function processCurrencies (line 103) | function processCurrencies(profileInventory: D1Inventory, defs: D1Manife...
  function processCharacter (line 127) | function processCharacter(
  function processVault (line 153) | function processVault(
  function findLastPlayedDate (line 177) | function findLastPlayedDate(characterData: D1CharacterData[]): Date {

FILE: src/app/inventory/d2-stores.ts
  constant TAG (line 46) | const TAG = 'd2-stores';
  function updateCharacters (line 57) | function updateCharacters(): ThunkResult {
  function loadStores (line 115) | function loadStores({
  constant FRESH_ENOUGH_TO_CLEAN_INFOS (line 194) | const FRESH_ENOUGH_TO_CLEAN_INFOS = 90_000;
  function loadProfile (line 196) | function loadProfile(
  function loadStoresData (line 326) | function loadStoresData(
  function processCurrencies (line 503) | function processCurrencies(profileInfo: DestinyProfileResponse, defs: D2...

FILE: src/app/inventory/dim-item-info.ts
  type TagValue (line 53) | type TagValue = keyof typeof tagConfig;
  type TagCommand (line 54) | type TagCommand = TagValue | 'clear';
  type ItemInfos (line 104) | interface ItemInfos {
  type TagInfo (line 108) | interface TagInfo {
  function cleanInfos (line 130) | function cleanInfos(stores: DimStore[]): ThunkResult {
  function getTag (line 206) | function getTag(
  function getNotes (line 218) | function getNotes(

FILE: src/app/inventory/inventory-buckets.ts
  type D2BucketCategory (line 4) | type D2BucketCategory = 'Postmaster' | 'Weapons' | 'Armor' | 'General' |...
  type D1BucketCategory (line 5) | type D1BucketCategory = 'Postmaster' | 'Weapons' | 'Armor' | 'General' |...
  type BucketSortType (line 6) | type BucketSortType = D2BucketCategory | D1BucketCategory | 'Unknown';
  type InventoryBucket (line 8) | type InventoryBucket = {
  type InventoryBuckets (line 27) | interface InventoryBuckets {

FILE: src/app/inventory/item-move-service.ts
  constant TAG (line 61) | const TAG = 'move';
  type MoveSession (line 68) | interface MoveSession {
  function createMoveSession (line 82) | function createMoveSession(
  type MoveReservations (line 101) | interface MoveReservations {
  type Exclusion (line 110) | interface Exclusion {
  function setItemLockState (line 118) | function setItemLockState(
  function equipApi (line 143) | function equipApi(item: DimItem): typeof d2equip {
  function equipItemsApi (line 147) | function equipItemsApi(item: DimItem): typeof d2EquipItems {
  function transferApi (line 151) | function transferApi(item: DimItem): typeof d2Transfer {
  function updateItemModel (line 159) | function updateItemModel(
  function getItemAcrossStores (line 194) | function getItemAcrossStores<Item extends DimItem, Store extends DimStor...
  function getSimilarItem (line 216) | function getSimilarItem(
  function equipItems (line 261) | function equipItems(
  function equipItem (line 348) | function equipItem(item: DimItem, cancelToken: CancelToken): ThunkResult...
  function dequipItem (line 366) | function dequipItem(
  function moveToVault (line 389) | function moveToVault(item: DimItem, amount: number, session: MoveSession...
  function moveToStore (line 394) | function moveToStore(
  function canEquipExotic (line 494) | function canEquipExotic(
  function getOtherExoticThatNeedsDequipping (line 525) | function getOtherExoticThatNeedsDequipping(item: DimItem, store: DimStor...
  type MoveContext (line 537) | interface MoveContext {
  function chooseMoveAsideItem (line 561) | function chooseMoveAsideItem(
  function ensureCanMoveToStore (line 752) | function ensureCanMoveToStore(
  function canEquip (line 909) | function canEquip(item: DimItem, store: DimStore): void {
  function ensureValidTransfer (line 935) | function ensureValidTransfer(
  function executeMoveItem (line 970) | function executeMoveItem(
  function sortMoveAsideCandidatesForStore (line 1113) | function sortMoveAsideCandidatesForStore(
  function searchForSimilarItem (line 1195) | function searchForSimilarItem(

FILE: src/app/inventory/item-types.ts
  type DimItem (line 37) | interface DimItem {
  type D1Item (line 268) | interface D1Item extends DimItem {
  type DimMasterwork (line 284) | interface DimMasterwork {
  type DimCrafted (line 299) | interface DimCrafted {
  type DimCatalyst (line 310) | interface DimCatalyst {
  type DimStat (line 319) | interface DimStat {
  type D1Stat (line 353) | interface D1Stat extends DimStat {
  type D1TalentGrid (line 367) | interface D1TalentGrid {
  type D1GridNode (line 386) | interface D1GridNode {
  type PluggableInventoryItemDefinition (line 420) | interface PluggableInventoryItemDefinition extends DestinyInventoryItemD...
  type PlugStatActivationRule (line 425) | type PlugStatActivationRule =
  type DimPlugInvestmentStat (line 465) | interface DimPlugInvestmentStat extends Omit<
  type DimPlug (line 476) | interface DimPlug {
  type DimPlugSet (line 498) | interface DimPlugSet {
  type DimSocket (line 541) | interface DimSocket {
  type DimSocketCategory (line 602) | interface DimSocketCategory {
  type DimSockets (line 609) | interface DimSockets {
  type DimPursuitExpiration (line 624) | interface DimPursuitExpiration {
  type DimQuestLine (line 635) | interface DimQuestLine {
  type DimPursuit (line 641) | interface DimPursuit {

FILE: src/app/inventory/locate-item.ts
  function locateItem (line 9) | function locateItem(item: DimItem) {

FILE: src/app/inventory/manual-moves.ts
  function updateManualMoveTimestamp (line 11) | function updateManualMoveTimestamp(item: DimItem) {
  function getLastManuallyMoved (line 15) | function getLastManuallyMoved(item: DimItem) {

FILE: src/app/inventory/move-item.ts
  constant TAG (line 29) | const TAG = 'move';
  function moveItemToCurrentStore (line 34) | function moveItemToCurrentStore(item: DimItem, e?: React.MouseEvent): Th...
  function pullItem (line 50) | function pullItem(
  function dropItem (line 75) | function dropItem(item: DimItem, storeId: string, equip = false): ThunkR...
  function moveItemTo (line 86) | function moveItemTo(
  function consolidate (line 186) | function consolidate(actionableItem: DimItem, store: DimStore): ThunkRes...
  type Move (line 240) | interface Move {
  function distribute (line 249) | function distribute(actionableItem: DimItem): ThunkResult {

FILE: src/app/inventory/note-hashtags.ts
  class HashTagTracker (line 9) | class HashTagTracker {
    method addHashtag (line 21) | addHashtag(hashtag: string) {
    method canonicalForm (line 32) | canonicalForm(hashtag: string): string {
    method allHashtags (line 41) | allHashtags(): string[] {
  function extractMostPopular (line 49) | function extractMostPopular(normalizedMeta: {
  function collectHashtagsFromInfos (line 63) | function collectHashtagsFromInfos(itemInfos: ItemInfos) {
  function getHashtagsFromString (line 78) | function getHashtagsFromString(...notes: (string | null | undefined)[]) {
  function appendedToNote (line 87) | function appendedToNote(originalNote: string | undefined, append: string) {
  function removedFromNote (line 111) | function removedFromNote(originalNote: string | undefined, removed: stri...
  function segmentHashtags (line 141) | function segmentHashtags(

FILE: src/app/inventory/observers.ts
  type SaveInfosObservedState (line 8) | interface SaveInfosObservedState {
  function createSaveItemInfosObserver (line 16) | function createSaveItemInfosObserver(): StoreObserver<SaveInfosObservedS...

FILE: src/app/inventory/reducer.ts
  constant TAG (line 22) | const TAG = 'move';
  type InventoryState (line 25) | interface InventoryState {
  type InventoryAction (line 55) | type InventoryAction = ActionType<typeof actions>;
  function updateInventory (line 184) | function updateInventory(
  function updateCharacters (line 207) | function updateCharacters(state: InventoryState, characters: actions.Cha...
  function computeNewItems (line 236) | function computeNewItems(oldStores: DimStore[], oldNewItems: Set<string>...
  function setsEqual (line 288) | function setsEqual<T>(first: Set<T>, second: Set<T>) {
  function itemMoved (line 314) | function itemMoved(
  function itemLockStateChanged (line 429) | function itemLockStateChanged(
  function awaItemChanged (line 459) | function awaItemChanged(
  function removeItem (line 590) | function removeItem(store: Draft<DimStore>, item: Draft<DimItem>) {
  function addItem (line 601) | function addItem(store: Draft<DimStore>, item: Draft<DimItem>) {

FILE: src/app/inventory/rewards.ts
  function useRewardMultiplier (line 20) | function useRewardMultiplier(

FILE: src/app/inventory/selectors.ts
  constant STORE_SPECIFIC_OWNERSHIP_BUCKETS (line 222) | const STORE_SPECIFIC_OWNERSHIP_BUCKETS = [
  type OwnedItemsInfo (line 239) | interface OwnedItemsInfo {
  function gatherUnlockedPlugSetItems (line 328) | function gatherUnlockedPlugSetItems(
  function getArtifactUnlocks (line 400) | function getArtifactUnlocks(

FILE: src/app/inventory/spreadsheets.ts
  function getClass (line 27) | function getClass(type: DestinyClass) {
  constant D1_FILTERED_NODE_HASHES (line 42) | const D1_FILTERED_NODE_HASHES = [
  function generateCSVExportData (line 98) | function generateCSVExportData(
  function downloadCsvFiles (line 235) | function downloadCsvFiles(type: 'weapon' | 'armor' | 'ghost'): ThunkResu...
  type CSVRow (line 263) | interface CSVRow {
  function importTagsNotesFromCsv (line 271) | function importTagsNotesFromCsv(files: File[]): ThunkResult<number | und...
  function buildSocketNames (line 340) | function buildSocketNames(item: DimItem): string[] {
  function buildNodeNames (line 374) | function buildNodeNames(nodes: D1GridNode[]): string[] {

FILE: src/app/inventory/store-types.ts
  type DimStore (line 21) | interface DimStore<Item = DimItem> {
  type DimTitle (line 80) | interface DimTitle {
  type AccountCurrency (line 88) | interface AccountCurrency {
  type DimCharacterStatSource (line 94) | type DimCharacterStatSource = 'armorStats' | 'armorPlug' | 'subclassPlug...
  type DimCharacterStatChange (line 101) | interface DimCharacterStatChange {
  type DimCharacterStat (line 117) | interface DimCharacterStat {
  type D1Progression (line 129) | interface D1Progression extends D1LevelProgression {
  type D1Store (line 150) | interface D1Store extends DimStore<D1Item> {

FILE: src/app/inventory/store/armor-quality.ts
  function getQualityRating (line 16) | function getQualityRating(
  function getQualityRange (line 135) | function getQualityRange(light: number, quality: { min: number; max: num...
  function fitValue (line 149) | function fitValue(light: number) {
  function getScaledStat (line 159) | function getScaledStat(base: number, light: number) {

FILE: src/app/inventory/store/catalyst.ts
  function buildCatalystInfo (line 10) | function buildCatalystInfo(

FILE: src/app/inventory/store/character-utils.ts
  function getBonus (line 14) | function getBonus(light: number, bucketHash: ArmorTypes): number {
  function getCharacterStatsData (line 73) | function getCharacterStatsData(
  function characterStatFromStatDef (line 89) | function characterStatFromStatDef(

FILE: src/app/inventory/store/crafted.ts
  function buildCraftedInfo (line 22) | function buildCraftedInfo(
  function getCraftedSocket (line 44) | function getCraftedSocket(item: DimItem): DimSocket | undefined {
  function getEnhancementTier (line 50) | function getEnhancementTier(item: DimItem): number {
  function getCraftingInfo (line 60) | function getCraftingInfo(

FILE: src/app/inventory/store/d1-item-factory.ts
  constant TAG (line 46) | const TAG = 'd1-stores';
  function processItems (line 54) | function processItems(
  function makeFakeItem (line 133) | function makeFakeItem(
  function makeItem (line 186) | function makeItem(
  function getAmmoType (line 505) | function getAmmoType(bucketHash: BucketHashes) {
  function buildTalentGrid (line 518) | function buildTalentGrid(
  function buildStats (line 689) | function buildStats(

FILE: src/app/inventory/store/d1-store-factory.ts
  function makeCharacter (line 27) | function makeCharacter(
  function makeVault (line 102) | function makeVault() {

FILE: src/app/inventory/store/d2-item-factory.ts
  constant TAG (line 66) | const TAG = 'd2-stores';
  function processItems (line 76) | function processItems(
  function makeFakeItem (line 147) | function makeFakeItem(
  function makeItemSingle (line 196) | function makeItemSingle(
  type ItemCreationContext (line 238) | interface ItemCreationContext {
  function makeItem (line 253) | function makeItem(
  function isLegendaryOrBetter (line 790) | function isLegendaryOrBetter(item: DimItem) {
  function getQuestLineInfo (line 794) | function getQuestLineInfo(
  function getExpirationInfo (line 809) | function getExpirationInfo(
  function buildPursuitInfo (line 824) | function buildPursuitInfo(
  function getItemCategoryHashes (line 848) | function getItemCategoryHashes(itemDef: DestinyInventoryItemDefinition):...

FILE: src/app/inventory/store/d2-store-factory.ts
  function buildStores (line 23) | function buildStores(itemCreationContext: ItemCreationContext): DimStore...
  function processCharacter (line 64) | function processCharacter(
  function processVault (line 95) | function processVault(itemCreationContext: ItemCreationContext): DimStore {
  function findLastPlayedDate (line 119) | function findLastPlayedDate(profileInfo: DestinyProfileResponse) {
  function makeCharacter (line 138) | function makeCharacter(
  function makeVault (line 186) | function makeVault(): DimStore {
  function getCharacterStatsData (line 216) | function getCharacterStatsData(
  function getTitleInfo (line 242) | function getTitleInfo(

FILE: src/app/inventory/store/deepsight.ts
  function buildDeepsightInfo (line 6) | function buildDeepsightInfo(item: DimItem): boolean {
  function getResonanceSocket (line 11) | function getResonanceSocket(item: DimItem): DimSocket | undefined {
  function isDeepsightResonanceSocket (line 17) | function isDeepsightResonanceSocket(socket: DimSocket): boolean {
  function isHarmonizable (line 23) | function isHarmonizable(item: DimItem): boolean | undefined {

FILE: src/app/inventory/store/energy.ts
  function getEnergyUpgradePlugs (line 18) | function getEnergyUpgradePlugs(item: DimItem) {
  function getEnergyUpgradeHashes (line 53) | function getEnergyUpgradeHashes(item: DimItem, newEnergyCapacity: number) {
  function sumModCosts (line 64) | function sumModCosts(

FILE: src/app/inventory/store/hooks.ts
  function useLoadStores (line 21) | function useLoadStores(account: DestinyAccount | undefined) {
  function useCurrentSetBonus (line 73) | function useCurrentSetBonus(storeId: string) {

FILE: src/app/inventory/store/item-index.ts
  function resetItemIndexGenerator (line 5) | function resetItemIndexGenerator() {
  function createItemIndex (line 10) | function createItemIndex(item: DimItem): string {

FILE: src/app/inventory/store/masterwork.ts
  function buildMasterwork (line 29) | function buildMasterwork(
  function buildMasterworkInfo (line 43) | function buildMasterworkInfo(
  function isValidMasterworkStat (line 116) | function isValidMasterworkStat(

FILE: src/app/inventory/store/objectives.ts
  function buildObjectives (line 22) | function buildObjectives(
  function getValueStyle (line 48) | function getValueStyle(
  function isObjectiveWithPlaceholderGoal (line 69) | function isObjectiveWithPlaceholderGoal(
  function isBooleanObjective (line 81) | function isBooleanObjective(
  function isTrialsPassage (line 103) | function isTrialsPassage(itemHash: number) {
  function isFlawlessPassage (line 110) | function isFlawlessPassage(objectives: DestinyObjectiveProgress[] | unde...
  function isFlawlessObjective (line 116) | function isFlawlessObjective(objectiveHash: number) {
  function isWinsObjective (line 120) | function isWinsObjective(objectiveHash: number) {
  function isRoundsWonObjective (line 124) | function isRoundsWonObjective(objectiveHash: number) {

FILE: src/app/inventory/store/override-sockets.ts
  type SocketOverrides (line 17) | interface SocketOverrides {
  function applySocketOverrides (line 24) | function applySocketOverrides(
  function useSocketOverrides (line 119) | function useSocketOverrides(): [
  type SocketOverridesForItems (line 143) | interface SocketOverridesForItems {
  type PlugClickedHandler (line 147) | type PlugClickedHandler = (value: {
  function useSocketOverridesForItems (line 156) | function useSocketOverridesForItems(

FILE: src/app/inventory/store/patterns.ts
  function buildPatternInfo (line 30) | function buildPatternInfo(

FILE: src/app/inventory/store/season.ts
  function getSeason (line 22) | function getSeason(
  function getSeasonFromOverlayAndSource (line 63) | function getSeasonFromOverlayAndSource(
  function getEvent (line 80) | function getEvent(item: DimItem): D2EventEnum | undefined {

FILE: src/app/inventory/store/selectors.ts
  function hasAffectingClassified (line 19) | function hasAffectingClassified(
  function getBucketsWithClassifiedItems (line 33) | function getBucketsWithClassifiedItems(allItems: DimItem[]) {
  type StorePowerLevel (line 43) | interface StorePowerLevel {

FILE: src/app/inventory/store/sockets.ts
  function buildSockets (line 62) | function buildSockets(
  function buildInstancedSockets (line 117) | function buildInstancedSockets(
  function buildDefinedSockets (line 173) | function buildDefinedSockets(
  function filterReusablePlug (line 221) | function filterReusablePlug(reusablePlug: DimPlug) {
  function isUncraftableEnhancedPerk (line 236) | function isUncraftableEnhancedPerk(
  function buildDefinedSocket (line 250) | function buildDefinedSocket(
  function isPluggableItem (line 449) | function isPluggableItem(
  function hashesToPluggableItems (line 458) | function hashesToPluggableItems(
  function isDestinyItemPlug (line 465) | function isDestinyItemPlug(
  function buildPlug (line 471) | function buildPlug(
  function buildDefinedPlug (line 515) | function buildDefinedPlug(
  function isKnownEmptyPlugItemHash (line 535) | function isKnownEmptyPlugItemHash(plugItemHash: number) {
  function findEmptyPlug (line 584) | function findEmptyPlug(
  function buildSocket (line 645) | function buildSocket(
  function buildCachedDimPlugSet (line 792) | function buildCachedDimPlugSet(defs: D2ManifestDefinitions, plugSetHash:...
  function plugCannotCurrentlyRoll (line 835) | function plugCannotCurrentlyRoll(plugs: DimPlug[], plugHash: number) {

FILE: src/app/inventory/store/stats-conditional.ts
  function getPlugInvestmentStatActivationRule (line 22) | function getPlugInvestmentStatActivationRule(
  function isPlugStatActive (line 121) | function isPlugStatActive(
  function getPlugInvestmentStats (line 196) | function getPlugInvestmentStats(

FILE: src/app/inventory/store/stats-custom.ts
  function makeCustomStat (line 17) | function makeCustomStat(

FILE: src/app/inventory/store/stats.ts
  function getStatSortOrder (line 78) | function getStatSortOrder(statHash: number) {
  function isAllowedItemStat (line 83) | function isAllowedItemStat(statHash: number) {
  function isAllowedPlugStat (line 92) | function isAllowedPlugStat(statHash: number) {
  type StatDisplayLookup (line 108) | interface StatDisplayLookup {
  type StatLookup (line 113) | interface StatLookup {
  function buildStats (line 126) | function buildStats(
  function shouldShowStat (line 189) | function shouldShowStat(
  function buildInvestmentStats (line 216) | function buildInvestmentStats(
  function buildStat (line 265) | function buildStat(
  function applyPlugsToStats (line 311) | function applyPlugsToStats(
  function generateAssumedMasterworkStats (line 392) | function generateAssumedMasterworkStats(
  function getPlugStatValue (line 414) | function getPlugStatValue(createdItem: DimItem, stat: DimPlugInvestmentS...
  function attachPlugStats (line 440) | function attachPlugStats(
  function interpolateStatValue (line 568) | function interpolateStatValue(value: number, statDisplay: DestinyStatDis...
  function bankersRound (line 608) | function bankersRound(x: number) {
  function keyByStatHash (line 615) | function keyByStatHash(stats: (DimStat | DestinyStatDisplayDefinition)[]...

FILE: src/app/inventory/store/well-rested.ts
  function useIsWellRested (line 11) | function useIsWellRested(

FILE: src/app/inventory/stores-helpers.ts
  function getArtifactBonus (line 55) | function getArtifactBonus(_store: DimStore) {
  function amountOfItem (line 65) | function amountOfItem(store: DimStore, item: { hash: number }) {
  function capacityForItem (line 75) | function capacityForItem(store: DimStore, item: DimItem) {
  function spaceLeftForItem (line 88) | function spaceLeftForItem(store: DimStore, item: DimItem, stores: DimSto...
  type SpaceLeft (line 92) | interface SpaceLeft {
  function potentialSpaceLeftForItem (line 104) | function potentialSpaceLeftForItem(
  function isD1Store (line 184) | function isD1Store(store: DimStore): store is D1Store {

FILE: src/app/inventory/subclass.ts
  type SubclassIconInfo (line 25) | interface SubclassIconInfo {
  function getSubclassIconInfo (line 29) | function getSubclassIconInfo(item: DimItem): SubclassIconInfo | undefined {
  function getDamageTypeForSubclassPlug (line 49) | function getDamageTypeForSubclassPlug(

FILE: src/app/issue-awareness-banner/Game2Give.m.scss.d.ts
  type CssExports (line 3) | interface CssExports {

FILE: src/app/issue-awareness-banner/Game2Give.tsx
  function Game2Give (line 9) | function Game2Give() {

FILE: src/app/issue-awareness-banner/IssueAwarenessBanner.tsx
  function IssueAwarenessBanner (line 9) | function IssueAwarenessBanner() {

FILE: src/app/issue-awareness-banner/useGame2GiveData.tsx
  type Game2GiveJSONResponse (line 5) | interface Game2GiveJSONResponse {
  function useGame2GiveData (line 13) | function useGame2GiveData() {

FILE: src/app/item-actions/ActionButton.m.scss.d.ts
  type CssExports (line 3) | interface CssExports {

FILE: src/app/item-actions/ActionButton.tsx
  function ActionButton (line 5) | function ActionButton({

FILE: src/app/item-actions/ActionButtons.m.scss.d.ts
  type CssExports (line 3) | interface CssExports {

FILE: src/app/item-actions/ActionButtons.tsx
  type ActionButtonProps (line 25) | interface ActionButtonProps {
  function CompareActionButton (line 30) | function CompareActionButton({ item, label }: ActionButtonProps) {
  function LockActionButton (line 50) | function LockActionButton({
  function TagActionButton (line 84) | function TagActionButton({
  function ConsolidateActionButton (line 105) | function ConsolidateActionButton({
  function DistributeActionButton (line 133) | function DistributeActionButton({
  function InfuseActionButton (line 157) | function InfuseActionButton({
  function LoadoutActionButton (line 179) | function LoadoutActionButton({

FILE: src/app/item-actions/ItemAccessoryButtons.tsx
  function ItemAccessoryButtons (line 19) | function ItemAccessoryButtons({

FILE: src/app/item-actions/ItemActionsDropdown.m.scss.d.ts
  type CssExports (line 3) | interface CssExports {

FILE: src/app/item-actions/ItemMoveLocations.m.scss.d.ts
  type CssExports (line 3) | interface CssExports {

FILE: src/app/item-actions/ItemMoveLocations.tsx
  type MoveSubmit (line 21) | type MoveSubmit = (store: DimStore, equip?: boolean, moveAmount?: number...
  function ItemMoveLocations (line 23) | function ItemMoveLocations({
  function VaultButton (line 104) | function VaultButton({ store, handleMove }: { store: DimStore; handleMov...
  function VaultActionButton (line 112) | function VaultActionButton({ vault, onClick }: { vault: DimStore; onClic...
  function MoveLocations (line 120) | function MoveLocations({
  function PullButtons (line 181) | function PullButtons({

FILE: src/app/item-actions/LockButton.m.scss.d.ts
  type CssExports (line 3) | interface CssExports {

FILE: src/app/item-actions/LockButton.tsx
  function LockButton (line 14) | function LockButton({
  function lockButtonTitle (line 90) | function lockButtonTitle(item: DimItem, type: 'lock' | 'track') {

FILE: src/app/item-feed/Highlights.m.scss.d.ts
  type CssExports (line 3) | interface CssExports {

FILE: src/app/item-feed/Highlights.tsx
  function Highlights (line 25) | function Highlights({ item }: { item: DimItem }) {

FILE: src/app/item-feed/ItemFeed.m.scss.d.ts
  type CssExports (line 3) | interface CssExports {

FILE: src/app/item-feed/ItemFeed.tsx
  function ItemFeed (line 70) | function ItemFeed({ page }: { page?: boolean }) {

FILE: src/app/item-feed/ItemFeedPage.m.scss.d.ts
  type CssExports (line 3) | interface CssExports {

FILE: src/app/item-feed/ItemFeedPage.tsx
  function ItemFeedPage (line 14) | function ItemFeedPage({ account }: { account: DestinyAccount }) {

FILE: src/app/item-feed/ItemFeedSidebar.m.scss.d.ts
  type CssExports (line 3) | interface CssExports {

FILE: src/app/item-feed/ItemFeedSidebar.tsx
  function ItemFeedSidebar (line 14) | function ItemFeedSidebar() {

FILE: src/app/item-feed/TagButtons.m.scss.d.ts
  type CssExports (line 3) | interface CssExports {

FILE: src/app/item-feed/TagButtons.tsx
  function TagButtons (line 14) | function TagButtons({ item, tag }: { item: DimItem; tag: TagValue | unde...

FILE: src/app/item-picker/ItemPicker.m.scss.d.ts
  type CssExports (line 3) | interface CssExports {

FILE: src/app/item-picker/ItemPicker.tsx
  function ItemPicker (line 21) | function ItemPicker({
  function ItemPickerItem (line 103) | function ItemPickerItem({

FILE: src/app/item-picker/ItemPickerContainer.tsx
  function ItemPickerContainer (line 15) | function ItemPickerContainer({ children }: { children: React.ReactNode }) {

FILE: src/app/item-picker/item-picker.ts
  type ItemPickerOptions (line 5) | interface ItemPickerOptions {
  type ItemPickerState (line 15) | type ItemPickerState = ItemPickerOptions & {
  type ShowItemPickerFn (line 24) | type ShowItemPickerFn = (options: ItemPickerOptions) => Promise<DimItem ...
  function useItemPicker (line 31) | function useItemPicker(): ShowItemPickerFn {
  function useHideItemPicker (line 45) | function useHideItemPicker() {

FILE: src/app/item-popup/AmmoIcon.m.scss.d.ts
  type CssExports (line 3) | interface CssExports {

FILE: src/app/item-popup/AmmoIcon.tsx
  function AmmoIcon (line 15) | function AmmoIcon({ type, className }: { type: DestinyAmmunitionType; cl...

FILE: src/app/item-popup/ApplyPerkSelection.m.scss.d.ts
  type CssExports (line 3) | interface CssExports {

FILE: src/app/item-popup/ApplyPerkSelection.tsx
  function ApplyPerkSelection (line 14) | function ApplyPerkSelection({

FILE: src/app/item-popup/ArchetypeSocket.m.scss.d.ts
  type CssExports (line 3) | interface CssExports {

FILE: src/app/item-popup/ArchetypeSocket.tsx
  function ArchetypeSocket (line 11) | function ArchetypeSocket({
  function ArchetypeRow (line 46) | function ArchetypeRow({

FILE: src/app/item-popup/BreakerType.m.scss.d.ts
  type CssExports (line 3) | interface CssExports {

FILE: src/app/item-popup/BreakerType.tsx
  function BreakerType (line 9) | function BreakerType({ item }: { item: DimItem }) {

FILE: src/app/item-popup/DeepSightHarmonizerIcon.m.scss.d.ts
  type CssExports (line 3) | interface CssExports {

FILE: src/app/item-popup/DeepsightHarmonizerIcon.tsx
  function DeepsightHarmonizerIcon (line 9) | function DeepsightHarmonizerIcon({ item }: { item: DimItem }) {
  function HarmonizerIcon (line 20) | function HarmonizerIcon() {
  function HarmonizableTooltipContent (line 26) | function HarmonizableTooltipContent({ item }: { item: DimItem }) {

FILE: src/app/item-popup/DesktopItemActions.m.scss.d.ts
  type CssExports (line 3) | interface CssExports {

FILE: src/app/item-popup/DesktopItemActions.tsx
  function DesktopItemActions (line 22) | function DesktopItemActions({

FILE: src/app/item-popup/EmblemPreview.m.scss.d.ts
  type CssExports (line 3) | interface CssExports {

FILE: src/app/item-popup/EmblemPreview.tsx
  function EmblemPreview (line 8) | function EmblemPreview({ item }: { item: DimItem }) {

FILE: src/app/item-popup/EmoteSockets.m.scss.d.ts
  type CssExports (line 3) | interface CssExports {

FILE: src/app/item-popup/EmoteSockets.tsx
  function EmoteSockets (line 13) | function EmoteSockets({

FILE: src/app/item-popup/EnergyMeter.m.scss.d.ts
  type CssExports (line 3) | interface CssExports {

FILE: src/app/item-popup/EnergyMeter.tsx
  function EnergyMeter (line 26) | function EnergyMeter({ item }: { item: DimItem }) {
  function EnergyUpgradePreview (line 111) | function EnergyUpgradePreview({

FILE: src/app/item-popup/ItemDescription.m.scss.d.ts
  type CssExports (line 3) | interface CssExports {

FILE: src/app/item-popup/ItemDescription.tsx
  function ItemDescription (line 11) | function ItemDescription({ item }: { item: DimItem }) {

FILE: src/app/item-popup/ItemDetails.m.scss.d.ts
  type CssExports (line 3) | interface CssExports {

FILE: src/app/item-popup/ItemDetails.tsx
  function ItemDetails (line 40) | function ItemDetails({

FILE: src/app/item-popup/ItemExpiration.tsx
  function ItemExpiration (line 7) | function ItemExpiration({ item, compact }: { item: DimItem; compact?: bo...

FILE: src/app/item-popup/ItemMoveAmount.m.scss.d.ts
  type CssExports (line 3) | interface CssExports {

FILE: src/app/item-popup/ItemMoveAmount.tsx
  function ItemMoveAmount (line 7) | function ItemMoveAmount({

FILE: src/app/item-popup/ItemPerks.m.scss.d.ts
  type CssExports (line 3) | interface CssExports {

FILE: src/app/item-popup/ItemPerks.tsx
  function ItemPerks (line 8) | function ItemPerks({ item }: { item: DimItem }) {
  function ItemPerk (line 22) | function ItemPerk({ perk }: { perk: DestinyItemPerkEntryDefinition }) {

FILE: src/app/item-popup/ItemPerksList.m.scss.d.ts
  type CssExports (line 3) | interface CssExports {

FILE: src/app/item-popup/ItemPerksList.tsx
  function ItemPerksList (line 18) | function ItemPerksList({
  function PerkSocket (line 66) | function PerkSocket({
  function PerkPlug (line 101) | function PerkPlug({

FILE: src/app/item-popup/ItemPopup.m.scss.d.ts
  type CssExports (line 3) | interface CssExports {

FILE: src/app/item-popup/ItemPopup.tsx
  function ItemPopup (line 42) | function ItemPopup({

FILE: src/app/item-popup/ItemPopupContainer.tsx
  type Props (line 14) | interface Props {
  function ItemPopupContainer (line 22) | function ItemPopupContainer({ boundarySelector }: Props) {
  function maybeFindItem (line 67) | function maybeFindItem(item: DimItem, stores: DimStore[]) {

FILE: src/app/item-popup/ItemPopupHeader.m.scss.d.ts
  type CssExports (line 3) | interface CssExports {

FILE: src/app/item-popup/ItemPopupHeader.tsx
  function ItemPopupHeader (line 28) | function ItemPopupHeader({
  function SeasonTierBanner (line 97) | function SeasonTierBanner({ item }: { item: DimItem }) {

FILE: src/app/item-popup/ItemPopupTabs.m.scss.d.ts
  type CssExports (line 3) | interface CssExports {

FILE: src/app/item-popup/ItemPopupTabs.tsx
  function useItemPopupTabs (line 13) | function useItemPopupTabs(item: DimItem, extraInfo: ItemPopupExtraInfo |...

FILE: src/app/item-popup/ItemSockets.m.scss.d.ts
  type CssExports (line 3) | interface CssExports {

FILE: src/app/item-popup/ItemSockets.tsx
  type PlugClickHandler (line 9) | type PlugClickHandler = (
  function ItemSocketsList (line 71) | function ItemSocketsList({

FILE: src/app/item-popup/ItemSocketsGeneral.m.scss.d.ts
  type CssExports (line 3) | interface CssExports {

FILE: src/app/item-popup/ItemSocketsGeneral.tsx
  function ItemSocketsGeneral (line 24) | function ItemSocketsGeneral({
  function IntrinsicArmorPerk (line 128) | function IntrinsicArmorPerk({
  function SocketCategoryHeader (line 166) | function SocketCategoryHeader({ children }: { children: React.ReactNode ...

FILE: src/app/item-popup/ItemSocketsWeapons.m.scss.d.ts
  type CssExports (line 3) | interface CssExports {

FILE: src/app/item-popup/ItemSocketsWeapons.tsx
  function ItemSocketsWeapons (line 23) | function ItemSocketsWeapons({
  function ItemModSockets (line 150) | function ItemModSockets({

FILE: src/app/item-popup/ItemStat.m.scss.d.ts
  type CssExports (line 3) | interface CssExports {

FILE: src/app/item-popup/ItemStat.tsx
  type StatSegmentType (line 44) | type StatSegmentType = 'base' | 'parts' | 'traits' | 'mod' | 'masterwork';
  type StatSegments (line 52) | type StatSegments = [value: number, statSegmentType: StatSegmentType, mo...
  function ItemStat (line 57) | function ItemStat({
  function StatBar (line 225) | function StatBar({ segments, stat }: { segments: StatSegments; stat: Dim...
  function StatBarTooltip (line 266) | function StatBarTooltip({ segments, stat }: { segments: StatSegments; st...
  function StatTotal (line 294) | function StatTotal({
  function D1QualitySummaryStat (line 334) | function D1QualitySummaryStat({ item }: { item: D1Item }) {
  function getNonReusableModSockets (line 358) | function getNonReusableModSockets(item: DimItem) {
  function getModEffects (line 382) | function getModEffects(item: DimItem, statHash: number) {
  function getWeaponComponentEffects (line 391) | function getWeaponComponentEffects(item: DimItem, statHash: number) {
  function getTraitEffects (line 400) | function getTraitEffects(item: DimItem, statHash: number) {
  function isD1Stat (line 405) | function isD1Stat(item: DimItem, _stat: DimStat): _stat is D1Stat {
  function getTotalPlugEffects (line 415) | function getTotalPlugEffects(sockets: DimSocket[], armorStatHashes: numb...
  function getPlugEffects (line 428) | function getPlugEffects(sockets: DimSocket[], statHashes: number[]) {
  function breakDownTotalValue (line 448) | function breakDownTotalValue(

FILE: src/app/item-popup/ItemStats.m.scss.d.ts
  type CssExports (line 3) | interface CssExports {

FILE: src/app/item-popup/ItemStats.tsx
  function ItemStats (line 7) | function ItemStats({

FILE: src/app/item-popup/ItemTagHotkeys.tsx
  type Props (line 13) | interface Props {
  function ItemTagHotkeys (line 17) | function ItemTagHotkeys({ item }: Props) {

FILE: src/app/item-popup/ItemTagSelector.m.scss.d.ts
  type CssExports (line 3) | interface CssExports {

FILE: src/app/item-popup/ItemTagSelector.tsx
  type Props (line 15) | interface Props {
  function ItemTagSelector (line 22) | function ItemTagSelector({ item, className, hideKeys, hideButtonLabel }:...
  function TagOption (line 59) | function TagOption({ tagOption, hideKeys }: { tagOption: TagInfo; hideKe...

FILE: src/app/item-popup/ItemTalentGrid.m.scss.d.ts
  type CssExports (line 3) | interface CssExports {

FILE: src/app/item-popup/ItemTalentGrid.tsx
  function talentGridNodesFilter (line 107) | function talentGridNodesFilter(nodes: D1GridNode[], hiddenColumns: numbe...

FILE: src/app/item-popup/KillTracker.tsx
  function KillTrackerInfo (line 13) | function KillTrackerInfo({

FILE: src/app/item-popup/MetricCategories.m.scss.d.ts
  type CssExports (line 3) | interface CssExports {

FILE: src/app/item-popup/MetricCategories.tsx
  function MetricCategories (line 5) | function MetricCategories({
  function MetricCategory (line 19) | function MetricCategory({ categoryHash }: { categoryHash: number }) {

FILE: src/app/item-popup/NotesArea.m.scss.d.ts
  type CssExports (line 3) | interface CssExports {

FILE: src/app/item-popup/NotesArea.tsx
  function NotesArea (line 20) | function NotesArea({
  function NotesEditor (line 70) | function NotesEditor({

FILE: src/app/item-popup/Plug.m.scss.d.ts
  type CssExports (line 3) | interface CssExports {

FILE: src/app/item-popup/Plug.tsx
  type PlugStatuses (line 14) | interface PlugStatuses {
  function Plug (line 23) | function Plug({
  function PerkCircleWithTooltip (line 101) | function PerkCircleWithTooltip({
  function PerkCircle (line 156) | function PerkCircle({

FILE: src/app/item-popup/PlugTooltip.m.scss.d.ts
  type CssExports (line 3) | interface CssExports {

FILE: src/app/item-popup/PlugTooltip.tsx
  function DimPlugTooltip (line 33) | function DimPlugTooltip({
  function PlugDefTooltip (line 76) | function PlugDefTooltip({
  function PlugTooltip (line 106) | function PlugTooltip({
  function PlugStats (line 315) | function PlugStats({ stats }: { stats: { statHash: number; value: number...
  function StatValue (line 325) | function StatValue({ value, statHash }: { value: number; statHash: numbe...

FILE: src/app/item-popup/RecoilStat.tsx
  function recoilDirection (line 5) | function recoilDirection(value: number) {
  function recoilValue (line 12) | function recoilValue(value: number) {
  function RecoilStat (line 22) | function RecoilStat({ value }: { value: number }) {

FILE: src/app/item-popup/SetBonus.m.scss.d.ts
  type CssExports (line 3) | interface CssExports {

FILE: src/app/item-popup/SetBonus.tsx
  function getSetBonusStatus (line 22) | function getSetBonusStatus(defs: D2ManifestDefinitions, items: DimItem[]) {
  type ActiveSetBonusInfo (line 77) | type ActiveSetBonusInfo = ReturnType<typeof getSetBonusStatus>;
  function SetBonusesStatus (line 83) | function SetBonusesStatus({
  function SetPerk (line 135) | function SetPerk({
  function SetPerkIcon (line 173) | function SetPerkIcon({
  function ContributingArmor (line 192) | function ContributingArmor({
  function SetBonus (line 224) | function SetBonus({

FILE: src/app/item-popup/Socket.m.scss.d.ts
  type CssExports (line 3) | interface CssExports {

FILE: src/app/item-popup/Socket.tsx
  function Socket (line 11) | function Socket({

FILE: src/app/item-popup/SocketDetails.m.scss.d.ts
  type CssExports (line 3) | interface CssExports {

FILE: src/app/item-popup/SocketDetails.tsx
  function buildUnlockedPlugs (line 34) | function buildUnlockedPlugs(
  function buildShownLockedPlugs (line 52) | function buildShownLockedPlugs(
  function buildInventoryPlugs (line 69) | function buildInventoryPlugs(allItems: DimItem[], socket: DimSocket, def...
  function SocketDetails (line 120) | function SocketDetails({

FILE: src/app/item-popup/SocketDetailsSelectedPlug.m.scss.d.ts
  type CssExports (line 3) | interface CssExports {

FILE: src/app/item-popup/SocketDetailsSelectedPlug.tsx
  function uiCategorizeSocket (line 74) | function uiCategorizeSocket(defs: D2ManifestDefinitions, socket: Destiny...
  function SocketDetailsSelectedPlug (line 104) | function SocketDetailsSelectedPlug({

FILE: src/app/item-popup/WeaponCatalystInfo.m.scss.d.ts
  type CssExports (line 3) | interface CssExports {

FILE: src/app/item-popup/WeaponCatalystInfo.tsx
  function WeaponCatalystInfo (line 12) | function WeaponCatalystInfo({ item }: { item: DimItem }) {

FILE: src/app/item-popup/WeaponCraftedInfo.m.scss.d.ts
  type CssExports (line 3) | interface CssExports {

FILE: src/app/item-popup/WeaponCraftedInfo.tsx
  function WeaponCraftedInfo (line 21) | function WeaponCraftedInfo({ item, className }: { item: DimItem; classNa...
  function CraftedDataMedallion (line 44) | function CraftedDataMedallion({ item }: { item: DimItem }) {

FILE: src/app/item-popup/WeaponDeepsightInfo.m.scss.d.ts
  type CssExports (line 3) | interface CssExports {

FILE: src/app/item-popup/WeaponDeepsightInfo.tsx
  function WeaponDeepsightInfo (line 9) | function WeaponDeepsightInfo({ item }: { item: DimItem }) {

FILE: src/app/item-popup/item-popup-actions.test.ts
  function getTestActions (line 18) | function getTestActions(itemPredicate: (item: DimItem) => boolean): [Dim...

FILE: src/app/item-popup/item-popup-actions.ts
  type StoreButtonInfo (line 9) | interface StoreButtonInfo {
  type ItemActionsModel (line 17) | interface ItemActionsModel {
  function buildItemActionsModel (line 54) | function buildItemActionsModel(item: DimItem, stores: DimStore[]): ItemA...
  function canTransferToVault (line 134) | function canTransferToVault(itemOwnerStore: DimStore, item: DimItem): bo...
  function storeButtonEnabled (line 147) | function storeButtonEnabled(
  function canShowStore (line 169) | function canShowStore(buttonStore: DimStore, itemOwnerStore: DimStore, i...

FILE: src/app/item-popup/item-popup.ts
  type ItemPopupExtraInfo (line 16) | interface ItemPopupExtraInfo {
  function showItemPopup (line 29) | function showItemPopup(
  function hideItemPopup (line 45) | function hideItemPopup() {

FILE: src/app/item-popup/sidecar-popper-modifier.ts
  type Options (line 5) | interface Options {
  function positionMenu (line 10) | function positionMenu({ state }: ModifierArguments<Options>) {
  function setupMenu (line 36) | function setupMenu({ state, options }: ModifierArguments<Options>) {

FILE: src/app/item-triage/ItemTriage.m.scss.d.ts
  type CssExports (line 3) | interface CssExports {

FILE: src/app/item-triage/ItemTriage.tsx
  function doShowTriage (line 46) | function doShowTriage(item: DimItem) {
  function TriageTabToggle (line 63) | function TriageTabToggle({ tabActive, item }: { tabActive: boolean; item...
  function ItemTriage (line 85) | function ItemTriage({ item, id }: { item: DimItem; id: string }) {
  function WishlistTriageSection (line 101) | function WishlistTriageSection({ item }: { item: DimItem }) {
  function LoadoutsTriageSection (line 129) | function LoadoutsTriageSection({ item }: { item: DimItem }) {
  function SimilarItemsTriageSection (line 215) | function SimilarItemsTriageSection({ item }: { item: DimItem }) {
  function BetterItemsTriageSection (line 270) | function BetterItemsTriageSection({ item }: { item: DimItem }) {
  function ArmorStatsTriageSection (line 370) | function ArmorStatsTriageSection({ item }: { item: DimItem }) {
  function FactorCombo (line 439) | function FactorCombo({
  function StartCompareButton (line 455) | function StartCompareButton({

FILE: src/app/item-triage/TriageFactors.m.scss.d.ts
  type CssExports (line 3) | interface CssExports {

FILE: src/app/item-triage/triage-factors.tsx
  type Factor (line 35) | interface Factor {
  type FactorComboCategory (line 43) | type FactorComboCategory = keyof typeof factorCombos;

FILE: src/app/item-triage/triage-utils.test.ts
  type Stats (line 6) | type Stats = [number, number, number, number, number, number];

FILE: src/app/item-triage/triage-utils.ts
  function getValueColors (line 14) | function getValueColors(value: number): [string, string] {
  function getSimilarItems (line 21) | function getSimilarItems(
  function getBetterWorseItems (line 68) | function getBetterWorseItems(
  function collectRelevantStatMaxes (line 200) | function collectRelevantStatMaxes(
  function getNotableStats (line 246) | function getNotableStats(
  function compareBetterStats (line 309) | function compareBetterStats(

FILE: src/app/loadout-analyzer/analysis.test.ts
  function noopProcessWorkerMock (line 44) | function noopProcessWorkerMock(..._args: Parameters<typeof runProcess>): {

FILE: src/app/loadout-analyzer/analysis.ts
  function analyzeLoadout (line 59) | async function analyzeLoadout(
  function matchesExoticArmorHash (line 401) | function matchesExoticArmorHash(
  function getFragmentProblems (line 421) | function getFragmentProblems(
  function getModProblems (line 442) | function getModProblems(
  function getStatProblems (line 499) | function getStatProblems(

FILE: src/app/loadout-analyzer/finding-display.ts
  type FindingDisplay (line 5) | interface FindingDisplay {

FILE: src/app/loadout-analyzer/hooks.tsx
  function MakeLoadoutAnalysisAvailable (line 78) | function MakeLoadoutAnalysisAvailable({ children }: { children: ReactNod...
  function useUpdateLoadoutAnalysisContext (line 96) | function useUpdateLoadoutAnalysisContext(storeId: string) {
  function useAnalyzeLoadout (line 110) | function useAnalyzeLoadout(
  function useSummaryLoadoutsAnalysis (line 137) | function useSummaryLoadoutsAnalysis(

FILE: src/app/loadout-analyzer/store.ts
  type Request (line 18) | interface Request {
  type ResultsForDimStore (line 35) | type ResultsForDimStore = WeakMap<
  type AnalysisStore (line 52) | interface AnalysisStore {
  class LoadoutBackgroundAnalyzer (line 62) | class LoadoutBackgroundAnalyzer {
    method constructor (line 68) | constructor() {
    method destroy (line 77) | destroy() {
    method checkStoreInit (line 83) | private checkStoreInit(storeId: string) {
    method updateAnalysisContext (line 95) | updateAnalysisContext(storeId: string, analysisContext: LoadoutAnalysi...
    method notifyAllSubscribers (line 116) | private notifyAllSubscribers(storeId: string) {
    method subscribeToSummary (line 132) | subscribeToSummary(
    method subscribeToLoadoutResult (line 162) | subscribeToLoadoutResult(
    method getSummary (line 185) | getSummary(subscriptionId: string): LoadoutAnalysisSummary | undefined {
    method getLoadoutResults (line 193) | getLoadoutResults(storeId: string, loadout: Loadout) {
    method setAnalysisResult (line 216) | setAnalysisResult(
    method updateSummary (line 236) | private updateSummary(subscription: Request) {
    method updateSummaries (line 278) | private updateSummaries(storeId: string) {
    method getNextLoadoutToAnalyze (line 288) | getNextLoadoutToAnalyze() {
  function analysisTask (line 328) | async function analysisTask(cancelToken: CancelToken, analyzer: LoadoutB...

FILE: src/app/loadout-analyzer/types.ts
  type LoadoutAnalysisResult (line 8) | interface LoadoutAnalysisResult {
  type LoadoutAnalysisSummary (line 19) | interface LoadoutAnalysisSummary {
  type ArmorAnalysisResult (line 25) | type ArmorAnalysisResult =
  type LoadoutFinding (line 39) | const enum LoadoutFinding {
  type LoadoutAnalysisContext (line 82) | interface LoadoutAnalysisContext {

FILE: src/app/loadout-analyzer/utils.ts
  function mergeStrictUpgradeStatConstraints (line 16) | function mergeStrictUpgradeStatConstraints(

FILE: src/app/loadout-builder/LoadoutBucketDropTarget.m.scss.d.ts
  type CssExports (line 3) | interface CssExports {

FILE: src/app/loadout-builder/LoadoutBucketDropTarget.tsx
  type Props (line 9) | interface Props {
  function LoadoutBucketDropTarget (line 18) | function LoadoutBucketDropTarget({ onItemLocked, children, className }: ...

FILE: src/app/loadout-builder/LoadoutBuilder.m.scss.d.ts
  type CssExports (line 3) | interface CssExports {

FILE: src/app/loadout-builder/LoadoutBuilder.tsx
  function hydrateArmorSet (line 295) | function hydrateArmorSet(processed: ProcessArmorSet): ArmorSet {
  function useRelevantLoadouts (line 616) | function useRelevantLoadouts(selectedStore: DimStore) {
  function useResolvedMods (line 640) | function useResolvedMods(
  function useArmorItems (line 655) | function useArmorItems(classType: DestinyClass, vendorItems: DimItem[]):...
  function useSaveLoadoutParameters (line 671) | function useSaveLoadoutParameters(
  function useSaveStatConstraints (line 705) | function useSaveStatConstraints(
  function UndoRedoControls (line 736) | function UndoRedoControls({
  function ExistingLoadoutStats (line 767) | function ExistingLoadoutStats({

FILE: src/app/loadout-builder/LoadoutBuilderContainer.tsx
  function LoadoutBuilderContainer (line 30) | function LoadoutBuilderContainer({ account }: { account: DestinyAccount ...

FILE: src/app/loadout-builder/LoadoutBuilderItem.tsx
  function LoadoutBuilderItem (line 9) | function LoadoutBuilderItem({

FILE: src/app/loadout-builder/NoBuildsFoundExplainer.m.scss.d.ts
  type CssExports (line 3) | interface CssExports {

FILE: src/app/loadout-builder/NoBuildsFoundExplainer.tsx
  type ActionableSuggestion (line 21) | interface ActionableSuggestion {
  type ProblemDescription (line 26) | interface ProblemDescription {
  constant LOWER_STAT_BOUNDS_WARN_RATIO (line 36) | const LOWER_STAT_BOUNDS_WARN_RATIO = 0.95;
  constant EARLY_MOD_REJECTION_WARN_RATIO (line 40) | const EARLY_MOD_REJECTION_WARN_RATIO = 0.8;
  function NoBuildsFoundExplainer (line 42) | function NoBuildsFoundExplainer({

FILE: src/app/loadout-builder/filter/EnergyOptions.m.scss.d.ts
  type CssExports (line 3) | interface CssExports {

FILE: src/app/loadout-builder/filter/EnergyOptions.tsx
  function EnergyOptions (line 9) | function EnergyOptions({

FILE: src/app/loadout-builder/filter/ExoticArmorChoice.m.scss.d.ts
  type CssExports (line 3) | interface CssExports {

FILE: src/app/loadout-builder/filter/ExoticArmorChoice.tsx
  function getLockedExotic (line 11) | function getLockedExotic(defs: D2ManifestDefinitions, lockedExoticHash: ...
  function ExoticArmorChoice (line 29) | function ExoticArmorChoice({

FILE: src/app/loadout-builder/filter/ExoticPicker.m.scss.d.ts
  type CssExports (line 3) | interface CssExports {

FILE: src/app/loadout-builder/filter/ExoticPicker.tsx
  function findLockableExotics (line 33) | function findLockableExotics(
  function resolveExoticInfo (line 77) | function resolveExoticInfo(item: DimItem) {
  function filterAndGroupExotics (line 96) | function filterAndGroupExotics(
  function ExoticPicker (line 144) | function ExoticPicker({

FILE: src/app/loadout-builder/filter/ExoticTile.m.scss.d.ts
  type CssExports (line 3) | interface CssExports {

FILE: src/app/loadout-builder/filter/ExoticTile.tsx
  type LockedExoticWithPlugs (line 11) | interface LockedExoticWithPlugs {
  function ExoticTile (line 27) | function ExoticTile({
  function exoticTileInfo (line 52) | function exoticTileInfo(defs: D2ManifestDefinitions, exotic: LockedExoti...
  function FakeExoticTile (line 92) | function FakeExoticTile({

FILE: src/app/loadout-builder/filter/LoadoutOptimizerExotic.m.scss.d.ts
  type CssExports (line 3) | interface CssExports {

FILE: src/app/loadout-builder/filter/LoadoutOptimizerExotic.tsx
  function ChosenExoticOption (line 88) | function ChosenExoticOption({

FILE: src/app/loadout-builder/filter/LoadoutOptimizerMenuItems.m.scss.d.ts
  type CssExports (line 3) | interface CssExports {

FILE: src/app/loadout-builder/filter/LoadoutOptimizerMenuItems.tsx
  type ChooseItemFunction (line 18) | type ChooseItemFunction = (

FILE: src/app/loadout-builder/filter/LoadoutOptimizerSetBonus.m.scss.d.ts
  type CssExports (line 3) | interface CssExports {

FILE: src/app/loadout-builder/filter/LoadoutOptimizerSetBonus.tsx
  function findSetBonuses (line 114) | function findSetBonuses(
  function SetBonusPicker (line 130) | function SetBonusPicker({
  function Footer (line 256) | function Footer({
  function SetBonusDisplay (line 280) | function SetBonusDisplay({ setBonuses }: { setBonuses: SetBonusCounts }) {

FILE: src/app/loadout-builder/filter/LockedItem.tsx
  function LockedItem (line 10) | function LockedItem({

FILE: src/app/loadout-builder/filter/NewFeaturedGearFilter.m.scss.d.ts
  type CssExports (line 3) | interface CssExports {

FILE: src/app/loadout-builder/filter/NewFeaturedGearFilter.tsx
  function NewFeaturedGearFilter (line 17) | function NewFeaturedGearFilter({ className }: { className?: string }) {

FILE: src/app/loadout-builder/filter/TierlessStatConstraintEditor.m.scss.d.ts
  type CssExports (line 3) | interface CssExports {

FILE: src/app/loadout-builder/filter/TierlessStatConstraintEditor.tsx
  function TierlessStatConstraintEditor (line 29) | function TierlessStatConstraintEditor({
  function StatRow (line 145) | function StatRow({
  function StatEditBar (line 275) | function StatEditBar({
  function StatBar (line 347) | function StatBar({

FILE: src/app/loadout-builder/generated-sets/CompareLoadoutsDrawer.m.scss.d.ts
  type CssExports (line 3) | interface CssExports {

FILE: src/app/loadout-builder/generated-sets/CompareLoadoutsDrawer.tsx
  function chooseInitialLoadout (line 20) | function chooseInitialLoadout(
  function CompareLoadoutsDrawer (line 42) | function CompareLoadoutsDrawer({

FILE: src/app/loadout-builder/generated-sets/GeneratedSet.m.scss.d.ts
  type CssExports (line 3) | interface CssExports {

FILE: src/app/loadout-builder/generated-sets/GeneratedSet.tsx
  function getStatsBreakdown (line 219) | function getStatsBreakdown(

FILE: src/app/loadout-builder/generated-sets/GeneratedSetButtons.m.scss.d.ts
  type CssExports (line 3) | interface CssExports {

FILE: src/app/loadout-builder/generated-sets/GeneratedSetButtons.tsx
  function GeneratedSetButtons (line 20) | function GeneratedSetButtons({

FILE: src/app/loadout-builder/generated-sets/GeneratedSetItem.m.scss.d.ts
  type CssExports (line 3) | interface CssExports {

FILE: src/app/loadout-builder/generated-sets/GeneratedSetItem.tsx
  function EnergySwap (line 22) | function EnergySwap({ energy }: { energy: { energyCapacity: number; ener...
  function GeneratedSetItem (line 41) | function GeneratedSetItem({

FILE: src/app/loadout-builder/generated-sets/GeneratedSets.tsx
  function GeneratedSets (line 21) | function GeneratedSets({

FILE: src/app/loadout-builder/generated-sets/SetStats.m.scss.d.ts
  type CssExports (line 3) | interface CssExports {

FILE: src/app/loadout-builder/generated-sets/SetStats.tsx
  function TierlessSetStats (line 28) | function TierlessSetStats({
  function TierlessStat (line 113) | function TierlessStat({
  function TotalStats (line 158) | function TotalStats({ totalStats, enabledStats }: { totalStats: number; ...
  function ReferenceConstraints (line 169) | function ReferenceConstraints({

FILE: src/app/loadout-builder/generated-sets/utils.ts
  function getComparatorsForMatchedSetSorting (line 7) | function getComparatorsForMatchedSetSorting(desiredStatRanges: DesiredSt...
  function sortGeneratedSets (line 33) | function sortGeneratedSets(
  function sumEnabledStats (line 40) | function sumEnabledStats(stats: ArmorStats, desiredStatRanges: DesiredSt...

FILE: src/app/loadout-builder/item-filter.test.ts
  function expectItemCount (line 26) | function expectItemCount(filterInfo: FilterInfo, expectedCount: number) {
  function noPinInvariants (line 74) | function noPinInvariants(filteredItems: ItemsByBucket, filterInfo: Filte...
  function pinInvariants (line 93) | function pinInvariants(filteredItems: ItemsByBucket, filterInfo: FilterI...

FILE: src/app/loadout-builder/item-filter.ts
  type FilterInfo (line 31) | interface FilterInfo {
  function filterItems (line 51) | function filterItems({

FILE: src/app/loadout-builder/loadout-builder-reducer.ts
  type LoadoutBuilderUI (line 49) | interface LoadoutBuilderUI {
  type LoadoutBuilderConfiguration (line 64) | interface LoadoutBuilderConfiguration {
  type LoadoutBuilderState (line 104) | type LoadoutBuilderState = LoadoutBuilderUI & LoadoutBuilderConfiguration;
  function warnMissingClass (line 106) | function warnMissingClass(classType: DestinyClass, defs: D2ManifestDefin...
  function stripAlwaysAutoAssignedMods (line 234) | function stripAlwaysAutoAssignedMods(defs: D2ManifestDefinitions, mods: ...
  type LoadoutBuilderConfigAction (line 245) | type LoadoutBuilderConfigAction =
  type LoadoutBuilderUIAction (line 279) | type LoadoutBuilderUIAction =
  type LoadoutBuilderAction (line 285) | type LoadoutBuilderAction =
  function lbUIReducer (line 291) | function lbUIReducer(state: LoadoutBuilderUI, action: LoadoutBuilderUIAc...
  function lbConfigReducer (line 310) | function lbConfigReducer(defs: D2ManifestDefinitions) {
  function updateLoadout (line 535) | function updateLoadout(state: LoadoutBuilderConfiguration, updateFn: Loa...
  function updateStatConstraints (line 542) | function updateStatConstraints(
  function useLbState (line 555) | function useLbState(

FILE: src/app/loadout-builder/loadout-builder-vendors.ts
  function useLoVendorItems (line 42) | function useLoVendorItems(selectedStoreId: string) {

FILE: src/app/loadout-builder/loadout-params.ts
  function resolveStatConstraints (line 14) | function resolveStatConstraints(
  function unresolveStatConstraints (line 36) | function unresolveStatConstraints(

FILE: src/app/loadout-builder/process-worker/ProcessWorker.ts
  type ProcessWorker (line 8) | type ProcessWorker = typeof exports;

FILE: src/app/loadout-builder/process-worker/auto-stat-mod-utils.ts
  type ModsPick (line 10) | interface ModsPick {
  type CacheForStat (line 32) | interface CacheForStat {
  type AutoModsCache (line 39) | interface AutoModsCache {
  function chooseAutoMods (line 55) | function chooseAutoMods(
  function doGeneralModsFit (line 79) | function doGeneralModsFit(
  function recursivelyChooseMods (line 109) | function recursivelyChooseMods(
  function buildCacheForStat (line 191) | function buildCacheForStat(
  function buildAutoModsMap (line 273) | function buildAutoModsMap(

FILE: src/app/loadout-builder/process-worker/process-utils.test.ts
  function modifyMod (line 51) | function modifyMod({
  function modifyItem (line 73) | function modifyItem({

FILE: src/app/loadout-builder/process-worker/process-utils.ts
  type LoSessionInfo (line 11) | interface LoSessionInfo {
  function precalculateStructures (line 26) | function precalculateStructures(
  function getRemainingEnergiesPerAssignment (line 59) | function getRemainingEnergiesPerAssignment(
  function updateMaxStats (line 117) | function updateMaxStats(
  function pickAndAssignSlotIndependentMods (line 252) | function pickAndAssignSlotIndependentMods(
  function pickOptimalStatMods (line 357) | function pickOptimalStatMods(
  function greedyPickStatMods (line 440) | function greedyPickStatMods(
  function generateProcessModPermutations (line 523) | function generateProcessModPermutations(mods: (ProcessMod | null)[]) {

FILE: src/app/loadout-builder/process-worker/process.ts
  constant RETURNED_ARMOR_SETS (line 35) | const RETURNED_ARMOR_SETS = 200;
  type ProcessInputs (line 37) | interface ProcessInputs {
  function process (line 64) | async function process(

FILE: src/app/loadout-builder/process-worker/set-tracker.ts
  type HeapEntry (line 7) | type HeapEntry<T> = {
  function isWorse (line 23) | function isWorse<T>(a: HeapEntry<T>, b: HeapEntry<T>): boolean {
  class HeapSetTracker (line 41) | class HeapSetTracker<T> {
    method constructor (line 45) | constructor(capacity: number) {
    method couldInsert (line 53) | couldInsert(totalTier: number): boolean {
    method insert (line 65) | insert(entry: HeapEntry<T>): boolean {
    method getArmorSets (line 88) | getArmorSets(): HeapEntry<T>[] {
    method totalSets (line 102) | get totalSets(): number {
    method bubbleUp (line 108) | private bubbleUp(index: number): void {
    method bubbleDown (line 120) | private bubbleDown(index: number): void {
  function encodeStatMix (line 154) | function encodeStatMix(
  function decodeStatMix (line 178) | function decodeStatMix(encoded: number, numStats: number): number[] {

FILE: src/app/loadout-builder/process-worker/types.ts
  type ProcessResult (line 3) | interface ProcessResult {
  type ProcessItem (line 19) | interface ProcessItem {
  type ProcessItemsByBucket (line 42) | type ProcessItemsByBucket = {
  type ProcessArmorSet (line 46) | interface ProcessArmorSet {
  type ProcessMod (line 66) | interface ProcessMod {
  type AutoModData (line 80) | interface AutoModData {
  type LockedProcessMods (line 90) | interface LockedProcessMods {
  type RejectionRate (line 95) | interface RejectionRate {
  type ModAssignmentStatistics (line 100) | interface ModAssignmentStatistics {
  type ProcessStatistics (line 118) | interface ProcessStatistics {

FILE: src/app/loadout-builder/process/mappers.ts
  function mapArmor2ModToProcessMod (line 38) | function mapArmor2ModToProcessMod(mod: PluggableInventoryItemDefinition)...
  function mapDimItemToProcessItems (line 60) | function mapDimItemToProcessItems({
  function mapAutoMods (line 153) | function mapAutoMods(defs: AutoModDefs): AutoModData {
  function getAutoMods (line 171) | function getAutoMods(defs: D2ManifestDefinitions, allUnlockedPlugs: Set<...

FILE: src/app/loadout-builder/process/process-wrapper.ts
  type MappedItem (line 31) | interface MappedItem {
  function createWorker (line 36) | function createWorker() {
  type RunProcessResult (line 52) | type RunProcessResult = Omit<ProcessResult, 'sets'> & {
  function runProcess (line 57) | function runProcess({
  function combineResults (line 206) | function combineResults(results: ProcessResult[]): ProcessResult {
  function combineStatRanges (line 233) | function combineStatRanges(a: StatRanges, b: StatRanges): StatRanges {
  function combineProcessInfo (line 242) | function combineProcessInfo(a: ProcessStatistics, b: ProcessStatistics):...
  function sliceInputForConcurrency (line 268) | function sliceInputForConcurrency(

FILE: src/app/loadout-builder/process/useProcess.ts
  type ProcessState (line 22) | interface ProcessState {
  function useProcess (line 54) | function useProcess({
  function useAutoMods (line 212) | function useAutoMods(storeId: string) {

FILE: src/app/loadout-builder/types.ts
  type MinMaxStat (line 8) | interface MinMaxStat {
  type ResolvedStatConstraint (line 20) | interface ResolvedStatConstraint extends Required<
  type DesiredStatRange (line 35) | type DesiredStatRange = Required<Omit<StatConstraint, 'minTier' | 'maxTi...
  type PinnedItems (line 38) | interface PinnedItems {
  type ExcludedItems (line 43) | interface ExcludedItems {
  type ArmorSet (line 50) | interface ArmorSet {
  type ItemsByBucket (line 61) | type ItemsByBucket = Readonly<{
  type AutoModDefs (line 68) | interface AutoModDefs {
  type ItemGroup (line 83) | type ItemGroup = Readonly<{
  type ArmorBucketHash (line 89) | type ArmorBucketHash =
  type ModStatChanges (line 98) | type ModStatChanges = {
  type ArmorStatHashes (line 102) | type ArmorStatHashes =
  type StatRanges (line 110) | type StatRanges = { [statHash in ArmorStatHashes]: MinMaxStat };
  type ArmorStats (line 111) | type ArmorStats = { [statHash in ArmorStatHashes]: number };
  constant LOCKED_EXOTIC_NO_EXOTIC (line 157) | const LOCKED_EXOTIC_NO_EXOTIC = -1;
  constant LOCKED_EXOTIC_ANY_EXOTIC (line 161) | const LOCKED_EXOTIC_ANY_EXOTIC = -2;
  constant MIN_LO_ITEM_ENERGY (line 165) | const MIN_LO_ITEM_ENERGY = 9;
  type ArmorEnergyRules (line 196) | interface ArmorEnergyRules {

FILE: src/app/loadout-builder/updated-loadout.ts
  function updateLoadoutWithArmorSet (line 15) | function updateLoadoutWithArmorSet(
  function mergeLoadout (line 61) | function mergeLoadout(

FILE: src/app/loadout-builder/useEquippedHashes.ts
  function useEquippedHashes (line 6) | function useEquippedHashes(

FILE: src/app/loadout-builder/utils.ts
  function statTier (line 5) | function statTier(stat: number) {
  function remEuclid (line 17) | function remEuclid(dividend: number, divisor: number) {
  function getPower (line 24) | function getPower(items: DimItem[] | ProcessItem[]) {

FILE: src/app/loadout-drawer/LoadoutDrawer.m.scss.d.ts
  type CssExports (line 3) | interface CssExports {

FILE: src/app/loadout-drawer/LoadoutDrawer.tsx
  function LoadoutDrawer (line 57) | function LoadoutDrawer({

FILE: src/app/loadout-drawer/LoadoutDrawerContainer.tsx
  function LoadoutDrawerContainer (line 34) | function LoadoutDrawerContainer({ account }: { account: DestinyAccount }) {

FILE: src/app/loadout-drawer/LoadoutDrawerDropTarget.m.scss.d.ts
  type CssExports (line 3) | interface CssExports {

FILE: src/app/loadout-drawer/LoadoutDrawerDropTarget.tsx
  function LoadoutDrawerDropTarget (line 29) | function LoadoutDrawerDropTarget({

FILE: src/app/loadout-drawer/LoadoutDrawerFooter.m.scss.d.ts
  type CssExports (line 3) | interface CssExports {

FILE: src/app/loadout-drawer/LoadoutDrawerFooter.tsx
  function LoadoutDrawerFooter (line 33) | function LoadoutDrawerFooter({

FILE: src/app/loadout-drawer/LoadoutDrawerHeader.m.scss.d.ts
  type CssExports (line 3) | interface CssExports {

FILE: src/app/loadout-drawer/LoadoutDrawerHeader.tsx
  function LoadoutDrawerHeader (line 10) | function LoadoutDrawerHeader({

FILE: src/app/loadout-drawer/auto-loadouts.ts
  function itemLevelingLoadout (line 31) | function itemLevelingLoadout(allItems: DimItem[], store: DimStore): Load...
  function maxLightLoadout (line 83) | function maxLightLoadout(allItems: DimItem[], store: DimStore): Loadout {
  function maxLightItemSet (line 96) | function maxLightItemSet(
  function maxStatLoadout (line 134) | function maxStatLoadout(statHash: number, allItems: DimItem[], store: Di...
  function itemMoveLoadout (line 169) | function itemMoveLoadout(items: DimItem[], store: DimStore): Loadout {
  function limitToBucketSize (line 192) | function limitToBucketSize(items: DimItem[], store: DimStore) {
  function addUpStackables (line 239) | function addUpStackables(items: DimItem[]) {
  function randomLoadout (line 270) | function randomLoadout(store: DimStore, allItems: DimItem[], filter: Ite...
  function randomSubclassConfiguration (line 288) | function randomSubclassConfiguration(

FILE: src/app/loadout-drawer/loadout-apply-state.ts
  type LoadoutApplyPhase (line 10) | const enum LoadoutApplyPhase {
  type LoadoutItemState (line 32) | const enum LoadoutItemState {
  type LoadoutItemResult (line 45) | interface LoadoutItemResult {
  type LoadoutModState (line 52) | const enum LoadoutModState {
  type LoadoutModResult (line 59) | interface LoadoutModResult {
  type LoadoutSocketOverrideState (line 65) | const enum LoadoutSocketOverrideState {
  type LoadoutSocketOverrideResult (line 71) | interface LoadoutSocketOverrideResult {
  type LoadoutApplyState (line 87) | interface LoadoutApplyState {
  type LoadoutStateGetter (line 118) | type LoadoutStateGetter = () => LoadoutApplyState;
  type LoadoutStateUpdater (line 119) | type LoadoutStateUpdater = (update: (state: LoadoutApplyState) => Loadou...
  function makeLoadoutApplyState (line 126) | function makeLoadoutApplyState(): [
  function setLoadoutApplyPhase (line 155) | function setLoadoutApplyPhase(phase: LoadoutApplyPhase) {
  function setModResult (line 162) | function setModResult(result: LoadoutModResult, equipNotPossible?: boole...
  function setSocketOverrideResult (line 177) | function setSocketOverrideResult(
  function anyActionFailed (line 201) | function anyActionFailed(state: LoadoutApplyState) {

FILE: src/app/loadout-drawer/loadout-apply.ts
  constant TAG (line 105) | const TAG = 'loadout';
  function applyLoadout (line 136) | function applyLoadout(
  function doApplyLoadout (line 203) | function doApplyLoadout(
  function applyLoadoutItem (line 706) | function applyLoadoutItem(
  function clearSpaceAfterLoadout (line 797) | function clearSpaceAfterLoadout(
  function clearItemsOffCharacter (line 859) | function clearItemsOffCharacter(
  function applySocketOverrides (line 961) | function applySocketOverrides(
  function applyLoadoutMods (line 1110) | function applyLoadoutMods(
  function allModsAreAlreadyApplied (line 1260) | function allModsAreAlreadyApplied(
  function equipModsToItem (line 1311) | function equipModsToItem(
  function applyMod (line 1398) | function applyMod(
  function checkEquipNotPossible (line 1434) | function checkEquipNotPossible(errorCode?: PlatformErrorCodes) {

FILE: src/app/loadout-drawer/loadout-drawer-reducer.ts
  type LoadoutUpdateFunction (line 63) | type LoadoutUpdateFunction = (loadout: Loadout) => Loadout;
  function useLoadoutUpdaters (line 66) | function useLoadoutUpdaters(
  function addItem (line 100) | function addItem(
  function removeItem (line 191) | function removeItem(
  function replaceItem (line 232) | function replaceItem(
  function unequipOtherItems (line 254) | function unequipOtherItems(
  function toggleEquipped (line 284) | function toggleEquipped(
  function applySocketOverrides (line 291) | function applySocketOverrides(
  function loadoutItemsInBucket (line 308) | function loadoutItemsInBucket(
  function getBucketHashFromItemHash (line 319) | function getBucketHashFromItemHash(
  function clearLoadoutOptimizerParameters (line 330) | function clearLoadoutOptimizerParameters(): LoadoutUpdateFunction {
  function clearSubclass (line 343) | function clearSubclass(
  function removeMod (line 364) | function removeMod(mod: ResolvedLoadoutMod): LoadoutUpdateFunction {
  function setLoadoutSubclassFromEquipped (line 378) | function setLoadoutSubclassFromEquipped(
  function fillLoadoutFromEquipped (line 399) | function fillLoadoutFromEquipped(
  function syncLoadoutCategoryFromEquipped (line 457) | function syncLoadoutCategoryFromEquipped(
  function fillLoadoutFromUnequipped (line 502) | function fillLoadoutFromUnequipped(
  function setName (line 522) | function setName(name: string): LoadoutUpdateFunction {
  function setNotes (line 529) | function setNotes(notes: string | undefined): LoadoutUpdateFunction {
  function setClassType (line 536) | function setClassType(classType: DestinyClass): LoadoutUpdateFunction {
  function setClearSpace (line 543) | function setClearSpace(
  function setLoadoutParameters (line 556) | function setLoadoutParameters(params: Partial<LoadoutParameters>): Loado...
  function syncModsFromEquipped (line 566) | function syncModsFromEquipped(store: DimStore): LoadoutUpdateFunction {
  function getLoadoutBucketHashesFromCategory (line 578) | function getLoadoutBucketHashesFromCategory(
  function clearBucketCategory (line 589) | function clearBucketCategory(
  function clearBuckets (line 599) | function clearBuckets(
  function clearMods (line 619) | function clearMods(): LoadoutUpdateFunction {
  function changeClearMods (line 625) | function changeClearMods(enabled: boolean): LoadoutUpdateFunction {
  function changeIncludeRuntimeStats (line 631) | function changeIncludeRuntimeStats(enabled: boolean): LoadoutUpdateFunct...
  function updateMods (line 637) | function updateMods(mods: number[]): LoadoutUpdateFunction {
  function updateModsByBucket (line 643) | function updateModsByBucket(
  function syncArtifactUnlocksFromEquipped (line 654) | function syncArtifactUnlocksFromEquipped(
  function clearArtifactUnlocks (line 674) | function clearArtifactUnlocks(): LoadoutUpdateFunction {
  function removeArtifactUnlock (line 683) | function removeArtifactUnlock(mod: number): LoadoutUpdateFunction {
  function randomizeLoadoutSubclass (line 695) | function randomizeLoadoutSubclass(
  function itemMatchesCategory (line 719) | function itemMatchesCategory(item: DimItem, category: D2BucketCategory |...
  function randomizeFullLoadout (line 730) | function randomizeFullLoadout(
  function randomizeLoadoutItems (line 746) | function randomizeLoadoutItems(
  function randomizeLoadoutMods (line 789) | function randomizeLoadoutMods(
  function setInGameLoadoutIdentifiers (line 856) | function setInGameLoadoutIdentifiers(identifiers: InGameLoadoutIdentifie...

FILE: src/app/loadout-drawer/loadout-events.ts
  type EditLoadoutState (line 5) | interface EditLoadoutState {
  function editLoadout (line 18) | function editLoadout(
  function addItemToLoadout (line 38) | function addItemToLoadout(item: DimItem) {
  function copyAndEditLoadout (line 45) | function copyAndEditLoadout(

FILE: src/app/loadout-drawer/loadout-item-conversion.ts
  function generateMissingLoadoutItemId (line 19) | function generateMissingLoadoutItemId() {
  function getItemsFromLoadoutItems (line 27) | function getItemsFromLoadoutItems(

FILE: src/app/loadout-drawer/loadout-utils.ts
  function newLoadout (line 120) | function newLoadout(name: string, items: LoadoutItem[], classType?: Dest...
  function createSocketOverridesFromEquipped (line 138) | function createSocketOverridesFromEquipped(item: DimItem) {
  function newLoadoutFromEquipped (line 180) | function newLoadoutFromEquipped(
  function inGameLoadoutItemsFromEquipped (line 237) | function inGameLoadoutItemsFromEquipped(store: DimStore): DestinyLoadout...
  function getLight (line 254) | function getLight(store: DimStore, items: DimItem[]): number {
  function getLoadoutStats (line 296) | function getLoadoutStats(
  function calculateAssumedMasterworkStats (line 368) | function calculateAssumedMasterworkStats(
  function optimalItemSet (line 422) | function optimalItemSet(
  function optimalLoadout (line 501) | function optimalLoadout(
  function backupLoadout (line 517) | function backupLoadout(store: DimStore, name: string): Loadout {
  function convertToLoadoutItem (line 541) | function convertToLoadoutItem(item: DimItem, equip: boolean): LoadoutItem {
  function extractArmorModHashes (line 552) | function extractArmorModHashes(item: DimItem) {
  function getResolutionInfo (line 605) | function getResolutionInfo(
  function findSameLoadoutItemIndex (line 650) | function findSameLoadoutItemIndex(
  function findItemForLoadout (line 672) | function findItemForLoadout(
  function getInstancedLoadoutItem (line 714) | function getInstancedLoadoutItem(allItems: DimItem[], loadoutItem: Loado...
  function getUninstancedLoadoutItem (line 733) | function getUninstancedLoadoutItem(
  function getLoadoutSubclassFragmentCapacity (line 755) | function getLoadoutSubclassFragmentCapacity(
  function isMissingItems (line 783) | function isMissingItems(
  function isFashionOnly (line 810) | function isFashionOnly(defs: D2ManifestDefinitions, loadout: Loadout): b...
  function isArmorModsOnly (line 836) | function isArmorModsOnly(defs: D2ManifestDefinitions, loadout: Loadout):...
  function isFashionPlug (line 867) | function isFashionPlug(modDef: DestinyInventoryItemDefinition | undefine...
  function getModsFromLoadout (line 880) | function getModsFromLoadout(
  function resolveLoadoutModHashes (line 911) | function resolveLoadoutModHashes(
  function getSubclassFragmentCapacity (line 946) | function getSubclassFragmentCapacity(subclassItem: DimItem): number {
  function sumAspectCapacity (line 952) | function sumAspectCapacity(
  function getUnequippedItemsForLoadout (line 968) | function getUnequippedItemsForLoadout(dimStore: DimStore, category?: str...
  function pickBackingStore (line 985) | function pickBackingStore(
  function filterLoadoutToAllowedItems (line 1003) | function filterLoadoutToAllowedItems(
  function getLoadoutSeason (line 1038) | function getLoadoutSeason(loadout: Loadout, seasons: DestinySeasonDefini...

FILE: src/app/loadout-drawer/postmaster.ts
  function makeRoomForPostmaster (line 41) | function makeRoomForPostmaster(store: DimStore, buckets: InventoryBucket...
  function pullablePostmasterItems (line 101) | function pullablePostmasterItems(store: DimStore, stores: DimStore[]) {
  function pullFromPostmasterAmount (line 110) | function pullFromPostmasterAmount(i: DimItem, store: DimStore, stores: D...
  constant POSTMASTER_SIZE (line 129) | const POSTMASTER_SIZE = 21;
  function postmasterAlmostFull (line 131) | function postmasterAlmostFull(store: DimStore) {
  function postmasterSpaceLeft (line 135) | function postmasterSpaceLeft(store: DimStore) {
  function postmasterSpaceUsed (line 138) | function postmasterSpaceUsed(store: DimStore) {
  function totalPostmasterItems (line 142) | function totalPostmasterItems(store: DimStore) {
  function pullFromPostmaster (line 158) | function pullFromPostmaster(store: DimStore): ThunkResult {
  function moveItemsToVault (line 234) | function moveItemsToVault(

FILE: src/app/loadout/LoadoutView.m.scss.d.ts
  type CssExports (line 3) | interface CssExports {

FILE: src/app/loadout/LoadoutView.tsx
  function getItemsAndSubclassFromLoadout (line 33) | function getItemsAndSubclassFromLoadout(
  function LoadoutView (line 73) | function LoadoutView({
  function loadoutPower (line 207) | function loadoutPower(store: DimStore, categories: Record<string, Resolv...

FILE: src/app/loadout/Loadouts.m.scss.d.ts
  type CssExports (line 3) | interface CssExports {

FILE: src/app/loadout/Loadouts.tsx
  function LoadoutsContainer (line 65) | function LoadoutsContainer({ account }: { account: DestinyAccount }) {
  function Loadouts (line 81) | function Loadouts({ account }: { account: DestinyAccount }) {
  function useAddSeasonHeaders (line 329) | function useAddSeasonHeaders(loadouts: Loadout[], loadoutSort: LoadoutSo...

FILE: src/app/loadout/ModPicker.tsx
  constant MAX_SLOT_INDEPENDENT_MODS (line 34) | const MAX_SLOT_INDEPENDENT_MODS = 5;
  function useUnlockedPlugSets (line 38) | function useUnlockedPlugSets(
  function ModPicker (line 270) | function ModPicker({
  function isModSelectable (line 357) | function isModSelectable(

FILE: src/app/loadout/SubclassPlugDrawer.tsx
  type PlugSetWithDefaultPlug (line 22) | type PlugSetWithDefaultPlug = PlugSet & { defaultPlug: PluggableInventor...
  function SubclassPlugDrawer (line 27) | function SubclassPlugDrawer({
  function getPlugsForSubclass (line 108) | function getPlugsForSubclass(

FILE: src/app/loadout/armor-upgrade-utils.ts
  function calculateAssumedItemEnergy (line 12) | function calculateAssumedItemEnergy(item: DimItem, armorEnergyRules: Arm...
  function isAssumedArtifice (line 30) | function isAssumedArtifice(item: DimItem, { assumeArmorMasterwork }: Arm...
  function isAssumedMasterworked (line 43) | function isAssumedMasterworked(item: DimItem, { assumeArmorMasterwork }:...

FILE: src/app/loadout/fashion/FashionDrawer.m.scss.d.ts
  type CssExports (line 3) | interface CssExports {

FILE: src/app/loadout/fashion/FashionDrawer.tsx
  type PickPlugState (line 35) | interface PickPlugState {
  function FashionDrawer (line 41) | function FashionDrawer({
  function FashionItem (line 405) | function FashionItem({
  function FashionSocket (line 484) | function FashionSocket({
  function findOtherCopies (line 550) | function findOtherCopies(
  function manuallyFindItemForCollectible (line 569) | function manuallyFindItemForCollectible(

FILE: src/app/loadout/ingame/EditInGameLoadout.m.scss.d.ts
  type CssExports (line 3) | interface CssExports {

FILE: src/app/loadout/ingame/EditInGameLoadout.tsx
  function EditInGameLoadout (line 20) | function EditInGameLoadout({

FILE: src/app/loadout/ingame/EditInGameLoadoutIdentifiers.m.scss.d.ts
  type CssExports (line 3) | interface CssExports {

FILE: src/app/loadout/ingame/EditInGameLoadoutIdentifiers.tsx
  function EditInGameLoadoutIdentifiers (line 12) | function EditInGameLoadoutIdentifiers({

FILE: src/app/loadout/ingame/InGameLoadoutDetailsSheet.m.scss.d.ts
  type CssExports (line 3) | interface CssExports {

FILE: src/app/loadout/ingame/InGameLoadoutDetailsSheet.tsx
  function InGameLoadoutDetails (line 24) | function InGameLoadoutDetails({
  function InGameLoadoutItemDetail (line 112) | function InGameLoadoutItemDetail({

FILE: src/app/loadout/ingame/InGameLoadoutIcon.m.scss.d.ts
  type CssExports (line 3) | interface CssExports {

FILE: src/app/loadout/ingame/InGameLoadoutIcon.tsx
  function InGameLoadoutIcon (line 9) | function InGameLoadoutIcon({
  function InGameLoadoutIconWithIndex (line 29) | function InGameLoadoutIconWithIndex({
  function InGameLoadoutIconFromIdentifiers (line 48) | function InGameLoadoutIconFromIdentifiers({

FILE: src/app/loadout/ingame/InGameLoadoutIdentifiersSelectButton.m.scss.d.ts
  type CssExports (line 3) | interface CssExports {

FILE: src/app/loadout/ingame/InGameLoadoutIdentifiersSelectButton.tsx
  function InGameLoadoutIdentifiersSelectButton (line 12) | function InGameLoadoutIdentifiersSelectButton({

FILE: src/app/loadout/ingame/InGameLoadoutStrip.m.scss.d.ts
  type CssExports (line 3) | interface CssExports {

FILE: src/app/loadout/ingame/InGameLoadoutStrip.tsx
  function InGameLoadoutStrip (line 23) | function InGameLoadoutStrip({
  function InGameLoadoutTile (line 65) | function InGameLoadoutTile({

FILE: src/app/loadout/ingame/RadioButton.m.scss.d.ts
  type CssExports (line 3) | interface CssExports {

FILE: src/app/loadout/ingame/RadioButton.tsx
  function RadioButton (line 7) | function RadioButton({

FILE: src/app/loadout/ingame/SelectInGameLoadoutIdentifiers.m.scss.d.ts
  type CssExports (line 3) | interface CssExports {

FILE: src/app/loadout/ingame/SelectInGameLoadoutIdentifiers.tsx
  function SelectInGameLoadoutIdentifiers (line 12) | function SelectInGameLoadoutIdentifiers({
  function useIdentifierValues (line 87) | function useIdentifierValues(defs: D2ManifestDefinitions) {

FILE: src/app/loadout/ingame/ingame-loadout-apply.ts
  function applyInGameLoadout (line 30) | function applyInGameLoadout(loadout: InGameLoadout, apply = true): Thunk...
  function updateAfterInGameLoadoutApply (line 50) | function updateAfterInGameLoadoutApply(loadout: InGameLoadout): ThunkRes...
  function deleteInGameLoadout (line 88) | function deleteInGameLoadout(loadout: InGameLoadout): ThunkResult {
  function editInGameLoadout (line 110) | function editInGameLoadout(loadout: InGameLoadout): ThunkResult {
  function snapshotInGameLoadout (line 126) | function snapshotInGameLoadout(loadout: InGameLoadout): ThunkResult {

FILE: src/app/loadout/ingame/ingame-loadout-utils.ts
  function getItemsFromInGameLoadout (line 21) | function getItemsFromInGameLoadout(
  function useItemsFromInGameLoadout (line 51) | function useItemsFromInGameLoadout(loadout: InGameLoadout) {
  function implementsDimLoadout (line 72) | function implementsDimLoadout(
  function itemCouldBeEquipped (line 142) | function itemCouldBeEquipped(store: DimStore, item: DimItem, _stores: Di...
  function isValidGameLoadoutPlug (line 149) | function isValidGameLoadoutPlug(hash: number) {

FILE: src/app/loadout/ingame/reducer.ts
  type InGameLoadoutState (line 7) | interface InGameLoadoutState {
  type InGameLoadoutAction (line 16) | type InGameLoadoutAction = ActionType<typeof actions>;

FILE: src/app/loadout/ingame/selectors.ts
  type FullyResolvedLoadout (line 33) | interface FullyResolvedLoadout {
  function fullyResolveLoadout (line 73) | function fullyResolveLoadout(

FILE: src/app/loadout/known-values.ts
  constant UNSET_PLUG_HASH (line 36) | const UNSET_PLUG_HASH = 2166136261;
  constant MAX_TIER (line 38) | const MAX_TIER = 10;
  constant MAX_STAT (line 39) | const MAX_STAT = 200;
  constant EFFECTIVE_MAX_STAT (line 48) | const EFFECTIVE_MAX_STAT = edgeOfFateReleased ? MAX_STAT : 10 * MAX_TIER;

FILE: src/app/loadout/loadout-edit/LoadoutEdit.m.scss.d.ts
  type CssExports (line 3) | interface CssExports {

FILE: src/app/loadout/loadout-edit/LoadoutEdit.tsx
  function LoadoutEdit (line 73) | function LoadoutEdit({
  function pickLoadoutItem (line 156) | async function pickLoadoutItem(
  function LoadoutEditSubclassSection (line 182) | function LoadoutEditSubclassSection({
  function LoadoutEditCategorySection (line 248) | function LoadoutEditCategorySection({
  function LoadoutEditModsSection (line 388) | function LoadoutEditModsSection({
  function LoadoutArtifactUnlocksSection (line 458) | function LoadoutArtifactUnlocksSection({
  function disableFillInForCategory (line 522) | function disableFillInForCategory(

FILE: src/app/loadout/loadout-edit/LoadoutEditBucket.m.scss.d.ts
  type CssExports (line 3) | interface CssExports {

FILE: src/app/loadout/loadout-edit/LoadoutEditBucket.tsx
  type EditableCategories (line 31) | type EditableCategories = 'Weapons' | 'Armor' | 'General';
  function LoadoutEditBucket (line 39) | function LoadoutEditBucket({
  function ArmorExtras (line 103) | function ArmorExtras({
  function ItemBucket (line 146) | function ItemBucket({
  function DraggableItem (line 262) | function DraggableItem({
  function AddItemButton (line 300) | function AddItemButton({
  function FashionButton (line 314) | function FashionButton({

FILE: src/app/loadout/loadout-edit/LoadoutEditSection.m.scss.d.ts
  type CssExports (line 3) | interface CssExports {

FILE: src/app/loadout/loadout-edit/LoadoutEditSection.tsx
  function LoadoutEditSection (line 17) | function LoadoutEditSection({

FILE: src/app/loadout/loadout-edit/LoadoutEditSubclass.m.scss.d.ts
  type CssExports (line 3) | interface CssExports {

FILE: src/app/loadout/loadout-edit/LoadoutEditSubclass.tsx
  function LoadoutEditSubclass (line 44) | function LoadoutEditSubclass({

FILE: src/app/loadout/loadout-edit/useEquipDropTargets.tsx
  function useEquipDropTargets (line 46) | function useEquipDropTargets(accept: TargetType, classType: DestinyClass) {

FILE: src/app/loadout/loadout-item-utils.ts
  function isLoadoutBuilderItem (line 15) | function isLoadoutBuilderItem(item: DimItem) {
  function getSubclassPlugHashes (line 23) | function getSubclassPlugHashes(subclass: ResolvedLoadoutItem | undefined) {
  function getSubclassPlugs (line 50) | function getSubclassPlugs(

FILE: src/app/loadout/loadout-menu/LoadoutPopup.m.scss.d.ts
  type CssExports (line 3) | interface CssExports {

FILE: src/app/loadout/loadout-menu/LoadoutPopup.tsx
  function LoadoutPopup (line 82) | function LoadoutPopup({
  function filterLoadoutToEquipped (line 366) | function filterLoadoutToEquipped(loadout: Loadout) {
  function RandomLoadoutButton (line 373) | function RandomLoadoutButton({
  function createRandomLoadout (line 417) | function createRandomLoadout(store: DimStore): ThunkResult {
  function doApplyRandomLoadout (line 429) | function doApplyRandomLoadout(store: DimStore, options: RandomLoadoutOpt...
  function RewardMultiplier (line 463) | function RewardMultiplier({ defs, store }: { defs: D2ManifestDefinitions...

FILE: src/app/loadout/loadout-menu/LoadoutPopupRandomize.m.scss.d.ts
  type CssExports (line 3) | interface CssExports {

FILE: src/app/loadout/loadout-menu/LoadoutPopupRandomize.tsx
  type RandomLoadoutOptions (line 9) | interface RandomLoadoutOptions {
  function useRandomizeLoadout (line 34) | function useRandomizeLoadout(): [
  function RandomizeLoadoutDialog (line 49) | function RandomizeLoadoutDialog({

FILE: src/app/loadout/loadout-menu/MaxlightButton.m.scss.d.ts
  type CssExports (line 3) | interface CssExports {

FILE: src/app/loadout/loadout-menu/MaxlightButton.tsx
  type Props (line 15) | interface Props {
  function MaxlightButton (line 21) | function MaxlightButton({ allItems, dimStore, hasClassified }: Props) {

FILE: src/app/loadout/loadout-share/LoadoutImportSheet.m.scss.d.ts
  type CssExports (line 3) | interface CssExports {

FILE: src/app/loadout/loadout-share/LoadoutImportSheet.tsx
  function LoadoutImportSheet (line 15) | function LoadoutImportSheet({

FILE: src/app/loadout/loadout-share/LoadoutShareSheet.m.scss.d.ts
  type CssExports (line 3) | interface CssExports {

FILE: src/app/loadout/loadout-share/LoadoutShareSheet.tsx
  function LoadoutShareSheet (line 20) | function LoadoutShareSheet({

FILE: src/app/loadout/loadout-share/loadout-import.ts
  type UrlLoadoutParameters (line 16) | interface UrlLoadoutParameters {
  type DecodedShareLink (line 23) | type DecodedShareLink =
  function getDecodedLoadout (line 37) | async function getDecodedLoadout(decodedUrl: DecodedShareLink): Promise<...
  function decodeShareUrl (line 58) | function decodeShareUrl(shareUrl: string): DecodedShareLink | undefined {
  function decodeUrlLoadout (line 78) | function decodeUrlLoadout(search: string): Loadout | undefined {
  function getDimSharedLoadout (line 88) | async function getDimSharedLoadout(shareId: string) {
  function preprocessReceivedLoadout (line 97) | function preprocessReceivedLoadout(loadout: Loadout): Loadout {

FILE: src/app/loadout/loadout-type-converters.ts
  function convertDimLoadoutToApiLoadout (line 32) | function convertDimLoadoutToApiLoadout(dimLoadout: DimLoadout): Loadout {
  function convertDimLoadoutItemToLoadoutItem (line 52) | function convertDimLoadoutItemToLoadoutItem(item: DimLoadoutItem): Loado...
  function migrateLoadoutParameters (line 71) | function migrateLoadoutParameters(
  function convertDimApiLoadoutToLoadout (line 91) | function convertDimApiLoadoutToLoadout(loadout: Loadout): DimLoadout {
  function convertDimApiLoadoutItemToLoadoutItem (line 107) | function convertDimApiLoadoutItemToLoadoutItem(
  function convertDestinyLoadoutComponentToInGameLoadout (line 137) | function convertDestinyLoadoutComponentToInGameLoadout(
  function resolveInGameLoadoutIdentifiers (line 162) | function resolveInGameLoadoutIdentifiers(
  function convertInGameLoadoutToDimLoadout (line 172) | function convertInGameLoadoutToDimLoadout(
  function convertInGameLoadoutPlugItemHashesToSocketOverrides (line 249) | function convertInGameLoadoutPlugItemHashesToSocketOverrides(

FILE: src/app/loadout/loadout-types.ts
  type LoadoutItem (line 8) | type LoadoutItem = DimApiLoadoutItem & {
  type Loadout (line 26) | type Loadout = Omit<DimApiLoadout, 'equipped' | 'unequipped'> & {
  type InGameLoadout (line 36) | type InGameLoadout = DestinyLoadoutComponent & {
  type ResolvedLoadoutItem (line 67) | interface ResolvedLoadoutItem {
  type ResolvedLoadoutMod (line 90) | interface ResolvedLoadoutMod {
  type Assignment (line 98) | interface Assignment {
  type PluggingAction (line 112) | interface PluggingAction extends Assignment {
  function isInGameLoadout (line 133) | function isInGameLoadout(loadout: Loadout | InGameLoadout): loadout is I...

FILE: src/app/loadout/loadout-ui/BucketPlaceholder.m.scss.d.ts
  type CssExports (line 3) | interface CssExports {

FILE: src/app/loadout/loadout-ui/BucketPlaceholder.tsx
  function BucketPlaceholder (line 11) | function BucketPlaceholder({

FILE: src/app/loadout/loadout-ui/EmptySubclass.tsx
  function EmptySubclass (line 1) | function EmptySubclass({ border }: { border?: boolean }) {

FILE: src/app/loadout/loadout-ui/FashionMods.m.scss.d.ts
  type CssExports (line 3) | interface CssExports {

FILE: src/app/loadout/loadout-ui/FashionMods.tsx
  function FashionMods (line 15) | function FashionMods({

FILE: src/app/loadout/loadout-ui/LoadoutItemCategorySection.m.scss.d.ts
  type CssExports (line 3) | interface CssExports {

FILE: src/app/loadout/loadout-ui/LoadoutItemCategorySection.tsx
  function LoadoutItemCategorySection (line 41) | function LoadoutItemCategorySection({
  function ItemBucket (line 173) | function ItemBucket({

FILE: src/app/loadout/loadout-ui/LoadoutMods.m.scss.d.ts
  type CssExports (line 3) | interface CssExports {

FILE: src/app/loadout/loadout-ui/LoadoutMods.tsx
  function ShowModAssignmentButton (line 308) | function ShowModAssignmentButton({

FILE: src/app/loadout/loadout-ui/LoadoutParametersDisplay.m.scss.d.ts
  type CssExports (line 3) | interface CssExports {

FILE: src/app/loadout/loadout-ui/LoadoutParametersDisplay.tsx
  function hasVisibleLoadoutParameters (line 18) | function hasVisibleLoadoutParameters(params: LoadoutParameters | undefin...
  function LoadoutParametersDisplay (line 30) | function LoadoutParametersDisplay({ params }: { params: LoadoutParameter...
  function StatConstraintRange (line 93) | function StatConstraintRange({
  function StatConstraintRangeExpression (line 108) | function StatConstraintRangeExpression({ statConstraint }: { statConstra...
  function SetBonuses (line 151) | function SetBonuses({ setBonuses }: { setBonuses: SetBonusCounts }) {

FILE: src/app/loadout/loadout-ui/LoadoutSubclassSection.m.scss.d.ts
  type CssExports (line 3) | interface CssExports {

FILE: src/app/loadout/loadout-ui/LoadoutSubclassSection.tsx
  function LoadoutSubclassSection (line 20) | function LoadoutSubclassSection({
  function SubclassIcon (line 42) | function SubclassIcon({
  function SubclassContainer (line 93) | function SubclassContainer({
  function SubclassMods (line 110) | function SubclassMods({

FILE: src/app/loadout/loadout-ui/OptimizerButton.tsx
  function OptimizerButton (line 13) | function OptimizerButton({
  function armorItemsMissing (line 41) | function armorItemsMissing(items?: ResolvedLoadoutItem[]) {

FILE: src/app/loadout/loadout-ui/PlugDef.tsx
  function PlugDef (line 12) | function PlugDef({

FILE: src/app/loadout/loadout-ui/Sockets.m.scss.d.ts
  type CssExports (line 3) | interface CssExports {

FILE: src/app/loadout/loadout-ui/Sockets.tsx
  function Sockets (line 30) | function Sockets({
  function VendorItemPlug (line 130) | function VendorItemPlug({ item }: { item: DimItem }) {

FILE: src/app/loadout/loadout-ui/menu-hooks.m.scss.d.ts
  type CssExports (line 3) | interface CssExports {

FILE: src/app/loadout/loadout-ui/menu-hooks.tsx
  type LoadoutSpecialization (line 30) | type LoadoutSpecialization = (typeof loadoutSpecializations)[number];
  type FilterPillType (line 31) | type FilterPillType =
  function useLoadoutFilterPills (line 46) | function useLoadoutFilterPills(
  function groupLoadoutsByHashtag (line 206) | function groupLoadoutsByHashtag(loadouts: Loadout[]): { [hashtag: string...
  function AnalysisProgress (line 232) | function AnalysisProgress({
  function searchAndSortLoadoutsByQuery (line 269) | function searchAndSortLoadoutsByQuery(
  function FashionIcon (line 291) | function FashionIcon({ className }: { className: string }) {
  function ModificationsIcon (line 305) | function ModificationsIcon({ className }: { className: string }) {

FILE: src/app/loadout/mod-assignment-drawer/ModAssignmentDrawer.m.scss.d.ts
  type CssExports (line 3) | interface CssExports {

FILE: src/app/loadout/mod-assignment-drawer/ModAssignmentDrawer.tsx
  function Header (line 23) | function Header({
  function ModAssignmentDrawer (line 55) | function ModAssignmentDrawer({

FILE: src/app/loadout/mod-assignment-drawer/selectors.ts
  function useEquippedLoadoutArmorAndSubclass (line 31) | function useEquippedLoadoutArmorAndSubclass(
  function useLoadoutMods (line 94) | function useLoadoutMods(loadout: Loadout, storeId: string) {

FILE: src/app/loadout/mod-assignment-utils.test.ts
  function processAction (line 20) | function processAction(defs: D2ManifestDefinitions, originalItem: DimIte...
  function processActions (line 71) | function processActions(
  function applyMods (line 144) | function applyMods(
  function checkNumRequiredActions (line 158) | function checkNumRequiredActions(strategy: PluggingAction[], num: number) {

FILE: src/app/loadout/mod-assignment-utils.ts
  type ModAssignments (line 41) | interface ModAssignments {
  type ModMap (line 53) | interface ModMap {
  function categorizeArmorMods (line 82) | function categorizeArmorMods(
  function getUpgradeCost (line 170) | function getUpgradeCost(
  type EnergyUpgradeCostModel (line 221) | interface EnergyUpgradeCostModel {
  function getExoticArtificeCosts (line 228) | function getExoticArtificeCosts(defs: D2ManifestDefinitions): number[] |...
  function compareCosts (line 258) | function compareCosts(a: number[], b: number[]) {
  function fitMostMods (line 284) | function fitMostMods({
  function getArmorSocketsAndMods (line 557) | function getArmorSocketsAndMods(
  function assignBucketSpecificMods (line 604) | function assignBucketSpecificMods(
  function pickPlugPositions (line 670) | function pickPlugPositions(
  function createPluggingStrategy (line 761) | function createPluggingStrategy(
  function isActivityModValid (line 933) | function isActivityModValid(
  function calculateUpgradeCost (line 945) | function calculateUpgradeCost(
  function buildItemEnergy (line 974) | function buildItemEnergy({
  type ItemEnergy (line 991) | interface ItemEnergy {
  function isModEnergyValid (line 1003) | function isModEnergyValid(
  function isAssigningToDefault (line 1018) | function isAssigningToDefault(item: DimItem, assignment: Assignment) {
  function countBucketIndependentModChangesForItem (line 1040) | function countBucketIndependentModChangesForItem(

FILE: src/app/loadout/mod-permutations.ts
  function generateModPermutations (line 3) | function generateModPermutations(mods: (PluggableInventoryItemDefinition...
  function generatePermutationsOfFive (line 16) | function generatePermutationsOfFive<T>(

FILE: src/app/loadout/mod-utils.ts
  function isInsertableArmor2Mod (line 53) | function isInsertableArmor2Mod(
  function createGetModRenderKey (line 75) | function createGetModRenderKey() {
  function groupModsByModType (line 88) | function groupModsByModType(plugs: PluggableInventoryItemDefinition[]) {
  function mapToAvailableModCostVariant (line 120) | function mapToAvailableModCostVariant(plugHash: number, unlockedPlugs: S...
  function mapToNonReducedModCostVariant (line 137) | function mapToNonReducedModCostVariant(plugHash: number): number {
  function isReducedModCostVariant (line 141) | function isReducedModCostVariant(plugHash: number): boolean {
  function mapToOtherModCostVariant (line 148) | function mapToOtherModCostVariant(plugHash: number): number | undefined {
  function getModExclusionGroup (line 157) | function getModExclusionGroup(mod: PluggableInventoryItemDefinition): st...

FILE: src/app/loadout/plug-drawer/Footer.m.scss.d.ts
  type CssExports (line 3) | interface CssExports {

FILE: src/app/loadout/plug-drawer/Footer.tsx
  function Footer (line 11) | function Footer({

FILE: src/app/loadout/plug-drawer/PlugDrawer.tsx
  type Props (line 18) | interface Props {
  function PlugDrawer (line 59) | function PlugDrawer({

FILE: src/app/loadout/plug-drawer/PlugSection.m.scss.d.ts
  type CssExports (line 3) | interface CssExports {

FILE: src/app/loadout/plug-drawer/PlugSection.tsx
  function PlugSection (line 16) | function PlugSection({

FILE: src/app/loadout/plug-drawer/PlugStackableIcon.m.scss.d.ts
  type CssExports (line 3) | interface CssExports {

FILE: src/app/loadout/plug-drawer/PlugStackableIcon.tsx
  function PlugStackableIcon (line 9) | function PlugStackableIcon({

FILE: src/app/loadout/plug-drawer/SelectablePlug.m.scss.d.ts
  type CssExports (line 3) | interface CssExports {

FILE: src/app/loadout/plug-drawer/SelectablePlug.tsx
  function SelectablePlug (line 22) | function SelectablePlug({
  function SelectablePlugDetails (line 134) | function SelectablePlugDetails({

FILE: src/app/loadout/plug-drawer/types.ts
  type PlugSelectionType (line 5) | const enum PlugSelectionType {
  type PlugSet (line 20) | interface PlugSet {

FILE: src/app/loadout/reducer.ts
  type LoadoutsState (line 6) | interface LoadoutsState {
  type LoadoutsAction (line 13) | type LoadoutsAction = ActionType<typeof actions>;

FILE: src/app/loadout/selectors.ts
  type LoadoutsByItem (line 28) | interface LoadoutsByItem {

FILE: src/app/loadout/spreadsheets.ts
  function downloadLoadoutsCsv (line 38) | function downloadLoadoutsCsv(): ThunkResult {

FILE: src/app/loadout/stats.ts
  type FontModStatBoosts (line 47) | type FontModStatBoosts = {
  function getFontMods (line 56) | function getFontMods(mods: PluggableInventoryItemDefinition[]) {
  function includesRuntimeStatMods (line 74) | function includesRuntimeStatMods(modHashes: number[]) {
  function invertModAssignments (line 83) | function invertModAssignments(
  function getTotalModStatChanges (line 102) | function getTotalModStatChanges(

FILE: src/app/login/Login.m.scss.d.ts
  type CssExports (line 3) | interface CssExports {

FILE: src/app/login/Login.tsx
  function Login (line 16) | function Login() {

FILE: src/app/manifest/actions.ts
  function loadCoreSettings (line 12) | function loadCoreSettings(): ThunkResult {

FILE: src/app/manifest/d1-manifest-service.ts
  constant TAG (line 17) | const TAG = 'manifest';
  function getManifest (line 34) | function getManifest(): ThunkResult<AllD1DestinyManifestComponents> {
  function doGetManifest (line 38) | function doGetManifest(): ThunkResult<AllD1DestinyManifestComponents> {
  function loadManifest (line 67) | function loadManifest(): ThunkResult<AllD1DestinyManifestComponents> {
  function loadManifestRemote (line 88) | function loadManifestRemote(
  function saveManifestToIndexedDB (line 113) | async function saveManifestToIndexedDB(typedArray: unknown, version: str...
  function deleteManifestFile (line 128) | function deleteManifestFile() {
  function loadManifestFromCache (line 137) | async function loadManifestFromCache(version: string): Promise<AllD1Dest...

FILE: src/app/manifest/manifest-service-json.ts
  constant TAG (line 34) | const TAG = 'manifest';
  function checkForNewManifest (line 132) | async function checkForNewManifest() {
  type TrimTableName (line 138) | type TrimTableName<T extends string> = T extends `Destiny${infer U}Defin...
  type TableShortName (line 139) | type TableShortName = TrimTableName<DestinyManifestComponentName>;
  function getManifest (line 146) | function getManifest(
  function doGetManifest (line 152) | function doGetManifest(
  function loadManifest (line 185) | function loadManifest(tableAllowList: TableShortName[]): ThunkResult<All...
  function loadManifestRemote (line 223) | function loadManifestRemote(
  function downloadManifestComponents (line 244) | async function downloadManifestComponents(
  function saveManifestToIndexedDB (line 299) | async function saveManifestToIndexedDB(
  function deleteManifestFile (line 327) | async function deleteManifestFile() {
  function loadManifestFromCache (line 342) | async function loadManifestFromCache(

FILE: src/app/manifest/reducer.ts
  type ManifestState (line 10) | interface ManifestState {
  type ManifestAction (line 22) | type ManifestAction = ActionType<typeof actions>;

FILE: src/app/manifest/selectors.ts
  function useD1Definitions (line 21) | function useD1Definitions() {
  function useD2Definitions (line 24) | function useD2Definitions() {
  function useDefinitions (line 27) | function useDefinitions() {

FILE: src/app/material-counts/MaterialCounts.m.scss.d.ts
  type CssExports (line 3) | interface CssExports {

FILE: src/app/material-counts/MaterialCounts.tsx
  function MaterialCounts (line 52) | function MaterialCounts({
  function CurrencyGroup (line 150) | function CurrencyGroup({

FILE: src/app/material-counts/MaterialCountsWrappers.m.scss.d.ts
  type CssExports (line 3) | interface CssExports {

FILE: src/app/material-counts/MaterialCountsWrappers.tsx
  function showMaterialCount (line 17) | function showMaterialCount() {
  function MaterialCountsSheet (line 21) | function MaterialCountsSheet() {
  function MaterialCountsTooltip (line 40) | function MaterialCountsTooltip() {

FILE: src/app/notifications/Notification.m.scss.d.ts
  type CssExports (line 3) | interface CssExports {

FILE: src/app/notifications/Notification.tsx
  type Props (line 21) | interface Props extends MotionProps {
  function Notification (line 26) | function Notification({ notification, onClose, ...animation }: Props) {

FILE: src/app/notifications/NotificationButton.m.scss.d.ts
  type CssExports (line 3) | interface CssExports {

FILE: src/app/notifications/NotificationButton.tsx
  function NotificationButton (line 9) | function NotificationButton({

FILE: src/app/notifications/NotificationsContainer.m.scss.d.ts
  type CssExports (line 3) | interface CssExports {

FILE: src/app/notifications/NotificationsContainer.tsx
  function NotificationsContainer (line 16) | function NotificationsContainer() {

FILE: src/app/notifications/notifications.ts
  type NotificationType (line 4) | type NotificationType = 'success' | 'info' | 'warning' | 'error' | 'prog...
  type NotifyInput (line 6) | interface NotifyInput {
  type Notify (line 23) | interface Notify {
  class NotificationError (line 41) | class NotificationError extends Error {
    method constructor (line 48) | constructor(
  function showNotification (line 77) | function showNotification(notification: NotifyInput) {

FILE: src/app/organizer/Columns.m.scss.d.ts
  type CssExports (line 3) | interface CssExports {

FILE: src/app/organizer/Columns.tsx
  function getColumnSelectionId (line 101) | function getColumnSelectionId(column: ColumnDefinition) {
  function c (line 154) | function c<V extends Value>(columnDef: ColumnDefinition<V>): ColumnDefin...
  function modsColumn (line 167) | function modsColumn(
  function perksGridColumn (line 197) | function perksGridColumn(
  function getColumns (line 232) | function getColumns(
  function getStatColumns (line 979) | function getStatColumns(
  function LoadoutsCell (line 1243) | function LoadoutsCell({
  function PerksCell (line 1273) | function PerksCell({
  function D1PerksCell (line 1332) | function D1PerksCell({ item }: { item: D1Item }) {
  function StoreLocation (line 1385) | function StoreLocation({ storeId }: { storeId: string }) {
  function perkString (line 1395) | function perkString(sockets: DimSocket[]): string | undefined {
  function getIntrinsicSockets (line 1407) | function getIntrinsicSockets(item: DimItem): DimSocket[] {
  function buildStatInfo (line 1421) | function buildStatInfo(items: DimItem[]): DimStat[] {
  function source (line 1440) | function source(item: DimItem) {

FILE: src/app/organizer/CustomStatColumns.tsx
  function createCustomStatColumns (line 10) | function createCustomStatColumns(

FILE: src/app/organizer/DropDown.m.scss.d.ts
  type CssExports (line 3) | interface CssExports {

FILE: src/app/organizer/DropDown.tsx
  type DropDownItem (line 10) | interface DropDownItem {
  function MenuItem (line 18) | function MenuItem({ item, forClass }: { item: DropDownItem; forClass?: D...
  function DropDown (line 39) | function DropDown({

FILE: src/app/organizer/ItemActions.m.scss.d.ts
  type CssExports (line 3) | interface CssExports {

FILE: src/app/organizer/ItemActions.tsx
  type TagCommandInfo (line 22) | interface TagCommandInfo {
  function ItemActions (line 34) | function ItemActions({

FILE: src/app/organizer/ItemTable.m.scss.d.ts
  type CssExports (line 3) | interface CssExports {

FILE: src/app/organizer/ItemTable.tsx
  constant EXPAND_INCREMENT (line 80) | const EXPAND_INCREMENT = 20;
  function ItemTable (line 82) | function ItemTable({ categories }: { categories: ItemCategoryTreeNode[] ...
  function buildRows (line 546) | function buildRows(items: DimItem[], filteredColumns: ColumnDefinition[]) {
  function sortRows (line 577) | function sortRows(
  function TableRow (line 612) | function TableRow({
  function columnSetting (line 647) | function columnSetting(itemType: 'weapon' | 'armor' | 'ghost') {
  function ItemListExpander (line 658) | function ItemListExpander({ onExpand, numItems }: { onExpand: () => void...

FILE: src/app/organizer/ItemTypeSelector.m.scss.d.ts
  type CssExports (line 3) | interface CssExports {

FILE: src/app/organizer/ItemTypeSelector.tsx
  type ItemCategoryTreeNode (line 16) | interface ItemCategoryTreeNode {
  function getSelectionTree (line 321) | function getSelectionTree(destinyVersion: DestinyVersion) {
  function ItemTypeSelector (line 335) | function ItemTypeSelector({

FILE: src/app/organizer/Organizer.m.scss.d.ts
  type CssExports (line 3) | interface CssExports {

FILE: src/app/organizer/Organizer.tsx
  type Props (line 17) | interface Props {
  function drillToSelection (line 26) | function drillToSelection(
  function Organizer (line 52) | function Organizer({ account }: Props) {

FILE: src/app/organizer/table-types.ts
  type Value (line 9) | type Value = string | number | boolean | undefined;
  type ColumnGroup (line 14) | interface ColumnGroup {
  type CSVColumn (line 20) | type CSVColumn = [name: string, value: CsvValue];
  type ColumnDefinition (line 26) | interface ColumnDefinition<V extends Value = Value> {
  type SpreadsheetContext (line 88) | interface SpreadsheetContext {
  type Row (line 95) | interface Row {
  type TableContext (line 103) | interface TableContext {
  type ColumnWithStat (line 110) | type ColumnWithStat = ColumnDefinition & { statHash: number };

FILE: src/app/progress/ActivityModifier.m.scss.d.ts
  type CssExports (line 3) | interface CssExports {

FILE: src/app/progress/ActivityModifier.tsx
  function ActivityModifier (line 8) | function ActivityModifier({

FILE: src/app/progress/BountyGuide.m.scss.d.ts
  type CssExports (line 3) | interface CssExports {

FILE: src/app/progress/BountyGuide.tsx
  type KillType (line 26) | const enum KillType {
  type DefType (line 49) | type DefType =
  type BountyFilter (line 73) | interface BountyFilter {
  function BountyGuide (line 83) | function BountyGuide({
  function contentFromDisplayProperties (line 234) | function contentFromDisplayProperties(
  function PillContent (line 252) | function PillContent({
  function matchPill (line 293) | function matchPill(type: DefType, hash: number, filters: BountyFilter[]) {
  function matchBountyFilters (line 300) | function matchBountyFilters(

FILE: src/app/progress/Event.m.scss.d.ts
  type CssExports (line 3) | interface CssExports {

FILE: src/app/progress/Event.tsx
  function Event (line 25) | function Event({

FILE: src/app/progress/FactionIcon.m.scss.d.ts
  type CssExports (line 3) | interface CssExports {

FILE: src/app/progress/FactionIcon.tsx
  function FactionIcon (line 10) | function FactionIcon({

FILE: src/app/progress/Milestones.m.scss.d.ts
  type CssExports (line 3) | interface CssExports {

FILE: src/app/progress/Milestones.tsx
  function Milestones (line 25) | function Milestones({
  function milestonesForProfile (line 79) | function milestonesForProfile(
  function milestonesForCharacter (line 103) | function milestonesForCharacter(

FILE: src/app/progress/Objective.m.scss.d.ts
  type CssExports (line 3) | interface CssExports {

FILE: src/app/progress/Objective.tsx
  function Objective (line 29) | function Objective({
  function ObjectiveRow (line 134) | function ObjectiveRow({
  function ObjectiveCheckbox (line 156) | function ObjectiveCheckbox({
  function ObjectiveProgressBar (line 176) | function ObjectiveProgressBar({
  function ObjectiveProgress (line 198) | function ObjectiveProgress({ children }: { children: React.ReactNode }) {
  function ObjectiveDescription (line 205) | function ObjectiveDescription({
  function ObjectiveText (line 223) | function ObjectiveText({ children }: { children: React.ReactNode }) {
  function ObjectiveValue (line 231) | function ObjectiveValue({

FILE: src/app/progress/Pathfinder.m.scss.d.ts
  type CssExports (line 3) | interface CssExports {

FILE: src/app/progress/Pathfinder.tsx
  function Pathfinder (line 17) | function Pathfinder({

FILE: src/app/progress/Progress.m.scss.d.ts
  type CssExports (line 3) | interface CssExports {

FILE: src/app/progress/Progress.tsx
  function Progress (line 35) | function Progress({ account }: { account: DestinyAccount }) {

FILE: src/app/progress/Pursuit.tsx
  function Pursuit (line 20) | function Pursuit({
  function showPursuitAsExpired (line 95) | function showPursuitAsExpired(item: DimItem) {

FILE: src/app/progress/PursuitGrid.m.scss.d.ts
  type CssExports (line 3) | interface CssExports {

FILE: src/app/progress/PursuitGrid.tsx
  function PursuitGrid (line 9) | function PursuitGrid({

FILE: src/app/progress/PursuitItem.m.scss.d.ts
  type CssExports (line 3) | interface CssExports {

FILE: src/app/progress/PursuitItem.tsx
  function PursuitItem (line 22) | function PursuitItem({
  function ProgressBar (line 85) | function ProgressBar({
  function StackAmount (line 99) | function StackAmount({ amount, full }: { amount: number; full?: boolean ...

FILE: src/app/progress/Pursuits.tsx
  function Pursuits (line 36) | function Pursuits({ store }: { store: DimStore }) {
  function PursuitsGroup (line 79) | function PursuitsGroup({

FILE: src/app/progress/Raid.tsx
  function Raid (line 10) | function Raid({ raid }: { raid: DestinyMilestone }) {

FILE: src/app/progress/RaidDisplay.m.scss.d.ts
  type CssExports (line 3) | interface CssExports {

FILE: src/app/progress/RaidDisplay.tsx
  function RaidDisplay (line 25) | function RaidDisplay(props: {
  function RaidActivity (line 50) | function RaidActivity({

FILE: src/app/progress/Raids.tsx
  function Raids (line 14) | function Raids({

FILE: src/app/progress/Ranks.tsx
  function Ranks (line 58) | function Ranks({

FILE: src/app/progress/ReputationRank.m.scss.d.ts
  type CssExports (line 3) | interface CssExports {

FILE: src/app/progress/ReputationRank.tsx
  function ReputationRank (line 15) | function ReputationRank({
  function ReputationRankIcon (line 86) | function ReputationRankIcon({ progress }: { progress: DestinyProgression...

FILE: src/app/progress/Reward.m.scss.d.ts
  type CssExports (line 3) | interface CssExports {

FILE: src/app/progress/Reward.tsx
  function Reward (line 12) | function Reward({

FILE: src/app/progress/SeasonalChallenges.tsx
  function SeasonalChallenges (line 19) | function SeasonalChallenges({
  function flattenRecords (line 70) | function flattenRecords(nodeTree: DimPresentationNode): DimRecord[] {

FILE: src/app/progress/SeasonalRank.m.scss.d.ts
  type CssExports (line 3) | interface CssExports {

FILE: src/app/progress/SeasonalRank.tsx
  function SeasonalRank (line 25) | function SeasonalRank({
  function SeasonPrestigeRank (line 173) | function SeasonPrestigeRank({
  function ReputationRankIcon (line 225) | function ReputationRankIcon({
  function getSeasonPassStatus (line 258) | function getSeasonPassStatus(
  function fakeReward (line 315) | function fakeReward(hash: number, level: number): DestinyProgressionRewa...

FILE: src/app/progress/TrackedTriumphs.m.scss.d.ts
  type CssExports (line 3) | interface CssExports {

FILE: src/app/progress/TrackedTriumphs.tsx
  function TrackedTriumphs (line 13) | function TrackedTriumphs({ searchQuery }: { searchQuery?: string }) {

FILE: src/app/progress/WellRestedPerkIcon.tsx
  function WellRestedPerkIcon (line 8) | function WellRestedPerkIcon({

FILE: src/app/progress/engrams.ts
  type PowerCap (line 9) | const enum PowerCap {
  function getEngramPowerBonus (line 77) | function getEngramPowerBonus(

FILE: src/app/progress/milestone-items.ts
  function milestoneToItems (line 25) | function milestoneToItems(
  function milestoneExpiration (line 72) | function milestoneExpiration(milestone: DestinyMilestone): DimPursuitExp...
  function availableQuestToItem (line 82) | function availableQuestToItem(
  function activityMilestoneToItem (line 153) | function activityMilestoneToItem(
  function weeklyClanMilestoneToItems (line 201) | function weeklyClanMilestoneToItems(
  function makeFakePursuitItem (line 233) | function makeFakePursuitItem(
  function makeMilestonePursuitItem (line 308) | function makeMilestonePursuitItem(
  function milestoneTypeName (line 342) | function milestoneTypeName(milestoneType: DestinyMilestoneType) {
  function recordToPursuitItem (line 359) | function recordToPursuitItem(
  function calculatePercentComplete (line 403) | function calculatePercentComplete(objectives: DestinyObjectiveProgress[]) {
  function processRewards (line 414) | function processRewards(

FILE: src/app/progress/xp.ts
  function getXPValue (line 18) | function getXPValue(hash: number) {

FILE: src/app/records/Collectible.tsx
  type Props (line 5) | interface Props {
  function Collectible (line 10) | function Collectible({ collectible, owned }: Props) {

FILE: src/app/records/CollectiblesGrid.m.scss.d.ts
  type CssExports (line 3) | interface CssExports {

FILE: src/app/records/CollectiblesGrid.tsx
  function CollectiblesGrid (line 7) | function CollectiblesGrid({ children }: { children: React.ReactNode }) {

FILE: src/app/records/Craftable.tsx
  function Craftable (line 4) | function Craftable({ craftable }: { craftable: DimCraftable }) {

FILE: src/app/records/Metric.m.scss.d.ts
  type CssExports (line 3) | interface CssExports {

FILE: src/app/records/Metric.tsx
  type Props (line 12) | interface Props {
  function Metric (line 16) | function Metric({ metric }: Props) {

FILE: src/app/records/MetricBanner.m.scss.d.ts
  type CssExports (line 3) | interface CssExports {

FILE: src/app/records/MetricBanner.tsx
  type Props (line 10) | interface Props {
  function MetricBanner (line 16) | function MetricBanner({ metricHash, objectiveProgress, className }: Prop...

FILE: src/app/records/Metrics.m.scss.d.ts
  type CssExports (line 3) | interface CssExports {

FILE: src/app/records/Metrics.tsx
  function Metrics (line 7) | function Metrics({ metrics }: { metrics: DimMetric[] }) {

FILE: src/app/records/PresentationNode.m.scss.d.ts
  type CssExports (line 3) | interface CssExports {

FILE: src/app/records/PresentationNode.tsx
  function PresentationNode (line 20) | function PresentationNode({
  function useScrollNodeIntoView (line 194) | function useScrollNodeIntoView(path: number[], presentationNodeHash: num...
  function PresentationNodeProgress (line 222) | function PresentationNodeProgress({ acquired, visible }: { acquired: num...
  function PresentationNodeTitle (line 238) | function PresentationNodeTitle({

FILE: src/app/records/PresentationNodeLeaf.tsx
  function PresentationNodeLeaf (line 19) | function PresentationNodeLeaf({
  function sortRecords (line 76) | function sortRecords(records: DimRecord[]): DimRecord[] {
  function sortCollectibles (line 109) | function sortCollectibles(collectibles: DimCollectible[]): DimCollectibl...
  function sortMetrics (line 120) | function sortMetrics(metrics: DimMetric[]): DimMetric[] {

FILE: src/app/records/PresentationNodeRoot.m.scss.d.ts
  type CssExports (line 3) | interface CssExports {

FILE: src/app/records/PresentationNodeRoot.tsx
  type Props (line 17) | interface Props {
  function PresentationNodeRoot (line 42) | function PresentationNodeRoot({

FILE: src/app/records/PresentationNodeSearchResults.m.scss.d.ts
  type CssExports (line 3) | interface CssExports {

FILE: src/app/records/PresentationNodeSearchResults.tsx
  function PresentationNodeSearchResults (line 9) | function PresentationNodeSearchResults({
  function PresentationNodeSearchResult (line 32) | function PresentationNodeSearchResult({

FILE: src/app/records/Record.m.scss.d.ts
  type CssExports (line 3) | interface CssExports {

FILE: src/app/records/Record.tsx
  type RecordInterval (line 36) | interface RecordInterval {
  function Record (line 46) | function Record({
  function getIntervals (line 240) | function getIntervals(
  function RecordGrid (line 282) | function RecordGrid({

FILE: src/app/records/Records.m.scss.d.ts
  type CssExports (line 3) | interface CssExports {

FILE: src/app/records/Records.tsx
  type Props (line 28) | interface Props {
  function Records (line 35) | function Records({ account }: Props) {

FILE: src/app/records/SetCard.m.scss.d.ts
  type CssExports (line 3) | interface CssExports {

FILE: src/app/records/SetCard.tsx
  function SetCard (line 8) | f
Copy disabled (too large) Download .json
Condensed preview — 1630 files, each showing path, character count, and a content snippet. Download the .json file for the full structured content (11,494K chars).
[
  {
    "path": ".dockerignore",
    "chars": 152,
    "preview": "# Dependency directories\nnode_modules\n\n# Logs\nlogs\n*.log\nnpm-debug.log*\nyarn-debug.log*\nyarn-error.log*\n\n# Documentation"
  },
  {
    "path": ".editorconfig",
    "chars": 215,
    "preview": "# http://editorconfig.org\nroot = true\n\n[*]\nend_of_line = lf\ninsert_final_newline = true\ntrim_trailing_whitespace = true\n"
  },
  {
    "path": ".git-blame-ignore-revs",
    "chars": 76,
    "preview": "# Added trailing commas everywhere\n4ecced03d68e8ef1c4addd24ad32d1cde3d393e9\n"
  },
  {
    "path": ".gitattributes",
    "chars": 176,
    "preview": "# Default core.autocrlf on\n* text=auto\n\nCHANGELOG.md merge=union\n\n*.png binary\n*.jpg binary\n\n# Generated files can alway"
  },
  {
    "path": ".github/FUNDING.yml",
    "chars": 461,
    "preview": "# These are supported funding model platforms\n\ngithub: [DestinyItemManager] # Replace with up to 4 GitHub Sponsors-enabl"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/bug_report.yml",
    "chars": 1732,
    "preview": "name: Bug\ndescription: File a bug or report an issue\nlabels: [Bug]\nbody:\n- type: markdown\n  attributes:\n    value: |\n   "
  },
  {
    "path": ".github/ISSUE_TEMPLATE/feature_request.yml",
    "chars": 1017,
    "preview": "name: Feature Request\ndescription: Let us know what you want to see next in DIM\nlabels: [Enhancement]\nbody:\n- type: mark"
  },
  {
    "path": ".github/actions/setup-pnpm/action.yml",
    "chars": 652,
    "preview": "name: 'Setup PNPM Environment'\ndescription: 'Setup Node.js with PNPM and install dependencies with proper caching'\n\ninpu"
  },
  {
    "path": ".github/copilot-instructions.md",
    "chars": 1445,
    "preview": "# General DIM Code Style\n\nAlways follow the [Contributing Guide](../docs/CONTRIBUTING.md).\n\n## JS\n\n- Pure JavaScript fil"
  },
  {
    "path": ".github/dependabot.yml",
    "chars": 752,
    "preview": "version: 2\nupdates:\n  - directory: /\n    package-ecosystem: \"npm\"\n    schedule:\n      interval: \"weekly\"\n      time: \"18"
  },
  {
    "path": ".github/pull_request_template.md",
    "chars": 140,
    "preview": "<!-- To add entries to the CHANGELOG.md, include lines in your commit messages that start with `Changelog:` followed by "
  },
  {
    "path": ".github/scripts/discord_changelog.py",
    "chars": 6446,
    "preview": "#!/usr/bin/env python3\n\"\"\"\nDiscord changelog helper for DIMmit.\nUsed by .github/workflows/notify-discord-changelog.yml\n\n"
  },
  {
    "path": ".github/scripts/i18n_discord.py",
    "chars": 5584,
    "preview": "#!/usr/bin/env python3\n\"\"\"\nDiscord i18n diff helper for DIMi18n.\nUsed by .github/workflows/notify-discord-i18n.yml\n\nUsag"
  },
  {
    "path": ".github/workflows/auto-merge.yml",
    "chars": 1333,
    "preview": "name: Auto-merge\n\non:\n  pull_request_target:\n\npermissions:\n  contents: write\n  pull-requests: write\n\njobs:\n  auto-merge:"
  },
  {
    "path": ".github/workflows/changelog-updater.yml",
    "chars": 1080,
    "preview": "name: Update Changelog\n\non:\n  push:\n    branches: [master]\n    paths-ignore:\n      - 'docs/CHANGELOG.md'  # Prevent infi"
  },
  {
    "path": ".github/workflows/copilot-setup-steps.yml",
    "chars": 597,
    "preview": "name: \"Copilot Setup Steps\"\n\non:\n  workflow_dispatch:\n  push:\n    paths:\n      - .github/workflows/copilot-setup-steps.y"
  },
  {
    "path": ".github/workflows/deploy-beta.yml",
    "chars": 2760,
    "preview": "name: Deploy Beta\n\non:\n  workflow_dispatch:\n  push:\n    branches:\n      - master\n\n# Ensures that only one deploy task pe"
  },
  {
    "path": ".github/workflows/deploy-prod.yml",
    "chars": 2578,
    "preview": "name: Deploy Prod\n\non:\n  workflow_dispatch:\n    inputs:\n      patch:\n        description: 'Should this be a patch releas"
  },
  {
    "path": ".github/workflows/i18n-bot-download.yml",
    "chars": 1984,
    "preview": "# This workflow runs every Saturday @ 1900 UTC (NOON PST)\nname: i18n download bot\n\non:\n  workflow_dispatch:\n  schedule:\n"
  },
  {
    "path": ".github/workflows/i18n-bot-upload.yml",
    "chars": 1174,
    "preview": "# This workflow runs whenever locale/en.json is updated on the master branch\n# It updates crowdin with new translation s"
  },
  {
    "path": ".github/workflows/i18n-update.yml",
    "chars": 542,
    "preview": "name: i18n-update\n\non:\n  push:\n    branches: [master]\n    paths:\n      - 'config/i18n.json'\n      - 'src/locale/en.json'"
  },
  {
    "path": ".github/workflows/lint-workflows.yml",
    "chars": 631,
    "preview": "name: Lint Workflows\n\non:\n  pull_request:\n    paths:\n      - '.github/workflows/**'\n      - '.github/actions/**'\n  push:"
  },
  {
    "path": ".github/workflows/notify-discord-changelog.yml",
    "chars": 527,
    "preview": "name: Notify Discord - Changelog\n\non:\n  workflow_dispatch:\n  push:\n    branches:\n      - master\n    paths:\n      - 'docs"
  },
  {
    "path": ".github/workflows/notify-discord-i18n.yml",
    "chars": 516,
    "preview": "name: Notify Discord - i18n\n\non:\n  workflow_dispatch:\n  push:\n    branches:\n      - master\n    paths:\n      - 'src/local"
  },
  {
    "path": ".github/workflows/pr-cleanup.yml",
    "chars": 741,
    "preview": "name: PR Cleanup\non:\n  pull_request:\n    types: [closed]\n\njobs:\n  # Remove the preview build directory\n  cleanup:\n    ru"
  },
  {
    "path": ".github/workflows/pr-reports.yml",
    "chars": 3651,
    "preview": "name: PR Reports\n\non:\n  workflow_run:\n    workflows: ['PR Validation']\n    types: [completed]\n\npermissions:\n  checks: wr"
  },
  {
    "path": ".github/workflows/pr-validation.yml",
    "chars": 6392,
    "preview": "name: PR Validation\n\non:\n  pull_request:\n    types: [opened, synchronize, reopened]\n    paths-ignore:\n      - 'docs/**'\n"
  },
  {
    "path": ".gitignore",
    "chars": 334,
    "preview": "dist/\n.settings/\n.idea/\nnode_modules/\ncoverage/\n*.DS_Store\nconfig/dim_travis.rsa\ncert.pem\nkey.pem\nca.crt\nca.key\n.bracket"
  },
  {
    "path": ".gitmodules",
    "chars": 119,
    "preview": "[submodule \"destiny-icons\"]\n\tpath = destiny-icons\n\turl = https://github.com/justrealmilk/destiny-icons\n\tbranch = master"
  },
  {
    "path": ".husky/pre-commit",
    "chars": 30,
    "preview": "node_modules/.bin/lint-staged\n"
  },
  {
    "path": ".npmrc",
    "chars": 106,
    "preview": "# Tells pnpm to use a shell emulator that works the same on macOS, linux, and Windows\nshell-emulator=true\n"
  },
  {
    "path": ".nvmrc",
    "chars": 2,
    "preview": "24"
  },
  {
    "path": ".prettierignore",
    "chars": 73,
    "preview": "Gruntfile.js\ntools/\ndist/\nextension/\n*.md\n*.yml\n*.m.scss.d.ts\nsrc/data/**"
  },
  {
    "path": ".prettierrc",
    "chars": 98,
    "preview": "{\n  \"printWidth\": 100,\n  \"singleQuote\": true,\n  \"plugins\": [\"prettier-plugin-organize-imports\"]\n}\n"
  },
  {
    "path": ".stylelintrc",
    "chars": 2784,
    "preview": "{\n  \"plugins\": [\n    \"stylelint-order\"\n  ],\n  \"extends\": [\n    \"stylelint-config-standard-scss\",\n    \"stylelint-config-c"
  },
  {
    "path": ".svgo.yml",
    "chars": 91,
    "preview": "plugins:\n  - name: preset-default\n    params:\n      overrides:\n        removeViewBox: false"
  },
  {
    "path": ".vscode/css.json",
    "chars": 281,
    "preview": "{\n  \"version\": 1.1,\n  \"properties\": [\n    {\n      \"name\": \"composes\",\n      \"description\": \"css modules compose\"\n    }\n "
  },
  {
    "path": ".vscode/dim.code-snippets",
    "chars": 1725,
    "preview": "{\n  // Place your global snippets here. Each snippet is defined under a snippet name and has a scope, prefix, body and\n "
  },
  {
    "path": ".vscode/extensions.json",
    "chars": 513,
    "preview": "{\n  // See http://go.microsoft.com/fwlink/?LinkId=827846\n  // for the documentation about the extensions.json format\n  \""
  },
  {
    "path": ".vscode/launch.json",
    "chars": 1313,
    "preview": "{\n  // Use IntelliSense to learn about possible attributes.\n  // Hover to view descriptions of existing attributes.\n  //"
  },
  {
    "path": ".vscode/settings.json",
    "chars": 2183,
    "preview": "{\n  \"editor.tabSize\": 2,\n  \"editor.trimAutoWhitespace\": true,\n  \"files.trimTrailingWhitespace\": true,\n  \"typescript.tsdk"
  },
  {
    "path": ".vscode/tasks.json",
    "chars": 369,
    "preview": "{\n  // See https://go.microsoft.com/fwlink/?LinkId=733558\n  // for the documentation about the tasks.json format\n  \"vers"
  },
  {
    "path": "LICENSE.md",
    "chars": 1077,
    "preview": "MIT License\n\nCopyright (c) 2018 Destiny Item Manager\n\nPermission is hereby granted, free of charge, to any person obtain"
  },
  {
    "path": "README.md",
    "chars": 11644,
    "preview": "[![Crowdin](https://badges.crowdin.net/destiny-item-manager/localized.svg)](https://crowdin.com/project/destiny-item-man"
  },
  {
    "path": "babel.config.cjs",
    "chars": 3156,
    "preview": "const coreJSPackage = require('core-js/package.json');\n\nmodule.exports = function (api) {\n  const isProduction = api.env"
  },
  {
    "path": "build/deploy-prod.sh",
    "chars": 1020,
    "preview": "#!/bin/sh -exu\n\ngit config --global user.email \"destinyitemmanager@gmail.com\"\ngit config --global user.name \"DIM Release"
  },
  {
    "path": "build/purge-cloudflare.sh",
    "chars": 765,
    "preview": "#!/bin/bash -eux\n\nset -o pipefail\n\n# Set variables CLOUDFLARE_EMAIL, CLOUDFLARE_KEY, and APP_DOMAIN\n\n# Purge the cache i"
  },
  {
    "path": "build/rsync-deploy.sh",
    "chars": 645,
    "preview": "#!/bin/sh -exu\n\nREMOTE_SHELL=\"ssh -i ~/.ssh/dim.rsa -o StrictHostKeyChecking=no\"\n\n# Sync everything but the HTML first, "
  },
  {
    "path": "build/test-changelog.js",
    "chars": 2683,
    "preview": "#!/usr/bin/env node\n\n// Simple test for the changelog update logic\nimport { readFileSync, unlinkSync, writeFileSync } fr"
  },
  {
    "path": "build/update-changelog.js",
    "chars": 9257,
    "preview": "#!/usr/bin/env node\n\nimport { readFileSync } from 'fs';\nimport { dirname, join } from 'path';\nimport { fileURLToPath } f"
  },
  {
    "path": "config/.well-known/android-config.beta.json",
    "chars": 350,
    "preview": "[\n  {\n    \"relation\": [\n      \"delegate_permission/common.handle_all_urls\"\n    ],\n    \"target\": {\n      \"namespace\": \"an"
  },
  {
    "path": "config/.well-known/android-config.json",
    "chars": 993,
    "preview": "[\n  {\n    \"relation\": [\n      \"delegate_permission/common.handle_all_urls\"\n    ],\n    \"target\": {\n      \"namespace\": \"an"
  },
  {
    "path": "config/.well-known/apple-config.json",
    "chars": 488,
    "preview": "{\n  \"applinks\": {\n    \"details\": [\n      {\n        \"appIDs\": [\"P7G764E7RR.com.destinyitemmanager.app\"],\n        \"compone"
  },
  {
    "path": "config/content-security-policy.ts",
    "chars": 2831,
    "preview": "import builder from 'content-security-policy-builder';\nimport { type FeatureFlags } from './feature-flags.ts';\n\nconst SE"
  },
  {
    "path": "config/cspell/bungie-dict.txt",
    "chars": 417,
    "preview": "+s\nbnet\nBungie\nCalus\ncooldown\nCrota*\ncrownofsorrow\ncryptarchs\ndaito\nEspaña\nEververse\nexlusive\nFelwinter*\nfotl\nFynch\nGahl"
  },
  {
    "path": "config/cspell/dim-dict.txt",
    "chars": 646,
    "preview": "ARGH\nbois\ncurations\ndedupe\ndeduping\ndeduplicating\ndequip\ndequipped\ndequipping\ndequips\nDIM\nDTR\ndupelower\nelgato\nequippabi"
  },
  {
    "path": "config/cspell/dim-username-dict.txt",
    "chars": 89,
    "preview": "48klocs\nbhollis\ndelphiactual\niihavetoes\nJFLAY\nlowlines\nMercules\npandapaxxy\ntehdaw\nvthorn\n"
  },
  {
    "path": "config/cspell/programming-dict.txt",
    "chars": 450,
    "preview": "asyncs\nbrotli\ncaniuse\ncanonicalization\ncanonicalize\nceaser\nclsx\nCruver\ndestructurable\ndivs\nDont\nfalsyness\nfrecency\ngstat"
  },
  {
    "path": "config/dim_travis.rsa.pub",
    "chars": 742,
    "preview": "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQCiwgjtkq2QrAjJnK2EYfbkSGYTLIaJfQ2ILZ79ntBIti2ZXIvagbabOjjiirfIJrtN2j4zT0/UExGsUwUZ"
  },
  {
    "path": "config/feature-flags.ts",
    "chars": 2526,
    "preview": "/**\n * Return a set of compile time feature flags. These values will be inlined into\n * the code at build time, based on"
  },
  {
    "path": "config/i18n.json",
    "chars": 90576,
    "preview": "{\n  \"AWA\": {\n    \"ConfirmDescription\": \"Please use the Destiny 2 Companion App to approve DIM to modify your items.\",\n  "
  },
  {
    "path": "config/manifest-webapp.ts",
    "chars": 1758,
    "preview": "export default function createWebAppManifest(publicPath: string) {\n  return {\n    name: 'Destiny Item Manager',\n    shor"
  },
  {
    "path": "config/notify-webpack-plugin.ts",
    "chars": 1237,
    "preview": "// Originally from https://github.com/joshhunt/notify-webpack-plugin/, converted to TypeScript\n\nimport { type Compiler, "
  },
  {
    "path": "config/webpack.ts",
    "chars": 19279,
    "preview": "import { InjectManifest } from '@aaroon/workbox-rspack-plugin';\nimport filterWebpackStats from '@bundle-stats/plugin-web"
  },
  {
    "path": "crowdin.yml",
    "chars": 235,
    "preview": "\"project_id_env\": \"CROWDIN_PROJECT_ID\"\n\"api_token_env\": \"CROWDIN_PERSONAL_TOKEN\"\n\"base_path\": \".\"\n\n\"files\": [\n  {\n    \"s"
  },
  {
    "path": "cspell.json",
    "chars": 2011,
    "preview": "{\n  \"version\": \"0.2\",\n  \"language\": \"en\",\n  \"dictionaries\": [\n    \"workspace\",\n    \"workspace-bungie-names\",\n    \"worksp"
  },
  {
    "path": "docker-compose.yml",
    "chars": 573,
    "preview": "version: '3'\n\nservices:\n  webpack:\n    container_name: dim-webpack\n    image: node:24\n    ports:\n      - 8080:8080\n    w"
  },
  {
    "path": "docs/CHANGELOG.md",
    "chars": 128085,
    "preview": "## Next\n\n* Restyle Collections Armor to match Universal Ornaments.\n* d2foundry.gg is back, and so are our links to it.\n\n"
  },
  {
    "path": "docs/CODE_OF_CONDUCT.md",
    "chars": 3226,
    "preview": "# Contributor Covenant Code of Conduct\n\n## Our Pledge\n\nIn the interest of fostering an open and welcoming environment, w"
  },
  {
    "path": "docs/COMMUNITY_CURATIONS.md",
    "chars": 76,
    "preview": "Moved to https://github.com/DestinyItemManager/DIM/wiki/Creating-Wish-Lists\n"
  },
  {
    "path": "docs/CONTRIBUTING.md",
    "chars": 7769,
    "preview": "First, thank you for contributing to DIM! We're a community-driven project and we appreciate improvements, large and sma"
  },
  {
    "path": "docs/Docker.md",
    "chars": 2713,
    "preview": "# Docker Development Quick Start\n\n### Pre-Requisites\nTo get started with Docker, follow the steps below.\n\nIf you already"
  },
  {
    "path": "docs/OLD_CHANGELOG/OLD_CHANGELOG_3.X.X.md",
    "chars": 34401,
    "preview": "## v4 CHANGELOG\n\n* v4 CHANGELOG available [here](/docs/OLD_CHANGELOG/OLD_CHANGELOG_4.X.X.md)\n\n## 3.17.1\n\n* Fixed a bug w"
  },
  {
    "path": "docs/OLD_CHANGELOG/OLD_CHANGELOG_4.X.X.md",
    "chars": 37851,
    "preview": "## v5 CHANGELOG\n\n* v5 CHANGELOG available [here](/docs/OLD_CHANGELOG/OLD_CHANGELOG_5.X.X.md)\n\n## 4.77.0 <span className="
  },
  {
    "path": "docs/OLD_CHANGELOG/OLD_CHANGELOG_5.X.X.md",
    "chars": 36948,
    "preview": "## v6 CHANGELOG\n\n* v6 CHANGELOG available [here](/docs/OLD_CHANGELOG/OLD_CHANGELOG_6.X.X.md)\n\n## 5.74.0 <span className="
  },
  {
    "path": "docs/OLD_CHANGELOG/OLD_CHANGELOG_6.X.X.md",
    "chars": 83740,
    "preview": "## v7 CHANGELOG\n\n* v7 CHANGELOG available [here](/docs/CHANGELOG.md)\n\n## 6.99.1 <span class=\"changelog-date\">(2022-01-10"
  },
  {
    "path": "docs/TRANSLATIONS.md",
    "chars": 2555,
    "preview": "# Supported Languages\nDue to what information is provided by Bungie about item names and descriptions the following lang"
  },
  {
    "path": "docs/clean-changelog.rb",
    "chars": 312,
    "preview": "\n\nARGF.each_line do |line|\n  if line =~ /^# v?([\\d.]+)/\n    version = $1\n    date = `git show v#{version} --quiet --pret"
  },
  {
    "path": "eslint.config.js",
    "chars": 16205,
    "preview": "import cssModules from '@bhollis/eslint-plugin-css-modules';\nimport react from '@eslint-react/eslint-plugin';\nimport { f"
  },
  {
    "path": "i18next-scanner.config.cjs",
    "chars": 2684,
    "preview": "const fs = require('fs');\nconst path = require('path');\nconst typescript = require('typescript');\n\nmodule.exports = {\n  "
  },
  {
    "path": "icons/build_icons.cjs",
    "chars": 2012,
    "preview": "#!/usr/bin/env node\n\nconst { execSync } = require('child_process');\nconst rimraf = require('rimraf');\nconst fs = require"
  },
  {
    "path": "icons/splash.json",
    "chars": 837,
    "preview": "[\n  [320, 568, 2, \"landscape\", 1136, 640],\n  [375, 812, 3, \"landscape\", 2436, 1125],\n  [414, 896, 2, \"landscape\", 1792, "
  },
  {
    "path": "jest.config.js",
    "chars": 1298,
    "preview": "import { pathsToModuleNameMapper } from 'ts-jest';\nimport tsconfig from './tsconfig.json' with { type: 'json' };\n\nconst "
  },
  {
    "path": "package.json",
    "chars": 10156,
    "preview": "{\n  \"name\": \"dim\",\n  \"version\": \"8.122.0\",\n  \"description\": \"An item manager for Destiny.\",\n  \"main\": \"app/index.html\",\n"
  },
  {
    "path": "src/404.html",
    "chars": 199,
    "preview": "<!doctype html>\n<html lang=\"\">\n  <head>\n    <meta charset=\"utf-8\" />\n    <title>Not Found</title>\n  </head>\n\n  <body>\n  "
  },
  {
    "path": "src/@types/i18next.d.ts",
    "chars": 260,
    "preview": "// import the original type declarations\nimport type en from 'config/i18n.json' with { type: 'json' };\nimport 'i18next';"
  },
  {
    "path": "src/Index.tsx",
    "chars": 3074,
    "preview": "// organize-imports-ignore\n// We want our main CSS to load before all other CSS.\nimport './app/main.scss';\n// Pull the s"
  },
  {
    "path": "src/StorageTest.tsx",
    "chars": 1933,
    "preview": "import { t } from 'app/i18next-t';\nimport ErrorPanel from 'app/shell/ErrorPanel';\nimport { deleteDatabase, get, set } fr"
  },
  {
    "path": "src/__mocks__/fileMock.js",
    "chars": 35,
    "preview": "module.exports = 'test-file-stub';\n"
  },
  {
    "path": "src/app/App.m.scss",
    "chars": 637,
    "preview": "@use 'variables.scss' as *;\n\n.app {\n  padding-left: env(safe-area-inset-left);\n  padding-right: env(safe-area-inset-righ"
  },
  {
    "path": "src/app/App.m.scss.d.ts",
    "chars": 176,
    "preview": "// This file is automatically generated.\n// Please do not change this file!\ninterface CssExports {\n  'app': string;\n}\nex"
  },
  {
    "path": "src/app/App.tsx",
    "chars": 5250,
    "preview": "import { settingSelector } from 'app/dim-api/selectors';\nimport { RootState } from 'app/store/types';\nimport clsx from '"
  },
  {
    "path": "src/app/Root.tsx",
    "chars": 1623,
    "preview": "import { withProfiler } from '@sentry/react';\nimport { LocationSwitcher } from 'app/shell/LocationSwitcher';\nimport { HT"
  },
  {
    "path": "src/app/_variables.scss",
    "chars": 5497,
    "preview": "@use 'sass:color';\n\n// Variables and mixins that can be used from any SCSS file\n$dim-brand: #e8a534;\n$red: #ff3232; // F"
  },
  {
    "path": "src/app/accounts/Account.m.scss",
    "chars": 696,
    "preview": "@use '../variables.scss' as *;\n\n.account {\n  cursor: pointer;\n  line-height: 15px;\n  text-align: left;\n  position: relat"
  },
  {
    "path": "src/app/accounts/Account.m.scss.d.ts",
    "chars": 228,
    "preview": "// This file is automatically generated.\n// Please do not change this file!\ninterface CssExports {\n  'account': string;\n"
  },
  {
    "path": "src/app/accounts/Account.tsx",
    "chars": 1251,
    "preview": "import { compareBy } from 'app/utils/comparators';\nimport { BungieMembershipType } from 'bungie-api-ts/destiny2';\nimport"
  },
  {
    "path": "src/app/accounts/MenuAccounts.m.scss",
    "chars": 779,
    "preview": "@use '../variables.scss' as *;\n\n.accountSelect {\n  color: var(--theme-text);\n  height: auto;\n  flex: 1 0 auto;\n  display"
  },
  {
    "path": "src/app/accounts/MenuAccounts.m.scss.d.ts",
    "chars": 231,
    "preview": "// This file is automatically generated.\n// Please do not change this file!\ninterface CssExports {\n  'accountName': stri"
  },
  {
    "path": "src/app/accounts/MenuAccounts.tsx",
    "chars": 2009,
    "preview": "import { t } from 'app/i18next-t';\nimport { accountRoute } from 'app/routes';\nimport { useThunkDispatch } from 'app/stor"
  },
  {
    "path": "src/app/accounts/SelectAccount.m.scss",
    "chars": 688,
    "preview": "@use '../variables.scss' as *;\n\n.accountSelect {\n  margin: 0 10px;\n}\n\n.accountList {\n  display: grid;\n  grid-template-co"
  },
  {
    "path": "src/app/accounts/SelectAccount.m.scss.d.ts",
    "chars": 260,
    "preview": "// This file is automatically generated.\n// Please do not change this file!\ninterface CssExports {\n  'account': string;\n"
  },
  {
    "path": "src/app/accounts/SelectAccount.tsx",
    "chars": 1969,
    "preview": "import { t } from 'app/i18next-t';\nimport { accountRoute } from 'app/routes';\nimport { AppIcon, signOutIcon } from 'app/"
  },
  {
    "path": "src/app/accounts/actions.ts",
    "chars": 1390,
    "preview": "import { FatalTokenError } from 'app/bungie-api/authenticated-fetch';\nimport { ThunkResult } from 'app/store/types';\nimp"
  },
  {
    "path": "src/app/accounts/bungie-account.ts",
    "chars": 778,
    "preview": "import { getToken } from '../bungie-api/oauth-tokens';\n\n/**\n * A Bungie account is an account on Bungie.net, which is as"
  },
  {
    "path": "src/app/accounts/destiny-account.test.ts",
    "chars": 4460,
    "preview": "import { Tokens } from 'app/bungie-api/oauth-tokens';\nimport {\n  BungieMembershipType,\n  DestinyLinkedProfilesResponse,\n"
  },
  {
    "path": "src/app/accounts/destiny-account.ts",
    "chars": 9146,
    "preview": "import { DestinyVersion } from '@destinyitemmanager/dim-api-types';\nimport { IconDefinition } from '@fortawesome/fontawe"
  },
  {
    "path": "src/app/accounts/observers.ts",
    "chars": 634,
    "preview": "import { set } from 'app/storage/idb-keyval';\nimport { StoreObserver } from 'app/store/observerMiddleware';\nimport { sha"
  },
  {
    "path": "src/app/accounts/platforms.ts",
    "chars": 4211,
    "preview": "import { loadDimApiData } from 'app/dim-api/actions';\nimport { deleteDimApiToken } from 'app/dim-api/dim-api-helper';\nim"
  },
  {
    "path": "src/app/accounts/reducer.ts",
    "chars": 3917,
    "preview": "import { DestinyVersion } from '@destinyitemmanager/dim-api-types';\nimport { API_KEY as BUNGIE_API_KEY } from 'app/bungi"
  },
  {
    "path": "src/app/accounts/selectors.ts",
    "chars": 1208,
    "preview": "import { RootState } from 'app/store/types';\n\nexport const accountsSelector = (state: RootState) => state.accounts.accou"
  },
  {
    "path": "src/app/armory/AllWishlistRolls.m.scss",
    "chars": 807,
    "preview": "@use 'sass:color';\n@use '../variables.scss' as *;\n\n.roll {\n  display: flex;\n  flex-direction: row;\n  gap: 2px;\n}\n\n.orGro"
  },
  {
    "path": "src/app/armory/AllWishlistRolls.m.scss.d.ts",
    "chars": 287,
    "preview": "// This file is automatically generated.\n// Please do not change this file!\ninterface CssExports {\n  'invalidPlug': stri"
  },
  {
    "path": "src/app/armory/AllWishlistRolls.tsx",
    "chars": 8766,
    "preview": "import ExternalLink from 'app/dim-ui/ExternalLink';\nimport { PressTip } from 'app/dim-ui/PressTip';\nimport { t } from 'a"
  },
  {
    "path": "src/app/armory/Armory.m.scss",
    "chars": 2254,
    "preview": "@use '../variables' as *;\n\n.armory {\n  background-repeat: no-repeat;\n  background-position: top center;\n  background-siz"
  },
  {
    "path": "src/app/armory/Armory.m.scss.d.ts",
    "chars": 451,
    "preview": "// This file is automatically generated.\n// Please do not change this file!\ninterface CssExports {\n  'alternate': string"
  },
  {
    "path": "src/app/armory/Armory.tsx",
    "chars": 16773,
    "preview": "import ItemGrid from 'app/armory/ItemGrid';\nimport { addCompareItem } from 'app/compare/actions';\nimport { stripAdept } "
  },
  {
    "path": "src/app/armory/ArmoryPage.tsx",
    "chars": 1214,
    "preview": "import { DestinyAccount } from 'app/accounts/destiny-account';\nimport ShowPageLoading from 'app/dim-ui/ShowPageLoading';"
  },
  {
    "path": "src/app/armory/ArmorySheet.m.scss",
    "chars": 49,
    "preview": ".sheet {\n  max-width: 900px;\n  margin: 0 auto;\n}\n"
  },
  {
    "path": "src/app/armory/ArmorySheet.m.scss.d.ts",
    "chars": 178,
    "preview": "// This file is automatically generated.\n// Please do not change this file!\ninterface CssExports {\n  'sheet': string;\n}\n"
  },
  {
    "path": "src/app/armory/ArmorySheet.tsx",
    "chars": 1869,
    "preview": "import ClickOutsideRoot from 'app/dim-ui/ClickOutsideRoot';\nimport Sheet from 'app/dim-ui/Sheet';\nimport { DimItem } fro"
  },
  {
    "path": "src/app/armory/ItemGrid.tsx",
    "chars": 1748,
    "preview": "/**\n * A simple item grid that manages its own item popup separate from the global popup. Useful for showing items withi"
  },
  {
    "path": "src/app/armory/LazyArmory.ts",
    "chars": 122,
    "preview": "import { lazy } from 'react';\n\nexport default lazy(() => import('./Armory' /* webpackChunkName: \"item-popup-armory\" */))"
  },
  {
    "path": "src/app/armory/Links.m.scss",
    "chars": 510,
    "preview": "@use '../variables' as *;\n\n.links {\n  display: flex;\n  flex-direction: column;\n  float: right;\n  margin: 0 0 0 32px;\n  p"
  },
  {
    "path": "src/app/armory/Links.m.scss.d.ts",
    "chars": 178,
    "preview": "// This file is automatically generated.\n// Please do not change this file!\ninterface CssExports {\n  'links': string;\n}\n"
  },
  {
    "path": "src/app/armory/Links.tsx",
    "chars": 5453,
    "preview": "import { languageSelector } from 'app/dim-api/selectors';\nimport ExternalLink from 'app/dim-ui/ExternalLink';\nimport { t"
  },
  {
    "path": "src/app/armory/WishListEntry.m.scss",
    "chars": 111,
    "preview": ".wishlist {\n  width: 100%;\n  display: flex;\n  gap: 8px;\n  align-items: center;\n\n  > input {\n    flex: 1;\n  }\n}\n"
  },
  {
    "path": "src/app/armory/WishListEntry.m.scss.d.ts",
    "chars": 181,
    "preview": "// This file is automatically generated.\n// Please do not change this file!\ninterface CssExports {\n  'wishlist': string;"
  },
  {
    "path": "src/app/armory/WishListEntry.tsx",
    "chars": 1854,
    "preview": "import HelpLink from 'app/dim-ui/HelpLink';\nimport { t } from 'app/i18next-t';\nimport { DimItem } from 'app/inventory/it"
  },
  {
    "path": "src/app/armory/crafting-utils.ts",
    "chars": 1142,
    "preview": "import { D2ManifestDefinitions } from 'app/destiny2/d2-definitions';\nimport { DestinyInventoryItemDefinition } from 'bun"
  },
  {
    "path": "src/app/armory/trait-to-enhanced-trait.d.ts",
    "chars": 138,
    "preview": "declare module 'data/d2/trait-to-enhanced-trait.json' {\n  const x: { readonly [hash: number]: number | undefined };\n  ex"
  },
  {
    "path": "src/app/armory/wishlist-collapser.test.ts",
    "chars": 1903,
    "preview": "import { consolidateSecondaryPerks } from './wishlist-collapser';\n\ndescribe('perkConsolidator', () => {\n  it('does its t"
  },
  {
    "path": "src/app/armory/wishlist-collapser.ts",
    "chars": 10537,
    "preview": "import { D2ManifestDefinitions } from 'app/destiny2/d2-definitions';\nimport { DimItem } from 'app/inventory/item-types';"
  },
  {
    "path": "src/app/bungie-api/README.md",
    "chars": 171,
    "preview": "# Bungie API Helpers\n\nThese files export methods for dealing with the Bungie API (D1, D2, User, etc) in terms of DIM con"
  },
  {
    "path": "src/app/bungie-api/__snapshots__/http-client.test.ts.snap",
    "chars": 3200,
    "preview": "// Jest Snapshot v1, https://jestjs.io/docs/snapshot-testing\n\nexports[`check Request builder for [Function getItem] 1`] "
  },
  {
    "path": "src/app/bungie-api/authenticated-fetch.ts",
    "chars": 6002,
    "preview": "import { t } from 'app/i18next-t';\nimport { infoLog, warnLog } from 'app/utils/log';\nimport { PlatformErrorCodes } from "
  },
  {
    "path": "src/app/bungie-api/bungie-api-utils.ts",
    "chars": 844,
    "preview": "import { HttpClientConfig, HttpQueryParams } from 'bungie-api-ts/http';\n\nexport const API_KEY = $DIM_FLAVOR !== 'dev' ? "
  },
  {
    "path": "src/app/bungie-api/bungie-core-api.ts",
    "chars": 719,
    "preview": "import {\n  CoreSettingsConfiguration,\n  getCommonSettings,\n  getGlobalAlerts as getGlobalAlertsApi,\n  GlobalAlert,\n} fro"
  },
  {
    "path": "src/app/bungie-api/bungie-service-helper.ts",
    "chars": 8144,
    "preview": "import { t } from 'app/i18next-t';\nimport { showNotification } from 'app/notifications/notifications';\nimport { DimError"
  },
  {
    "path": "src/app/bungie-api/destiny1-api.ts",
    "chars": 7254,
    "preview": "import { Vendor } from 'app/destiny1/vendors/vendor.service';\nimport { t } from 'app/i18next-t';\nimport { compareBy } fr"
  },
  {
    "path": "src/app/bungie-api/destiny2-api.ts",
    "chars": 10929,
    "preview": "import { t } from 'app/i18next-t';\nimport { InGameLoadout } from 'app/loadout/loadout-types';\nimport { compareBy } from "
  },
  {
    "path": "src/app/bungie-api/error-toaster.tsx",
    "chars": 1343,
    "preview": "import { t } from 'app/i18next-t';\nimport { bungieHelpAccount, bungieHelpLink } from 'app/shell/links';\nimport ExternalL"
  },
  {
    "path": "src/app/bungie-api/http-client.test.ts",
    "chars": 3911,
    "preview": "import {\n  DestinyComponentType,\n  getItem,\n  getLinkedProfiles,\n  getProfile,\n  getVendor,\n  pullFromPostmaster,\n} from"
  },
  {
    "path": "src/app/bungie-api/http-client.ts",
    "chars": 7014,
    "preview": "import { convertToError } from 'app/utils/errors';\nimport { delay } from 'app/utils/promises';\nimport { PlatformErrorCod"
  },
  {
    "path": "src/app/bungie-api/oauth-tokens.ts",
    "chars": 2651,
    "preview": "/* Helpers for storing and retrieving our OAuth tokens from localStorage */\n\n/**\n * An OAuth token, either authorization"
  },
  {
    "path": "src/app/bungie-api/oauth.ts",
    "chars": 2783,
    "preview": "import { infoLog } from 'app/utils/log';\nimport { dedupePromise } from 'app/utils/promises';\nimport { oauthClientId, oau"
  },
  {
    "path": "src/app/bungie-api/rate-limit-config.ts",
    "chars": 2135,
    "preview": "import { addLimiter, RateLimiterQueue } from './rate-limiter';\n\nexport default function setupRateLimiter() {\n  addLimite"
  },
  {
    "path": "src/app/bungie-api/rate-limiter.ts",
    "chars": 3409,
    "preview": "import { noop } from 'app/utils/functions';\n\n/**\n * A rate limiter queue applies when the path of a request matches its "
  },
  {
    "path": "src/app/character-tile/CharacterHeaderXP.m.scss",
    "chars": 380,
    "preview": "@use '../variables.scss' as *;\n\n$xp-bar-height: 2px;\n\n.xpBar {\n  position: absolute;\n  width: 100%;\n  bottom: 0;\n}\n\n.lev"
  },
  {
    "path": "src/app/character-tile/CharacterHeaderXP.m.scss.d.ts",
    "chars": 256,
    "preview": "// This file is automatically generated.\n// Please do not change this file!\ninterface CssExports {\n  'levelBar': string;"
  },
  {
    "path": "src/app/character-tile/CharacterHeaderXP.tsx",
    "chars": 1440,
    "preview": "import { t } from 'app/i18next-t';\nimport { D1ProgressionHashes } from 'app/search/d1-known-values';\nimport { percent } "
  },
  {
    "path": "src/app/character-tile/CharacterTile.m.scss",
    "chars": 4448,
    "preview": "@use '../variables.scss' as *;\n\n// Shared styles between vault and character tile\n.tileCommon {\n  flex: 1;\n  position: r"
  },
  {
    "path": "src/app/character-tile/CharacterTile.m.scss.d.ts",
    "chars": 638,
    "preview": "// This file is automatically generated.\n// Please do not change this file!\ninterface CssExports {\n  'bigPowerLevel': st"
  },
  {
    "path": "src/app/character-tile/CharacterTile.tsx",
    "chars": 3973,
    "preview": "import FractionalPowerLevel from 'app/dim-ui/FractionalPowerLevel';\nimport type { DimStore, DimTitle } from 'app/invento"
  },
  {
    "path": "src/app/character-tile/CharacterTileButton.m.scss",
    "chars": 577,
    "preview": "@use '../variables.scss' as *;\n\n.character {\n  composes: resetButton from '../dim-ui/common.m.scss';\n  composes: flexRow"
  },
  {
    "path": "src/app/character-tile/CharacterTileButton.m.scss.d.ts",
    "chars": 182,
    "preview": "// This file is automatically generated.\n// Please do not change this file!\ninterface CssExports {\n  'character': string"
  },
  {
    "path": "src/app/character-tile/CharacterTileButton.tsx",
    "chars": 901,
    "preview": "import clsx from 'clsx';\nimport { DimStore } from '../inventory/store-types';\nimport CharacterTile from './CharacterTile"
  },
  {
    "path": "src/app/character-tile/StoreHeading.m.scss",
    "chars": 1017,
    "preview": "@use '../variables.scss' as *;\n\n.loadoutButton {\n  background-color: black;\n  width: 16px;\n  display: flex;\n  justify-co"
  },
  {
    "path": "src/app/character-tile/StoreHeading.m.scss.d.ts",
    "chars": 240,
    "preview": "// This file is automatically generated.\n// Please do not change this file!\ninterface CssExports {\n  'characterHeader': "
  },
  {
    "path": "src/app/character-tile/StoreHeading.tsx",
    "chars": 3425,
    "preview": "import { useFixOverscrollBehavior } from 'app/dim-ui/useFixOverscrollBehavior';\nimport { usePopper } from 'app/dim-ui/us"
  },
  {
    "path": "src/app/character-tile/StoreIcon.m.scss",
    "chars": 206,
    "preview": ".classIcon {\n  width: 16px;\n  height: 16px;\n  margin-right: 4px;\n}\n\n.label {\n  position: relative;\n  font-weight: bold;\n"
  },
  {
    "path": "src/app/character-tile/StoreIcon.m.scss.d.ts",
    "chars": 223,
    "preview": "// This file is automatically generated.\n// Please do not change this file!\ninterface CssExports {\n  'classIcon': string"
  },
  {
    "path": "src/app/character-tile/StoreIcon.tsx",
    "chars": 1141,
    "preview": "import ClassIcon from 'app/dim-ui/ClassIcon';\nimport { DimStore } from 'app/inventory/store-types';\nimport clsx from 'cl"
  },
  {
    "path": "src/app/clarity/about.ts",
    "chars": 384,
    "preview": "const clarityLinkDirect = 'https://url.d2clarity.com/websiteDIM';\nexport const clarityLink = `<a href='${clarityLinkDire"
  },
  {
    "path": "src/app/clarity/actions.ts",
    "chars": 426,
    "preview": "import { createAction } from 'typesafe-actions';\nimport { ClarityCharacterStats } from './descriptions/character-stats';"
  },
  {
    "path": "src/app/clarity/descriptions/ClarityDescriptions.tsx",
    "chars": 2891,
    "preview": "import { languageSelector } from 'app/dim-api/selectors';\nimport ExternalLink from 'app/dim-ui/ExternalLink';\nimport { t"
  },
  {
    "path": "src/app/clarity/descriptions/Description.m.scss",
    "chars": 1231,
    "preview": "@use '../../variables' as *;\n@use 'sass:string';\n\n/* stylelint-disable selector-class-pattern */\n.communityDescription {"
  },
  {
    "path": "src/app/clarity/descriptions/Description.m.scss.d.ts",
    "chars": 507,
    "preview": "// This file is automatically generated.\n// Please do not change this file!\ninterface CssExports {\n  'background': strin"
  },
  {
    "path": "src/app/clarity/descriptions/character-stats.ts",
    "chars": 9570,
    "preview": "export interface ClarityCharacterStats {\n  Mobility: Mobility;\n  Resilience: Resilience;\n  Recovery: Recovery;\n  Discipl"
  },
  {
    "path": "src/app/clarity/descriptions/descriptionInterface.ts",
    "chars": 1255,
    "preview": "import { DimLanguage } from 'app/i18n';\n\nexport type DescriptionClassNames =\n  | 'background'\n  | 'blue'\n  | 'bold'\n  | "
  },
  {
    "path": "src/app/clarity/descriptions/loadDescriptions.ts",
    "chars": 5793,
    "preview": "import { get, set } from 'app/storage/idb-keyval';\nimport { ThunkResult } from 'app/store/types';\nimport { isEmpty } fro"
  },
  {
    "path": "src/app/clarity/reducer.ts",
    "chars": 1232,
    "preview": "import { Reducer } from 'redux';\nimport { ActionType, getType } from 'typesafe-actions';\nimport * as actions from './act"
  },
  {
    "path": "src/app/clarity/selectors.ts",
    "chars": 237,
    "preview": "import { RootState } from 'app/store/types';\n\nexport const clarityDescriptionsSelector = (state: RootState) => state.cla"
  },
  {
    "path": "src/app/compare/Compare.m.scss",
    "chars": 1651,
    "preview": "@use '../variables' as *;\n\n.organizerLink {\n  composes: dim-button from global;\n  margin-left: auto;\n\n  @include phone-p"
  },
  {
    "path": "src/app/compare/Compare.m.scss.d.ts",
    "chars": 407,
    "preview": "// This file is automatically generated.\n// Please do not change this file!\ninterface CssExports {\n  'bucket': string;\n "
  },
  {
    "path": "src/app/compare/Compare.tsx",
    "chars": 13827,
    "preview": "import { CustomStatDef } from '@destinyitemmanager/dim-api-types';\nimport { languageSelector } from 'app/dim-api/selecto"
  },
  {
    "path": "src/app/compare/CompareButtons.m.scss",
    "chars": 260,
    "preview": ".svgIcon {\n  img,\n  svg {\n    height: 1.3em;\n  }\n}\n\n.inlineImageIcon {\n  display: inline-block;\n  vertical-align: middle"
  },
  {
    "path": "src/app/compare/CompareButtons.m.scss.d.ts",
    "chars": 264,
    "preview": "// This file is automatically generated.\n// Please do not change this file!\ninterface CssExports {\n  'inlineImageIcon': "
  },
  {
    "path": "src/app/compare/CompareColumns.m.scss",
    "chars": 1738,
    "preview": "@use '../variables.scss' as *;\n\n.name {\n  padding-top: 2px;\n  padding-bottom: 2px;\n  text-overflow: ellipsis;\n  white-sp"
  },
  {
    "path": "src/app/compare/CompareColumns.m.scss.d.ts",
    "chars": 382,
    "preview": "// This file is automatically generated.\n// Please do not change this file!\ninterface CssExports {\n  'archetype': string"
  },
  {
    "path": "src/app/compare/CompareColumns.tsx",
    "chars": 7602,
    "preview": "import { CustomStatDef, DestinyVersion } from '@destinyitemmanager/dim-api-types';\nimport { EnergyCostIcon } from 'app/d"
  },
  {
    "path": "src/app/compare/CompareContainer.tsx",
    "chars": 1220,
    "preview": "import { DestinyVersion } from '@destinyitemmanager/dim-api-types';\nimport { gaPageView } from 'app/google';\nimport { us"
  },
  {
    "path": "src/app/compare/CompareItem.m.scss",
    "chars": 2325,
    "preview": "@use '../variables.scss' as *;\n\n/* Row Headers */\n.header {\n  composes: flexRow from '../dim-ui/common.m.scss';\n  align-"
  },
  {
    "path": "src/app/compare/CompareItem.m.scss.d.ts",
    "chars": 439,
    "preview": "// This file is automatically generated.\n// Please do not change this file!\ninterface CssExports {\n  'close': string;\n  "
  },
  {
    "path": "src/app/compare/CompareItem.tsx",
    "chars": 7507,
    "preview": "import { PressTip } from 'app/dim-ui/PressTip';\nimport { useDynamicStringReplacer } from 'app/dim-ui/destiny-symbols/Ric"
  },
  {
    "path": "src/app/compare/CompareStat.m.scss",
    "chars": 1184,
    "preview": "@use '../variables.scss' as *;\n\n.range {\n  font-size: 0.9em;\n}\n\n.stat {\n  composes: flexRow from '../dim-ui/common.m.scs"
  },
  {
    "path": "src/app/compare/CompareStat.m.scss.d.ts",
    "chars": 428,
    "preview": "// This file is automatically generated.\n// Please do not change this file!\ninterface CssExports {\n  'customStat': strin"
  },
  {
    "path": "src/app/compare/CompareStat.tsx",
    "chars": 3875,
    "preview": "import AnimatedNumber from 'app/dim-ui/AnimatedNumber';\nimport RecoilStat, { recoilValue } from 'app/item-popup/RecoilSt"
  },
  {
    "path": "src/app/compare/CompareSuggestions.tsx",
    "chars": 3474,
    "preview": "import { DimItem } from 'app/inventory/item-types';\nimport { filterFactorySelector } from 'app/search/items/item-search-"
  },
  {
    "path": "src/app/compare/actions.ts",
    "chars": 1128,
    "preview": "import { DimItem } from 'app/inventory/item-types';\nimport { createAction } from 'typesafe-actions';\n\n/** Add an item to"
  },
  {
    "path": "src/app/compare/compare-buttons.tsx",
    "chars": 12871,
    "preview": "import BungieImage from 'app/dim-ui/BungieImage';\nimport ElementIcon from 'app/dim-ui/ElementIcon';\nimport { ArmorSlotIc"
  },
  {
    "path": "src/app/compare/compare-utils.ts",
    "chars": 863,
    "preview": "import { t } from 'app/i18next-t';\nimport { DimItem } from 'app/inventory/item-types';\nimport { quoteFilterString } from"
  },
  {
    "path": "src/app/compare/reducer.ts",
    "chars": 8874,
    "preview": "import { t } from 'app/i18next-t';\nimport { DimItem } from 'app/inventory/item-types';\nimport { showNotification } from "
  },
  {
    "path": "src/app/compare/selectors.ts",
    "chars": 2687,
    "preview": "import { currentAccountSelector } from 'app/accounts/selectors';\nimport { DimItem } from 'app/inventory/item-types';\nimp"
  },
  {
    "path": "src/app/compare/types.ts",
    "chars": 656,
    "preview": "import { DimPlug } from 'app/inventory/item-types';\n\nexport interface DimAdjustedItemPlug {\n  /** A plug selected for st"
  },
  {
    "path": "src/app/css-variables.ts",
    "chars": 5782,
    "preview": "import { OrnamentDisplay } from '@destinyitemmanager/dim-api-types';\nimport { settingsSelector } from 'app/dim-api/selec"
  },
  {
    "path": "src/app/debug/Debug.m.scss",
    "chars": 440,
    "preview": ".debugPage {\n  margin: 2em 10px;\n}\n\n.cells {\n  display: grid;\n  grid-template-columns: repeat(auto-fill, minmax(250px, 1"
  },
  {
    "path": "src/app/debug/Debug.m.scss.d.ts",
    "chars": 239,
    "preview": "// This file is automatically generated.\n// Please do not change this file!\ninterface CssExports {\n  'cells': string;\n  "
  },
  {
    "path": "src/app/debug/Debug.tsx",
    "chars": 11636,
    "preview": "import Account from 'app/accounts/Account';\nimport { accountsSelector, currentAccountSelector } from 'app/accounts/selec"
  },
  {
    "path": "src/app/destiny1/activities/Activities.m.scss",
    "chars": 1797,
    "preview": "@use '../../variables.scss' as *;\n\n.activities {\n  composes: dim-page from global;\n\n  width: calc(\n    (40px + var(--ite"
  }
]

// ... and 1430 more files (download for full content)

About this extraction

This page contains the full source code of the kyleshay/DIM GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 1630 files (354.9 MB), approximately 2.7M tokens, and a symbol index with 2947 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!