forked from OpenWF/SpaceNinjaServer
		
	Compare commits
	
		
			328 Commits
		
	
	
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 2264ae176b | |||
| 9369e6cc5a | |||
| 49eb14f758 | |||
| 5e455d1e90 | |||
| 4d93dc80dc | |||
| 38326fc452 | |||
| 6e9c787c59 | |||
| 82fe598056 | |||
| bc271216ac | |||
| c5463166a8 | |||
| 8bce83d14c | |||
| cc5682760d | |||
| 00acaed62a | |||
| d794bd94ce | |||
| cecc65197b | |||
| b1c1b56de3 | |||
| 167da9c573 | |||
| 5e6955ae32 | |||
| f2145ed91b | |||
| 20d9a699b4 | |||
| 2b054d1728 | |||
| 5ac73528a0 | |||
| 678ad0c4a1 | |||
| 4bdb759463 | |||
| 71be8a2868 | |||
| f3072e84c9 | |||
| b2749765a3 | |||
| 654652b889 | |||
| e3048ea188 | |||
| bb1d6a98c5 | |||
| c3bf0ae7c7 | |||
| 3a72617a0f | |||
| 3ae535ccbc | |||
| 23abe5de02 | |||
| 0d21c73ab7 | |||
| 482101ccd0 | |||
| 60e87543aa | |||
| c4c17f24d7 | |||
| 43fa1978c0 | |||
| 18fafc38b5 | |||
| 98a46e51de | |||
| 2a7767ef4a | |||
| e867123f89 | |||
| 2322a994c6 | |||
| be8e2feae6 | |||
| 4f8b07322e | |||
| 4b3b1969da | |||
| a0ce110e7e | |||
| 7fe00da2a4 | |||
| bac23a8465 | |||
| db112ee5ed | |||
| 86998b6760 | |||
| be3dd7ab66 | |||
| e6fb675e21 | |||
| fb4c42490e | |||
| 96a15e25df | |||
| ff234c9874 | |||
| 7d3915fe05 | |||
| 4b3e2dfc62 | |||
| 737d013655 | |||
| 1f8d437fad | |||
| 9263b8f179 | |||
| 875f4b9fa4 | |||
| fd7ddd9696 | |||
| 065afc0089 | |||
| c1c14b2068 | |||
| 9e66d22256 | |||
| 02f0935710 | |||
| af4c3a93ce | |||
| 4141970530 | |||
| ca589cb7cf | |||
| d6ed22d1ff | |||
| 610a432e46 | |||
| 2ca895a5f8 | |||
| fd2286c253 | |||
| 5a582daa1a | |||
| 6a571e5e78 | |||
| 0349c4a32c | |||
| e1563bf298 | |||
| af6f422fec | |||
| f5c1b83598 | |||
| 30f380f37e | |||
| 0f7a85db59 | |||
| 43bc12713a | |||
| 6022bf97b5 | |||
| 159e151dc0 | |||
| 56954260c8 | |||
| c535044af8 | |||
| f5146be129 | |||
| d38ec06ed6 | |||
| 060f65900f | |||
| 66d3057d40 | |||
| b14a5925df | |||
| 9da47c406a | |||
| 09065bdb4e | |||
| 8f04fc5fdf | |||
| 230ee5f638 | |||
| 21db6ce265 | |||
| 1ecf53c96b | |||
| e67ef63b77 | |||
| 5772ebe746 | |||
| 0136e4d152 | |||
| 8b3ee4b4f5 | |||
| 6e8800f048 | |||
| d65a667acd | |||
| c6a3e86d2b | |||
| a8e41c95e7 | |||
| 9426359370 | |||
| e5247700df | |||
| 1c3f1e2276 | |||
| 7710e7c13f | |||
| a64c5ea3c1 | |||
| 17e1eb86dd | |||
| de9dfb3d71 | |||
| fc38f818dd | |||
| e76f08db89 | |||
| 7bcb5f21ce | |||
| 3641d63f6f | |||
| 71c4835a69 | |||
| 86a63ace41 | |||
| 32c95b6715 | |||
| 6f8b14fb2d | |||
| 3d8aa60838 | |||
| 87da94658d | |||
| 05fbefa7f4 | |||
| a2abf6db8f | |||
| 64a1c8b276 | |||
| 4fa07a1319 | |||
| a3cc7d9f92 | |||
| c47c60fdcc | |||
| 367455baaa | |||
| 6c2b7a61e2 | |||
| 6a6683fb25 | |||
| e3b6accb5d | |||
| 7e437d75bf | |||
| 62570177b6 | |||
| d2aff211c6 | |||
| 791ae389d8 | |||
| d027e7f26e | |||
| cd6ce61b80 | |||
| a5be29159f | |||
| f099b64ef4 | |||
| c4f348c252 | |||
| 0d388b4b0f | |||
| d64531f4b2 | |||
| 01b8f7acf3 | |||
| 8a7db2cd85 | |||
| 5a9415ae0c | |||
| 39f898cd30 | |||
| 9c55a8a4aa | |||
| 253ae09f24 | |||
| 703e9007b0 | |||
| 3e555b1753 | |||
| 1066b4a983 | |||
| b9a2cea862 | |||
| 0342f52359 | |||
| ea9012bd56 | |||
| 13400b6d83 | |||
| 8d57eda9d2 | |||
| 6b66cb495b | |||
| f4f7ed00d1 | |||
| 18556cb2f5 | |||
| 648af9ae18 | |||
| e16da9da44 | |||
| 4d8dbd99aa | |||
| 0a3f9549a9 | |||
| 2cfb21b98e | |||
| 3fedc701f1 | |||
| ed596aa3f3 | |||
| e2349b361e | |||
| 9221178522 | |||
| 9a5c2ab4a4 | |||
| d4c477769a | |||
| 6de9f0dcdb | |||
| 9662da00de | |||
| 662d824369 | |||
| a0bac12e95 | |||
| e98cb2ec24 | |||
| b5c6c3e485 | |||
| fa65ba3f25 | |||
| 0c54c064eb | |||
| b4e789bf0d | |||
| 9add016d7b | |||
| a2171c80a5 | |||
| 5a2fa2c2c3 | |||
| 4b2b184b8f | |||
| dc401de1e9 | |||
| 1439fdc083 | |||
| 6771a129f5 | |||
| f13de810e5 | |||
| c52f7dcedc | |||
| 0bf142ed50 | |||
| 0d791ad145 | |||
| 5396eefe75 | |||
| a9a197b005 | |||
| 1ade801e7c | |||
| c9cc1fa089 | |||
| 287acab892 | |||
| 30398021b3 | |||
| 15578b04d2 | |||
| 9d034824f7 | |||
| 8b8d66ab2e | |||
| 78b8cf4c77 | |||
| 1ead04ddc1 | |||
| c97c22b434 | |||
| d7a93463c0 | |||
| f6b73e58da | |||
| 28b8fb3e78 | |||
| 895e76b45e | |||
| 71d0c140ae | |||
| f06a3b8187 | |||
| ffcbbb480b | |||
| dfd1fb834b | |||
| 2c43d897c0 | |||
| 217eb1f61b | |||
| 5e1ff64cca | |||
| 9c232bfc1f | |||
| 9e73fc7fb1 | |||
| 03b8b610db | |||
| 4b46938dab | |||
| 6230f52f27 | |||
| 460cb20af7 | |||
| 1e4007f6da | |||
| 7dc44e81ec | |||
| bfc4048721 | |||
| 7174848588 | |||
| a5b667c331 | |||
| 9b6abff2be | |||
| 7c7f37e46b | |||
| 52a560bef2 | |||
| 369794dcdb | |||
| 956ba38b7d | |||
| 660c3f3ddf | |||
| 024b806af1 | |||
| b885d7766c | |||
| d0743654dd | |||
| cddd2cdd2b | |||
| 62a6042c9c | |||
| e8d4d84d6e | |||
| 62881aaa36 | |||
| df316e3a7a | |||
| 264e9cfc98 | |||
| 5d5554a80e | |||
| da14a4081b | |||
| b0b68f474a | |||
| ab214df1a8 | |||
| 9f8105d7f1 | |||
| c47a29ec96 | |||
| 6d727c50f4 | |||
| bf04755c36 | |||
| e345fc35b6 | |||
| f5335704b4 | |||
| 79c5f7a67a | |||
| e97b107853 | |||
| 7bc5065251 | |||
| 3194a693b3 | |||
| 261dbd5fdf | |||
| fd2ec696a0 | |||
| 9cc0c76ef5 | |||
| 2a4488d1dd | |||
| 2e1326cde8 | |||
| 70be467cbf | |||
| fac3ec01c6 | |||
| ebdca760e6 | |||
| 51c0ddda38 | |||
| 9129bdb5fc | |||
| a4922d4c35 | |||
| 679752633a | |||
| 67b5890f39 | |||
| 5d54e79e5d | |||
| 4606f28a58 | |||
| a2d383ee3c | |||
| 834b7a8196 | |||
| 4a2d863c9c | |||
| 9f0cd91105 | |||
| ebfef52fb1 | |||
| dd7bacd22e | |||
| c00967931e | |||
| b15a635e11 | |||
| 7e618539fa | |||
| a29398fae6 | |||
| 601091f1c0 | |||
| f561884f2c | |||
| 6e1cb0c9f9 | |||
| 9286627668 | |||
| f94f2005d3 | |||
| 9901b7af54 | |||
| 2fa846f465 | |||
| 541ec3d702 | |||
| 0a28eab65d | |||
| 8e639a16bd | |||
| 522924a823 | |||
| 48e3f324e2 | |||
| 8f77c722cb | |||
| e7287933b5 | |||
| b21bca7a6d | |||
| d30d450311 | |||
| b62e326920 | |||
| 8b4bc114f6 | |||
| 564aa06762 | |||
| 2e84f71af8 | |||
| ddfa98e0b2 | |||
| bb3c3e01b0 | |||
| 695dcf98e0 | |||
| 509f7f0d9b | |||
| aada031a80 | |||
| a2a441ecb0 | |||
| c0a0463a68 | |||
| 2307a40833 | |||
| 304af514e2 | |||
| ddf3cd49b5 | |||
| 41e3f0136f | |||
| c0ca9d9398 | |||
| 0f6b55beed | |||
| f8550e9afe | |||
| b53c4d9125 | |||
| 922b65cfab | |||
| 2f642df20a | |||
| 62314e89c7 | |||
| 56aa3e3331 | |||
| c3f486488f | |||
| 49c353d895 | |||
| 90ab560620 | |||
| b0e80fcfa8 | |||
| 2c62fb3c3c | |||
| 5b215733aa | |||
| 39866b9a2b | |||
| fad1ee9314 | 
@ -3,3 +3,6 @@
 | 
				
			|||||||
Dockerfile*
 | 
					Dockerfile*
 | 
				
			||||||
.*
 | 
					.*
 | 
				
			||||||
docker-data/
 | 
					docker-data/
 | 
				
			||||||
 | 
					node_modules/
 | 
				
			||||||
 | 
					static/data/
 | 
				
			||||||
 | 
					logs/
 | 
				
			||||||
 | 
				
			|||||||
@ -13,6 +13,7 @@
 | 
				
			|||||||
        "node": true
 | 
					        "node": true
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    "rules": {
 | 
					    "rules": {
 | 
				
			||||||
 | 
					        "@typescript-eslint/consistent-type-imports": "error",
 | 
				
			||||||
        "@typescript-eslint/explicit-function-return-type": "error",
 | 
					        "@typescript-eslint/explicit-function-return-type": "error",
 | 
				
			||||||
        "@typescript-eslint/restrict-template-expressions": "error",
 | 
					        "@typescript-eslint/restrict-template-expressions": "error",
 | 
				
			||||||
        "@typescript-eslint/restrict-plus-operands": "error",
 | 
					        "@typescript-eslint/restrict-plus-operands": "error",
 | 
				
			||||||
@ -21,7 +22,7 @@
 | 
				
			|||||||
        "@typescript-eslint/no-unsafe-argument": "error",
 | 
					        "@typescript-eslint/no-unsafe-argument": "error",
 | 
				
			||||||
        "@typescript-eslint/no-unsafe-call": "error",
 | 
					        "@typescript-eslint/no-unsafe-call": "error",
 | 
				
			||||||
        "@typescript-eslint/no-unsafe-assignment": "error",
 | 
					        "@typescript-eslint/no-unsafe-assignment": "error",
 | 
				
			||||||
        "@typescript-eslint/no-explicit-any": "error",
 | 
					        "@typescript-eslint/no-explicit-any": "off",
 | 
				
			||||||
        "no-loss-of-precision": "error",
 | 
					        "no-loss-of-precision": "error",
 | 
				
			||||||
        "@typescript-eslint/no-unnecessary-condition": "error",
 | 
					        "@typescript-eslint/no-unnecessary-condition": "error",
 | 
				
			||||||
        "@typescript-eslint/no-base-to-string": "off",
 | 
					        "@typescript-eslint/no-base-to-string": "off",
 | 
				
			||||||
@ -30,7 +31,8 @@
 | 
				
			|||||||
        "no-mixed-spaces-and-tabs": "error",
 | 
					        "no-mixed-spaces-and-tabs": "error",
 | 
				
			||||||
        "@typescript-eslint/require-await": "error",
 | 
					        "@typescript-eslint/require-await": "error",
 | 
				
			||||||
        "import/no-named-as-default-member": "off",
 | 
					        "import/no-named-as-default-member": "off",
 | 
				
			||||||
        "import/no-cycle": "warn"
 | 
					        "import/no-cycle": "warn",
 | 
				
			||||||
 | 
					        "@typescript-eslint/no-deprecated": "warn"
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    "parser": "@typescript-eslint/parser",
 | 
					    "parser": "@typescript-eslint/parser",
 | 
				
			||||||
    "parserOptions": {
 | 
					    "parserOptions": {
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										5
									
								
								.github/workflows/build.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										5
									
								
								.github/workflows/build.yml
									
									
									
									
										vendored
									
									
								
							@ -12,14 +12,13 @@ jobs:
 | 
				
			|||||||
            - name: Setup Node.js environment
 | 
					            - name: Setup Node.js environment
 | 
				
			||||||
              uses: actions/setup-node@v4.0.2
 | 
					              uses: actions/setup-node@v4.0.2
 | 
				
			||||||
              with:
 | 
					              with:
 | 
				
			||||||
                  node-version: ">=20.6.0"
 | 
					                  node-version: ">=20.18.1"
 | 
				
			||||||
            - run: npm ci
 | 
					            - run: npm ci
 | 
				
			||||||
            - run: cp config.json.example config.json
 | 
					            - run: cp config-vanilla.json config.json
 | 
				
			||||||
            - run: npm run verify
 | 
					            - run: npm run verify
 | 
				
			||||||
            - run: npm run lint:ci
 | 
					            - run: npm run lint:ci
 | 
				
			||||||
            - run: npm run prettier
 | 
					            - run: npm run prettier
 | 
				
			||||||
            - run: npm run update-translations
 | 
					            - run: npm run update-translations
 | 
				
			||||||
            - run: npm run fix-imports
 | 
					 | 
				
			||||||
            - name: Fail if there are uncommitted changes
 | 
					            - name: Fail if there are uncommitted changes
 | 
				
			||||||
              run: |
 | 
					              run: |
 | 
				
			||||||
                  if [[ -n "$(git status --porcelain)" ]]; then
 | 
					                  if [[ -n "$(git status --porcelain)" ]]; then
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										25
									
								
								.github/workflows/docker.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										25
									
								
								.github/workflows/docker.yml
									
									
									
									
										vendored
									
									
								
							@ -4,9 +4,9 @@ on:
 | 
				
			|||||||
        branches:
 | 
					        branches:
 | 
				
			||||||
            - main
 | 
					            - main
 | 
				
			||||||
jobs:
 | 
					jobs:
 | 
				
			||||||
    docker-amd64:
 | 
					    docker:
 | 
				
			||||||
        if: github.repository == 'OpenWF/SpaceNinjaServer'
 | 
					        if: github.repository == 'OpenWF/SpaceNinjaServer'
 | 
				
			||||||
        runs-on: amd64
 | 
					        runs-on: ubuntu-latest
 | 
				
			||||||
        steps:
 | 
					        steps:
 | 
				
			||||||
            - name: Set up Docker buildx
 | 
					            - name: Set up Docker buildx
 | 
				
			||||||
              uses: docker/setup-buildx-action@v3
 | 
					              uses: docker/setup-buildx-action@v3
 | 
				
			||||||
@ -18,27 +18,10 @@ jobs:
 | 
				
			|||||||
            - name: Build and push
 | 
					            - name: Build and push
 | 
				
			||||||
              uses: docker/build-push-action@v6
 | 
					              uses: docker/build-push-action@v6
 | 
				
			||||||
              with:
 | 
					              with:
 | 
				
			||||||
                  platforms: linux/amd64
 | 
					                  platforms: linux/arm64,linux/amd64
 | 
				
			||||||
                  push: true
 | 
					                  push: true
 | 
				
			||||||
                  tags: |
 | 
					                  tags: |
 | 
				
			||||||
                      openwf/spaceninjaserver:latest
 | 
					                      openwf/spaceninjaserver:latest
 | 
				
			||||||
                      openwf/spaceninjaserver:${{ github.sha }}
 | 
					 | 
				
			||||||
    docker-arm64:
 | 
					 | 
				
			||||||
        if: github.repository == 'OpenWF/SpaceNinjaServer'
 | 
					 | 
				
			||||||
        runs-on: arm64
 | 
					 | 
				
			||||||
        steps:
 | 
					 | 
				
			||||||
            - name: Set up Docker buildx
 | 
					 | 
				
			||||||
              uses: docker/setup-buildx-action@v3
 | 
					 | 
				
			||||||
            - name: Log in to container registry
 | 
					 | 
				
			||||||
              uses: docker/login-action@v3
 | 
					 | 
				
			||||||
              with:
 | 
					 | 
				
			||||||
                  username: openwf
 | 
					 | 
				
			||||||
                  password: ${{ secrets.DOCKERHUB_TOKEN }}
 | 
					 | 
				
			||||||
            - name: Build and push
 | 
					 | 
				
			||||||
              uses: docker/build-push-action@v6
 | 
					 | 
				
			||||||
              with:
 | 
					 | 
				
			||||||
                  platforms: linux/arm64
 | 
					 | 
				
			||||||
                  push: true
 | 
					 | 
				
			||||||
                  tags: |
 | 
					 | 
				
			||||||
                      openwf/spaceninjaserver:latest-arm64
 | 
					                      openwf/spaceninjaserver:latest-arm64
 | 
				
			||||||
 | 
					                      openwf/spaceninjaserver:${{ github.sha }}
 | 
				
			||||||
                      openwf/spaceninjaserver:${{ github.sha }}-arm64
 | 
					                      openwf/spaceninjaserver:${{ github.sha }}-arm64
 | 
				
			||||||
 | 
				
			|||||||
@ -2,3 +2,4 @@ src/routes/api.ts
 | 
				
			|||||||
static/webui/libs/
 | 
					static/webui/libs/
 | 
				
			||||||
*.html
 | 
					*.html
 | 
				
			||||||
*.md
 | 
					*.md
 | 
				
			||||||
 | 
					config-vanilla.json
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										3
									
								
								.vscode/settings.json
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								.vscode/settings.json
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@ -0,0 +1,3 @@
 | 
				
			|||||||
 | 
					{
 | 
				
			||||||
 | 
					  "typescript.preferences.preferTypeOnlyAutoImports": true
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										17
									
								
								AGENTS.md
									
									
									
									
									
								
							
							
						
						
									
										17
									
								
								AGENTS.md
									
									
									
									
									
								
							@ -1,17 +0,0 @@
 | 
				
			|||||||
## In General
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
### Prerequisites
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
Use `npm i` or `npm ci` to install all dependencies.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
### Testing
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
Use `npm run verify` to verify that your changes pass TypeScript's checks.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
### Formatting
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
Use `npm run prettier` to ensure your formatting matches the expected format. Failing to do so will cause CI failure.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
## WebUI Specific
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
The translation system is designed around additions being made to `static/webui/translations/en.js`. They are copied over for translation via `npm run update-translations`. DO NOT produce non-English strings; we want them to be translated by humans who can understand the full context.
 | 
					 | 
				
			||||||
							
								
								
									
										19
									
								
								CONTRIBUTING.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								CONTRIBUTING.md
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,19 @@
 | 
				
			|||||||
 | 
					## In General
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### Prerequisites
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Use `npm i` or `npm ci` to install all dependencies, including dev dependencies.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## Development Process
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Auto reloading is supported for server and WebUI development. Simply use `npm run dev` or `npm run dev:bun` to start the server and edit away.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### Testing
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Before submitting a PR:
 | 
				
			||||||
 | 
					- Use `npm run verify` to verify that the code is type-safe.
 | 
				
			||||||
 | 
					- Use `npm run fix` to fix formatting issues as well as be informed of any unfixable issues. Avoid introducing new warnings.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## WebUI Specific
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					The translation system is designed around additions being made to `static/webui/translations/en.js`. They are copied over for translation via `npm run update-translations`. DO NOT provide translations generated by AI or other automated tools.
 | 
				
			||||||
@ -5,7 +5,7 @@ RUN apk add --no-cache bash jq
 | 
				
			|||||||
COPY . /app
 | 
					COPY . /app
 | 
				
			||||||
WORKDIR /app
 | 
					WORKDIR /app
 | 
				
			||||||
 | 
					
 | 
				
			||||||
RUN npm i --omit=dev
 | 
					RUN npm i --omit=dev --omit=optional
 | 
				
			||||||
RUN npm run build
 | 
					RUN date '+%d %B %Y' > BUILD_DATE
 | 
				
			||||||
 | 
					
 | 
				
			||||||
ENTRYPOINT ["/app/docker-entrypoint.sh"]
 | 
					ENTRYPOINT ["/app/docker-entrypoint.sh"]
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										11
									
								
								README.md
									
									
									
									
									
								
							
							
						
						
									
										11
									
								
								README.md
									
									
									
									
									
								
							@ -6,18 +6,21 @@ More information for the moment here: [https://discord.gg/PNNZ3asUuY](https://di
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
This project is in active development at <https://onlyg.it/OpenWF/SpaceNinjaServer>.
 | 
					This project is in active development at <https://onlyg.it/OpenWF/SpaceNinjaServer>.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
To get an idea of what functionality you can expect to be missing [have a look through the issues](https://onlyg.it/OpenWF/SpaceNinjaServer/issues?q=&type=all&state=open&labels=-4%2C-10&milestone=0&assignee=0&poster=). However, many things have been implemented and *should* work as expected. Please open an issue for anything where that's not the case and/or the server is reporting errors.
 | 
					To get an idea of what functionality you can expect to be missing [have a look through the issues](https://onlyg.it/OpenWF/SpaceNinjaServer/issues). However, many things have been implemented and *should* work as expected. Please open an issue for anything where that's not the case and/or the server is reporting errors.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
## config.json
 | 
					## config.json
 | 
				
			||||||
 | 
					
 | 
				
			||||||
SpaceNinjaServer requires a `config.json`. To set it up, you can copy the [config.json.example](config.json.example), which has most cheats disabled.
 | 
					SpaceNinjaServer requires a `config.json`. To set it up, you can copy the [config-vanilla.json](config-vanilla.json), which has most cheats disabled.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- `skipTutorial` affects only newly created accounts, so you may wish to change it before logging in for the first time.
 | 
				
			||||||
- `logger.level` can be `fatal`, `error`, `warn`, `info`, `http`, `debug`, or `trace`.
 | 
					- `logger.level` can be `fatal`, `error`, `warn`, `info`, `http`, `debug`, or `trace`.
 | 
				
			||||||
- `myIrcAddresses` can be used to point to an IRC server. If not provided, defaults to `[ myAddress ]`.
 | 
					- `ircExecutable` can be provided with a relative path to an EXE which will be ran as a child process of SpaceNinjaServer.
 | 
				
			||||||
 | 
					- `ircAddress`, `hubAddress`, and `nrsAddress` can be provided if these secondary servers are on a different machine.
 | 
				
			||||||
- `worldState.eidolonOverride` can be set to `day` or `night` to lock the time to day/fass and night/vome on Plains of Eidolon/Cambion Drift.
 | 
					- `worldState.eidolonOverride` can be set to `day` or `night` to lock the time to day/fass and night/vome on Plains of Eidolon/Cambion Drift.
 | 
				
			||||||
- `worldState.vallisOverride` can be set to `warm` or `cold` to lock the temperature on Orb Vallis.
 | 
					- `worldState.vallisOverride` can be set to `warm` or `cold` to lock the temperature on Orb Vallis.
 | 
				
			||||||
- `worldState.duviriOverride` can be set to `joy`, `anger`, `envy`, `sorrow`, or `fear` to lock the Duviri spiral.
 | 
					- `worldState.duviriOverride` can be set to `joy`, `anger`, `envy`, `sorrow`, or `fear` to lock the Duviri spiral.
 | 
				
			||||||
- `worldState.nightwaveOverride` will lock the nightwave season, assuming the client is new enough for it. Valid values:
 | 
					- `worldState.nightwaveOverride` will lock the nightwave season, assuming the client is new enough for it. Valid values:
 | 
				
			||||||
 | 
					  - `RadioLegionIntermission14Syndicate` for Nora's Mix: Dreams of the Dead
 | 
				
			||||||
  - `RadioLegionIntermission13Syndicate` for Nora's Mix Vol. 9
 | 
					  - `RadioLegionIntermission13Syndicate` for Nora's Mix Vol. 9
 | 
				
			||||||
  - `RadioLegionIntermission12Syndicate` for Nora's Mix Vol. 8
 | 
					  - `RadioLegionIntermission12Syndicate` for Nora's Mix Vol. 8
 | 
				
			||||||
  - `RadioLegionIntermission11Syndicate` for Nora's Mix Vol. 7
 | 
					  - `RadioLegionIntermission11Syndicate` for Nora's Mix Vol. 7
 | 
				
			||||||
@ -34,5 +37,5 @@ SpaceNinjaServer requires a `config.json`. To set it up, you can copy the [confi
 | 
				
			|||||||
  - `RadioLegion2Syndicate` for The Emissary
 | 
					  - `RadioLegion2Syndicate` for The Emissary
 | 
				
			||||||
  - `RadioLegionIntermissionSyndicate` for Intermission I
 | 
					  - `RadioLegionIntermissionSyndicate` for Intermission I
 | 
				
			||||||
  - `RadioLegionSyndicate` for The Wolf of Saturn Six
 | 
					  - `RadioLegionSyndicate` for The Wolf of Saturn Six
 | 
				
			||||||
- `allTheFissures` can be set to `normal` or `hard` to enable all fissures either in normal or steel path, respectively.
 | 
					- `worldState.allTheFissures` can be set to `normal` or `hard` to enable all fissures either in normal or steel path, respectively.
 | 
				
			||||||
- `worldState.circuitGameModes` can be set to an array of game modes which will override the otherwise-random pattern in The Circuit. Valid element values are `Survival`, `VoidFlood`, `Excavation`, `Defense`, `Exterminate`, `Assassination`, and `Alchemy`.
 | 
					- `worldState.circuitGameModes` can be set to an array of game modes which will override the otherwise-random pattern in The Circuit. Valid element values are `Survival`, `VoidFlood`, `Excavation`, `Defense`, `Exterminate`, `Assassination`, and `Alchemy`.
 | 
				
			||||||
 | 
				
			|||||||
@ -2,24 +2,32 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
echo Updating SpaceNinjaServer...
 | 
					echo Updating SpaceNinjaServer...
 | 
				
			||||||
git fetch --prune
 | 
					git fetch --prune
 | 
				
			||||||
git stash
 | 
					if %errorlevel% == 0 (
 | 
				
			||||||
git checkout -f origin/main
 | 
						git stash
 | 
				
			||||||
 | 
						git checkout -f origin/main
 | 
				
			||||||
 | 
					
 | 
				
			||||||
if exist static\data\0\ (
 | 
						if exist static\data\0\ (
 | 
				
			||||||
		echo Updating stripped assets...
 | 
							echo Updating stripped assets...
 | 
				
			||||||
		cd static\data\0\
 | 
							cd static\data\0\
 | 
				
			||||||
		git pull
 | 
							git pull
 | 
				
			||||||
		cd ..\..\..\
 | 
							cd ..\..\..\
 | 
				
			||||||
)
 | 
						)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
echo Updating dependencies...
 | 
						echo Updating dependencies...
 | 
				
			||||||
call npm i --omit=dev
 | 
						node scripts/raw-precheck.js > NUL
 | 
				
			||||||
 | 
						if %errorlevel% == 0 (
 | 
				
			||||||
call npm run build
 | 
							call npm i --omit=dev --omit=optional
 | 
				
			||||||
if %errorlevel% == 0 (
 | 
							call npm run raw
 | 
				
			||||||
 | 
						) else (
 | 
				
			||||||
 | 
							call npm i --omit=dev
 | 
				
			||||||
 | 
							call npm run build
 | 
				
			||||||
 | 
							if %errorlevel% == 0 (
 | 
				
			||||||
			call npm run start
 | 
								call npm run start
 | 
				
			||||||
 | 
							)
 | 
				
			||||||
 | 
						)
 | 
				
			||||||
	echo SpaceNinjaServer seems to have crashed.
 | 
						echo SpaceNinjaServer seems to have crashed.
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
:a
 | 
					:a
 | 
				
			||||||
pause > nul
 | 
					pause > nul
 | 
				
			||||||
goto a
 | 
					goto a
 | 
				
			||||||
 | 
				
			|||||||
@ -2,22 +2,28 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
echo "Updating SpaceNinjaServer..."
 | 
					echo "Updating SpaceNinjaServer..."
 | 
				
			||||||
git fetch --prune
 | 
					git fetch --prune
 | 
				
			||||||
git stash
 | 
					if [ $? -eq 0 ]; then
 | 
				
			||||||
git checkout -f origin/main
 | 
					    git stash
 | 
				
			||||||
 | 
					    git checkout -f origin/main
 | 
				
			||||||
 | 
					
 | 
				
			||||||
if [ -d "static/data/0/" ]; then
 | 
					    if [ -d "static/data/0/" ]; then
 | 
				
			||||||
        echo "Updating stripped assets..."
 | 
					        echo "Updating stripped assets..."
 | 
				
			||||||
        cd static/data/0/
 | 
					        cd static/data/0/
 | 
				
			||||||
        git pull
 | 
					        git pull
 | 
				
			||||||
        cd ../../../
 | 
					        cd ../../../
 | 
				
			||||||
fi
 | 
					    fi
 | 
				
			||||||
 | 
					
 | 
				
			||||||
echo "Updating dependencies..."
 | 
					    echo "Updating dependencies..."
 | 
				
			||||||
npm i --omit=dev
 | 
					    node scripts/raw-precheck.js > /dev/null
 | 
				
			||||||
 | 
					    if [ $? -eq 0 ]; then
 | 
				
			||||||
npm run build
 | 
					        npm i --omit=dev --omit=optional
 | 
				
			||||||
if [ $? -eq 0 ]; then
 | 
					        npm run raw
 | 
				
			||||||
 | 
					    else
 | 
				
			||||||
 | 
					        npm i --omit=dev
 | 
				
			||||||
 | 
					        npm run build
 | 
				
			||||||
 | 
					        if [ $? -eq 0 ]; then
 | 
				
			||||||
            npm run start
 | 
					            npm run start
 | 
				
			||||||
 | 
					        fi
 | 
				
			||||||
 | 
					    fi
 | 
				
			||||||
    echo "SpaceNinjaServer seems to have crashed."
 | 
					    echo "SpaceNinjaServer seems to have crashed."
 | 
				
			||||||
fi
 | 
					fi
 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										74
									
								
								config-vanilla.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										74
									
								
								config-vanilla.json
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,74 @@
 | 
				
			|||||||
 | 
					{
 | 
				
			||||||
 | 
					  "mongodbUrl": "mongodb://127.0.0.1:27017/openWF",
 | 
				
			||||||
 | 
					  "logger": {
 | 
				
			||||||
 | 
					    "files": true,
 | 
				
			||||||
 | 
					    "level": "trace"
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					  "myAddress": "localhost",
 | 
				
			||||||
 | 
					  "bindAddress": "0.0.0.0",
 | 
				
			||||||
 | 
					  "httpPort": 80,
 | 
				
			||||||
 | 
					  "httpsPort": 443,
 | 
				
			||||||
 | 
					  "ircExecutable": null,
 | 
				
			||||||
 | 
					  "ircAddress": null,
 | 
				
			||||||
 | 
					  "hubAddress": null,
 | 
				
			||||||
 | 
					  "nrsAddress": null,
 | 
				
			||||||
 | 
					  "administratorNames": [],
 | 
				
			||||||
 | 
					  "autoCreateAccount": true,
 | 
				
			||||||
 | 
					  "skipTutorial": false,
 | 
				
			||||||
 | 
					  "unlockAllSkins": false,
 | 
				
			||||||
 | 
					  "fullyStockedVendors": false,
 | 
				
			||||||
 | 
					  "skipClanKeyCrafting": false,
 | 
				
			||||||
 | 
					  "unfaithfulBugFixes": {
 | 
				
			||||||
 | 
					    "ignore1999LastRegionPlayed": false,
 | 
				
			||||||
 | 
					    "fixXtraCheeseTimer": false,
 | 
				
			||||||
 | 
					    "useAnniversaryTagForOldGoals": true
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					  "worldState": {
 | 
				
			||||||
 | 
					    "creditBoost": false,
 | 
				
			||||||
 | 
					    "affinityBoost": false,
 | 
				
			||||||
 | 
					    "resourceBoost": false,
 | 
				
			||||||
 | 
					    "tennoLiveRelay": false,
 | 
				
			||||||
 | 
					    "baroTennoConRelay": false,
 | 
				
			||||||
 | 
					    "baroAlwaysAvailable": false,
 | 
				
			||||||
 | 
					    "baroFullyStocked": false,
 | 
				
			||||||
 | 
					    "varziaFullyStocked": false,
 | 
				
			||||||
 | 
					    "wolfHunt": null,
 | 
				
			||||||
 | 
					    "orphixVenom": false,
 | 
				
			||||||
 | 
					    "longShadow": false,
 | 
				
			||||||
 | 
					    "hallowedFlame": false,
 | 
				
			||||||
 | 
					    "anniversary": null,
 | 
				
			||||||
 | 
					    "hallowedNightmares": false,
 | 
				
			||||||
 | 
					    "hallowedNightmaresRewardsOverride": 0,
 | 
				
			||||||
 | 
					    "naberusNightsOverride": null,
 | 
				
			||||||
 | 
					    "proxyRebellion": false,
 | 
				
			||||||
 | 
					    "proxyRebellionRewardsOverride": 0,
 | 
				
			||||||
 | 
					    "voidCorruption2025Week1": false,
 | 
				
			||||||
 | 
					    "voidCorruption2025Week2": false,
 | 
				
			||||||
 | 
					    "voidCorruption2025Week3": false,
 | 
				
			||||||
 | 
					    "voidCorruption2025Week4": false,
 | 
				
			||||||
 | 
					    "qtccAlerts": false,
 | 
				
			||||||
 | 
					    "galleonOfGhouls": 0,
 | 
				
			||||||
 | 
					    "ghoulEmergenceOverride": null,
 | 
				
			||||||
 | 
					    "plagueStarOverride": null,
 | 
				
			||||||
 | 
					    "starDaysOverride": null,
 | 
				
			||||||
 | 
					    "dogDaysOverride": null,
 | 
				
			||||||
 | 
					    "dogDaysRewardsOverride": null,
 | 
				
			||||||
 | 
					    "bellyOfTheBeast": false,
 | 
				
			||||||
 | 
					    "bellyOfTheBeastProgressOverride": 0,
 | 
				
			||||||
 | 
					    "eightClaw": false,
 | 
				
			||||||
 | 
					    "eightClawProgressOverride": 0,
 | 
				
			||||||
 | 
					    "thermiaFracturesOverride": null,
 | 
				
			||||||
 | 
					    "thermiaFracturesProgressOverride": 0,
 | 
				
			||||||
 | 
					    "eidolonOverride": "",
 | 
				
			||||||
 | 
					    "vallisOverride": "",
 | 
				
			||||||
 | 
					    "duviriOverride": "",
 | 
				
			||||||
 | 
					    "nightwaveOverride": "",
 | 
				
			||||||
 | 
					    "allTheFissures": "",
 | 
				
			||||||
 | 
					    "varziaOverride": "",
 | 
				
			||||||
 | 
					    "circuitGameModes": null,
 | 
				
			||||||
 | 
					    "darvoStockMultiplier": 1
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					  "dev": {
 | 
				
			||||||
 | 
					    "keepVendorsExpired": false
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@ -1,88 +0,0 @@
 | 
				
			|||||||
{
 | 
					 | 
				
			||||||
  "mongodbUrl": "mongodb://127.0.0.1:27017/openWF",
 | 
					 | 
				
			||||||
  "logger": {
 | 
					 | 
				
			||||||
    "files": true,
 | 
					 | 
				
			||||||
    "level": "trace"
 | 
					 | 
				
			||||||
  },
 | 
					 | 
				
			||||||
  "myAddress": "localhost",
 | 
					 | 
				
			||||||
  "httpPort": 80,
 | 
					 | 
				
			||||||
  "httpsPort": 443,
 | 
					 | 
				
			||||||
  "NRS": ["localhost"],
 | 
					 | 
				
			||||||
  "administratorNames": [],
 | 
					 | 
				
			||||||
  "autoCreateAccount": true,
 | 
					 | 
				
			||||||
  "skipTutorial": false,
 | 
					 | 
				
			||||||
  "skipAllDialogue": false,
 | 
					 | 
				
			||||||
  "unlockAllScans": false,
 | 
					 | 
				
			||||||
  "infiniteCredits": false,
 | 
					 | 
				
			||||||
  "infinitePlatinum": false,
 | 
					 | 
				
			||||||
  "infiniteEndo": false,
 | 
					 | 
				
			||||||
  "infiniteRegalAya": false,
 | 
					 | 
				
			||||||
  "infiniteHelminthMaterials": false,
 | 
					 | 
				
			||||||
  "claimingBlueprintRefundsIngredients": false,
 | 
					 | 
				
			||||||
  "dontSubtractPurchaseCreditCost": false,
 | 
					 | 
				
			||||||
  "dontSubtractPurchasePlatinumCost": false,
 | 
					 | 
				
			||||||
  "dontSubtractPurchaseItemCost": false,
 | 
					 | 
				
			||||||
  "dontSubtractPurchaseStandingCost": false,
 | 
					 | 
				
			||||||
  "dontSubtractVoidTraces": false,
 | 
					 | 
				
			||||||
  "dontSubtractConsumables": false,
 | 
					 | 
				
			||||||
  "unlockAllShipFeatures": false,
 | 
					 | 
				
			||||||
  "unlockAllShipDecorations": false,
 | 
					 | 
				
			||||||
  "unlockAllFlavourItems": false,
 | 
					 | 
				
			||||||
  "unlockAllSkins": false,
 | 
					 | 
				
			||||||
  "unlockAllCapturaScenes": false,
 | 
					 | 
				
			||||||
  "universalPolarityEverywhere": false,
 | 
					 | 
				
			||||||
  "unlockDoubleCapacityPotatoesEverywhere": false,
 | 
					 | 
				
			||||||
  "unlockExilusEverywhere": false,
 | 
					 | 
				
			||||||
  "unlockArcanesEverywhere": false,
 | 
					 | 
				
			||||||
  "noDailyStandingLimits": false,
 | 
					 | 
				
			||||||
  "noDailyFocusLimit": false,
 | 
					 | 
				
			||||||
  "noArgonCrystalDecay": false,
 | 
					 | 
				
			||||||
  "noMasteryRankUpCooldown": false,
 | 
					 | 
				
			||||||
  "noVendorPurchaseLimits": false,
 | 
					 | 
				
			||||||
  "noDeathMarks": false,
 | 
					 | 
				
			||||||
  "noKimCooldowns": false,
 | 
					 | 
				
			||||||
  "fullyStockedVendors": false,
 | 
					 | 
				
			||||||
  "baroAlwaysAvailable": false,
 | 
					 | 
				
			||||||
  "baroFullyStocked": false,
 | 
					 | 
				
			||||||
  "syndicateMissionsRepeatable": false,
 | 
					 | 
				
			||||||
  "unlockAllProfitTakerStages": false,
 | 
					 | 
				
			||||||
  "instantFinishRivenChallenge": false,
 | 
					 | 
				
			||||||
  "instantResourceExtractorDrones": false,
 | 
					 | 
				
			||||||
  "noResourceExtractorDronesDamage": false,
 | 
					 | 
				
			||||||
  "skipClanKeyCrafting": false,
 | 
					 | 
				
			||||||
  "noDojoRoomBuildStage": false,
 | 
					 | 
				
			||||||
  "noDecoBuildStage": false,
 | 
					 | 
				
			||||||
  "fastDojoRoomDestruction": false,
 | 
					 | 
				
			||||||
  "noDojoResearchCosts": false,
 | 
					 | 
				
			||||||
  "noDojoResearchTime": false,
 | 
					 | 
				
			||||||
  "fastClanAscension": false,
 | 
					 | 
				
			||||||
  "missionsCanGiveAllRelics": false,
 | 
					 | 
				
			||||||
  "unlockAllSimarisResearchEntries": false,
 | 
					 | 
				
			||||||
  "disableDailyTribute": false,
 | 
					 | 
				
			||||||
  "spoofMasteryRank": -1,
 | 
					 | 
				
			||||||
  "relicRewardItemCountMultiplier": 1,
 | 
					 | 
				
			||||||
  "nightwaveStandingMultiplier": 1,
 | 
					 | 
				
			||||||
  "unfaithfulBugFixes": {
 | 
					 | 
				
			||||||
    "ignore1999LastRegionPlayed": false,
 | 
					 | 
				
			||||||
    "fixXtraCheeseTimer": false
 | 
					 | 
				
			||||||
  },
 | 
					 | 
				
			||||||
  "worldState": {
 | 
					 | 
				
			||||||
    "creditBoost": false,
 | 
					 | 
				
			||||||
    "affinityBoost": false,
 | 
					 | 
				
			||||||
    "resourceBoost": false,
 | 
					 | 
				
			||||||
    "starDays": true,
 | 
					 | 
				
			||||||
    "galleonOfGhouls": 0,
 | 
					 | 
				
			||||||
    "eidolonOverride": "",
 | 
					 | 
				
			||||||
    "vallisOverride": "",
 | 
					 | 
				
			||||||
    "duviriOverride": "",
 | 
					 | 
				
			||||||
    "nightwaveOverride": "",
 | 
					 | 
				
			||||||
    "allTheFissures": "",
 | 
					 | 
				
			||||||
    "circuitGameModes": null,
 | 
					 | 
				
			||||||
    "darvoStockMultiplier": 1,
 | 
					 | 
				
			||||||
    "varziaOverride": "",
 | 
					 | 
				
			||||||
    "varziaFullyStocked": false
 | 
					 | 
				
			||||||
  },
 | 
					 | 
				
			||||||
  "dev": {
 | 
					 | 
				
			||||||
    "keepVendorsExpired": false
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
@ -1,6 +1,5 @@
 | 
				
			|||||||
services:
 | 
					services:
 | 
				
			||||||
    spaceninjaserver:
 | 
					    spaceninjaserver:
 | 
				
			||||||
        # The image to use. If you have an ARM CPU, replace 'latest' with 'latest-arm64'.
 | 
					 | 
				
			||||||
        image: openwf/spaceninjaserver:latest
 | 
					        image: openwf/spaceninjaserver:latest
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        volumes:
 | 
					        volumes:
 | 
				
			||||||
@ -19,9 +18,6 @@ services:
 | 
				
			|||||||
            - mongodb
 | 
					            - mongodb
 | 
				
			||||||
    mongodb:
 | 
					    mongodb:
 | 
				
			||||||
        image: docker.io/library/mongo:8.0.0-noble
 | 
					        image: docker.io/library/mongo:8.0.0-noble
 | 
				
			||||||
        environment:
 | 
					 | 
				
			||||||
            MONGO_INITDB_ROOT_USERNAME: openwfagent
 | 
					 | 
				
			||||||
            MONGO_INITDB_ROOT_PASSWORD: spaceninjaserver
 | 
					 | 
				
			||||||
        volumes:
 | 
					        volumes:
 | 
				
			||||||
            - ./docker-data/database:/data/db
 | 
					            - ./docker-data/database:/data/db
 | 
				
			||||||
        command: mongod --quiet --logpath /dev/null
 | 
					        command: mongod --quiet --logpath /dev/null
 | 
				
			||||||
 | 
				
			|||||||
@ -2,7 +2,7 @@
 | 
				
			|||||||
set -e
 | 
					set -e
 | 
				
			||||||
 | 
					
 | 
				
			||||||
if [ ! -f conf/config.json ]; then
 | 
					if [ ! -f conf/config.json ]; then
 | 
				
			||||||
	jq --arg value "mongodb://openwfagent:spaceninjaserver@mongodb:27017/" '.mongodbUrl = $value' /app/config.json.example > /app/conf/config.json
 | 
						jq --arg value "mongodb://mongodb:27017/openWF" '.mongodbUrl = $value' /app/config-vanilla.json > /app/conf/config.json
 | 
				
			||||||
fi
 | 
					fi
 | 
				
			||||||
 | 
					
 | 
				
			||||||
exec npm run start -- --configPath conf/config.json
 | 
					exec npm run raw -- --configPath conf/config.json
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										731
									
								
								package-lock.json
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										731
									
								
								package-lock.json
									
									
									
										generated
									
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										46
									
								
								package.json
									
									
									
									
									
								
							
							
						
						
									
										46
									
								
								package.json
									
									
									
									
									
								
							@ -4,32 +4,29 @@
 | 
				
			|||||||
  "description": "WF Emulator",
 | 
					  "description": "WF Emulator",
 | 
				
			||||||
  "main": "index.ts",
 | 
					  "main": "index.ts",
 | 
				
			||||||
  "scripts": {
 | 
					  "scripts": {
 | 
				
			||||||
    "start": "node --enable-source-maps --import ./build/src/pathman.js build/src/index.js",
 | 
					    "start": "node --enable-source-maps build/src/index.js",
 | 
				
			||||||
    "build": "tsgo --sourceMap && ncp static/webui build/static/webui",
 | 
					    "build": "tsgo --inlineSourceMap && ncp static/webui build/static/webui",
 | 
				
			||||||
    "build:tsc": "tsc --incremental --sourceMap && ncp static/webui build/static/webui",
 | 
					    "build:tsc": "tsc --incremental --inlineSourceMap && ncp static/webui build/static/webui",
 | 
				
			||||||
    "build:dev": "tsgo --sourceMap",
 | 
					    "build:dev": "tsgo --inlineSourceMap",
 | 
				
			||||||
    "build:dev:tsc": "tsc --incremental --sourceMap",
 | 
					    "build:dev:tsc": "tsc --incremental --inlineSourceMap",
 | 
				
			||||||
    "build-and-start": "npm run build && npm run start",
 | 
					    "build-and-start": "npm run build && npm run start",
 | 
				
			||||||
    "build-and-start:bun": "npm run verify && npm run bun-run",
 | 
					    "dev": "node scripts/dev.cjs",
 | 
				
			||||||
    "dev": "node scripts/dev.js",
 | 
					    "dev:bun": "bun scripts/dev.cjs",
 | 
				
			||||||
    "dev:bun": "bun scripts/dev.js",
 | 
					 | 
				
			||||||
    "verify": "tsgo --noEmit",
 | 
					    "verify": "tsgo --noEmit",
 | 
				
			||||||
    "bun-run": "bun src/index.ts",
 | 
					    "verify:tsc": "tsc --noEmit",
 | 
				
			||||||
 | 
					    "raw": "node scripts/raw-precheck.js && node --experimental-transform-types src/index.ts",
 | 
				
			||||||
 | 
					    "raw:bun": "bun src/index.ts",
 | 
				
			||||||
    "lint": "eslint --ext .ts .",
 | 
					    "lint": "eslint --ext .ts .",
 | 
				
			||||||
    "lint:ci": "eslint --ext .ts --rule \"prettier/prettier: off\" .",
 | 
					    "lint:ci": "eslint --ext .ts --rule \"prettier/prettier: off\" .",
 | 
				
			||||||
    "lint:fix": "eslint --fix --ext .ts .",
 | 
					    "lint:fix": "eslint --fix --ext .ts .",
 | 
				
			||||||
    "prettier": "prettier --write .",
 | 
					    "prettier": "prettier --write .",
 | 
				
			||||||
    "update-translations": "cd scripts && node update-translations.js",
 | 
					    "update-translations": "cd scripts && node update-translations.cjs",
 | 
				
			||||||
    "fix-imports": "cd scripts && node fix-imports.js",
 | 
					    "fix": "npm run update-translations && npm run prettier"
 | 
				
			||||||
    "fix": "npm run update-translations && npm run fix-imports && npm run prettier"
 | 
					 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
  "license": "GNU",
 | 
					  "license": "GNU",
 | 
				
			||||||
 | 
					  "type": "module",
 | 
				
			||||||
  "dependencies": {
 | 
					  "dependencies": {
 | 
				
			||||||
    "@types/express": "^5",
 | 
					    "body-parser": "^2.2.0",
 | 
				
			||||||
    "@types/morgan": "^1.9.9",
 | 
					 | 
				
			||||||
    "@types/websocket": "^1.0.10",
 | 
					 | 
				
			||||||
    "@types/ws": "^8.18.1",
 | 
					 | 
				
			||||||
    "@typescript/native-preview": "^7.0.0-dev.20250625.1",
 | 
					 | 
				
			||||||
    "chokidar": "^4.0.3",
 | 
					    "chokidar": "^4.0.3",
 | 
				
			||||||
    "crc-32": "^1.2.2",
 | 
					    "crc-32": "^1.2.2",
 | 
				
			||||||
    "express": "^5",
 | 
					    "express": "^5",
 | 
				
			||||||
@ -37,14 +34,22 @@
 | 
				
			|||||||
    "mongoose": "^8.11.0",
 | 
					    "mongoose": "^8.11.0",
 | 
				
			||||||
    "morgan": "^1.10.0",
 | 
					    "morgan": "^1.10.0",
 | 
				
			||||||
    "ncp": "^2.0.0",
 | 
					    "ncp": "^2.0.0",
 | 
				
			||||||
    "typescript": "^5.5",
 | 
					 | 
				
			||||||
    "undici": "^7.10.0",
 | 
					    "undici": "^7.10.0",
 | 
				
			||||||
    "warframe-public-export-plus": "^0.5.78",
 | 
					    "warframe-public-export-plus": "^0.5.93",
 | 
				
			||||||
    "warframe-riven-info": "^0.1.2",
 | 
					    "warframe-riven-info": "^0.1.2",
 | 
				
			||||||
    "winston": "^3.17.0",
 | 
					    "winston": "^3.17.0",
 | 
				
			||||||
    "winston-daily-rotate-file": "^5.0.0",
 | 
					    "winston-daily-rotate-file": "^5.0.0",
 | 
				
			||||||
    "ws": "^8.18.2"
 | 
					    "ws": "^8.18.2"
 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
 | 
					  "optionalDependencies": {
 | 
				
			||||||
 | 
					    "@types/body-parser": "^1.19.6",
 | 
				
			||||||
 | 
					    "@types/express": "^5",
 | 
				
			||||||
 | 
					    "@types/morgan": "^1.9.9",
 | 
				
			||||||
 | 
					    "@types/websocket": "^1.0.10",
 | 
				
			||||||
 | 
					    "@types/ws": "^8.18.1",
 | 
				
			||||||
 | 
					    "@typescript/native-preview": "^7.0.0-dev.20250625.1",
 | 
				
			||||||
 | 
					    "typescript": "^5.7"
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
  "devDependencies": {
 | 
					  "devDependencies": {
 | 
				
			||||||
    "@typescript-eslint/eslint-plugin": "^8.28.0",
 | 
					    "@typescript-eslint/eslint-plugin": "^8.28.0",
 | 
				
			||||||
    "@typescript-eslint/parser": "^8.28.0",
 | 
					    "@typescript-eslint/parser": "^8.28.0",
 | 
				
			||||||
@ -54,5 +59,8 @@
 | 
				
			|||||||
    "eslint-plugin-prettier": "^5.2.5",
 | 
					    "eslint-plugin-prettier": "^5.2.5",
 | 
				
			||||||
    "prettier": "^3.5.3",
 | 
					    "prettier": "^3.5.3",
 | 
				
			||||||
    "tree-kill": "^1.2.2"
 | 
					    "tree-kill": "^1.2.2"
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					  "engines": {
 | 
				
			||||||
 | 
					    "node": ">=20.18.1"
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -13,6 +13,17 @@ args.push("--dev");
 | 
				
			|||||||
args.push("--secret");
 | 
					args.push("--secret");
 | 
				
			||||||
args.push(secret);
 | 
					args.push(secret);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const cangoraw = (() => {
 | 
				
			||||||
 | 
					    if (process.versions.bun) {
 | 
				
			||||||
 | 
					        return true;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    const [major, minor] = process.versions.node.split(".").map(x => parseInt(x));
 | 
				
			||||||
 | 
					    if (major > 22 || (major == 22 && minor >= 7)) {
 | 
				
			||||||
 | 
					        return true;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return false;
 | 
				
			||||||
 | 
					})();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
let buildproc, runproc;
 | 
					let buildproc, runproc;
 | 
				
			||||||
const spawnopts = { stdio: "inherit", shell: true };
 | 
					const spawnopts = { stdio: "inherit", shell: true };
 | 
				
			||||||
function run(changedFile) {
 | 
					function run(changedFile) {
 | 
				
			||||||
@ -29,7 +40,10 @@ function run(changedFile) {
 | 
				
			|||||||
        runproc = undefined;
 | 
					        runproc = undefined;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    const thisbuildproc = spawn("npm", ["run", process.versions.bun ? "verify" : "build:dev"], spawnopts);
 | 
					    const thisbuildproc = spawn(
 | 
				
			||||||
 | 
					        [process.versions.bun ? "bun" : "npm", "run", cangoraw ? "verify" : "build:dev"].join(" "),
 | 
				
			||||||
 | 
					        spawnopts
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
    const thisbuildstart = Date.now();
 | 
					    const thisbuildstart = Date.now();
 | 
				
			||||||
    buildproc = thisbuildproc;
 | 
					    buildproc = thisbuildproc;
 | 
				
			||||||
    buildproc.on("exit", code => {
 | 
					    buildproc.on("exit", code => {
 | 
				
			||||||
@ -38,8 +52,17 @@ function run(changedFile) {
 | 
				
			|||||||
        }
 | 
					        }
 | 
				
			||||||
        buildproc = undefined;
 | 
					        buildproc = undefined;
 | 
				
			||||||
        if (code === 0) {
 | 
					        if (code === 0) {
 | 
				
			||||||
            console.log(`${process.versions.bun ? "Verified" : "Built"} in ${Date.now() - thisbuildstart} ms`);
 | 
					            console.log(`${cangoraw ? "Verified" : "Built"} in ${Date.now() - thisbuildstart} ms`);
 | 
				
			||||||
            runproc = spawn("npm", ["run", process.versions.bun ? "bun-run" : "start", "--", ...args], spawnopts);
 | 
					            runproc = spawn(
 | 
				
			||||||
 | 
					                [
 | 
				
			||||||
 | 
					                    process.versions.bun ? "bun" : "npm",
 | 
				
			||||||
 | 
					                    "run",
 | 
				
			||||||
 | 
					                    cangoraw ? (process.versions.bun ? "raw:bun" : "raw") : "start",
 | 
				
			||||||
 | 
					                    "--",
 | 
				
			||||||
 | 
					                    ...args
 | 
				
			||||||
 | 
					                ].join(" "),
 | 
				
			||||||
 | 
					                spawnopts
 | 
				
			||||||
 | 
					            );
 | 
				
			||||||
            runproc.on("exit", () => {
 | 
					            runproc.on("exit", () => {
 | 
				
			||||||
                runproc = undefined;
 | 
					                runproc = undefined;
 | 
				
			||||||
            });
 | 
					            });
 | 
				
			||||||
@ -1,46 +0,0 @@
 | 
				
			|||||||
/* eslint-disable */
 | 
					 | 
				
			||||||
const fs = require("fs");
 | 
					 | 
				
			||||||
const path = require("path");
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
const root = path.join(process.cwd(), "..");
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
function listFiles(dir) {
 | 
					 | 
				
			||||||
    const entries = fs.readdirSync(dir, { withFileTypes: true });
 | 
					 | 
				
			||||||
    let results = [];
 | 
					 | 
				
			||||||
    for (const entry of entries) {
 | 
					 | 
				
			||||||
        const fullPath = path.join(dir, entry.name);
 | 
					 | 
				
			||||||
        if (entry.isDirectory()) {
 | 
					 | 
				
			||||||
            results = results.concat(listFiles(fullPath));
 | 
					 | 
				
			||||||
        } else {
 | 
					 | 
				
			||||||
            results.push(fullPath);
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    return results;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
const files = listFiles(path.join(root, "src"));
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
for (const file of files) {
 | 
					 | 
				
			||||||
    let content;
 | 
					 | 
				
			||||||
    try {
 | 
					 | 
				
			||||||
        content = fs.readFileSync(file, "utf8");
 | 
					 | 
				
			||||||
    } catch (e) {
 | 
					 | 
				
			||||||
        continue;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    const dir = path.dirname(file);
 | 
					 | 
				
			||||||
    const fixedContent = content.replaceAll(/} from "([^"]+)";/g, (sub, importPath) => {
 | 
					 | 
				
			||||||
        if (!importPath.startsWith("@/")) {
 | 
					 | 
				
			||||||
            const fullImportPath = path.resolve(dir, importPath);
 | 
					 | 
				
			||||||
            if (fs.existsSync(fullImportPath + ".ts")) {
 | 
					 | 
				
			||||||
                const relative = path.relative(root, fullImportPath).replace(/\\/g, "/");
 | 
					 | 
				
			||||||
                const fixedPath = "@/" + relative;
 | 
					 | 
				
			||||||
                console.log(`${importPath} -> ${fixedPath}`);
 | 
					 | 
				
			||||||
                return sub.split(importPath).join(fixedPath);
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        return sub;
 | 
					 | 
				
			||||||
    });
 | 
					 | 
				
			||||||
    if (content != fixedContent) {
 | 
					 | 
				
			||||||
        fs.writeFileSync(file, fixedContent, "utf8");
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
							
								
								
									
										9
									
								
								scripts/raw-precheck.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								scripts/raw-precheck.js
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,9 @@
 | 
				
			|||||||
 | 
					const [major, minor] = process.versions.node.split(".").map(x => parseInt(x));
 | 
				
			||||||
 | 
					if (major > 22 || (major == 22 && minor >= 7)) {
 | 
				
			||||||
 | 
					    // ok
 | 
				
			||||||
 | 
					} else {
 | 
				
			||||||
 | 
					    console.log("Sorry, your Node version is a bit too old for this. You have 2 options:");
 | 
				
			||||||
 | 
					    console.log("- Update Node.js.");
 | 
				
			||||||
 | 
					    console.log("- Use 'npm run build && npm run start'. Optional libraries must be installed for this.");
 | 
				
			||||||
 | 
					    process.exit(1);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@ -31,7 +31,7 @@ fs.readdirSync("../static/webui/translations").forEach(file => {
 | 
				
			|||||||
            const strings = extractStrings(line);
 | 
					            const strings = extractStrings(line);
 | 
				
			||||||
            if (Object.keys(strings).length > 0) {
 | 
					            if (Object.keys(strings).length > 0) {
 | 
				
			||||||
                Object.entries(strings).forEach(([key, value]) => {
 | 
					                Object.entries(strings).forEach(([key, value]) => {
 | 
				
			||||||
                    if (targetStrings.hasOwnProperty(key) && !targetStrings[key].startsWith("[UNTRANSLATED] ")) {
 | 
					                    if (targetStrings.hasOwnProperty(key) && !targetStrings[key].startsWith("[UNTRANSLATED]")) {
 | 
				
			||||||
                        fs.writeSync(fileHandle, `    ${key}: \`${targetStrings[key]}\`,\n`);
 | 
					                        fs.writeSync(fileHandle, `    ${key}: \`${targetStrings[key]}\`,\n`);
 | 
				
			||||||
                    } else {
 | 
					                    } else {
 | 
				
			||||||
                        fs.writeSync(fileHandle, `    ${key}: \`[UNTRANSLATED] ${value}\`,\n`);
 | 
					                        fs.writeSync(fileHandle, `    ${key}: \`[UNTRANSLATED] ${value}\`,\n`);
 | 
				
			||||||
							
								
								
									
										22
									
								
								src/app.ts
									
									
									
									
									
								
							
							
						
						
									
										22
									
								
								src/app.ts
									
									
									
									
									
								
							@ -1,23 +1,23 @@
 | 
				
			|||||||
import express from "express";
 | 
					import express from "express";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import bodyParser from "body-parser";
 | 
					import bodyParser from "body-parser";
 | 
				
			||||||
import { unknownEndpointHandler } from "@/src/middleware/middleware";
 | 
					import { unknownEndpointHandler } from "./middleware/middleware.ts";
 | 
				
			||||||
import { requestLogger } from "@/src/middleware/morgenMiddleware";
 | 
					import { requestLogger } from "./middleware/morgenMiddleware.ts";
 | 
				
			||||||
import { errorHandler } from "@/src/middleware/errorHandler";
 | 
					import { errorHandler } from "./middleware/errorHandler.ts";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import { apiRouter } from "@/src/routes/api";
 | 
					import { apiRouter } from "./routes/api.ts";
 | 
				
			||||||
import { cacheRouter } from "@/src/routes/cache";
 | 
					import { cacheRouter } from "./routes/cache.ts";
 | 
				
			||||||
import { customRouter } from "@/src/routes/custom";
 | 
					import { customRouter } from "./routes/custom.ts";
 | 
				
			||||||
import { dynamicController } from "@/src/routes/dynamic";
 | 
					import { dynamicController } from "./routes/dynamic.ts";
 | 
				
			||||||
import { payRouter } from "@/src/routes/pay";
 | 
					import { payRouter } from "./routes/pay.ts";
 | 
				
			||||||
import { statsRouter } from "@/src/routes/stats";
 | 
					import { statsRouter } from "./routes/stats.ts";
 | 
				
			||||||
import { webuiRouter } from "@/src/routes/webui";
 | 
					import { webuiRouter } from "./routes/webui.ts";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const app = express();
 | 
					const app = express();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
app.use((req, _res, next) => {
 | 
					app.use((req, _res, next) => {
 | 
				
			||||||
    // 38.5.0 introduced "ezip" for encrypted body blobs and "e" for request verification only (encrypted body blobs with no application data).
 | 
					    // 38.5.0 introduced "ezip" for encrypted body blobs and "e" for request verification only (encrypted body blobs with no application data).
 | 
				
			||||||
    // The bootstrapper decrypts it for us but having an unsupported Content-Encoding here would still be an issue for Express, so removing it.
 | 
					    // The client patch is expected to decrypt it for us but having an unsupported Content-Encoding here would still be an issue for Express, so removing it.
 | 
				
			||||||
    if (req.headers["content-encoding"] == "ezip" || req.headers["content-encoding"] == "e") {
 | 
					    if (req.headers["content-encoding"] == "ezip" || req.headers["content-encoding"] == "e") {
 | 
				
			||||||
        req.headers["content-encoding"] = undefined;
 | 
					        req.headers["content-encoding"] = undefined;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
				
			|||||||
@ -1,3 +1,5 @@
 | 
				
			|||||||
 | 
					export const EPOCH = 1734307200_000; // Monday, Dec 16, 2024 @ 00:00 UTC+0; should logically be the start of winter in 1999 iteration 0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const millisecondsPerSecond = 1000;
 | 
					const millisecondsPerSecond = 1000;
 | 
				
			||||||
const secondsPerMinute = 60;
 | 
					const secondsPerMinute = 60;
 | 
				
			||||||
const minutesPerHour = 60;
 | 
					const minutesPerHour = 60;
 | 
				
			||||||
 | 
				
			|||||||
@ -1,6 +1,6 @@
 | 
				
			|||||||
import { getInventory } from "@/src/services/inventoryService";
 | 
					import { getInventory } from "../../services/inventoryService.ts";
 | 
				
			||||||
import { getAccountIdForRequest } from "@/src/services/loginService";
 | 
					import { getAccountIdForRequest } from "../../services/loginService.ts";
 | 
				
			||||||
import { RequestHandler } from "express";
 | 
					import type { RequestHandler } from "express";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export const abandonLibraryDailyTaskController: RequestHandler = async (req, res) => {
 | 
					export const abandonLibraryDailyTaskController: RequestHandler = async (req, res) => {
 | 
				
			||||||
    const accountId = await getAccountIdForRequest(req);
 | 
					    const accountId = await getAccountIdForRequest(req);
 | 
				
			||||||
 | 
				
			|||||||
@ -5,11 +5,11 @@ import {
 | 
				
			|||||||
    hasGuildPermission,
 | 
					    hasGuildPermission,
 | 
				
			||||||
    removeDojoDeco,
 | 
					    removeDojoDeco,
 | 
				
			||||||
    removeDojoRoom
 | 
					    removeDojoRoom
 | 
				
			||||||
} from "@/src/services/guildService";
 | 
					} from "../../services/guildService.ts";
 | 
				
			||||||
import { getInventory } from "@/src/services/inventoryService";
 | 
					import { getInventory } from "../../services/inventoryService.ts";
 | 
				
			||||||
import { getAccountIdForRequest } from "@/src/services/loginService";
 | 
					import { getAccountIdForRequest } from "../../services/loginService.ts";
 | 
				
			||||||
import { GuildPermission } from "@/src/types/guildTypes";
 | 
					import { GuildPermission } from "../../types/guildTypes.ts";
 | 
				
			||||||
import { RequestHandler } from "express";
 | 
					import type { RequestHandler } from "express";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export const abortDojoComponentController: RequestHandler = async (req, res) => {
 | 
					export const abortDojoComponentController: RequestHandler = async (req, res) => {
 | 
				
			||||||
    const accountId = await getAccountIdForRequest(req);
 | 
					    const accountId = await getAccountIdForRequest(req);
 | 
				
			||||||
@ -31,12 +31,13 @@ export const abortDojoComponentController: RequestHandler = async (req, res) =>
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    if (request.DecoId) {
 | 
					    if (request.DecoId) {
 | 
				
			||||||
        removeDojoDeco(guild, request.ComponentId, request.DecoId);
 | 
					        removeDojoDeco(guild, request.ComponentId, request.DecoId);
 | 
				
			||||||
    } else {
 | 
					 | 
				
			||||||
        await removeDojoRoom(guild, request.ComponentId);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        await guild.save();
 | 
					        await guild.save();
 | 
				
			||||||
        res.json(await getDojoClient(guild, 0, request.ComponentId));
 | 
					        res.json(await getDojoClient(guild, 0, request.ComponentId));
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					        await removeDojoRoom(guild, request.ComponentId);
 | 
				
			||||||
 | 
					        await guild.save();
 | 
				
			||||||
 | 
					        res.json(await getDojoClient(guild, 0));
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
interface IAbortDojoComponentRequest {
 | 
					interface IAbortDojoComponentRequest {
 | 
				
			||||||
 | 
				
			|||||||
@ -1,8 +1,13 @@
 | 
				
			|||||||
import { getDojoClient, getGuildForRequestEx, hasAccessToDojo, hasGuildPermission } from "@/src/services/guildService";
 | 
					import {
 | 
				
			||||||
import { getInventory } from "@/src/services/inventoryService";
 | 
					    getDojoClient,
 | 
				
			||||||
import { getAccountIdForRequest } from "@/src/services/loginService";
 | 
					    getGuildForRequestEx,
 | 
				
			||||||
import { GuildPermission } from "@/src/types/guildTypes";
 | 
					    hasAccessToDojo,
 | 
				
			||||||
import { RequestHandler } from "express";
 | 
					    hasGuildPermission
 | 
				
			||||||
 | 
					} from "../../services/guildService.ts";
 | 
				
			||||||
 | 
					import { getInventory } from "../../services/inventoryService.ts";
 | 
				
			||||||
 | 
					import { getAccountIdForRequest } from "../../services/loginService.ts";
 | 
				
			||||||
 | 
					import { GuildPermission } from "../../types/guildTypes.ts";
 | 
				
			||||||
 | 
					import type { RequestHandler } from "express";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export const abortDojoComponentDestructionController: RequestHandler = async (req, res) => {
 | 
					export const abortDojoComponentDestructionController: RequestHandler = async (req, res) => {
 | 
				
			||||||
    const accountId = await getAccountIdForRequest(req);
 | 
					    const accountId = await getAccountIdForRequest(req);
 | 
				
			||||||
 | 
				
			|||||||
@ -1,20 +1,19 @@
 | 
				
			|||||||
import { toOid } from "@/src/helpers/inventoryHelpers";
 | 
					import { toOid } from "../../helpers/inventoryHelpers.ts";
 | 
				
			||||||
import {
 | 
					import {
 | 
				
			||||||
    createVeiledRivenFingerprint,
 | 
					    createVeiledRivenFingerprint,
 | 
				
			||||||
    createUnveiledRivenFingerprint,
 | 
					    createUnveiledRivenFingerprint,
 | 
				
			||||||
    rivenRawToRealWeighted
 | 
					    rivenRawToRealWeighted
 | 
				
			||||||
} from "@/src/helpers/rivenHelper";
 | 
					} from "../../helpers/rivenHelper.ts";
 | 
				
			||||||
import { getJSONfromString } from "@/src/helpers/stringHelpers";
 | 
					import { getJSONfromString } from "../../helpers/stringHelpers.ts";
 | 
				
			||||||
import { addMods, getInventory } from "@/src/services/inventoryService";
 | 
					import { addMods, getInventory } from "../../services/inventoryService.ts";
 | 
				
			||||||
import { getAccountIdForRequest } from "@/src/services/loginService";
 | 
					import { getAccountIdForRequest } from "../../services/loginService.ts";
 | 
				
			||||||
import { getRandomElement } from "@/src/services/rngService";
 | 
					import { getRandomElement } from "../../services/rngService.ts";
 | 
				
			||||||
import { RequestHandler } from "express";
 | 
					import type { RequestHandler } from "express";
 | 
				
			||||||
import { ExportUpgrades } from "warframe-public-export-plus";
 | 
					import { ExportUpgrades } from "warframe-public-export-plus";
 | 
				
			||||||
import { config } from "@/src/services/configService";
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
export const activateRandomModController: RequestHandler = async (req, res) => {
 | 
					export const activateRandomModController: RequestHandler = async (req, res) => {
 | 
				
			||||||
    const accountId = await getAccountIdForRequest(req);
 | 
					    const accountId = await getAccountIdForRequest(req);
 | 
				
			||||||
    const inventory = await getInventory(accountId);
 | 
					    const inventory = await getInventory(accountId, "RawUpgrades Upgrades instantFinishRivenChallenge");
 | 
				
			||||||
    const request = getJSONfromString<IActiveRandomModRequest>(String(req.body));
 | 
					    const request = getJSONfromString<IActiveRandomModRequest>(String(req.body));
 | 
				
			||||||
    addMods(inventory, [
 | 
					    addMods(inventory, [
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
@ -23,7 +22,7 @@ export const activateRandomModController: RequestHandler = async (req, res) => {
 | 
				
			|||||||
        }
 | 
					        }
 | 
				
			||||||
    ]);
 | 
					    ]);
 | 
				
			||||||
    const rivenType = getRandomElement(rivenRawToRealWeighted[request.ItemType])!;
 | 
					    const rivenType = getRandomElement(rivenRawToRealWeighted[request.ItemType])!;
 | 
				
			||||||
    const fingerprint = config.instantFinishRivenChallenge
 | 
					    const fingerprint = inventory.instantFinishRivenChallenge
 | 
				
			||||||
        ? createUnveiledRivenFingerprint(ExportUpgrades[rivenType])
 | 
					        ? createUnveiledRivenFingerprint(ExportUpgrades[rivenType])
 | 
				
			||||||
        : createVeiledRivenFingerprint(ExportUpgrades[rivenType]);
 | 
					        : createVeiledRivenFingerprint(ExportUpgrades[rivenType]);
 | 
				
			||||||
    const upgradeIndex =
 | 
					    const upgradeIndex =
 | 
				
			||||||
 | 
				
			|||||||
@ -1,10 +1,10 @@
 | 
				
			|||||||
import { toOid } from "@/src/helpers/inventoryHelpers";
 | 
					import { toOid } from "../../helpers/inventoryHelpers.ts";
 | 
				
			||||||
import { getJSONfromString } from "@/src/helpers/stringHelpers";
 | 
					import { getJSONfromString } from "../../helpers/stringHelpers.ts";
 | 
				
			||||||
import { Friendship } from "@/src/models/friendModel";
 | 
					import { Friendship } from "../../models/friendModel.ts";
 | 
				
			||||||
import { addAccountDataToFriendInfo, addInventoryDataToFriendInfo } from "@/src/services/friendService";
 | 
					import { addAccountDataToFriendInfo, addInventoryDataToFriendInfo } from "../../services/friendService.ts";
 | 
				
			||||||
import { getAccountIdForRequest } from "@/src/services/loginService";
 | 
					import { getAccountIdForRequest } from "../../services/loginService.ts";
 | 
				
			||||||
import { IFriendInfo } from "@/src/types/friendTypes";
 | 
					import type { IFriendInfo } from "../../types/friendTypes.ts";
 | 
				
			||||||
import { RequestHandler } from "express";
 | 
					import type { RequestHandler } from "express";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export const addFriendController: RequestHandler = async (req, res) => {
 | 
					export const addFriendController: RequestHandler = async (req, res) => {
 | 
				
			||||||
    const accountId = await getAccountIdForRequest(req);
 | 
					    const accountId = await getAccountIdForRequest(req);
 | 
				
			||||||
 | 
				
			|||||||
@ -1,7 +1,7 @@
 | 
				
			|||||||
import { RequestHandler } from "express";
 | 
					import type { RequestHandler } from "express";
 | 
				
			||||||
import { getJSONfromString } from "@/src/helpers/stringHelpers";
 | 
					import { getJSONfromString } from "../../helpers/stringHelpers.ts";
 | 
				
			||||||
import { getAccountIdForRequest } from "@/src/services/loginService";
 | 
					import { getAccountIdForRequest } from "../../services/loginService.ts";
 | 
				
			||||||
import { Inventory } from "@/src/models/inventoryModels/inventoryModel";
 | 
					import { Inventory } from "../../models/inventoryModels/inventoryModel.ts";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export const addFriendImageController: RequestHandler = async (req, res) => {
 | 
					export const addFriendImageController: RequestHandler = async (req, res) => {
 | 
				
			||||||
    const accountId = await getAccountIdForRequest(req);
 | 
					    const accountId = await getAccountIdForRequest(req);
 | 
				
			||||||
 | 
				
			|||||||
@ -1,9 +1,9 @@
 | 
				
			|||||||
import { toOid } from "@/src/helpers/inventoryHelpers";
 | 
					import { toOid } from "../../helpers/inventoryHelpers.ts";
 | 
				
			||||||
import { getJSONfromString } from "@/src/helpers/stringHelpers";
 | 
					import { getJSONfromString } from "../../helpers/stringHelpers.ts";
 | 
				
			||||||
import { Account, Ignore } from "@/src/models/loginModel";
 | 
					import { Account, Ignore } from "../../models/loginModel.ts";
 | 
				
			||||||
import { getAccountIdForRequest } from "@/src/services/loginService";
 | 
					import { getAccountIdForRequest } from "../../services/loginService.ts";
 | 
				
			||||||
import { IFriendInfo } from "@/src/types/friendTypes";
 | 
					import type { IFriendInfo } from "../../types/friendTypes.ts";
 | 
				
			||||||
import { RequestHandler } from "express";
 | 
					import type { RequestHandler } from "express";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export const addIgnoredUserController: RequestHandler = async (req, res) => {
 | 
					export const addIgnoredUserController: RequestHandler = async (req, res) => {
 | 
				
			||||||
    const accountId = await getAccountIdForRequest(req);
 | 
					    const accountId = await getAccountIdForRequest(req);
 | 
				
			||||||
 | 
				
			|||||||
@ -1,12 +1,12 @@
 | 
				
			|||||||
import { toMongoDate, toOid } from "@/src/helpers/inventoryHelpers";
 | 
					import { toMongoDate, toOid } from "../../helpers/inventoryHelpers.ts";
 | 
				
			||||||
import { getJSONfromString } from "@/src/helpers/stringHelpers";
 | 
					import { getJSONfromString } from "../../helpers/stringHelpers.ts";
 | 
				
			||||||
import { Friendship } from "@/src/models/friendModel";
 | 
					import { Friendship } from "../../models/friendModel.ts";
 | 
				
			||||||
import { Account } from "@/src/models/loginModel";
 | 
					import { Account } from "../../models/loginModel.ts";
 | 
				
			||||||
import { addInventoryDataToFriendInfo, areFriendsOfFriends } from "@/src/services/friendService";
 | 
					import { addInventoryDataToFriendInfo, areFriendsOfFriends } from "../../services/friendService.ts";
 | 
				
			||||||
import { getInventory } from "@/src/services/inventoryService";
 | 
					import { getInventory } from "../../services/inventoryService.ts";
 | 
				
			||||||
import { getAccountIdForRequest } from "@/src/services/loginService";
 | 
					import { getAccountIdForRequest } from "../../services/loginService.ts";
 | 
				
			||||||
import { IFriendInfo } from "@/src/types/friendTypes";
 | 
					import type { IFriendInfo } from "../../types/friendTypes.ts";
 | 
				
			||||||
import { RequestHandler } from "express";
 | 
					import type { RequestHandler } from "express";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export const addPendingFriendController: RequestHandler = async (req, res) => {
 | 
					export const addPendingFriendController: RequestHandler = async (req, res) => {
 | 
				
			||||||
    const payload = getJSONfromString<IAddPendingFriendRequest>(String(req.body));
 | 
					    const payload = getJSONfromString<IAddPendingFriendRequest>(String(req.body));
 | 
				
			||||||
 | 
				
			|||||||
@ -1,11 +1,11 @@
 | 
				
			|||||||
import { getJSONfromString, regexEscape } from "@/src/helpers/stringHelpers";
 | 
					import { getJSONfromString, regexEscape } from "../../helpers/stringHelpers.ts";
 | 
				
			||||||
import { Alliance, AllianceMember, Guild, GuildMember } from "@/src/models/guildModel";
 | 
					import { Alliance, AllianceMember, Guild, GuildMember } from "../../models/guildModel.ts";
 | 
				
			||||||
import { createMessage } from "@/src/services/inboxService";
 | 
					import { createMessage } from "../../services/inboxService.ts";
 | 
				
			||||||
import { getEffectiveAvatarImageType, getInventory } from "@/src/services/inventoryService";
 | 
					import { getEffectiveAvatarImageType, getInventory } from "../../services/inventoryService.ts";
 | 
				
			||||||
import { getAccountForRequest, getSuffixedName } from "@/src/services/loginService";
 | 
					import { getAccountForRequest, getSuffixedName } from "../../services/loginService.ts";
 | 
				
			||||||
import { GuildPermission } from "@/src/types/guildTypes";
 | 
					import { GuildPermission } from "../../types/guildTypes.ts";
 | 
				
			||||||
import { logger } from "@/src/utils/logger";
 | 
					import { logger } from "../../utils/logger.ts";
 | 
				
			||||||
import { RequestHandler } from "express";
 | 
					import type { RequestHandler } from "express";
 | 
				
			||||||
import { ExportFlavour } from "warframe-public-export-plus";
 | 
					import { ExportFlavour } from "warframe-public-export-plus";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export const addToAllianceController: RequestHandler = async (req, res) => {
 | 
					export const addToAllianceController: RequestHandler = async (req, res) => {
 | 
				
			||||||
 | 
				
			|||||||
@ -1,15 +1,16 @@
 | 
				
			|||||||
import { toMongoDate } from "@/src/helpers/inventoryHelpers";
 | 
					import { toMongoDate } from "../../helpers/inventoryHelpers.ts";
 | 
				
			||||||
import { Guild, GuildMember } from "@/src/models/guildModel";
 | 
					import { Guild, GuildMember } from "../../models/guildModel.ts";
 | 
				
			||||||
import { Account } from "@/src/models/loginModel";
 | 
					import { Account } from "../../models/loginModel.ts";
 | 
				
			||||||
import { addInventoryDataToFriendInfo, areFriends } from "@/src/services/friendService";
 | 
					import { addInventoryDataToFriendInfo, areFriends } from "../../services/friendService.ts";
 | 
				
			||||||
import { hasGuildPermission } from "@/src/services/guildService";
 | 
					import { hasGuildPermission } from "../../services/guildService.ts";
 | 
				
			||||||
import { createMessage } from "@/src/services/inboxService";
 | 
					import { createMessage } from "../../services/inboxService.ts";
 | 
				
			||||||
import { getEffectiveAvatarImageType, getInventory } from "@/src/services/inventoryService";
 | 
					import { getEffectiveAvatarImageType, getInventory } from "../../services/inventoryService.ts";
 | 
				
			||||||
import { getAccountForRequest, getAccountIdForRequest, getSuffixedName } from "@/src/services/loginService";
 | 
					import { getAccountForRequest, getAccountIdForRequest, getSuffixedName } from "../../services/loginService.ts";
 | 
				
			||||||
import { IOid } from "@/src/types/commonTypes";
 | 
					import type { IOid } from "../../types/commonTypes.ts";
 | 
				
			||||||
import { GuildPermission, IGuildMemberClient } from "@/src/types/guildTypes";
 | 
					import type { IGuildMemberClient } from "../../types/guildTypes.ts";
 | 
				
			||||||
import { logger } from "@/src/utils/logger";
 | 
					import { GuildPermission } from "../../types/guildTypes.ts";
 | 
				
			||||||
import { RequestHandler } from "express";
 | 
					import { logger } from "../../utils/logger.ts";
 | 
				
			||||||
 | 
					import type { RequestHandler } from "express";
 | 
				
			||||||
import { ExportFlavour } from "warframe-public-export-plus";
 | 
					import { ExportFlavour } from "warframe-public-export-plus";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export const addToGuildController: RequestHandler = async (req, res) => {
 | 
					export const addToGuildController: RequestHandler = async (req, res) => {
 | 
				
			||||||
 | 
				
			|||||||
@ -1,7 +1,7 @@
 | 
				
			|||||||
import { getJSONfromString } from "@/src/helpers/stringHelpers";
 | 
					import { getJSONfromString } from "../../helpers/stringHelpers.ts";
 | 
				
			||||||
import { getInventory } from "@/src/services/inventoryService";
 | 
					import { getInventory } from "../../services/inventoryService.ts";
 | 
				
			||||||
import { getAccountIdForRequest } from "@/src/services/loginService";
 | 
					import { getAccountIdForRequest } from "../../services/loginService.ts";
 | 
				
			||||||
import { RequestHandler } from "express";
 | 
					import type { RequestHandler } from "express";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export const adoptPetController: RequestHandler = async (req, res) => {
 | 
					export const adoptPetController: RequestHandler = async (req, res) => {
 | 
				
			||||||
    const accountId = await getAccountIdForRequest(req);
 | 
					    const accountId = await getAccountIdForRequest(req);
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										22
									
								
								src/controllers/api/apartmentController.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								src/controllers/api/apartmentController.ts
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,22 @@
 | 
				
			|||||||
 | 
					import { getAccountIdForRequest } from "../../services/loginService.ts";
 | 
				
			||||||
 | 
					import { getPersonalRooms } from "../../services/personalRoomsService.ts";
 | 
				
			||||||
 | 
					import type { RequestHandler } from "express";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export const apartmentController: RequestHandler = async (req, res) => {
 | 
				
			||||||
 | 
					    const accountId = await getAccountIdForRequest(req);
 | 
				
			||||||
 | 
					    const personalRooms = await getPersonalRooms(accountId, "Apartment");
 | 
				
			||||||
 | 
					    const response: IApartmentResponse = {};
 | 
				
			||||||
 | 
					    if (req.query.backdrop !== undefined) {
 | 
				
			||||||
 | 
					        response.NewBackdropItem = personalRooms.Apartment.VideoWallBackdrop = req.query.backdrop as string;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    if (req.query.soundscape !== undefined) {
 | 
				
			||||||
 | 
					        response.NewSoundscapeItem = personalRooms.Apartment.Soundscape = req.query.soundscape as string;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    await personalRooms.save();
 | 
				
			||||||
 | 
					    res.json(response);
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					interface IApartmentResponse {
 | 
				
			||||||
 | 
					    NewBackdropItem?: string;
 | 
				
			||||||
 | 
					    NewSoundscapeItem?: string;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@ -1,8 +1,8 @@
 | 
				
			|||||||
import { RequestHandler } from "express";
 | 
					import type { RequestHandler } from "express";
 | 
				
			||||||
import { getJSONfromString } from "@/src/helpers/stringHelpers";
 | 
					import { getJSONfromString } from "../../helpers/stringHelpers.ts";
 | 
				
			||||||
import { getAccountIdForRequest } from "@/src/services/loginService";
 | 
					import { getAccountIdForRequest } from "../../services/loginService.ts";
 | 
				
			||||||
import { getInventory, addMods } from "@/src/services/inventoryService";
 | 
					import { getInventory, addMods } from "../../services/inventoryService.ts";
 | 
				
			||||||
import { IOid } from "@/src/types/commonTypes";
 | 
					import type { IOid } from "../../types/commonTypes.ts";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export const arcaneCommonController: RequestHandler = async (req, res) => {
 | 
					export const arcaneCommonController: RequestHandler = async (req, res) => {
 | 
				
			||||||
    const accountId = await getAccountIdForRequest(req);
 | 
					    const accountId = await getAccountIdForRequest(req);
 | 
				
			||||||
 | 
				
			|||||||
@ -1,8 +1,8 @@
 | 
				
			|||||||
import { RequestHandler } from "express";
 | 
					import type { RequestHandler } from "express";
 | 
				
			||||||
import { getAccountIdForRequest } from "@/src/services/loginService";
 | 
					import { getAccountIdForRequest } from "../../services/loginService.ts";
 | 
				
			||||||
import { addMiscItems, getInventory } from "@/src/services/inventoryService";
 | 
					import { addMiscItems, getInventory } from "../../services/inventoryService.ts";
 | 
				
			||||||
import { IMiscItem } from "@/src/types/inventoryTypes/inventoryTypes";
 | 
					import type { IMiscItem } from "../../types/inventoryTypes/inventoryTypes.ts";
 | 
				
			||||||
import { colorToShard, combineColors, shardToColor } from "@/src/helpers/shardHelper";
 | 
					import { colorToShard, combineColors, shardToColor } from "../../helpers/shardHelper.ts";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export const archonFusionController: RequestHandler = async (req, res) => {
 | 
					export const archonFusionController: RequestHandler = async (req, res) => {
 | 
				
			||||||
    const accountId = await getAccountIdForRequest(req);
 | 
					    const accountId = await getAccountIdForRequest(req);
 | 
				
			||||||
 | 
				
			|||||||
@ -1,11 +1,12 @@
 | 
				
			|||||||
import { fromOid, toOid } from "@/src/helpers/inventoryHelpers";
 | 
					import { fromOid, toOid } from "../../helpers/inventoryHelpers.ts";
 | 
				
			||||||
import { createVeiledRivenFingerprint, rivenRawToRealWeighted } from "@/src/helpers/rivenHelper";
 | 
					import { createVeiledRivenFingerprint, rivenRawToRealWeighted } from "../../helpers/rivenHelper.ts";
 | 
				
			||||||
import { addMiscItems, addMods, getInventory } from "@/src/services/inventoryService";
 | 
					import { addMiscItems, addMods, getInventory } from "../../services/inventoryService.ts";
 | 
				
			||||||
import { getAccountIdForRequest } from "@/src/services/loginService";
 | 
					import { getAccountIdForRequest } from "../../services/loginService.ts";
 | 
				
			||||||
import { getRandomElement, getRandomWeightedReward, getRandomWeightedRewardUc } from "@/src/services/rngService";
 | 
					import { getRandomElement, getRandomWeightedReward, getRandomWeightedRewardUc } from "../../services/rngService.ts";
 | 
				
			||||||
import { IUpgradeFromClient } from "@/src/types/inventoryTypes/inventoryTypes";
 | 
					import type { IUpgradeFromClient } from "../../types/inventoryTypes/inventoryTypes.ts";
 | 
				
			||||||
import { RequestHandler } from "express";
 | 
					import type { RequestHandler } from "express";
 | 
				
			||||||
import { ExportBoosterPacks, ExportUpgrades, TRarity } from "warframe-public-export-plus";
 | 
					import type { TRarity } from "warframe-public-export-plus";
 | 
				
			||||||
 | 
					import { ExportBoosterPacks, ExportUpgrades } from "warframe-public-export-plus";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export const artifactTransmutationController: RequestHandler = async (req, res) => {
 | 
					export const artifactTransmutationController: RequestHandler = async (req, res) => {
 | 
				
			||||||
    const accountId = await getAccountIdForRequest(req);
 | 
					    const accountId = await getAccountIdForRequest(req);
 | 
				
			||||||
 | 
				
			|||||||
@ -1,9 +1,9 @@
 | 
				
			|||||||
import { getJSONfromString } from "@/src/helpers/stringHelpers";
 | 
					import { getJSONfromString } from "../../helpers/stringHelpers.ts";
 | 
				
			||||||
import { getAccountIdForRequest } from "@/src/services/loginService";
 | 
					import { getAccountIdForRequest } from "../../services/loginService.ts";
 | 
				
			||||||
import { RequestHandler } from "express";
 | 
					import type { RequestHandler } from "express";
 | 
				
			||||||
import { IInventoryClient, IUpgradeClient } from "@/src/types/inventoryTypes/inventoryTypes";
 | 
					import type { IInventoryClient, IUpgradeClient } from "../../types/inventoryTypes/inventoryTypes.ts";
 | 
				
			||||||
import { addMods, getInventory } from "@/src/services/inventoryService";
 | 
					import { addMods, getInventory } from "../../services/inventoryService.ts";
 | 
				
			||||||
import { config } from "@/src/services/configService";
 | 
					import { broadcastInventoryUpdate } from "../../services/wsService.ts";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export const artifactsController: RequestHandler = async (req, res) => {
 | 
					export const artifactsController: RequestHandler = async (req, res) => {
 | 
				
			||||||
    const accountId = await getAccountIdForRequest(req);
 | 
					    const accountId = await getAccountIdForRequest(req);
 | 
				
			||||||
@ -34,10 +34,10 @@ export const artifactsController: RequestHandler = async (req, res) => {
 | 
				
			|||||||
        addMods(inventory, [{ ItemType, ItemCount: -1 }]);
 | 
					        addMods(inventory, [{ ItemType, ItemCount: -1 }]);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (!config.infiniteCredits) {
 | 
					    if (!inventory.infiniteCredits) {
 | 
				
			||||||
        inventory.RegularCredits -= Cost;
 | 
					        inventory.RegularCredits -= Cost;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    if (!config.infiniteEndo) {
 | 
					    if (!inventory.infiniteEndo) {
 | 
				
			||||||
        inventory.FusionPoints -= FusionPointCost;
 | 
					        inventory.FusionPoints -= FusionPointCost;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -58,6 +58,7 @@ export const artifactsController: RequestHandler = async (req, res) => {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    res.send(itemId);
 | 
					    res.send(itemId);
 | 
				
			||||||
 | 
					    broadcastInventoryUpdate(req);
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
interface IArtifactsRequest {
 | 
					interface IArtifactsRequest {
 | 
				
			||||||
 | 
				
			|||||||
@ -1,9 +1,9 @@
 | 
				
			|||||||
import { GuildAd } from "@/src/models/guildModel";
 | 
					import { GuildAd } from "../../models/guildModel.ts";
 | 
				
			||||||
import { getGuildForRequestEx, hasGuildPermission } from "@/src/services/guildService";
 | 
					import { getGuildForRequestEx, hasGuildPermission } from "../../services/guildService.ts";
 | 
				
			||||||
import { getInventory } from "@/src/services/inventoryService";
 | 
					import { getInventory } from "../../services/inventoryService.ts";
 | 
				
			||||||
import { getAccountIdForRequest } from "@/src/services/loginService";
 | 
					import { getAccountIdForRequest } from "../../services/loginService.ts";
 | 
				
			||||||
import { GuildPermission } from "@/src/types/guildTypes";
 | 
					import { GuildPermission } from "../../types/guildTypes.ts";
 | 
				
			||||||
import { RequestHandler } from "express";
 | 
					import type { RequestHandler } from "express";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export const cancelGuildAdvertisementController: RequestHandler = async (req, res) => {
 | 
					export const cancelGuildAdvertisementController: RequestHandler = async (req, res) => {
 | 
				
			||||||
    const accountId = await getAccountIdForRequest(req);
 | 
					    const accountId = await getAccountIdForRequest(req);
 | 
				
			||||||
 | 
				
			|||||||
@ -1,10 +1,16 @@
 | 
				
			|||||||
import { RequestHandler } from "express";
 | 
					import type { RequestHandler } from "express";
 | 
				
			||||||
import { getDojoClient, getGuildForRequestEx, hasAccessToDojo, hasGuildPermission } from "@/src/services/guildService";
 | 
					import {
 | 
				
			||||||
import { logger } from "@/src/utils/logger";
 | 
					    getDojoClient,
 | 
				
			||||||
import { GuildPermission, IDojoComponentDatabase } from "@/src/types/guildTypes";
 | 
					    getGuildForRequestEx,
 | 
				
			||||||
 | 
					    hasAccessToDojo,
 | 
				
			||||||
 | 
					    hasGuildPermission
 | 
				
			||||||
 | 
					} from "../../services/guildService.ts";
 | 
				
			||||||
 | 
					import { logger } from "../../utils/logger.ts";
 | 
				
			||||||
 | 
					import type { IDojoComponentDatabase } from "../../types/guildTypes.ts";
 | 
				
			||||||
 | 
					import { GuildPermission } from "../../types/guildTypes.ts";
 | 
				
			||||||
import { Types } from "mongoose";
 | 
					import { Types } from "mongoose";
 | 
				
			||||||
import { getAccountIdForRequest } from "@/src/services/loginService";
 | 
					import { getAccountIdForRequest } from "../../services/loginService.ts";
 | 
				
			||||||
import { getInventory } from "@/src/services/inventoryService";
 | 
					import { getInventory } from "../../services/inventoryService.ts";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export const changeDojoRootController: RequestHandler = async (req, res) => {
 | 
					export const changeDojoRootController: RequestHandler = async (req, res) => {
 | 
				
			||||||
    const accountId = await getAccountIdForRequest(req);
 | 
					    const accountId = await getAccountIdForRequest(req);
 | 
				
			||||||
 | 
				
			|||||||
@ -1,8 +1,8 @@
 | 
				
			|||||||
import { GuildMember } from "@/src/models/guildModel";
 | 
					import { GuildMember } from "../../models/guildModel.ts";
 | 
				
			||||||
import { getGuildForRequest, hasGuildPermissionEx } from "@/src/services/guildService";
 | 
					import { getGuildForRequest, hasGuildPermissionEx } from "../../services/guildService.ts";
 | 
				
			||||||
import { getAccountIdForRequest } from "@/src/services/loginService";
 | 
					import { getAccountIdForRequest } from "../../services/loginService.ts";
 | 
				
			||||||
import { GuildPermission } from "@/src/types/guildTypes";
 | 
					import { GuildPermission } from "../../types/guildTypes.ts";
 | 
				
			||||||
import { RequestHandler } from "express";
 | 
					import type { RequestHandler } from "express";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export const changeGuildRankController: RequestHandler = async (req, res) => {
 | 
					export const changeGuildRankController: RequestHandler = async (req, res) => {
 | 
				
			||||||
    const accountId = await getAccountIdForRequest(req);
 | 
					    const accountId = await getAccountIdForRequest(req);
 | 
				
			||||||
 | 
				
			|||||||
@ -1,5 +1,5 @@
 | 
				
			|||||||
import { getAccountForRequest } from "@/src/services/loginService";
 | 
					import { getAccountForRequest } from "../../services/loginService.ts";
 | 
				
			||||||
import { RequestHandler } from "express";
 | 
					import type { RequestHandler } from "express";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export const checkDailyMissionBonusController: RequestHandler = async (req, res) => {
 | 
					export const checkDailyMissionBonusController: RequestHandler = async (req, res) => {
 | 
				
			||||||
    const account = await getAccountForRequest(req);
 | 
					    const account = await getAccountForRequest(req);
 | 
				
			||||||
 | 
				
			|||||||
@ -1,12 +1,13 @@
 | 
				
			|||||||
//this is a controller for the claimCompletedRecipe route
 | 
					//this is a controller for the claimCompletedRecipe route
 | 
				
			||||||
//it will claim a recipe for the user
 | 
					//it will claim a recipe for the user
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import { RequestHandler } from "express";
 | 
					import type { RequestHandler } from "express";
 | 
				
			||||||
import { logger } from "@/src/utils/logger";
 | 
					import { logger } from "../../utils/logger.ts";
 | 
				
			||||||
import { getRecipe } from "@/src/services/itemDataService";
 | 
					import { getRecipe } from "../../services/itemDataService.ts";
 | 
				
			||||||
import { IOid, IOidWithLegacySupport } from "@/src/types/commonTypes";
 | 
					import type { IOidWithLegacySupport } from "../../types/commonTypes.ts";
 | 
				
			||||||
import { getJSONfromString } from "@/src/helpers/stringHelpers";
 | 
					import { getJSONfromString } from "../../helpers/stringHelpers.ts";
 | 
				
			||||||
import { getAccountForRequest } from "@/src/services/loginService";
 | 
					import type { TAccountDocument } from "../../services/loginService.ts";
 | 
				
			||||||
 | 
					import { getAccountForRequest } from "../../services/loginService.ts";
 | 
				
			||||||
import {
 | 
					import {
 | 
				
			||||||
    getInventory,
 | 
					    getInventory,
 | 
				
			||||||
    updateCurrency,
 | 
					    updateCurrency,
 | 
				
			||||||
@ -17,26 +18,36 @@ import {
 | 
				
			|||||||
    addKubrowPetPrint,
 | 
					    addKubrowPetPrint,
 | 
				
			||||||
    addPowerSuit,
 | 
					    addPowerSuit,
 | 
				
			||||||
    addEquipment
 | 
					    addEquipment
 | 
				
			||||||
} from "@/src/services/inventoryService";
 | 
					} from "../../services/inventoryService.ts";
 | 
				
			||||||
import { IInventoryChanges } from "@/src/types/purchaseTypes";
 | 
					import type { IInventoryChanges } from "../../types/purchaseTypes.ts";
 | 
				
			||||||
import { InventorySlot, IPendingRecipeDatabase } from "@/src/types/inventoryTypes/inventoryTypes";
 | 
					import type { IPendingRecipeDatabase } from "../../types/inventoryTypes/inventoryTypes.ts";
 | 
				
			||||||
import { toOid2 } from "@/src/helpers/inventoryHelpers";
 | 
					import { InventorySlot } from "../../types/inventoryTypes/inventoryTypes.ts";
 | 
				
			||||||
import { TInventoryDatabaseDocument } from "@/src/models/inventoryModels/inventoryModel";
 | 
					import { fromOid, toOid2 } from "../../helpers/inventoryHelpers.ts";
 | 
				
			||||||
import { IRecipe } from "warframe-public-export-plus";
 | 
					import type { TInventoryDatabaseDocument } from "../../models/inventoryModels/inventoryModel.ts";
 | 
				
			||||||
import { config } from "@/src/services/configService";
 | 
					import type { IRecipe } from "warframe-public-export-plus";
 | 
				
			||||||
import { EquipmentFeatures, IEquipmentClient, Status } from "@/src/types/equipmentTypes";
 | 
					import type { IEquipmentClient } from "../../types/equipmentTypes.ts";
 | 
				
			||||||
 | 
					import { EquipmentFeatures, Status } from "../../types/equipmentTypes.ts";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
interface IClaimCompletedRecipeRequest {
 | 
					interface IClaimCompletedRecipeRequest {
 | 
				
			||||||
    RecipeIds: IOid[];
 | 
					    RecipeIds: IOidWithLegacySupport[];
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					interface IClaimCompletedRecipeResponse {
 | 
				
			||||||
 | 
					    InventoryChanges: IInventoryChanges;
 | 
				
			||||||
 | 
					    BrandedSuits?: IOidWithLegacySupport[];
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export const claimCompletedRecipeController: RequestHandler = async (req, res) => {
 | 
					export const claimCompletedRecipeController: RequestHandler = async (req, res) => {
 | 
				
			||||||
    const claimCompletedRecipeRequest = getJSONfromString<IClaimCompletedRecipeRequest>(String(req.body));
 | 
					    const claimCompletedRecipeRequest = getJSONfromString<IClaimCompletedRecipeRequest>(String(req.body));
 | 
				
			||||||
    const account = await getAccountForRequest(req);
 | 
					    const account = await getAccountForRequest(req);
 | 
				
			||||||
    const inventory = await getInventory(account._id.toString());
 | 
					    const inventory = await getInventory(account._id.toString());
 | 
				
			||||||
    const pendingRecipe = inventory.PendingRecipes.id(claimCompletedRecipeRequest.RecipeIds[0].$oid);
 | 
					    const resp: IClaimCompletedRecipeResponse = {
 | 
				
			||||||
 | 
					        InventoryChanges: {}
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					    for (const recipeId of claimCompletedRecipeRequest.RecipeIds) {
 | 
				
			||||||
 | 
					        const pendingRecipe = inventory.PendingRecipes.id(fromOid(recipeId));
 | 
				
			||||||
        if (!pendingRecipe) {
 | 
					        if (!pendingRecipe) {
 | 
				
			||||||
        throw new Error(`no pending recipe found with id ${claimCompletedRecipeRequest.RecipeIds[0].$oid}`);
 | 
					            throw new Error(`no pending recipe found with id ${fromOid(recipeId)}`);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        //check recipe is indeed ready to be completed
 | 
					        //check recipe is indeed ready to be completed
 | 
				
			||||||
@ -56,17 +67,30 @@ export const claimCompletedRecipeController: RequestHandler = async (req, res) =
 | 
				
			|||||||
            await refundRecipeIngredients(inventory, inventoryChanges, recipe, pendingRecipe);
 | 
					            await refundRecipeIngredients(inventory, inventoryChanges, recipe, pendingRecipe);
 | 
				
			||||||
            await inventory.save();
 | 
					            await inventory.save();
 | 
				
			||||||
            res.json(inventoryChanges); // Not a bug: In the specific case of cancelling a recipe, InventoryChanges are expected to be the root.
 | 
					            res.json(inventoryChanges); // Not a bug: In the specific case of cancelling a recipe, InventoryChanges are expected to be the root.
 | 
				
			||||||
    } else {
 | 
					            return;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        await claimCompletedRecipe(account, inventory, recipe, pendingRecipe, resp, req.query.rush);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    await inventory.save();
 | 
				
			||||||
 | 
					    res.json(resp);
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const claimCompletedRecipe = async (
 | 
				
			||||||
 | 
					    account: TAccountDocument,
 | 
				
			||||||
 | 
					    inventory: TInventoryDatabaseDocument,
 | 
				
			||||||
 | 
					    recipe: IRecipe,
 | 
				
			||||||
 | 
					    pendingRecipe: IPendingRecipeDatabase,
 | 
				
			||||||
 | 
					    resp: IClaimCompletedRecipeResponse,
 | 
				
			||||||
 | 
					    rush: any
 | 
				
			||||||
 | 
					): Promise<void> => {
 | 
				
			||||||
    logger.debug("Claiming Recipe", { recipe, pendingRecipe });
 | 
					    logger.debug("Claiming Recipe", { recipe, pendingRecipe });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        let BrandedSuits: undefined | IOidWithLegacySupport[];
 | 
					 | 
				
			||||||
    if (recipe.secretIngredientAction == "SIA_SPECTRE_LOADOUT_COPY") {
 | 
					    if (recipe.secretIngredientAction == "SIA_SPECTRE_LOADOUT_COPY") {
 | 
				
			||||||
        inventory.PendingSpectreLoadouts ??= [];
 | 
					        inventory.PendingSpectreLoadouts ??= [];
 | 
				
			||||||
        inventory.SpectreLoadouts ??= [];
 | 
					        inventory.SpectreLoadouts ??= [];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            const pendingLoadoutIndex = inventory.PendingSpectreLoadouts.findIndex(
 | 
					        const pendingLoadoutIndex = inventory.PendingSpectreLoadouts.findIndex(x => x.ItemType == recipe.resultType);
 | 
				
			||||||
                x => x.ItemType == recipe.resultType
 | 
					 | 
				
			||||||
            );
 | 
					 | 
				
			||||||
        if (pendingLoadoutIndex != -1) {
 | 
					        if (pendingLoadoutIndex != -1) {
 | 
				
			||||||
            const loadoutIndex = inventory.SpectreLoadouts.findIndex(x => x.ItemType == recipe.resultType);
 | 
					            const loadoutIndex = inventory.SpectreLoadouts.findIndex(x => x.ItemType == recipe.resultType);
 | 
				
			||||||
            if (loadoutIndex != -1) {
 | 
					            if (loadoutIndex != -1) {
 | 
				
			||||||
@ -84,10 +108,9 @@ export const claimCompletedRecipeController: RequestHandler = async (req, res) =
 | 
				
			|||||||
            inventory.BrandedSuits!.findIndex(x => x.equals(pendingRecipe.SuitToUnbrand)),
 | 
					            inventory.BrandedSuits!.findIndex(x => x.equals(pendingRecipe.SuitToUnbrand)),
 | 
				
			||||||
            1
 | 
					            1
 | 
				
			||||||
        );
 | 
					        );
 | 
				
			||||||
            BrandedSuits = [toOid2(pendingRecipe.SuitToUnbrand!, account.BuildLabel)];
 | 
					        resp.BrandedSuits = [toOid2(pendingRecipe.SuitToUnbrand!, account.BuildLabel)];
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        let InventoryChanges: IInventoryChanges = {};
 | 
					 | 
				
			||||||
    if (recipe.consumeOnUse) {
 | 
					    if (recipe.consumeOnUse) {
 | 
				
			||||||
        addRecipes(inventory, [
 | 
					        addRecipes(inventory, [
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
@ -96,17 +119,16 @@ export const claimCompletedRecipeController: RequestHandler = async (req, res) =
 | 
				
			|||||||
            }
 | 
					            }
 | 
				
			||||||
        ]);
 | 
					        ]);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
        if (req.query.rush) {
 | 
					
 | 
				
			||||||
 | 
					    if (rush) {
 | 
				
			||||||
        const end = Math.trunc(pendingRecipe.CompletionDate.getTime() / 1000);
 | 
					        const end = Math.trunc(pendingRecipe.CompletionDate.getTime() / 1000);
 | 
				
			||||||
        const start = end - recipe.buildTime;
 | 
					        const start = end - recipe.buildTime;
 | 
				
			||||||
        const secondsElapsed = Math.trunc(Date.now() / 1000) - start;
 | 
					        const secondsElapsed = Math.trunc(Date.now() / 1000) - start;
 | 
				
			||||||
        const progress = secondsElapsed / recipe.buildTime;
 | 
					        const progress = secondsElapsed / recipe.buildTime;
 | 
				
			||||||
        logger.debug(`rushing recipe at ${Math.trunc(progress * 100)}% completion`);
 | 
					        logger.debug(`rushing recipe at ${Math.trunc(progress * 100)}% completion`);
 | 
				
			||||||
            const cost = Math.round(recipe.skipBuildTimePrice * (1 - (progress - 0.5)));
 | 
					        const cost =
 | 
				
			||||||
            InventoryChanges = {
 | 
					            progress > 0.5 ? Math.round(recipe.skipBuildTimePrice * (1 - (progress - 0.5))) : recipe.skipBuildTimePrice;
 | 
				
			||||||
                ...InventoryChanges,
 | 
					        combineInventoryChanges(resp.InventoryChanges, updateCurrency(inventory, cost, true));
 | 
				
			||||||
                ...updateCurrency(inventory, cost, true)
 | 
					 | 
				
			||||||
            };
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (recipe.secretIngredientAction == "SIA_CREATE_KUBROW") {
 | 
					    if (recipe.secretIngredientAction == "SIA_CREATE_KUBROW") {
 | 
				
			||||||
@ -124,7 +146,7 @@ export const claimCompletedRecipeController: RequestHandler = async (req, res) =
 | 
				
			|||||||
        pet.Details!.Status = canSetActive ? Status.StatusAvailable : Status.StatusStasis;
 | 
					        pet.Details!.Status = canSetActive ? Status.StatusAvailable : Status.StatusStasis;
 | 
				
			||||||
    } else if (recipe.secretIngredientAction == "SIA_DISTILL_PRINT") {
 | 
					    } else if (recipe.secretIngredientAction == "SIA_DISTILL_PRINT") {
 | 
				
			||||||
        const pet = inventory.KubrowPets.id(pendingRecipe.KubrowPet!)!;
 | 
					        const pet = inventory.KubrowPets.id(pendingRecipe.KubrowPet!)!;
 | 
				
			||||||
            addKubrowPetPrint(inventory, pet, InventoryChanges);
 | 
					        addKubrowPetPrint(inventory, pet, resp.InventoryChanges);
 | 
				
			||||||
    } else if (recipe.secretIngredientAction != "SIA_UNBRAND") {
 | 
					    } else if (recipe.secretIngredientAction != "SIA_UNBRAND") {
 | 
				
			||||||
        if (recipe.resultType == "/Lotus/Powersuits/Excalibur/ExcaliburUmbra") {
 | 
					        if (recipe.resultType == "/Lotus/Powersuits/Excalibur/ExcaliburUmbra") {
 | 
				
			||||||
            // Quite the special case here...
 | 
					            // Quite the special case here...
 | 
				
			||||||
@ -181,8 +203,8 @@ export const claimCompletedRecipeController: RequestHandler = async (req, res) =
 | 
				
			|||||||
                    `{"lvl":5}`
 | 
					                    `{"lvl":5}`
 | 
				
			||||||
                )
 | 
					                )
 | 
				
			||||||
            ).Upgrades![0];
 | 
					            ).Upgrades![0];
 | 
				
			||||||
                InventoryChanges.Upgrades ??= [];
 | 
					            resp.InventoryChanges.Upgrades ??= [];
 | 
				
			||||||
                InventoryChanges.Upgrades.push(umbraModA, umbraModB, umbraModC, sacrificeModA, sacrificeModB);
 | 
					            resp.InventoryChanges.Upgrades.push(umbraModA, umbraModB, umbraModC, sacrificeModA, sacrificeModB);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            await addPowerSuit(
 | 
					            await addPowerSuit(
 | 
				
			||||||
                inventory,
 | 
					                inventory,
 | 
				
			||||||
@ -205,7 +227,7 @@ export const claimCompletedRecipeController: RequestHandler = async (req, res) =
 | 
				
			|||||||
                    XP: 900_000,
 | 
					                    XP: 900_000,
 | 
				
			||||||
                    Features: EquipmentFeatures.DOUBLE_CAPACITY
 | 
					                    Features: EquipmentFeatures.DOUBLE_CAPACITY
 | 
				
			||||||
                },
 | 
					                },
 | 
				
			||||||
                    InventoryChanges
 | 
					                resp.InventoryChanges
 | 
				
			||||||
            );
 | 
					            );
 | 
				
			||||||
            inventory.XPInfo.push({
 | 
					            inventory.XPInfo.push({
 | 
				
			||||||
                ItemType: "/Lotus/Powersuits/Excalibur/ExcaliburUmbra",
 | 
					                ItemType: "/Lotus/Powersuits/Excalibur/ExcaliburUmbra",
 | 
				
			||||||
@ -223,34 +245,31 @@ export const claimCompletedRecipeController: RequestHandler = async (req, res) =
 | 
				
			|||||||
                    XP: 450_000,
 | 
					                    XP: 450_000,
 | 
				
			||||||
                    Features: EquipmentFeatures.DOUBLE_CAPACITY
 | 
					                    Features: EquipmentFeatures.DOUBLE_CAPACITY
 | 
				
			||||||
                },
 | 
					                },
 | 
				
			||||||
                    InventoryChanges
 | 
					                resp.InventoryChanges
 | 
				
			||||||
            );
 | 
					            );
 | 
				
			||||||
            inventory.XPInfo.push({
 | 
					            inventory.XPInfo.push({
 | 
				
			||||||
                ItemType: "/Lotus/Weapons/Tenno/Melee/Swords/UmbraKatana/UmbraKatana",
 | 
					                ItemType: "/Lotus/Weapons/Tenno/Melee/Swords/UmbraKatana/UmbraKatana",
 | 
				
			||||||
                XP: 450_000
 | 
					                XP: 450_000
 | 
				
			||||||
            });
 | 
					            });
 | 
				
			||||||
        } else {
 | 
					        } else {
 | 
				
			||||||
                InventoryChanges = {
 | 
					            combineInventoryChanges(
 | 
				
			||||||
                    ...InventoryChanges,
 | 
					                resp.InventoryChanges,
 | 
				
			||||||
                    ...(await addItem(
 | 
					                await addItem(
 | 
				
			||||||
                    inventory,
 | 
					                    inventory,
 | 
				
			||||||
                    recipe.resultType,
 | 
					                    recipe.resultType,
 | 
				
			||||||
                    recipe.num,
 | 
					                    recipe.num,
 | 
				
			||||||
                    false,
 | 
					                    false,
 | 
				
			||||||
                    undefined,
 | 
					                    undefined,
 | 
				
			||||||
                    pendingRecipe.TargetFingerprint
 | 
					                    pendingRecipe.TargetFingerprint
 | 
				
			||||||
                    ))
 | 
					                )
 | 
				
			||||||
                };
 | 
					            );
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    if (
 | 
					    if (
 | 
				
			||||||
            config.claimingBlueprintRefundsIngredients &&
 | 
					        inventory.claimingBlueprintRefundsIngredients &&
 | 
				
			||||||
        recipe.secretIngredientAction != "SIA_CREATE_KUBROW" // Can't refund the egg
 | 
					        recipe.secretIngredientAction != "SIA_CREATE_KUBROW" // Can't refund the egg
 | 
				
			||||||
    ) {
 | 
					    ) {
 | 
				
			||||||
            await refundRecipeIngredients(inventory, InventoryChanges, recipe, pendingRecipe);
 | 
					        await refundRecipeIngredients(inventory, resp.InventoryChanges, recipe, pendingRecipe);
 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        await inventory.save();
 | 
					 | 
				
			||||||
        res.json({ InventoryChanges, BrandedSuits });
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -1,8 +1,8 @@
 | 
				
			|||||||
import { getJSONfromString } from "@/src/helpers/stringHelpers";
 | 
					import { getJSONfromString } from "../../helpers/stringHelpers.ts";
 | 
				
			||||||
import { combineInventoryChanges, getInventory } from "@/src/services/inventoryService";
 | 
					import { combineInventoryChanges, getInventory } from "../../services/inventoryService.ts";
 | 
				
			||||||
import { getAccountIdForRequest } from "@/src/services/loginService";
 | 
					import { getAccountIdForRequest } from "../../services/loginService.ts";
 | 
				
			||||||
import { handleStoreItemAcquisition } from "@/src/services/purchaseService";
 | 
					import { handleStoreItemAcquisition } from "../../services/purchaseService.ts";
 | 
				
			||||||
import { RequestHandler } from "express";
 | 
					import type { RequestHandler } from "express";
 | 
				
			||||||
import { ExportChallenges } from "warframe-public-export-plus";
 | 
					import { ExportChallenges } from "warframe-public-export-plus";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export const claimJunctionChallengeRewardController: RequestHandler = async (req, res) => {
 | 
					export const claimJunctionChallengeRewardController: RequestHandler = async (req, res) => {
 | 
				
			||||||
 | 
				
			|||||||
@ -1,6 +1,6 @@
 | 
				
			|||||||
import { addFusionPoints, getInventory } from "@/src/services/inventoryService";
 | 
					import { addFusionPoints, getInventory } from "../../services/inventoryService.ts";
 | 
				
			||||||
import { getAccountIdForRequest } from "@/src/services/loginService";
 | 
					import { getAccountIdForRequest } from "../../services/loginService.ts";
 | 
				
			||||||
import { RequestHandler } from "express";
 | 
					import type { RequestHandler } from "express";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export const claimLibraryDailyTaskRewardController: RequestHandler = async (req, res) => {
 | 
					export const claimLibraryDailyTaskRewardController: RequestHandler = async (req, res) => {
 | 
				
			||||||
    const accountId = await getAccountIdForRequest(req);
 | 
					    const accountId = await getAccountIdForRequest(req);
 | 
				
			||||||
 | 
				
			|||||||
@ -1,6 +1,6 @@
 | 
				
			|||||||
import { getInventory } from "@/src/services/inventoryService";
 | 
					import { getInventory } from "../../services/inventoryService.ts";
 | 
				
			||||||
import { getAccountIdForRequest } from "@/src/services/loginService";
 | 
					import { getAccountIdForRequest } from "../../services/loginService.ts";
 | 
				
			||||||
import { RequestHandler } from "express";
 | 
					import type { RequestHandler } from "express";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export const clearDialogueHistoryController: RequestHandler = async (req, res) => {
 | 
					export const clearDialogueHistoryController: RequestHandler = async (req, res) => {
 | 
				
			||||||
    const accountId = await getAccountIdForRequest(req);
 | 
					    const accountId = await getAccountIdForRequest(req);
 | 
				
			||||||
 | 
				
			|||||||
@ -1,4 +1,4 @@
 | 
				
			|||||||
import { RequestHandler } from "express";
 | 
					import type { RequestHandler } from "express";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// example req.body: {"NewEpisodeReward":true,"crossPlaySetting":"ENABLED"}
 | 
					// example req.body: {"NewEpisodeReward":true,"crossPlaySetting":"ENABLED"}
 | 
				
			||||||
export const clearNewEpisodeRewardController: RequestHandler = (_req, res) => {
 | 
					export const clearNewEpisodeRewardController: RequestHandler = (_req, res) => {
 | 
				
			||||||
 | 
				
			|||||||
@ -1,9 +1,9 @@
 | 
				
			|||||||
import { checkCalendarAutoAdvance, getCalendarProgress, getInventory } from "@/src/services/inventoryService";
 | 
					import { checkCalendarAutoAdvance, getCalendarProgress, getInventory } from "../../services/inventoryService.ts";
 | 
				
			||||||
import { getAccountIdForRequest } from "@/src/services/loginService";
 | 
					import { getAccountIdForRequest } from "../../services/loginService.ts";
 | 
				
			||||||
import { handleStoreItemAcquisition } from "@/src/services/purchaseService";
 | 
					import { handleStoreItemAcquisition } from "../../services/purchaseService.ts";
 | 
				
			||||||
import { getWorldState } from "@/src/services/worldStateService";
 | 
					import { getWorldState } from "../../services/worldStateService.ts";
 | 
				
			||||||
import { IInventoryChanges } from "@/src/types/purchaseTypes";
 | 
					import type { IInventoryChanges } from "../../types/purchaseTypes.ts";
 | 
				
			||||||
import { RequestHandler } from "express";
 | 
					import type { RequestHandler } from "express";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// GET request; query parameters: CompletedEventIdx=0&Iteration=4&Version=19&Season=CST_SUMMER
 | 
					// GET request; query parameters: CompletedEventIdx=0&Iteration=4&Version=19&Season=CST_SUMMER
 | 
				
			||||||
export const completeCalendarEventController: RequestHandler = async (req, res) => {
 | 
					export const completeCalendarEventController: RequestHandler = async (req, res) => {
 | 
				
			||||||
 | 
				
			|||||||
@ -1,11 +1,10 @@
 | 
				
			|||||||
import { RequestHandler } from "express";
 | 
					import type { RequestHandler } from "express";
 | 
				
			||||||
import { getAccountIdForRequest } from "@/src/services/loginService";
 | 
					import { getAccountIdForRequest } from "../../services/loginService.ts";
 | 
				
			||||||
import { addMiscItems, getInventory, updateCurrency } from "@/src/services/inventoryService";
 | 
					import { addMiscItems, getInventory, updateCurrency } from "../../services/inventoryService.ts";
 | 
				
			||||||
import { IInventoryChanges } from "@/src/types/purchaseTypes";
 | 
					import type { IInventoryChanges } from "../../types/purchaseTypes.ts";
 | 
				
			||||||
import { IMiscItem } from "@/src/types/inventoryTypes/inventoryTypes";
 | 
					import type { IMiscItem } from "../../types/inventoryTypes/inventoryTypes.ts";
 | 
				
			||||||
import { getJSONfromString } from "@/src/helpers/stringHelpers";
 | 
					import { getJSONfromString } from "../../helpers/stringHelpers.ts";
 | 
				
			||||||
import { createUnveiledRivenFingerprint } from "@/src/helpers/rivenHelper";
 | 
					import type { IVeiledRivenFingerprint } from "../../helpers/rivenHelper.ts";
 | 
				
			||||||
import { ExportUpgrades } from "warframe-public-export-plus";
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
export const completeRandomModChallengeController: RequestHandler = async (req, res) => {
 | 
					export const completeRandomModChallengeController: RequestHandler = async (req, res) => {
 | 
				
			||||||
    const accountId = await getAccountIdForRequest(req);
 | 
					    const accountId = await getAccountIdForRequest(req);
 | 
				
			||||||
@ -27,10 +26,11 @@ export const completeRandomModChallengeController: RequestHandler = async (req,
 | 
				
			|||||||
        inventoryChanges.MiscItems = miscItemChanges;
 | 
					        inventoryChanges.MiscItems = miscItemChanges;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // Update riven fingerprint to a randomised unveiled state
 | 
					    // Complete the riven challenge
 | 
				
			||||||
    const upgrade = inventory.Upgrades.id(request.ItemId)!;
 | 
					    const upgrade = inventory.Upgrades.id(request.ItemId)!;
 | 
				
			||||||
    const meta = ExportUpgrades[upgrade.ItemType];
 | 
					    const fp = JSON.parse(upgrade.UpgradeFingerprint!) as IVeiledRivenFingerprint;
 | 
				
			||||||
    upgrade.UpgradeFingerprint = JSON.stringify(createUnveiledRivenFingerprint(meta));
 | 
					    fp.challenge.Progress = fp.challenge.Required;
 | 
				
			||||||
 | 
					    upgrade.UpgradeFingerprint = JSON.stringify(fp);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    await inventory.save();
 | 
					    await inventory.save();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -1,7 +1,7 @@
 | 
				
			|||||||
import { Alliance, AllianceMember, Guild, GuildMember } from "@/src/models/guildModel";
 | 
					import { Alliance, AllianceMember, Guild, GuildMember } from "../../models/guildModel.ts";
 | 
				
			||||||
import { getAllianceClient } from "@/src/services/guildService";
 | 
					import { getAllianceClient } from "../../services/guildService.ts";
 | 
				
			||||||
import { getAccountIdForRequest } from "@/src/services/loginService";
 | 
					import { getAccountIdForRequest } from "../../services/loginService.ts";
 | 
				
			||||||
import { RequestHandler } from "express";
 | 
					import type { RequestHandler } from "express";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export const confirmAllianceInvitationController: RequestHandler = async (req, res) => {
 | 
					export const confirmAllianceInvitationController: RequestHandler = async (req, res) => {
 | 
				
			||||||
    // Check requester is a warlord in their guild
 | 
					    // Check requester is a warlord in their guild
 | 
				
			||||||
 | 
				
			|||||||
@ -1,18 +1,18 @@
 | 
				
			|||||||
import { getJSONfromString } from "@/src/helpers/stringHelpers";
 | 
					import { getJSONfromString } from "../../helpers/stringHelpers.ts";
 | 
				
			||||||
import { Guild, GuildMember } from "@/src/models/guildModel";
 | 
					import { Guild, GuildMember } from "../../models/guildModel.ts";
 | 
				
			||||||
import { Account } from "@/src/models/loginModel";
 | 
					import { Account } from "../../models/loginModel.ts";
 | 
				
			||||||
import {
 | 
					import {
 | 
				
			||||||
    deleteGuild,
 | 
					    deleteGuild,
 | 
				
			||||||
    getGuildClient,
 | 
					    getGuildClient,
 | 
				
			||||||
    giveClanKey,
 | 
					    giveClanKey,
 | 
				
			||||||
    hasGuildPermission,
 | 
					    hasGuildPermission,
 | 
				
			||||||
    removeDojoKeyItems
 | 
					    removeDojoKeyItems
 | 
				
			||||||
} from "@/src/services/guildService";
 | 
					} from "../../services/guildService.ts";
 | 
				
			||||||
import { getInventory } from "@/src/services/inventoryService";
 | 
					import { getInventory } from "../../services/inventoryService.ts";
 | 
				
			||||||
import { getAccountForRequest, getAccountIdForRequest, getSuffixedName } from "@/src/services/loginService";
 | 
					import { getAccountForRequest, getAccountIdForRequest, getSuffixedName } from "../../services/loginService.ts";
 | 
				
			||||||
import { GuildPermission } from "@/src/types/guildTypes";
 | 
					import { GuildPermission } from "../../types/guildTypes.ts";
 | 
				
			||||||
import { IInventoryChanges } from "@/src/types/purchaseTypes";
 | 
					import type { IInventoryChanges } from "../../types/purchaseTypes.ts";
 | 
				
			||||||
import { RequestHandler } from "express";
 | 
					import type { RequestHandler } from "express";
 | 
				
			||||||
import { Types } from "mongoose";
 | 
					import { Types } from "mongoose";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// GET request: A player accepting an invite they got in their inbox.
 | 
					// GET request: A player accepting an invite they got in their inbox.
 | 
				
			||||||
 | 
				
			|||||||
@ -1,10 +1,10 @@
 | 
				
			|||||||
import { toMongoDate } from "@/src/helpers/inventoryHelpers";
 | 
					import { toMongoDate } from "../../helpers/inventoryHelpers.ts";
 | 
				
			||||||
import { getJSONfromString } from "@/src/helpers/stringHelpers";
 | 
					import { getJSONfromString } from "../../helpers/stringHelpers.ts";
 | 
				
			||||||
import { Guild } from "@/src/models/guildModel";
 | 
					import { Guild } from "../../models/guildModel.ts";
 | 
				
			||||||
import { checkClanAscensionHasRequiredContributors } from "@/src/services/guildService";
 | 
					import { checkClanAscensionHasRequiredContributors } from "../../services/guildService.ts";
 | 
				
			||||||
import { addFusionPoints, getInventory } from "@/src/services/inventoryService";
 | 
					import { addFusionPoints, getInventory } from "../../services/inventoryService.ts";
 | 
				
			||||||
import { getAccountIdForRequest } from "@/src/services/loginService";
 | 
					import { getAccountIdForRequest } from "../../services/loginService.ts";
 | 
				
			||||||
import { RequestHandler } from "express";
 | 
					import type { RequestHandler } from "express";
 | 
				
			||||||
import { Types } from "mongoose";
 | 
					import { Types } from "mongoose";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export const contributeGuildClassController: RequestHandler = async (req, res) => {
 | 
					export const contributeGuildClassController: RequestHandler = async (req, res) => {
 | 
				
			||||||
 | 
				
			|||||||
@ -1,5 +1,6 @@
 | 
				
			|||||||
import { GuildMember, TGuildDatabaseDocument } from "@/src/models/guildModel";
 | 
					import type { TGuildDatabaseDocument } from "../../models/guildModel.ts";
 | 
				
			||||||
import { TInventoryDatabaseDocument } from "@/src/models/inventoryModels/inventoryModel";
 | 
					import { GuildMember } from "../../models/guildModel.ts";
 | 
				
			||||||
 | 
					import type { TInventoryDatabaseDocument } from "../../models/inventoryModels/inventoryModel.ts";
 | 
				
			||||||
import {
 | 
					import {
 | 
				
			||||||
    addGuildMemberMiscItemContribution,
 | 
					    addGuildMemberMiscItemContribution,
 | 
				
			||||||
    getDojoClient,
 | 
					    getDojoClient,
 | 
				
			||||||
@ -8,14 +9,15 @@ import {
 | 
				
			|||||||
    processDojoBuildMaterialsGathered,
 | 
					    processDojoBuildMaterialsGathered,
 | 
				
			||||||
    scaleRequiredCount,
 | 
					    scaleRequiredCount,
 | 
				
			||||||
    setDojoRoomLogFunded
 | 
					    setDojoRoomLogFunded
 | 
				
			||||||
} from "@/src/services/guildService";
 | 
					} from "../../services/guildService.ts";
 | 
				
			||||||
import { addMiscItems, getInventory, updateCurrency } from "@/src/services/inventoryService";
 | 
					import { addMiscItems, getInventory, updateCurrency } from "../../services/inventoryService.ts";
 | 
				
			||||||
import { getAccountIdForRequest } from "@/src/services/loginService";
 | 
					import { getAccountIdForRequest } from "../../services/loginService.ts";
 | 
				
			||||||
import { IDojoContributable, IGuildMemberDatabase } from "@/src/types/guildTypes";
 | 
					import type { IDojoContributable, IGuildMemberDatabase } from "../../types/guildTypes.ts";
 | 
				
			||||||
import { IMiscItem } from "@/src/types/inventoryTypes/inventoryTypes";
 | 
					import type { IMiscItem } from "../../types/inventoryTypes/inventoryTypes.ts";
 | 
				
			||||||
import { IInventoryChanges } from "@/src/types/purchaseTypes";
 | 
					import type { IInventoryChanges } from "../../types/purchaseTypes.ts";
 | 
				
			||||||
import { RequestHandler } from "express";
 | 
					import type { RequestHandler } from "express";
 | 
				
			||||||
import { ExportDojoRecipes, IDojoBuild } from "warframe-public-export-plus";
 | 
					import type { IDojoBuild } from "warframe-public-export-plus";
 | 
				
			||||||
 | 
					import { ExportDojoRecipes } from "warframe-public-export-plus";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
interface IContributeToDojoComponentRequest {
 | 
					interface IContributeToDojoComponentRequest {
 | 
				
			||||||
    ComponentId: string;
 | 
					    ComponentId: string;
 | 
				
			||||||
 | 
				
			|||||||
@ -1,10 +1,5 @@
 | 
				
			|||||||
import {
 | 
					import type { TGuildDatabaseDocument, TGuildMemberDatabaseDocument } from "../../models/guildModel.ts";
 | 
				
			||||||
    Alliance,
 | 
					import { Alliance, Guild, GuildMember } from "../../models/guildModel.ts";
 | 
				
			||||||
    Guild,
 | 
					 | 
				
			||||||
    GuildMember,
 | 
					 | 
				
			||||||
    TGuildDatabaseDocument,
 | 
					 | 
				
			||||||
    TGuildMemberDatabaseDocument
 | 
					 | 
				
			||||||
} from "@/src/models/guildModel";
 | 
					 | 
				
			||||||
import {
 | 
					import {
 | 
				
			||||||
    addGuildMemberMiscItemContribution,
 | 
					    addGuildMemberMiscItemContribution,
 | 
				
			||||||
    addGuildMemberShipDecoContribution,
 | 
					    addGuildMemberShipDecoContribution,
 | 
				
			||||||
@ -12,18 +7,18 @@ import {
 | 
				
			|||||||
    addVaultMiscItems,
 | 
					    addVaultMiscItems,
 | 
				
			||||||
    addVaultShipDecos,
 | 
					    addVaultShipDecos,
 | 
				
			||||||
    getGuildForRequestEx
 | 
					    getGuildForRequestEx
 | 
				
			||||||
} from "@/src/services/guildService";
 | 
					} from "../../services/guildService.ts";
 | 
				
			||||||
import {
 | 
					import {
 | 
				
			||||||
    addFusionTreasures,
 | 
					    addFusionTreasures,
 | 
				
			||||||
    addMiscItems,
 | 
					    addMiscItems,
 | 
				
			||||||
    addShipDecorations,
 | 
					    addShipDecorations,
 | 
				
			||||||
    getInventory,
 | 
					    getInventory,
 | 
				
			||||||
    updateCurrency
 | 
					    updateCurrency
 | 
				
			||||||
} from "@/src/services/inventoryService";
 | 
					} from "../../services/inventoryService.ts";
 | 
				
			||||||
import { getAccountIdForRequest } from "@/src/services/loginService";
 | 
					import { getAccountIdForRequest } from "../../services/loginService.ts";
 | 
				
			||||||
import { ITypeCount } from "@/src/types/commonTypes";
 | 
					import type { ITypeCount } from "../../types/commonTypes.ts";
 | 
				
			||||||
import { IFusionTreasure, IMiscItem } from "@/src/types/inventoryTypes/inventoryTypes";
 | 
					import type { IFusionTreasure, IMiscItem } from "../../types/inventoryTypes/inventoryTypes.ts";
 | 
				
			||||||
import { RequestHandler } from "express";
 | 
					import type { RequestHandler } from "express";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export const contributeToVaultController: RequestHandler = async (req, res) => {
 | 
					export const contributeToVaultController: RequestHandler = async (req, res) => {
 | 
				
			||||||
    const accountId = await getAccountIdForRequest(req);
 | 
					    const accountId = await getAccountIdForRequest(req);
 | 
				
			||||||
 | 
				
			|||||||
@ -1,10 +1,10 @@
 | 
				
			|||||||
import { getJSONfromString } from "@/src/helpers/stringHelpers";
 | 
					import { getJSONfromString } from "../../helpers/stringHelpers.ts";
 | 
				
			||||||
import { Alliance, AllianceMember, Guild, GuildMember } from "@/src/models/guildModel";
 | 
					import { Alliance, AllianceMember, Guild, GuildMember } from "../../models/guildModel.ts";
 | 
				
			||||||
import { getAllianceClient } from "@/src/services/guildService";
 | 
					import { getAllianceClient } from "../../services/guildService.ts";
 | 
				
			||||||
import { getInventory } from "@/src/services/inventoryService";
 | 
					import { getInventory } from "../../services/inventoryService.ts";
 | 
				
			||||||
import { getAccountIdForRequest } from "@/src/services/loginService";
 | 
					import { getAccountIdForRequest } from "../../services/loginService.ts";
 | 
				
			||||||
import { GuildPermission } from "@/src/types/guildTypes";
 | 
					import { GuildPermission } from "../../types/guildTypes.ts";
 | 
				
			||||||
import { RequestHandler } from "express";
 | 
					import type { RequestHandler } from "express";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export const createAllianceController: RequestHandler = async (req, res) => {
 | 
					export const createAllianceController: RequestHandler = async (req, res) => {
 | 
				
			||||||
    const accountId = await getAccountIdForRequest(req);
 | 
					    const accountId = await getAccountIdForRequest(req);
 | 
				
			||||||
 | 
				
			|||||||
@ -1,15 +1,27 @@
 | 
				
			|||||||
import { RequestHandler } from "express";
 | 
					import type { RequestHandler } from "express";
 | 
				
			||||||
import { getAccountForRequest } from "@/src/services/loginService";
 | 
					import { getAccountForRequest } from "../../services/loginService.ts";
 | 
				
			||||||
import { getJSONfromString } from "@/src/helpers/stringHelpers";
 | 
					import { getJSONfromString } from "../../helpers/stringHelpers.ts";
 | 
				
			||||||
import { Guild, GuildMember } from "@/src/models/guildModel";
 | 
					import { Guild, GuildMember } from "../../models/guildModel.ts";
 | 
				
			||||||
import { createUniqueClanName, getGuildClient, giveClanKey } from "@/src/services/guildService";
 | 
					import { createUniqueClanName, getGuildClient, giveClanKey } from "../../services/guildService.ts";
 | 
				
			||||||
import { getInventory } from "@/src/services/inventoryService";
 | 
					import { getInventory } from "../../services/inventoryService.ts";
 | 
				
			||||||
import { IInventoryChanges } from "@/src/types/purchaseTypes";
 | 
					import type { IInventoryChanges } from "../../types/purchaseTypes.ts";
 | 
				
			||||||
 | 
					import { sendWsBroadcastTo } from "../../services/wsService.ts";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export const createGuildController: RequestHandler = async (req, res) => {
 | 
					export const createGuildController: RequestHandler = async (req, res) => {
 | 
				
			||||||
    const account = await getAccountForRequest(req);
 | 
					    const account = await getAccountForRequest(req);
 | 
				
			||||||
    const payload = getJSONfromString<ICreateGuildRequest>(String(req.body));
 | 
					    const payload = getJSONfromString<ICreateGuildRequest>(String(req.body));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const inventory = await getInventory(account._id.toString(), "GuildId LevelKeys Recipes");
 | 
				
			||||||
 | 
					    if (inventory.GuildId) {
 | 
				
			||||||
 | 
					        const guild = await Guild.findById(inventory.GuildId);
 | 
				
			||||||
 | 
					        if (guild) {
 | 
				
			||||||
 | 
					            res.json({
 | 
				
			||||||
 | 
					                ...(await getGuildClient(guild, account))
 | 
				
			||||||
 | 
					            });
 | 
				
			||||||
 | 
					            return;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // Remove pending applications for this account
 | 
					    // Remove pending applications for this account
 | 
				
			||||||
    await GuildMember.deleteMany({ accountId: account._id, status: 1 });
 | 
					    await GuildMember.deleteMany({ accountId: account._id, status: 1 });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -27,7 +39,6 @@ export const createGuildController: RequestHandler = async (req, res) => {
 | 
				
			|||||||
        rank: 0
 | 
					        rank: 0
 | 
				
			||||||
    });
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    const inventory = await getInventory(account._id.toString(), "GuildId LevelKeys Recipes");
 | 
					 | 
				
			||||||
    inventory.GuildId = guild._id;
 | 
					    inventory.GuildId = guild._id;
 | 
				
			||||||
    const inventoryChanges: IInventoryChanges = {};
 | 
					    const inventoryChanges: IInventoryChanges = {};
 | 
				
			||||||
    giveClanKey(inventory, inventoryChanges);
 | 
					    giveClanKey(inventory, inventoryChanges);
 | 
				
			||||||
@ -37,6 +48,7 @@ export const createGuildController: RequestHandler = async (req, res) => {
 | 
				
			|||||||
        ...(await getGuildClient(guild, account)),
 | 
					        ...(await getGuildClient(guild, account)),
 | 
				
			||||||
        InventoryChanges: inventoryChanges
 | 
					        InventoryChanges: inventoryChanges
 | 
				
			||||||
    });
 | 
					    });
 | 
				
			||||||
 | 
					    sendWsBroadcastTo(account._id.toString(), { update_inventory: true });
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
interface ICreateGuildRequest {
 | 
					interface ICreateGuildRequest {
 | 
				
			||||||
 | 
				
			|||||||
@ -1,7 +1,6 @@
 | 
				
			|||||||
import { RequestHandler } from "express";
 | 
					import type { RequestHandler } from "express";
 | 
				
			||||||
import { config } from "@/src/services/configService";
 | 
					import { getAccountIdForRequest } from "../../services/loginService.ts";
 | 
				
			||||||
import { getAccountIdForRequest } from "@/src/services/loginService";
 | 
					import { getInventory } from "../../services/inventoryService.ts";
 | 
				
			||||||
import { getInventory } from "@/src/services/inventoryService";
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
export const creditsController: RequestHandler = async (req, res) => {
 | 
					export const creditsController: RequestHandler = async (req, res) => {
 | 
				
			||||||
    const inventory = (
 | 
					    const inventory = (
 | 
				
			||||||
@ -9,7 +8,7 @@ export const creditsController: RequestHandler = async (req, res) => {
 | 
				
			|||||||
            getAccountIdForRequest(req),
 | 
					            getAccountIdForRequest(req),
 | 
				
			||||||
            getInventory(
 | 
					            getInventory(
 | 
				
			||||||
                req.query.accountId as string,
 | 
					                req.query.accountId as string,
 | 
				
			||||||
                "RegularCredits TradesRemaining PremiumCreditsFree PremiumCredits"
 | 
					                "RegularCredits TradesRemaining PremiumCreditsFree PremiumCredits infiniteCredits infinitePlatinum"
 | 
				
			||||||
            )
 | 
					            )
 | 
				
			||||||
        ])
 | 
					        ])
 | 
				
			||||||
    )[1];
 | 
					    )[1];
 | 
				
			||||||
@ -21,10 +20,10 @@ export const creditsController: RequestHandler = async (req, res) => {
 | 
				
			|||||||
        PremiumCredits: inventory.PremiumCredits
 | 
					        PremiumCredits: inventory.PremiumCredits
 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (config.infiniteCredits) {
 | 
					    if (inventory.infiniteCredits) {
 | 
				
			||||||
        response.RegularCredits = 999999999;
 | 
					        response.RegularCredits = 999999999;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    if (config.infinitePlatinum) {
 | 
					    if (inventory.infinitePlatinum) {
 | 
				
			||||||
        response.PremiumCreditsFree = 0;
 | 
					        response.PremiumCreditsFree = 0;
 | 
				
			||||||
        response.PremiumCredits = 999999999;
 | 
					        response.PremiumCredits = 999999999;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
				
			|||||||
@ -1,9 +1,9 @@
 | 
				
			|||||||
import { getJSONfromString } from "@/src/helpers/stringHelpers";
 | 
					import { getJSONfromString } from "../../helpers/stringHelpers.ts";
 | 
				
			||||||
import { TInventoryDatabaseDocument } from "@/src/models/inventoryModels/inventoryModel";
 | 
					import type { TInventoryDatabaseDocument } from "../../models/inventoryModels/inventoryModel.ts";
 | 
				
			||||||
import { getInventory } from "@/src/services/inventoryService";
 | 
					import { getInventory } from "../../services/inventoryService.ts";
 | 
				
			||||||
import { getAccountIdForRequest } from "@/src/services/loginService";
 | 
					import { getAccountIdForRequest } from "../../services/loginService.ts";
 | 
				
			||||||
import { ICrewMemberClient } from "@/src/types/inventoryTypes/inventoryTypes";
 | 
					import type { ICrewMemberClient } from "../../types/inventoryTypes/inventoryTypes.ts";
 | 
				
			||||||
import { RequestHandler } from "express";
 | 
					import type { RequestHandler } from "express";
 | 
				
			||||||
import { Types } from "mongoose";
 | 
					import { Types } from "mongoose";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export const crewMembersController: RequestHandler = async (req, res) => {
 | 
					export const crewMembersController: RequestHandler = async (req, res) => {
 | 
				
			||||||
 | 
				
			|||||||
@ -1,10 +1,11 @@
 | 
				
			|||||||
import { getJSONfromString } from "@/src/helpers/stringHelpers";
 | 
					import { getJSONfromString } from "../../helpers/stringHelpers.ts";
 | 
				
			||||||
import { addMiscItems, freeUpSlot, getInventory, updateCurrency } from "@/src/services/inventoryService";
 | 
					import { addMiscItems, freeUpSlot, getInventory, updateCurrency } from "../../services/inventoryService.ts";
 | 
				
			||||||
import { getAccountIdForRequest } from "@/src/services/loginService";
 | 
					import { getAccountIdForRequest } from "../../services/loginService.ts";
 | 
				
			||||||
import { IOid } from "@/src/types/commonTypes";
 | 
					import type { IOid } from "../../types/commonTypes.ts";
 | 
				
			||||||
import { ICrewShipComponentFingerprint, InventorySlot } from "@/src/types/inventoryTypes/inventoryTypes";
 | 
					import type { ICrewShipComponentFingerprint } from "../../types/inventoryTypes/inventoryTypes.ts";
 | 
				
			||||||
import { IInventoryChanges } from "@/src/types/purchaseTypes";
 | 
					import { InventorySlot } from "../../types/inventoryTypes/inventoryTypes.ts";
 | 
				
			||||||
import { RequestHandler } from "express";
 | 
					import type { IInventoryChanges } from "../../types/purchaseTypes.ts";
 | 
				
			||||||
 | 
					import type { RequestHandler } from "express";
 | 
				
			||||||
import { ExportCustoms, ExportDojoRecipes } from "warframe-public-export-plus";
 | 
					import { ExportCustoms, ExportDojoRecipes } from "warframe-public-export-plus";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export const crewShipFusionController: RequestHandler = async (req, res) => {
 | 
					export const crewShipFusionController: RequestHandler = async (req, res) => {
 | 
				
			||||||
@ -80,7 +81,7 @@ export const crewShipFusionController: RequestHandler = async (req, res) => {
 | 
				
			|||||||
            const newFval = (newPerc - rangeA[0]) / (rangeA[1] - rangeA[0]);
 | 
					            const newFval = (newPerc - rangeA[0]) / (rangeA[1] - rangeA[0]);
 | 
				
			||||||
            buffA.Value = Math.trunc(newFval * 0x3fffffff);
 | 
					            buffA.Value = Math.trunc(newFval * 0x3fffffff);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        if (inferiorFingerprint.SubroutineIndex) {
 | 
					        if (inferiorFingerprint.SubroutineIndex !== undefined) {
 | 
				
			||||||
            const useSuperiorSubroutine = tierA < tierB ? !payload.UseSubroutineA : payload.UseSubroutineA;
 | 
					            const useSuperiorSubroutine = tierA < tierB ? !payload.UseSubroutineA : payload.UseSubroutineA;
 | 
				
			||||||
            if (!useSuperiorSubroutine) {
 | 
					            if (!useSuperiorSubroutine) {
 | 
				
			||||||
                fingerprint.SubroutineIndex = inferiorFingerprint.SubroutineIndex;
 | 
					                fingerprint.SubroutineIndex = inferiorFingerprint.SubroutineIndex;
 | 
				
			||||||
@ -88,7 +89,6 @@ export const crewShipFusionController: RequestHandler = async (req, res) => {
 | 
				
			|||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    superiorItem.UpgradeFingerprint = JSON.stringify(fingerprint);
 | 
					    superiorItem.UpgradeFingerprint = JSON.stringify(fingerprint);
 | 
				
			||||||
    // eslint-disable-next-line @typescript-eslint/no-explicit-any
 | 
					 | 
				
			||||||
    inventoryChanges[category] = [superiorItem.toJSON() as any];
 | 
					    inventoryChanges[category] = [superiorItem.toJSON() as any];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    await inventory.save();
 | 
					    await inventory.save();
 | 
				
			||||||
 | 
				
			|||||||
@ -3,16 +3,19 @@ import {
 | 
				
			|||||||
    addCrewShipRawSalvage,
 | 
					    addCrewShipRawSalvage,
 | 
				
			||||||
    getInventory,
 | 
					    getInventory,
 | 
				
			||||||
    addEquipment
 | 
					    addEquipment
 | 
				
			||||||
} from "@/src/services/inventoryService";
 | 
					} from "../../services/inventoryService.ts";
 | 
				
			||||||
import { getAccountIdForRequest } from "@/src/services/loginService";
 | 
					import { getAccountIdForRequest } from "../../services/loginService.ts";
 | 
				
			||||||
import { RequestHandler } from "express";
 | 
					import type { RequestHandler } from "express";
 | 
				
			||||||
import { ICrewShipComponentFingerprint, IInnateDamageFingerprint } from "@/src/types/inventoryTypes/inventoryTypes";
 | 
					import type {
 | 
				
			||||||
 | 
					    ICrewShipComponentFingerprint,
 | 
				
			||||||
 | 
					    IInnateDamageFingerprint
 | 
				
			||||||
 | 
					} from "../../types/inventoryTypes/inventoryTypes.ts";
 | 
				
			||||||
import { ExportCustoms, ExportRailjackWeapons, ExportUpgrades } from "warframe-public-export-plus";
 | 
					import { ExportCustoms, ExportRailjackWeapons, ExportUpgrades } from "warframe-public-export-plus";
 | 
				
			||||||
import { getJSONfromString } from "@/src/helpers/stringHelpers";
 | 
					import { getJSONfromString } from "../../helpers/stringHelpers.ts";
 | 
				
			||||||
import { IInventoryChanges } from "@/src/types/purchaseTypes";
 | 
					import type { IInventoryChanges } from "../../types/purchaseTypes.ts";
 | 
				
			||||||
import { getRandomInt } from "@/src/services/rngService";
 | 
					import { getRandomInt } from "../../services/rngService.ts";
 | 
				
			||||||
import { IFingerprintStat } from "@/src/helpers/rivenHelper";
 | 
					import type { IFingerprintStat } from "../../helpers/rivenHelper.ts";
 | 
				
			||||||
import { IEquipmentDatabase } from "@/src/types/equipmentTypes";
 | 
					import type { IEquipmentDatabase } from "../../types/equipmentTypes.ts";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export const crewShipIdentifySalvageController: RequestHandler = async (req, res) => {
 | 
					export const crewShipIdentifySalvageController: RequestHandler = async (req, res) => {
 | 
				
			||||||
    const accountId = await getAccountIdForRequest(req);
 | 
					    const accountId = await getAccountIdForRequest(req);
 | 
				
			||||||
 | 
				
			|||||||
@ -1,11 +1,11 @@
 | 
				
			|||||||
import { getJSONfromString } from "@/src/helpers/stringHelpers";
 | 
					import { getJSONfromString } from "../../helpers/stringHelpers.ts";
 | 
				
			||||||
import { Guild } from "@/src/models/guildModel";
 | 
					import { Guild } from "../../models/guildModel.ts";
 | 
				
			||||||
import { hasAccessToDojo, hasGuildPermission } from "@/src/services/guildService";
 | 
					import { hasAccessToDojo, hasGuildPermission } from "../../services/guildService.ts";
 | 
				
			||||||
import { getInventory } from "@/src/services/inventoryService";
 | 
					import { getInventory } from "../../services/inventoryService.ts";
 | 
				
			||||||
import { getAccountForRequest, getAccountIdForRequest } from "@/src/services/loginService";
 | 
					import { getAccountForRequest, getAccountIdForRequest } from "../../services/loginService.ts";
 | 
				
			||||||
import { GuildPermission } from "@/src/types/guildTypes";
 | 
					import { GuildPermission } from "../../types/guildTypes.ts";
 | 
				
			||||||
import { logger } from "@/src/utils/logger";
 | 
					import { logger } from "../../utils/logger.ts";
 | 
				
			||||||
import { RequestHandler } from "express";
 | 
					import type { RequestHandler } from "express";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export const customObstacleCourseLeaderboardController: RequestHandler = async (req, res) => {
 | 
					export const customObstacleCourseLeaderboardController: RequestHandler = async (req, res) => {
 | 
				
			||||||
    const data = getJSONfromString<ICustomObstacleCourseLeaderboardRequest>(String(req.body));
 | 
					    const data = getJSONfromString<ICustomObstacleCourseLeaderboardRequest>(String(req.body));
 | 
				
			||||||
 | 
				
			|||||||
@ -1,7 +1,8 @@
 | 
				
			|||||||
import { getGuildForRequest, hasGuildPermission } from "@/src/services/guildService";
 | 
					import { getGuildForRequest, hasGuildPermission } from "../../services/guildService.ts";
 | 
				
			||||||
import { getAccountIdForRequest } from "@/src/services/loginService";
 | 
					import { getAccountIdForRequest } from "../../services/loginService.ts";
 | 
				
			||||||
import { GuildPermission, IGuildRank } from "@/src/types/guildTypes";
 | 
					import type { IGuildRank } from "../../types/guildTypes.ts";
 | 
				
			||||||
import { RequestHandler } from "express";
 | 
					import { GuildPermission } from "../../types/guildTypes.ts";
 | 
				
			||||||
 | 
					import type { RequestHandler } from "express";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export const customizeGuildRanksController: RequestHandler = async (req, res) => {
 | 
					export const customizeGuildRanksController: RequestHandler = async (req, res) => {
 | 
				
			||||||
    const accountId = await getAccountIdForRequest(req);
 | 
					    const accountId = await getAccountIdForRequest(req);
 | 
				
			||||||
 | 
				
			|||||||
@ -1,6 +1,6 @@
 | 
				
			|||||||
import { AllianceMember, GuildMember } from "@/src/models/guildModel";
 | 
					import { AllianceMember, GuildMember } from "../../models/guildModel.ts";
 | 
				
			||||||
import { getAccountIdForRequest } from "@/src/services/loginService";
 | 
					import { getAccountIdForRequest } from "../../services/loginService.ts";
 | 
				
			||||||
import { RequestHandler } from "express";
 | 
					import type { RequestHandler } from "express";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export const declineAllianceInviteController: RequestHandler = async (req, res) => {
 | 
					export const declineAllianceInviteController: RequestHandler = async (req, res) => {
 | 
				
			||||||
    // Check requester is a warlord in their guild
 | 
					    // Check requester is a warlord in their guild
 | 
				
			||||||
 | 
				
			|||||||
@ -1,6 +1,6 @@
 | 
				
			|||||||
import { GuildMember } from "@/src/models/guildModel";
 | 
					import { GuildMember } from "../../models/guildModel.ts";
 | 
				
			||||||
import { getAccountForRequest } from "@/src/services/loginService";
 | 
					import { getAccountForRequest } from "../../services/loginService.ts";
 | 
				
			||||||
import { RequestHandler } from "express";
 | 
					import type { RequestHandler } from "express";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export const declineGuildInviteController: RequestHandler = async (req, res) => {
 | 
					export const declineGuildInviteController: RequestHandler = async (req, res) => {
 | 
				
			||||||
    const accountId = await getAccountForRequest(req);
 | 
					    const accountId = await getAccountForRequest(req);
 | 
				
			||||||
 | 
				
			|||||||
@ -1,9 +1,17 @@
 | 
				
			|||||||
import { RequestHandler } from "express";
 | 
					import type { RequestHandler } from "express";
 | 
				
			||||||
import { deleteSession } from "@/src/managers/sessionManager";
 | 
					import { deleteSession } from "../../managers/sessionManager.ts";
 | 
				
			||||||
 | 
					import { getAccountForRequest } from "../../services/loginService.ts";
 | 
				
			||||||
 | 
					import { version_compare } from "../../helpers/inventoryHelpers.ts";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const deleteSessionController: RequestHandler = (_req, res) => {
 | 
					const deleteSessionController: RequestHandler = async (_req, res) => {
 | 
				
			||||||
 | 
					    const account = await getAccountForRequest(_req);
 | 
				
			||||||
    deleteSession(_req.query.sessionId as string);
 | 
					    deleteSession(_req.query.sessionId as string);
 | 
				
			||||||
 | 
					    if (account.BuildLabel && version_compare(account.BuildLabel, "2016.07.08.16.56") < 0) {
 | 
				
			||||||
 | 
					        // Pre-Specters of the Rail
 | 
				
			||||||
 | 
					        res.send(_req.query.sessionId as string); // Unsure if this is correct, but the client is chill with it
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
        res.sendStatus(200);
 | 
					        res.sendStatus(200);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export { deleteSessionController };
 | 
					export { deleteSessionController };
 | 
				
			||||||
 | 
				
			|||||||
@ -3,12 +3,14 @@ import {
 | 
				
			|||||||
    getGuildForRequestEx,
 | 
					    getGuildForRequestEx,
 | 
				
			||||||
    hasAccessToDojo,
 | 
					    hasAccessToDojo,
 | 
				
			||||||
    hasGuildPermission,
 | 
					    hasGuildPermission,
 | 
				
			||||||
 | 
					    refundDojoDeco,
 | 
				
			||||||
    removeDojoDeco
 | 
					    removeDojoDeco
 | 
				
			||||||
} from "@/src/services/guildService";
 | 
					} from "../../services/guildService.ts";
 | 
				
			||||||
import { getInventory } from "@/src/services/inventoryService";
 | 
					import { getInventory } from "../../services/inventoryService.ts";
 | 
				
			||||||
import { getAccountIdForRequest } from "@/src/services/loginService";
 | 
					import { getAccountIdForRequest } from "../../services/loginService.ts";
 | 
				
			||||||
import { GuildPermission } from "@/src/types/guildTypes";
 | 
					import { GuildPermission } from "../../types/guildTypes.ts";
 | 
				
			||||||
import { RequestHandler } from "express";
 | 
					import { logger } from "../../utils/logger.ts";
 | 
				
			||||||
 | 
					import type { RequestHandler } from "express";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export const destroyDojoDecoController: RequestHandler = async (req, res) => {
 | 
					export const destroyDojoDecoController: RequestHandler = async (req, res) => {
 | 
				
			||||||
    const accountId = await getAccountIdForRequest(req);
 | 
					    const accountId = await getAccountIdForRequest(req);
 | 
				
			||||||
@ -18,9 +20,20 @@ export const destroyDojoDecoController: RequestHandler = async (req, res) => {
 | 
				
			|||||||
        res.json({ DojoRequestStatus: -1 });
 | 
					        res.json({ DojoRequestStatus: -1 });
 | 
				
			||||||
        return;
 | 
					        return;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    const request = JSON.parse(String(req.body)) as IDestroyDojoDecoRequest;
 | 
					    const request = JSON.parse(String(req.body)) as IDestroyDojoDecoRequest | IClearObstacleCourseRequest;
 | 
				
			||||||
 | 
					    if ("DecoType" in request) {
 | 
				
			||||||
        removeDojoDeco(guild, request.ComponentId, request.DecoId);
 | 
					        removeDojoDeco(guild, request.ComponentId, request.DecoId);
 | 
				
			||||||
 | 
					    } else if (request.Act == "cObst") {
 | 
				
			||||||
 | 
					        const component = guild.DojoComponents.id(request.ComponentId)!;
 | 
				
			||||||
 | 
					        if (component.Decos) {
 | 
				
			||||||
 | 
					            for (const deco of component.Decos) {
 | 
				
			||||||
 | 
					                refundDojoDeco(guild, component, deco);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            component.Decos.splice(0, component.Decos.length);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					        logger.error(`unhandled destroyDojoDeco request`, request);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    await guild.save();
 | 
					    await guild.save();
 | 
				
			||||||
    res.json(await getDojoClient(guild, 0, request.ComponentId));
 | 
					    res.json(await getDojoClient(guild, 0, request.ComponentId));
 | 
				
			||||||
@ -31,3 +44,8 @@ interface IDestroyDojoDecoRequest {
 | 
				
			|||||||
    ComponentId: string;
 | 
					    ComponentId: string;
 | 
				
			||||||
    DecoId: string;
 | 
					    DecoId: string;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					interface IClearObstacleCourseRequest {
 | 
				
			||||||
 | 
					    ComponentId: string;
 | 
				
			||||||
 | 
					    Act: "cObst" | "maybesomethingelsewedontknowabout";
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -1,9 +1,9 @@
 | 
				
			|||||||
import { Alliance, AllianceMember, Guild, GuildMember } from "@/src/models/guildModel";
 | 
					import { Alliance, AllianceMember, Guild, GuildMember } from "../../models/guildModel.ts";
 | 
				
			||||||
import { getAccountForRequest } from "@/src/services/loginService";
 | 
					import { getAccountForRequest } from "../../services/loginService.ts";
 | 
				
			||||||
import { GuildPermission } from "@/src/types/guildTypes";
 | 
					import { GuildPermission } from "../../types/guildTypes.ts";
 | 
				
			||||||
import { parallelForeach } from "@/src/utils/async-utils";
 | 
					import { parallelForeach } from "../../utils/async-utils.ts";
 | 
				
			||||||
import { logger } from "@/src/utils/logger";
 | 
					import { logger } from "../../utils/logger.ts";
 | 
				
			||||||
import { RequestHandler } from "express";
 | 
					import type { RequestHandler } from "express";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export const divvyAllianceVaultController: RequestHandler = async (req, res) => {
 | 
					export const divvyAllianceVaultController: RequestHandler = async (req, res) => {
 | 
				
			||||||
    // Afaict, there's no way to put anything other than credits in the alliance vault (anymore?), so just no-op if this is not a request to divvy credits.
 | 
					    // Afaict, there's no way to put anything other than credits in the alliance vault (anymore?), so just no-op if this is not a request to divvy credits.
 | 
				
			||||||
 | 
				
			|||||||
@ -1,10 +1,17 @@
 | 
				
			|||||||
import { GuildMember, TGuildDatabaseDocument } from "@/src/models/guildModel";
 | 
					import type { TGuildDatabaseDocument } from "../../models/guildModel.ts";
 | 
				
			||||||
import { getDojoClient, getGuildForRequestEx, hasAccessToDojo, scaleRequiredCount } from "@/src/services/guildService";
 | 
					import { GuildMember } from "../../models/guildModel.ts";
 | 
				
			||||||
import { getInventory, updateCurrency } from "@/src/services/inventoryService";
 | 
					import {
 | 
				
			||||||
import { getAccountIdForRequest } from "@/src/services/loginService";
 | 
					    getDojoClient,
 | 
				
			||||||
import { IDojoContributable } from "@/src/types/guildTypes";
 | 
					    getGuildForRequestEx,
 | 
				
			||||||
import { RequestHandler } from "express";
 | 
					    hasAccessToDojo,
 | 
				
			||||||
import { ExportDojoRecipes, IDojoBuild } from "warframe-public-export-plus";
 | 
					    scaleRequiredCount
 | 
				
			||||||
 | 
					} from "../../services/guildService.ts";
 | 
				
			||||||
 | 
					import { getInventory, updateCurrency } from "../../services/inventoryService.ts";
 | 
				
			||||||
 | 
					import { getAccountIdForRequest } from "../../services/loginService.ts";
 | 
				
			||||||
 | 
					import type { IDojoContributable } from "../../types/guildTypes.ts";
 | 
				
			||||||
 | 
					import type { RequestHandler } from "express";
 | 
				
			||||||
 | 
					import type { IDojoBuild } from "warframe-public-export-plus";
 | 
				
			||||||
 | 
					import { ExportDojoRecipes } from "warframe-public-export-plus";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
interface IDojoComponentRushRequest {
 | 
					interface IDojoComponentRushRequest {
 | 
				
			||||||
    DecoType?: string;
 | 
					    DecoType?: string;
 | 
				
			||||||
 | 
				
			|||||||
@ -1,4 +1,4 @@
 | 
				
			|||||||
import { RequestHandler } from "express";
 | 
					import type { RequestHandler } from "express";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Arbiter Dojo endpoints, not really used by us as we don't provide a ContentURL.
 | 
					// Arbiter Dojo endpoints, not really used by us as we don't provide a ContentURL.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -1,13 +1,12 @@
 | 
				
			|||||||
import { toMongoDate, toOid } from "@/src/helpers/inventoryHelpers";
 | 
					import { toMongoDate, toOid } from "../../helpers/inventoryHelpers.ts";
 | 
				
			||||||
import { config } from "@/src/services/configService";
 | 
					import { addMiscItems, getInventory } from "../../services/inventoryService.ts";
 | 
				
			||||||
import { addMiscItems, getInventory } from "@/src/services/inventoryService";
 | 
					import { fromStoreItem } from "../../services/itemDataService.ts";
 | 
				
			||||||
import { fromStoreItem } from "@/src/services/itemDataService";
 | 
					import { getAccountIdForRequest } from "../../services/loginService.ts";
 | 
				
			||||||
import { getAccountIdForRequest } from "@/src/services/loginService";
 | 
					import { getRandomInt, getRandomWeightedRewardUc } from "../../services/rngService.ts";
 | 
				
			||||||
import { getRandomInt, getRandomWeightedRewardUc } from "@/src/services/rngService";
 | 
					import type { IMongoDate, IOid } from "../../types/commonTypes.ts";
 | 
				
			||||||
import { IMongoDate, IOid } from "@/src/types/commonTypes";
 | 
					import type { IDroneClient } from "../../types/inventoryTypes/inventoryTypes.ts";
 | 
				
			||||||
import { IDroneClient } from "@/src/types/inventoryTypes/inventoryTypes";
 | 
					import type { IInventoryChanges } from "../../types/purchaseTypes.ts";
 | 
				
			||||||
import { IInventoryChanges } from "@/src/types/purchaseTypes";
 | 
					import type { RequestHandler } from "express";
 | 
				
			||||||
import { RequestHandler } from "express";
 | 
					 | 
				
			||||||
import { ExportDrones, ExportResources, ExportSystems } from "warframe-public-export-plus";
 | 
					import { ExportDrones, ExportResources, ExportSystems } from "warframe-public-export-plus";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export const dronesController: RequestHandler = async (req, res) => {
 | 
					export const dronesController: RequestHandler = async (req, res) => {
 | 
				
			||||||
@ -39,10 +38,13 @@ export const dronesController: RequestHandler = async (req, res) => {
 | 
				
			|||||||
            ActiveDrones: activeDrones
 | 
					            ActiveDrones: activeDrones
 | 
				
			||||||
        });
 | 
					        });
 | 
				
			||||||
    } else if ("droneId" in req.query && "systemIndex" in req.query) {
 | 
					    } else if ("droneId" in req.query && "systemIndex" in req.query) {
 | 
				
			||||||
        const inventory = await getInventory(accountId, "Drones");
 | 
					        const inventory = await getInventory(
 | 
				
			||||||
 | 
					            accountId,
 | 
				
			||||||
 | 
					            "Drones instantResourceExtractorDrones noResourceExtractorDronesDamage"
 | 
				
			||||||
 | 
					        );
 | 
				
			||||||
        const drone = inventory.Drones.id(req.query.droneId as string)!;
 | 
					        const drone = inventory.Drones.id(req.query.droneId as string)!;
 | 
				
			||||||
        const droneMeta = ExportDrones[drone.ItemType];
 | 
					        const droneMeta = ExportDrones[drone.ItemType];
 | 
				
			||||||
        drone.DeployTime = config.instantResourceExtractorDrones ? new Date(0) : new Date();
 | 
					        drone.DeployTime = inventory.instantResourceExtractorDrones ? new Date(0) : new Date();
 | 
				
			||||||
        if (drone.RepairStart) {
 | 
					        if (drone.RepairStart) {
 | 
				
			||||||
            const repairMinutes = (Date.now() - drone.RepairStart.getTime()) / 60_000;
 | 
					            const repairMinutes = (Date.now() - drone.RepairStart.getTime()) / 60_000;
 | 
				
			||||||
            const hpPerMinute = droneMeta.repairRate / 60;
 | 
					            const hpPerMinute = droneMeta.repairRate / 60;
 | 
				
			||||||
@ -51,11 +53,11 @@ export const dronesController: RequestHandler = async (req, res) => {
 | 
				
			|||||||
        }
 | 
					        }
 | 
				
			||||||
        drone.System = parseInt(req.query.systemIndex as string);
 | 
					        drone.System = parseInt(req.query.systemIndex as string);
 | 
				
			||||||
        const system = ExportSystems[drone.System - 1];
 | 
					        const system = ExportSystems[drone.System - 1];
 | 
				
			||||||
        drone.DamageTime = config.instantResourceExtractorDrones
 | 
					        drone.DamageTime = inventory.instantResourceExtractorDrones
 | 
				
			||||||
            ? new Date()
 | 
					            ? new Date()
 | 
				
			||||||
            : new Date(Date.now() + getRandomInt(3 * 3600 * 1000, 4 * 3600 * 1000));
 | 
					            : new Date(Date.now() + getRandomInt(3 * 3600 * 1000, 4 * 3600 * 1000));
 | 
				
			||||||
        drone.PendingDamage =
 | 
					        drone.PendingDamage =
 | 
				
			||||||
            !config.noResourceExtractorDronesDamage && Math.random() < system.damageChance
 | 
					            !inventory.noResourceExtractorDronesDamage && Math.random() < system.damageChance
 | 
				
			||||||
                ? getRandomInt(system.droneDamage.minValue, system.droneDamage.maxValue)
 | 
					                ? getRandomInt(system.droneDamage.minValue, system.droneDamage.maxValue)
 | 
				
			||||||
                : 0;
 | 
					                : 0;
 | 
				
			||||||
        const resource = getRandomWeightedRewardUc(system.resources, droneMeta.probabilities)!;
 | 
					        const resource = getRandomWeightedRewardUc(system.resources, droneMeta.probabilities)!;
 | 
				
			||||||
@ -72,7 +74,7 @@ export const dronesController: RequestHandler = async (req, res) => {
 | 
				
			|||||||
                );
 | 
					                );
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        } else {
 | 
					        } else {
 | 
				
			||||||
            drone.ResourceCount = 1;
 | 
					            drone.ResourceCount = droneMeta.binCapacity * droneMeta.capacityMultipliers[resource.Rarity];
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        await inventory.save();
 | 
					        await inventory.save();
 | 
				
			||||||
        res.json({});
 | 
					        res.json({});
 | 
				
			||||||
 | 
				
			|||||||
@ -1,13 +1,18 @@
 | 
				
			|||||||
import { RequestHandler } from "express";
 | 
					import type { RequestHandler } from "express";
 | 
				
			||||||
import { getAccountIdForRequest } from "@/src/services/loginService";
 | 
					import { getAccountIdForRequest } from "../../services/loginService.ts";
 | 
				
			||||||
import { combineInventoryChanges, getInventory } from "@/src/services/inventoryService";
 | 
					import { combineInventoryChanges, getInventory } from "../../services/inventoryService.ts";
 | 
				
			||||||
import { getJSONfromString } from "@/src/helpers/stringHelpers";
 | 
					import { getJSONfromString } from "../../helpers/stringHelpers.ts";
 | 
				
			||||||
import { IEndlessXpReward, IInventoryClient, TEndlessXpCategory } from "@/src/types/inventoryTypes/inventoryTypes";
 | 
					import type {
 | 
				
			||||||
import { logger } from "@/src/utils/logger";
 | 
					    IEndlessXpReward,
 | 
				
			||||||
import { ExportRewards, ICountedStoreItem } from "warframe-public-export-plus";
 | 
					    IInventoryClient,
 | 
				
			||||||
import { getRandomElement } from "@/src/services/rngService";
 | 
					    TEndlessXpCategory
 | 
				
			||||||
import { handleStoreItemAcquisition } from "@/src/services/purchaseService";
 | 
					} from "../../types/inventoryTypes/inventoryTypes.ts";
 | 
				
			||||||
import { IInventoryChanges } from "@/src/types/purchaseTypes";
 | 
					import { logger } from "../../utils/logger.ts";
 | 
				
			||||||
 | 
					import type { ICountedStoreItem } from "warframe-public-export-plus";
 | 
				
			||||||
 | 
					import { ExportRewards } from "warframe-public-export-plus";
 | 
				
			||||||
 | 
					import { getRandomElement } from "../../services/rngService.ts";
 | 
				
			||||||
 | 
					import { handleStoreItemAcquisition } from "../../services/purchaseService.ts";
 | 
				
			||||||
 | 
					import type { IInventoryChanges } from "../../types/purchaseTypes.ts";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export const endlessXpController: RequestHandler = async (req, res) => {
 | 
					export const endlessXpController: RequestHandler = async (req, res) => {
 | 
				
			||||||
    const accountId = await getAccountIdForRequest(req);
 | 
					    const accountId = await getAccountIdForRequest(req);
 | 
				
			||||||
 | 
				
			|||||||
@ -1,8 +1,8 @@
 | 
				
			|||||||
import { toMongoDate } from "@/src/helpers/inventoryHelpers";
 | 
					import { toMongoDate } from "../../helpers/inventoryHelpers.ts";
 | 
				
			||||||
import { getJSONfromString } from "@/src/helpers/stringHelpers";
 | 
					import { getJSONfromString } from "../../helpers/stringHelpers.ts";
 | 
				
			||||||
import { getInventory } from "@/src/services/inventoryService";
 | 
					import { getInventory, updateEntratiVault } from "../../services/inventoryService.ts";
 | 
				
			||||||
import { getAccountIdForRequest } from "@/src/services/loginService";
 | 
					import { getAccountIdForRequest } from "../../services/loginService.ts";
 | 
				
			||||||
import { RequestHandler } from "express";
 | 
					import type { RequestHandler } from "express";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export const entratiLabConquestModeController: RequestHandler = async (req, res) => {
 | 
					export const entratiLabConquestModeController: RequestHandler = async (req, res) => {
 | 
				
			||||||
    const accountId = await getAccountIdForRequest(req);
 | 
					    const accountId = await getAccountIdForRequest(req);
 | 
				
			||||||
@ -11,26 +11,7 @@ export const entratiLabConquestModeController: RequestHandler = async (req, res)
 | 
				
			|||||||
        "EntratiVaultCountResetDate EntratiVaultCountLastPeriod EntratiLabConquestUnlocked EchoesHexConquestUnlocked EchoesHexConquestActiveFrameVariants EchoesHexConquestActiveStickers EntratiLabConquestActiveFrameVariants EntratiLabConquestCacheScoreMission EchoesHexConquestCacheScoreMission"
 | 
					        "EntratiVaultCountResetDate EntratiVaultCountLastPeriod EntratiLabConquestUnlocked EchoesHexConquestUnlocked EchoesHexConquestActiveFrameVariants EchoesHexConquestActiveStickers EntratiLabConquestActiveFrameVariants EntratiLabConquestCacheScoreMission EchoesHexConquestCacheScoreMission"
 | 
				
			||||||
    );
 | 
					    );
 | 
				
			||||||
    const body = getJSONfromString<IEntratiLabConquestModeRequest>(String(req.body));
 | 
					    const body = getJSONfromString<IEntratiLabConquestModeRequest>(String(req.body));
 | 
				
			||||||
    if (!inventory.EntratiVaultCountResetDate || Date.now() >= inventory.EntratiVaultCountResetDate.getTime()) {
 | 
					    updateEntratiVault(inventory);
 | 
				
			||||||
        const EPOCH = 1734307200 * 1000; // Mondays, amirite?
 | 
					 | 
				
			||||||
        const day = Math.trunc((Date.now() - EPOCH) / 86400000);
 | 
					 | 
				
			||||||
        const week = Math.trunc(day / 7);
 | 
					 | 
				
			||||||
        const weekStart = EPOCH + week * 604800000;
 | 
					 | 
				
			||||||
        const weekEnd = weekStart + 604800000;
 | 
					 | 
				
			||||||
        inventory.EntratiVaultCountLastPeriod = 0;
 | 
					 | 
				
			||||||
        inventory.EntratiVaultCountResetDate = new Date(weekEnd);
 | 
					 | 
				
			||||||
        if (inventory.EntratiLabConquestUnlocked) {
 | 
					 | 
				
			||||||
            inventory.EntratiLabConquestUnlocked = 0;
 | 
					 | 
				
			||||||
            inventory.EntratiLabConquestCacheScoreMission = 0;
 | 
					 | 
				
			||||||
            inventory.EntratiLabConquestActiveFrameVariants = [];
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        if (inventory.EchoesHexConquestUnlocked) {
 | 
					 | 
				
			||||||
            inventory.EchoesHexConquestUnlocked = 0;
 | 
					 | 
				
			||||||
            inventory.EchoesHexConquestCacheScoreMission = 0;
 | 
					 | 
				
			||||||
            inventory.EchoesHexConquestActiveFrameVariants = [];
 | 
					 | 
				
			||||||
            inventory.EchoesHexConquestActiveStickers = [];
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    if (body.BuyMode) {
 | 
					    if (body.BuyMode) {
 | 
				
			||||||
        inventory.EntratiVaultCountLastPeriod! += 2;
 | 
					        inventory.EntratiVaultCountLastPeriod! += 2;
 | 
				
			||||||
        if (body.IsEchoesDeepArchemedea) {
 | 
					        if (body.IsEchoesDeepArchemedea) {
 | 
				
			||||||
@ -51,7 +32,7 @@ export const entratiLabConquestModeController: RequestHandler = async (req, res)
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
    await inventory.save();
 | 
					    await inventory.save();
 | 
				
			||||||
    res.json({
 | 
					    res.json({
 | 
				
			||||||
        EntratiVaultCountResetDate: toMongoDate(inventory.EntratiVaultCountResetDate),
 | 
					        EntratiVaultCountResetDate: toMongoDate(inventory.EntratiVaultCountResetDate!),
 | 
				
			||||||
        EntratiVaultCountLastPeriod: inventory.EntratiVaultCountLastPeriod,
 | 
					        EntratiVaultCountLastPeriod: inventory.EntratiVaultCountLastPeriod,
 | 
				
			||||||
        EntratiLabConquestUnlocked: inventory.EntratiLabConquestUnlocked,
 | 
					        EntratiLabConquestUnlocked: inventory.EntratiLabConquestUnlocked,
 | 
				
			||||||
        EntratiLabConquestCacheScoreMission: inventory.EntratiLabConquestCacheScoreMission,
 | 
					        EntratiLabConquestCacheScoreMission: inventory.EntratiLabConquestCacheScoreMission,
 | 
				
			||||||
 | 
				
			|||||||
@ -1,9 +1,10 @@
 | 
				
			|||||||
import { RequestHandler } from "express";
 | 
					import type { RequestHandler } from "express";
 | 
				
			||||||
import { getAccountIdForRequest } from "@/src/services/loginService";
 | 
					import { getAccountIdForRequest } from "../../services/loginService.ts";
 | 
				
			||||||
import { addMiscItems, getInventory } from "@/src/services/inventoryService";
 | 
					import { addMiscItems, getInventory } from "../../services/inventoryService.ts";
 | 
				
			||||||
import { getJSONfromString } from "@/src/helpers/stringHelpers";
 | 
					import { getJSONfromString } from "../../helpers/stringHelpers.ts";
 | 
				
			||||||
import { getRecipe, WeaponTypeInternal } from "@/src/services/itemDataService";
 | 
					import type { WeaponTypeInternal } from "../../services/itemDataService.ts";
 | 
				
			||||||
import { EquipmentFeatures } from "@/src/types/equipmentTypes";
 | 
					import { getRecipe } from "../../services/itemDataService.ts";
 | 
				
			||||||
 | 
					import { EquipmentFeatures } from "../../types/equipmentTypes.ts";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export const evolveWeaponController: RequestHandler = async (req, res) => {
 | 
					export const evolveWeaponController: RequestHandler = async (req, res) => {
 | 
				
			||||||
    const accountId = await getAccountIdForRequest(req);
 | 
					    const accountId = await getAccountIdForRequest(req);
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										62
									
								
								src/controllers/api/feedPrinceController.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										62
									
								
								src/controllers/api/feedPrinceController.ts
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,62 @@
 | 
				
			|||||||
 | 
					import type { RequestHandler } from "express";
 | 
				
			||||||
 | 
					import { getAccountIdForRequest } from "../../services/loginService.ts";
 | 
				
			||||||
 | 
					import { addMiscItem, getInventory } from "../../services/inventoryService.ts";
 | 
				
			||||||
 | 
					import { getJSONfromString } from "../../helpers/stringHelpers.ts";
 | 
				
			||||||
 | 
					import { logger } from "../../utils/logger.ts";
 | 
				
			||||||
 | 
					import type { IInventoryChanges } from "../../types/purchaseTypes.ts";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export const feedPrinceController: RequestHandler = async (req, res) => {
 | 
				
			||||||
 | 
					    const accountId = await getAccountIdForRequest(req);
 | 
				
			||||||
 | 
					    const inventory = await getInventory(accountId, "MiscItems NokkoColony NodeIntrosCompleted");
 | 
				
			||||||
 | 
					    const payload = getJSONfromString<IFeedPrinceRequest>(String(req.body));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    switch (payload.Mode) {
 | 
				
			||||||
 | 
					        case "r": {
 | 
				
			||||||
 | 
					            inventory.NokkoColony ??= {
 | 
				
			||||||
 | 
					                FeedLevel: 0,
 | 
				
			||||||
 | 
					                JournalEntries: []
 | 
				
			||||||
 | 
					            };
 | 
				
			||||||
 | 
					            const InventoryChanges: IInventoryChanges = {};
 | 
				
			||||||
 | 
					            inventory.NokkoColony.FeedLevel += payload.Amount;
 | 
				
			||||||
 | 
					            if (
 | 
				
			||||||
 | 
					                (!inventory.NodeIntrosCompleted.includes("CompletedVision1") && inventory.NokkoColony.FeedLevel > 20) ||
 | 
				
			||||||
 | 
					                (!inventory.NodeIntrosCompleted.includes("CompletedVision2") && inventory.NokkoColony.FeedLevel > 60)
 | 
				
			||||||
 | 
					            ) {
 | 
				
			||||||
 | 
					                res.json({
 | 
				
			||||||
 | 
					                    FeedSucceeded: false,
 | 
				
			||||||
 | 
					                    FeedLevel: inventory.NokkoColony.FeedLevel - payload.Amount,
 | 
				
			||||||
 | 
					                    InventoryChanges
 | 
				
			||||||
 | 
					                } satisfies IFeedPrinceResponse);
 | 
				
			||||||
 | 
					            } else {
 | 
				
			||||||
 | 
					                addMiscItem(
 | 
				
			||||||
 | 
					                    inventory,
 | 
				
			||||||
 | 
					                    "/Lotus/Types/Items/MiscItems/MushroomFood",
 | 
				
			||||||
 | 
					                    payload.Amount * -1,
 | 
				
			||||||
 | 
					                    InventoryChanges
 | 
				
			||||||
 | 
					                );
 | 
				
			||||||
 | 
					                await inventory.save();
 | 
				
			||||||
 | 
					                res.json({
 | 
				
			||||||
 | 
					                    FeedSucceeded: true,
 | 
				
			||||||
 | 
					                    FeedLevel: inventory.NokkoColony.FeedLevel,
 | 
				
			||||||
 | 
					                    InventoryChanges
 | 
				
			||||||
 | 
					                } satisfies IFeedPrinceResponse);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        default:
 | 
				
			||||||
 | 
					            logger.debug(`data provided to ${req.path}: ${String(req.body)}`);
 | 
				
			||||||
 | 
					            throw new Error(`unknown feedPrince mode: ${payload.Mode}`);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					interface IFeedPrinceRequest {
 | 
				
			||||||
 | 
					    Mode: string; // r
 | 
				
			||||||
 | 
					    Amount: number;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					interface IFeedPrinceResponse {
 | 
				
			||||||
 | 
					    FeedSucceeded: boolean;
 | 
				
			||||||
 | 
					    FeedLevel: number;
 | 
				
			||||||
 | 
					    InventoryChanges: IInventoryChanges;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@ -1,7 +1,7 @@
 | 
				
			|||||||
import { RequestHandler } from "express";
 | 
					import type { RequestHandler } from "express";
 | 
				
			||||||
import { getSession } from "@/src/managers/sessionManager";
 | 
					import { getSession } from "../../managers/sessionManager.ts";
 | 
				
			||||||
import { logger } from "@/src/utils/logger";
 | 
					import { logger } from "../../utils/logger.ts";
 | 
				
			||||||
import { IFindSessionRequest } from "@/src/types/session";
 | 
					import type { IFindSessionRequest } from "../../types/session.ts";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export const findSessionsController: RequestHandler = (_req, res) => {
 | 
					export const findSessionsController: RequestHandler = (_req, res) => {
 | 
				
			||||||
    const req = JSON.parse(String(_req.body)) as IFindSessionRequest;
 | 
					    const req = JSON.parse(String(_req.body)) as IFindSessionRequest;
 | 
				
			||||||
 | 
				
			|||||||
@ -1,8 +1,8 @@
 | 
				
			|||||||
import { getJSONfromString } from "@/src/helpers/stringHelpers";
 | 
					import { getJSONfromString } from "../../helpers/stringHelpers.ts";
 | 
				
			||||||
import { addMiscItems, addStanding, getInventory } from "@/src/services/inventoryService";
 | 
					import { addMiscItems, addStanding, getInventory } from "../../services/inventoryService.ts";
 | 
				
			||||||
import { getAccountIdForRequest } from "@/src/services/loginService";
 | 
					import { getAccountIdForRequest } from "../../services/loginService.ts";
 | 
				
			||||||
import { IMiscItem } from "@/src/types/inventoryTypes/inventoryTypes";
 | 
					import type { IMiscItem } from "../../types/inventoryTypes/inventoryTypes.ts";
 | 
				
			||||||
import { RequestHandler } from "express";
 | 
					import type { RequestHandler } from "express";
 | 
				
			||||||
import { ExportResources } from "warframe-public-export-plus";
 | 
					import { ExportResources } from "warframe-public-export-plus";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export const fishmongerController: RequestHandler = async (req, res) => {
 | 
					export const fishmongerController: RequestHandler = async (req, res) => {
 | 
				
			||||||
 | 
				
			|||||||
@ -1,22 +1,91 @@
 | 
				
			|||||||
import { RequestHandler } from "express";
 | 
					import type { RequestHandler } from "express";
 | 
				
			||||||
import { getAccountIdForRequest } from "@/src/services/loginService";
 | 
					import { getAccountForRequest } from "../../services/loginService.ts";
 | 
				
			||||||
import { getInventory, addMiscItems, addEquipment, occupySlot } from "@/src/services/inventoryService";
 | 
					import { getInventory, addMiscItems, addEquipment, occupySlot } from "../../services/inventoryService.ts";
 | 
				
			||||||
import { IMiscItem, TFocusPolarity, TEquipmentKey, InventorySlot } from "@/src/types/inventoryTypes/inventoryTypes";
 | 
					import type { IMiscItem, TFocusPolarity, TEquipmentKey } from "../../types/inventoryTypes/inventoryTypes.ts";
 | 
				
			||||||
import { logger } from "@/src/utils/logger";
 | 
					import { InventorySlot } from "../../types/inventoryTypes/inventoryTypes.ts";
 | 
				
			||||||
 | 
					import { logger } from "../../utils/logger.ts";
 | 
				
			||||||
import { ExportFocusUpgrades } from "warframe-public-export-plus";
 | 
					import { ExportFocusUpgrades } from "warframe-public-export-plus";
 | 
				
			||||||
import { Inventory } from "@/src/models/inventoryModels/inventoryModel";
 | 
					import { Inventory } from "../../models/inventoryModels/inventoryModel.ts";
 | 
				
			||||||
 | 
					import { version_compare } from "../../helpers/inventoryHelpers.ts";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export const focusController: RequestHandler = async (req, res) => {
 | 
					export const focusController: RequestHandler = async (req, res) => {
 | 
				
			||||||
    const accountId = await getAccountIdForRequest(req);
 | 
					    const account = await getAccountForRequest(req);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    let op = req.query.op as string;
 | 
				
			||||||
 | 
					    const focus2 = account.BuildLabel && version_compare(account.BuildLabel, "2022.04.29.12.53") < 0;
 | 
				
			||||||
 | 
					    if (focus2) {
 | 
				
			||||||
 | 
					        // Focus 2.0
 | 
				
			||||||
        switch (req.query.op) {
 | 
					        switch (req.query.op) {
 | 
				
			||||||
 | 
					            case Focus2Operation.InstallLens:
 | 
				
			||||||
 | 
					                op = "InstallLens";
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
 | 
					            case Focus2Operation.UnlockWay:
 | 
				
			||||||
 | 
					                op = "UnlockWay";
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
 | 
					            case Focus2Operation.UnlockUpgrade:
 | 
				
			||||||
 | 
					                op = "UnlockUpgrade";
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
 | 
					            case Focus2Operation.IncreasePool:
 | 
				
			||||||
 | 
					                op = "IncreasePool";
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
 | 
					            case Focus2Operation.LevelUpUpgrade:
 | 
				
			||||||
 | 
					                op = "LevelUpUpgrade";
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
 | 
					            case Focus2Operation.ActivateWay:
 | 
				
			||||||
 | 
					                op = "ActivateWay";
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
 | 
					            case Focus2Operation.UpdateUpgrade:
 | 
				
			||||||
 | 
					                op = "UpdateUpgrade";
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
 | 
					            case Focus2Operation.SentTrainingAmplifier:
 | 
				
			||||||
 | 
					                op = "SentTrainingAmplifier";
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
 | 
					            case Focus2Operation.UnbindUpgrade:
 | 
				
			||||||
 | 
					                op = "UnbindUpgrade";
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
 | 
					            case Focus2Operation.ConvertShard:
 | 
				
			||||||
 | 
					                op = "ConvertShard";
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					        // Focus 3.0
 | 
				
			||||||
 | 
					        switch (req.query.op) {
 | 
				
			||||||
 | 
					            case Focus3Operation.InstallLens:
 | 
				
			||||||
 | 
					                op = "InstallLens";
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
 | 
					            case Focus3Operation.UnlockWay:
 | 
				
			||||||
 | 
					                op = "UnlockWay";
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
 | 
					            case Focus3Operation.UnlockUpgrade:
 | 
				
			||||||
 | 
					                op = "UnlockUpgrade";
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
 | 
					            case Focus3Operation.LevelUpUpgrade:
 | 
				
			||||||
 | 
					                op = "LevelUpUpgrade";
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
 | 
					            case Focus3Operation.ActivateWay:
 | 
				
			||||||
 | 
					                op = "ActivateWay";
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
 | 
					            case Focus3Operation.SentTrainingAmplifier:
 | 
				
			||||||
 | 
					                op = "SentTrainingAmplifier";
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
 | 
					            case Focus3Operation.UnbindUpgrade:
 | 
				
			||||||
 | 
					                op = "UnbindUpgrade";
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
 | 
					            case Focus3Operation.ConvertShard:
 | 
				
			||||||
 | 
					                op = "ConvertShard";
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    switch (op) {
 | 
				
			||||||
        default:
 | 
					        default:
 | 
				
			||||||
            logger.error("Unhandled focus op type: " + String(req.query.op));
 | 
					            logger.error("Unhandled focus op type: " + String(req.query.op));
 | 
				
			||||||
            logger.debug(String(req.body));
 | 
					            logger.debug(String(req.body));
 | 
				
			||||||
            res.end();
 | 
					            res.end();
 | 
				
			||||||
            break;
 | 
					            break;
 | 
				
			||||||
        case FocusOperation.InstallLens: {
 | 
					        case "InstallLens": {
 | 
				
			||||||
            const request = JSON.parse(String(req.body)) as ILensInstallRequest;
 | 
					            const request = JSON.parse(String(req.body)) as ILensInstallRequest;
 | 
				
			||||||
            const inventory = await getInventory(accountId);
 | 
					            const inventory = await getInventory(account._id.toString());
 | 
				
			||||||
            const item = inventory[request.Category].id(request.WeaponId);
 | 
					            const item = inventory[request.Category].id(request.WeaponId);
 | 
				
			||||||
            if (item) {
 | 
					            if (item) {
 | 
				
			||||||
                item.FocusLens = request.LensType;
 | 
					                item.FocusLens = request.LensType;
 | 
				
			||||||
@ -34,15 +103,15 @@ export const focusController: RequestHandler = async (req, res) => {
 | 
				
			|||||||
            });
 | 
					            });
 | 
				
			||||||
            break;
 | 
					            break;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        case FocusOperation.UnlockWay: {
 | 
					        case "UnlockWay": {
 | 
				
			||||||
            const focusType = (JSON.parse(String(req.body)) as IWayRequest).FocusType;
 | 
					            const focusType = (JSON.parse(String(req.body)) as IWayRequest).FocusType;
 | 
				
			||||||
            const focusPolarity = focusTypeToPolarity(focusType);
 | 
					            const focusPolarity = focusTypeToPolarity(focusType);
 | 
				
			||||||
            const inventory = await getInventory(accountId);
 | 
					            const inventory = await getInventory(account._id.toString(), "FocusAbility FocusUpgrades FocusXP");
 | 
				
			||||||
            const cost = inventory.FocusAbility ? 50_000 : 0;
 | 
					            const cost = inventory.FocusAbility ? 50_000 : 0;
 | 
				
			||||||
            inventory.FocusAbility ??= focusType;
 | 
					            inventory.FocusAbility ??= focusType;
 | 
				
			||||||
            inventory.FocusUpgrades.push({ ItemType: focusType });
 | 
					            inventory.FocusUpgrades.push({ ItemType: focusType });
 | 
				
			||||||
            if (inventory.FocusXP) {
 | 
					            if (cost) {
 | 
				
			||||||
                inventory.FocusXP[focusPolarity]! -= cost;
 | 
					                inventory.FocusXP![focusPolarity]! -= cost;
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            await inventory.save();
 | 
					            await inventory.save();
 | 
				
			||||||
            res.json({
 | 
					            res.json({
 | 
				
			||||||
@ -51,12 +120,29 @@ export const focusController: RequestHandler = async (req, res) => {
 | 
				
			|||||||
            });
 | 
					            });
 | 
				
			||||||
            break;
 | 
					            break;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        case FocusOperation.ActivateWay: {
 | 
					        case "IncreasePool": {
 | 
				
			||||||
 | 
					            const request = JSON.parse(String(req.body)) as IIncreasePoolRequest;
 | 
				
			||||||
 | 
					            const focusPolarity = focusTypeToPolarity(request.FocusType);
 | 
				
			||||||
 | 
					            const inventory = await getInventory(account._id.toString(), "FocusXP FocusCapacity");
 | 
				
			||||||
 | 
					            let cost = 0;
 | 
				
			||||||
 | 
					            for (let capacity = request.CurrentTotalCapacity; capacity != request.NewTotalCapacity; ++capacity) {
 | 
				
			||||||
 | 
					                cost += increasePoolCost[capacity - 5];
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            inventory.FocusXP![focusPolarity]! -= cost;
 | 
				
			||||||
 | 
					            inventory.FocusCapacity = request.NewTotalCapacity;
 | 
				
			||||||
 | 
					            await inventory.save();
 | 
				
			||||||
 | 
					            res.json({
 | 
				
			||||||
 | 
					                TotalCapacity: request.NewTotalCapacity,
 | 
				
			||||||
 | 
					                FocusPointCosts: { [focusPolarity]: cost }
 | 
				
			||||||
 | 
					            });
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        case "ActivateWay": {
 | 
				
			||||||
            const focusType = (JSON.parse(String(req.body)) as IWayRequest).FocusType;
 | 
					            const focusType = (JSON.parse(String(req.body)) as IWayRequest).FocusType;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            await Inventory.updateOne(
 | 
					            await Inventory.updateOne(
 | 
				
			||||||
                {
 | 
					                {
 | 
				
			||||||
                    accountOwnerId: accountId
 | 
					                    accountOwnerId: account._id.toString()
 | 
				
			||||||
                },
 | 
					                },
 | 
				
			||||||
                {
 | 
					                {
 | 
				
			||||||
                    FocusAbility: focusType
 | 
					                    FocusAbility: focusType
 | 
				
			||||||
@ -68,13 +154,20 @@ export const focusController: RequestHandler = async (req, res) => {
 | 
				
			|||||||
            });
 | 
					            });
 | 
				
			||||||
            break;
 | 
					            break;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        case FocusOperation.UnlockUpgrade: {
 | 
					        case "UnlockUpgrade": {
 | 
				
			||||||
            const request = JSON.parse(String(req.body)) as IUnlockUpgradeRequest;
 | 
					            const request = JSON.parse(String(req.body)) as IUnlockUpgradeRequest;
 | 
				
			||||||
            const focusPolarity = focusTypeToPolarity(request.FocusTypes[0]);
 | 
					            const focusPolarity = focusTypeToPolarity(request.FocusTypes[0]);
 | 
				
			||||||
            const inventory = await getInventory(accountId);
 | 
					            const inventory = await getInventory(account._id.toString());
 | 
				
			||||||
            let cost = 0;
 | 
					            let cost = 0;
 | 
				
			||||||
            for (const focusType of request.FocusTypes) {
 | 
					            for (const focusType of request.FocusTypes) {
 | 
				
			||||||
 | 
					                if (focusType in ExportFocusUpgrades) {
 | 
				
			||||||
                    cost += ExportFocusUpgrades[focusType].baseFocusPointCost;
 | 
					                    cost += ExportFocusUpgrades[focusType].baseFocusPointCost;
 | 
				
			||||||
 | 
					                } else if (focusType == "/Lotus/Upgrades/Focus/Power/Residual/ChannelEfficiencyFocusUpgrade") {
 | 
				
			||||||
 | 
					                    // Zenurik's Inner Might (Focus 2.0)
 | 
				
			||||||
 | 
					                    cost += 50_000;
 | 
				
			||||||
 | 
					                } else {
 | 
				
			||||||
 | 
					                    logger.warn(`unknown focus upgrade ${focusType}, will unlock it for free`);
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
                inventory.FocusUpgrades.push({ ItemType: focusType, Level: 0 });
 | 
					                inventory.FocusUpgrades.push({ ItemType: focusType, Level: 0 });
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            inventory.FocusXP![focusPolarity]! -= cost;
 | 
					            inventory.FocusXP![focusPolarity]! -= cost;
 | 
				
			||||||
@ -85,16 +178,21 @@ export const focusController: RequestHandler = async (req, res) => {
 | 
				
			|||||||
            });
 | 
					            });
 | 
				
			||||||
            break;
 | 
					            break;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        case FocusOperation.LevelUpUpgrade: {
 | 
					        case "LevelUpUpgrade":
 | 
				
			||||||
 | 
					        case "UpdateUpgrade": {
 | 
				
			||||||
            const request = JSON.parse(String(req.body)) as ILevelUpUpgradeRequest;
 | 
					            const request = JSON.parse(String(req.body)) as ILevelUpUpgradeRequest;
 | 
				
			||||||
            const focusPolarity = focusTypeToPolarity(request.FocusInfos[0].ItemType);
 | 
					            const focusPolarity = focusTypeToPolarity(request.FocusInfos[0].ItemType);
 | 
				
			||||||
            const inventory = await getInventory(accountId);
 | 
					            const inventory = await getInventory(account._id.toString());
 | 
				
			||||||
            let cost = 0;
 | 
					            let cost = 0;
 | 
				
			||||||
            for (const focusUpgrade of request.FocusInfos) {
 | 
					            for (const focusUpgrade of request.FocusInfos) {
 | 
				
			||||||
                cost += focusUpgrade.FocusXpCost;
 | 
					                cost += focusUpgrade.FocusXpCost;
 | 
				
			||||||
                const focusUpgradeDb = inventory.FocusUpgrades.find(entry => entry.ItemType == focusUpgrade.ItemType)!;
 | 
					                const focusUpgradeDb = inventory.FocusUpgrades.find(entry => entry.ItemType == focusUpgrade.ItemType)!;
 | 
				
			||||||
 | 
					                if (op == "UpdateUpgrade") {
 | 
				
			||||||
 | 
					                    focusUpgradeDb.IsActive = focusUpgrade.IsActive;
 | 
				
			||||||
 | 
					                } else {
 | 
				
			||||||
                    focusUpgradeDb.Level = focusUpgrade.Level;
 | 
					                    focusUpgradeDb.Level = focusUpgrade.Level;
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
            inventory.FocusXP![focusPolarity]! -= cost;
 | 
					            inventory.FocusXP![focusPolarity]! -= cost;
 | 
				
			||||||
            await inventory.save();
 | 
					            await inventory.save();
 | 
				
			||||||
            res.json({
 | 
					            res.json({
 | 
				
			||||||
@ -103,9 +201,9 @@ export const focusController: RequestHandler = async (req, res) => {
 | 
				
			|||||||
            });
 | 
					            });
 | 
				
			||||||
            break;
 | 
					            break;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        case FocusOperation.SentTrainingAmplifier: {
 | 
					        case "SentTrainingAmplifier": {
 | 
				
			||||||
            const request = JSON.parse(String(req.body)) as ISentTrainingAmplifierRequest;
 | 
					            const request = JSON.parse(String(req.body)) as ISentTrainingAmplifierRequest;
 | 
				
			||||||
            const inventory = await getInventory(accountId);
 | 
					            const inventory = await getInventory(account._id.toString());
 | 
				
			||||||
            const inventoryChanges = addEquipment(inventory, "OperatorAmps", request.StartingWeaponType, {
 | 
					            const inventoryChanges = addEquipment(inventory, "OperatorAmps", request.StartingWeaponType, {
 | 
				
			||||||
                ModularParts: [
 | 
					                ModularParts: [
 | 
				
			||||||
                    "/Lotus/Weapons/Sentients/OperatorAmplifiers/SentTrainingAmplifier/SentAmpTrainingGrip",
 | 
					                    "/Lotus/Weapons/Sentients/OperatorAmplifiers/SentTrainingAmplifier/SentAmpTrainingGrip",
 | 
				
			||||||
@ -118,10 +216,10 @@ export const focusController: RequestHandler = async (req, res) => {
 | 
				
			|||||||
            res.json(inventoryChanges.OperatorAmps![0]);
 | 
					            res.json(inventoryChanges.OperatorAmps![0]);
 | 
				
			||||||
            break;
 | 
					            break;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        case FocusOperation.UnbindUpgrade: {
 | 
					        case "UnbindUpgrade": {
 | 
				
			||||||
            const request = JSON.parse(String(req.body)) as IUnbindUpgradeRequest;
 | 
					            const request = JSON.parse(String(req.body)) as IUnbindUpgradeRequest;
 | 
				
			||||||
            const focusPolarity = focusTypeToPolarity(request.FocusTypes[0]);
 | 
					            const focusPolarity = focusTypeToPolarity(request.FocusTypes[0]);
 | 
				
			||||||
            const inventory = await getInventory(accountId);
 | 
					            const inventory = await getInventory(account._id.toString());
 | 
				
			||||||
            inventory.FocusXP![focusPolarity]! -= 750_000 * request.FocusTypes.length;
 | 
					            inventory.FocusXP![focusPolarity]! -= 750_000 * request.FocusTypes.length;
 | 
				
			||||||
            addMiscItems(inventory, [
 | 
					            addMiscItems(inventory, [
 | 
				
			||||||
                {
 | 
					                {
 | 
				
			||||||
@ -148,7 +246,7 @@ export const focusController: RequestHandler = async (req, res) => {
 | 
				
			|||||||
            });
 | 
					            });
 | 
				
			||||||
            break;
 | 
					            break;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        case FocusOperation.ConvertShard: {
 | 
					        case "ConvertShard": {
 | 
				
			||||||
            const request = JSON.parse(String(req.body)) as IConvertShardRequest;
 | 
					            const request = JSON.parse(String(req.body)) as IConvertShardRequest;
 | 
				
			||||||
            // Tally XP
 | 
					            // Tally XP
 | 
				
			||||||
            let xp = 0;
 | 
					            let xp = 0;
 | 
				
			||||||
@ -166,7 +264,7 @@ export const focusController: RequestHandler = async (req, res) => {
 | 
				
			|||||||
            for (const shard of request.Shards) {
 | 
					            for (const shard of request.Shards) {
 | 
				
			||||||
                shard.ItemCount *= -1;
 | 
					                shard.ItemCount *= -1;
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            const inventory = await getInventory(accountId);
 | 
					            const inventory = await getInventory(account._id.toString());
 | 
				
			||||||
            const polarity = request.Polarity;
 | 
					            const polarity = request.Polarity;
 | 
				
			||||||
            inventory.FocusXP ??= {};
 | 
					            inventory.FocusXP ??= {};
 | 
				
			||||||
            inventory.FocusXP[polarity] ??= 0;
 | 
					            inventory.FocusXP[polarity] ??= 0;
 | 
				
			||||||
@ -178,7 +276,8 @@ export const focusController: RequestHandler = async (req, res) => {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
enum FocusOperation {
 | 
					// Focus 3.0
 | 
				
			||||||
 | 
					enum Focus3Operation {
 | 
				
			||||||
    InstallLens = "1",
 | 
					    InstallLens = "1",
 | 
				
			||||||
    UnlockWay = "2",
 | 
					    UnlockWay = "2",
 | 
				
			||||||
    UnlockUpgrade = "3",
 | 
					    UnlockUpgrade = "3",
 | 
				
			||||||
@ -189,6 +288,20 @@ enum FocusOperation {
 | 
				
			|||||||
    ConvertShard = "9"
 | 
					    ConvertShard = "9"
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Focus 2.0
 | 
				
			||||||
 | 
					enum Focus2Operation {
 | 
				
			||||||
 | 
					    InstallLens = "1",
 | 
				
			||||||
 | 
					    UnlockWay = "2",
 | 
				
			||||||
 | 
					    UnlockUpgrade = "3",
 | 
				
			||||||
 | 
					    IncreasePool = "4",
 | 
				
			||||||
 | 
					    LevelUpUpgrade = "5",
 | 
				
			||||||
 | 
					    ActivateWay = "6",
 | 
				
			||||||
 | 
					    UpdateUpgrade = "7", // used to change the IsActive state, same format as ILevelUpUpgradeRequest
 | 
				
			||||||
 | 
					    SentTrainingAmplifier = "9",
 | 
				
			||||||
 | 
					    UnbindUpgrade = "10",
 | 
				
			||||||
 | 
					    ConvertShard = "11"
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// For UnlockWay & ActivateWay
 | 
					// For UnlockWay & ActivateWay
 | 
				
			||||||
interface IWayRequest {
 | 
					interface IWayRequest {
 | 
				
			||||||
    FocusType: string;
 | 
					    FocusType: string;
 | 
				
			||||||
@ -198,6 +311,13 @@ interface IUnlockUpgradeRequest {
 | 
				
			|||||||
    FocusTypes: string[];
 | 
					    FocusTypes: string[];
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Focus 2.0
 | 
				
			||||||
 | 
					interface IIncreasePoolRequest {
 | 
				
			||||||
 | 
					    FocusType: string;
 | 
				
			||||||
 | 
					    CurrentTotalCapacity: number;
 | 
				
			||||||
 | 
					    NewTotalCapacity: number;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
interface ILevelUpUpgradeRequest {
 | 
					interface ILevelUpUpgradeRequest {
 | 
				
			||||||
    FocusInfos: {
 | 
					    FocusInfos: {
 | 
				
			||||||
        ItemType: string;
 | 
					        ItemType: string;
 | 
				
			||||||
@ -205,6 +325,7 @@ interface ILevelUpUpgradeRequest {
 | 
				
			|||||||
        IsUniversal: boolean;
 | 
					        IsUniversal: boolean;
 | 
				
			||||||
        Level: number;
 | 
					        Level: number;
 | 
				
			||||||
        IsActiveAbility: boolean;
 | 
					        IsActiveAbility: boolean;
 | 
				
			||||||
 | 
					        IsActive?: number; // Focus 2.0
 | 
				
			||||||
    }[];
 | 
					    }[];
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -230,7 +351,7 @@ interface ILensInstallRequest {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
// Works for ways & upgrades
 | 
					// Works for ways & upgrades
 | 
				
			||||||
const focusTypeToPolarity = (type: string): TFocusPolarity => {
 | 
					const focusTypeToPolarity = (type: string): TFocusPolarity => {
 | 
				
			||||||
    return ("AP_" + type.substr(1).split("/")[3].toUpperCase()) as TFocusPolarity;
 | 
					    return ("AP_" + type.substring(1).split("/")[3].toUpperCase()) as TFocusPolarity;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const shardValues = {
 | 
					const shardValues = {
 | 
				
			||||||
@ -239,3 +360,19 @@ const shardValues = {
 | 
				
			|||||||
    "/Lotus/Types/Gameplay/Eidolon/Resources/SentientShards/SentientShardBrilliantItem": 25_000,
 | 
					    "/Lotus/Types/Gameplay/Eidolon/Resources/SentientShards/SentientShardBrilliantItem": 25_000,
 | 
				
			||||||
    "/Lotus/Types/Gameplay/Eidolon/Resources/SentientShards/SentientShardBrilliantTierTwoItem": 40_000
 | 
					    "/Lotus/Types/Gameplay/Eidolon/Resources/SentientShards/SentientShardBrilliantTierTwoItem": 40_000
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Starting at a capacity of 5 (Source: https://wiki.warframe.com/w/Focus_2.0)
 | 
				
			||||||
 | 
					const increasePoolCost = [
 | 
				
			||||||
 | 
					    2576, 3099, 3638, 4190, 4755, 5331, 5918, 6514, 7120, 7734, 8357, 8988, 9626, 10271, 10923, 11582, 12247, 12918,
 | 
				
			||||||
 | 
					    13595, 14277, 14965, 15659, 16357, 17061, 17769, 18482, 19200, 19922, 20649, 21380, 22115, 22854, 23597, 24344,
 | 
				
			||||||
 | 
					    25095, 25850, 26609, 27371, 28136, 28905, 29678, 30454, 31233, 32015, 32801, 33590, 34382, 35176, 35974, 36775,
 | 
				
			||||||
 | 
					    37579, 38386, 39195, 40008, 40823, 41641, 42461, 43284, 44110, 44938, 45769, 46603, 47439, 48277, 49118, 49961,
 | 
				
			||||||
 | 
					    50807, 51655, 52505, 53357, 54212, 55069, 55929, 56790, 57654, 58520, 59388, 60258, 61130, 62005, 62881, 63759,
 | 
				
			||||||
 | 
					    64640, 65522, 66407, 67293, 68182, 69072, 69964, 70858, 71754, 72652, 73552, 74453, 75357, 76262, 77169, 78078,
 | 
				
			||||||
 | 
					    78988, 79900, 80814, 81730, 82648, 83567, 84488, 85410, 86334, 87260, 88188, 89117, 90047, 90980, 91914, 92849,
 | 
				
			||||||
 | 
					    93786, 94725, 95665, 96607, 97550, 98495, 99441, 100389, 101338, 102289, 103241, 104195, 105150, 106107, 107065,
 | 
				
			||||||
 | 
					    108024, 108985, 109948, 110911, 111877, 112843, 113811, 114780, 115751, 116723, 117696, 118671, 119647, 120624,
 | 
				
			||||||
 | 
					    121603, 122583, 123564, 124547, 125531, 126516, 127503, 128490, 129479, 130470, 131461, 132454, 133448, 134443,
 | 
				
			||||||
 | 
					    135440, 136438, 137437, 138437, 139438, 140441, 141444, 142449, 143455, 144463, 145471, 146481, 147492, 148503,
 | 
				
			||||||
 | 
					    149517
 | 
				
			||||||
 | 
					];
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										27
									
								
								src/controllers/api/forceRemoveItemController.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										27
									
								
								src/controllers/api/forceRemoveItemController.ts
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,27 @@
 | 
				
			|||||||
 | 
					import type { RequestHandler } from "express";
 | 
				
			||||||
 | 
					import { getAccountIdForRequest } from "../../services/loginService.ts";
 | 
				
			||||||
 | 
					import { getJSONfromString } from "../../helpers/stringHelpers.ts";
 | 
				
			||||||
 | 
					import { getInventory } from "../../services/inventoryService.ts";
 | 
				
			||||||
 | 
					import type { IInventoryChanges } from "../../types/purchaseTypes.ts";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export const forceRemoveItemController: RequestHandler = async (req, res) => {
 | 
				
			||||||
 | 
					    const accountId = await getAccountIdForRequest(req);
 | 
				
			||||||
 | 
					    const inventory = await getInventory(accountId, "MiscItems");
 | 
				
			||||||
 | 
					    const body = getJSONfromString<IForceRemoveItemRequest>(String(req.body));
 | 
				
			||||||
 | 
					    const inventoryChanges: IInventoryChanges = {};
 | 
				
			||||||
 | 
					    for (const item of body.items) {
 | 
				
			||||||
 | 
					        const index = inventory.MiscItems.findIndex(x => x.ItemType == item);
 | 
				
			||||||
 | 
					        if (index != -1) {
 | 
				
			||||||
 | 
					            inventoryChanges.MiscItems ??= [];
 | 
				
			||||||
 | 
					            inventoryChanges.MiscItems.push({ ItemType: item, ItemCount: inventory.MiscItems[index].ItemCount * -1 });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            inventory.MiscItems.splice(index, 1);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    await inventory.save();
 | 
				
			||||||
 | 
					    res.json({ InventoryChanges: inventoryChanges });
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					interface IForceRemoveItemRequest {
 | 
				
			||||||
 | 
					    items: string[];
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@ -1,23 +1,15 @@
 | 
				
			|||||||
import { RequestHandler } from "express";
 | 
					import type { RequestHandler } from "express";
 | 
				
			||||||
import { ExportResources } from "warframe-public-export-plus";
 | 
					import { ExportResources } from "warframe-public-export-plus";
 | 
				
			||||||
import { getAccountIdForRequest } from "@/src/services/loginService";
 | 
					import { getAccountIdForRequest } from "../../services/loginService.ts";
 | 
				
			||||||
import { addFusionTreasures, addMiscItems, getInventory } from "@/src/services/inventoryService";
 | 
					import { addFusionTreasures, addMiscItems, getInventory } from "../../services/inventoryService.ts";
 | 
				
			||||||
import { IFusionTreasure, IMiscItem } from "@/src/types/inventoryTypes/inventoryTypes";
 | 
					import type { IMiscItem } from "../../types/inventoryTypes/inventoryTypes.ts";
 | 
				
			||||||
 | 
					import { parseFusionTreasure } from "../../helpers/inventoryHelpers.ts";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
interface IFusionTreasureRequest {
 | 
					interface IFusionTreasureRequest {
 | 
				
			||||||
    oldTreasureName: string;
 | 
					    oldTreasureName: string;
 | 
				
			||||||
    newTreasureName: string;
 | 
					    newTreasureName: string;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const parseFusionTreasure = (name: string, count: number): IFusionTreasure => {
 | 
					 | 
				
			||||||
    const arr = name.split("_");
 | 
					 | 
				
			||||||
    return {
 | 
					 | 
				
			||||||
        ItemType: arr[0],
 | 
					 | 
				
			||||||
        Sockets: parseInt(arr[1], 16),
 | 
					 | 
				
			||||||
        ItemCount: count
 | 
					 | 
				
			||||||
    };
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
export const fusionTreasuresController: RequestHandler = async (req, res) => {
 | 
					export const fusionTreasuresController: RequestHandler = async (req, res) => {
 | 
				
			||||||
    const accountId = await getAccountIdForRequest(req);
 | 
					    const accountId = await getAccountIdForRequest(req);
 | 
				
			||||||
    const inventory = await getInventory(accountId);
 | 
					    const inventory = await getInventory(accountId);
 | 
				
			||||||
 | 
				
			|||||||
@ -1,14 +1,14 @@
 | 
				
			|||||||
import { toMongoDate } from "@/src/helpers/inventoryHelpers";
 | 
					import { toMongoDate } from "../../helpers/inventoryHelpers.ts";
 | 
				
			||||||
import { getJSONfromString } from "@/src/helpers/stringHelpers";
 | 
					import { getJSONfromString } from "../../helpers/stringHelpers.ts";
 | 
				
			||||||
import { addMiscItem, getInventory } from "@/src/services/inventoryService";
 | 
					import { addMiscItem, getInventory } from "../../services/inventoryService.ts";
 | 
				
			||||||
import { toStoreItem } from "@/src/services/itemDataService";
 | 
					import { toStoreItem } from "../../services/itemDataService.ts";
 | 
				
			||||||
import { getAccountIdForRequest } from "@/src/services/loginService";
 | 
					import { getAccountIdForRequest } from "../../services/loginService.ts";
 | 
				
			||||||
import { createGarden, getPersonalRooms } from "@/src/services/personalRoomsService";
 | 
					import { createGarden, getPersonalRooms } from "../../services/personalRoomsService.ts";
 | 
				
			||||||
import { IMongoDate } from "@/src/types/commonTypes";
 | 
					import type { IMongoDate } from "../../types/commonTypes.ts";
 | 
				
			||||||
import { IMissionReward } from "@/src/types/missionTypes";
 | 
					import type { IMissionReward } from "../../types/missionTypes.ts";
 | 
				
			||||||
import { IGardeningClient, IPersonalRoomsClient } from "@/src/types/personalRoomsTypes";
 | 
					import type { IGardeningClient, IPersonalRoomsClient } from "../../types/personalRoomsTypes.ts";
 | 
				
			||||||
import { IInventoryChanges } from "@/src/types/purchaseTypes";
 | 
					import type { IInventoryChanges } from "../../types/purchaseTypes.ts";
 | 
				
			||||||
import { RequestHandler } from "express";
 | 
					import type { RequestHandler } from "express";
 | 
				
			||||||
import { dict_en, ExportResources } from "warframe-public-export-plus";
 | 
					import { dict_en, ExportResources } from "warframe-public-export-plus";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export const gardeningController: RequestHandler = async (req, res) => {
 | 
					export const gardeningController: RequestHandler = async (req, res) => {
 | 
				
			||||||
 | 
				
			|||||||
@ -1,8 +1,8 @@
 | 
				
			|||||||
import { getAccountIdForRequest } from "@/src/services/loginService";
 | 
					import { getAccountIdForRequest } from "../../services/loginService.ts";
 | 
				
			||||||
import { updateGeneric } from "@/src/services/inventoryService";
 | 
					import { updateGeneric } from "../../services/inventoryService.ts";
 | 
				
			||||||
import { RequestHandler } from "express";
 | 
					import type { RequestHandler } from "express";
 | 
				
			||||||
import { getJSONfromString } from "@/src/helpers/stringHelpers";
 | 
					import { getJSONfromString } from "../../helpers/stringHelpers.ts";
 | 
				
			||||||
import { IGenericUpdate } from "@/src/types/genericUpdate";
 | 
					import type { IGenericUpdate } from "../../types/genericUpdate.ts";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// This endpoint used to be /api/genericUpdate.php, but sometime around the Jade Shadows update, it was changed to /api/updateNodeIntros.php.
 | 
					// This endpoint used to be /api/genericUpdate.php, but sometime around the Jade Shadows update, it was changed to /api/updateNodeIntros.php.
 | 
				
			||||||
// SpaceNinjaServer supports both endpoints right now.
 | 
					// SpaceNinjaServer supports both endpoints right now.
 | 
				
			||||||
 | 
				
			|||||||
@ -1,8 +1,8 @@
 | 
				
			|||||||
import { Alliance, Guild } from "@/src/models/guildModel";
 | 
					import { Alliance, Guild } from "../../models/guildModel.ts";
 | 
				
			||||||
import { getAllianceClient } from "@/src/services/guildService";
 | 
					import { getAllianceClient } from "../../services/guildService.ts";
 | 
				
			||||||
import { getInventory } from "@/src/services/inventoryService";
 | 
					import { getInventory } from "../../services/inventoryService.ts";
 | 
				
			||||||
import { getAccountIdForRequest } from "@/src/services/loginService";
 | 
					import { getAccountIdForRequest } from "../../services/loginService.ts";
 | 
				
			||||||
import { RequestHandler } from "express";
 | 
					import type { RequestHandler } from "express";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export const getAllianceController: RequestHandler = async (req, res) => {
 | 
					export const getAllianceController: RequestHandler = async (req, res) => {
 | 
				
			||||||
    const accountId = await getAccountIdForRequest(req);
 | 
					    const accountId = await getAccountIdForRequest(req);
 | 
				
			||||||
 | 
				
			|||||||
@ -1,5 +1,5 @@
 | 
				
			|||||||
import { DailyDeal } from "@/src/models/worldStateModel";
 | 
					import { DailyDeal } from "../../models/worldStateModel.ts";
 | 
				
			||||||
import { RequestHandler } from "express";
 | 
					import type { RequestHandler } from "express";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export const getDailyDealStockLevelsController: RequestHandler = async (req, res) => {
 | 
					export const getDailyDealStockLevelsController: RequestHandler = async (req, res) => {
 | 
				
			||||||
    const dailyDeal = (await DailyDeal.findOne({ StoreItem: req.query.productName }, "AmountSold"))!;
 | 
					    const dailyDeal = (await DailyDeal.findOne({ StoreItem: req.query.productName }, "AmountSold"))!;
 | 
				
			||||||
 | 
				
			|||||||
@ -1,9 +1,9 @@
 | 
				
			|||||||
import { toOid } from "@/src/helpers/inventoryHelpers";
 | 
					import { toOid } from "../../helpers/inventoryHelpers.ts";
 | 
				
			||||||
import { Friendship } from "@/src/models/friendModel";
 | 
					import { Friendship } from "../../models/friendModel.ts";
 | 
				
			||||||
import { addAccountDataToFriendInfo, addInventoryDataToFriendInfo } from "@/src/services/friendService";
 | 
					import { addAccountDataToFriendInfo, addInventoryDataToFriendInfo } from "../../services/friendService.ts";
 | 
				
			||||||
import { getAccountIdForRequest } from "@/src/services/loginService";
 | 
					import { getAccountIdForRequest } from "../../services/loginService.ts";
 | 
				
			||||||
import { IFriendInfo } from "@/src/types/friendTypes";
 | 
					import type { IFriendInfo } from "../../types/friendTypes.ts";
 | 
				
			||||||
import { Request, RequestHandler, Response } from "express";
 | 
					import type { Request, RequestHandler, Response } from "express";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// POST with {} instead of GET as of 38.5.0
 | 
					// POST with {} instead of GET as of 38.5.0
 | 
				
			||||||
export const getFriendsController: RequestHandler = async (req: Request, res: Response) => {
 | 
					export const getFriendsController: RequestHandler = async (req: Request, res: Response) => {
 | 
				
			||||||
 | 
				
			|||||||
@ -1,8 +1,8 @@
 | 
				
			|||||||
import { GuildMember } from "@/src/models/guildModel";
 | 
					import { GuildMember } from "../../models/guildModel.ts";
 | 
				
			||||||
import { getInventory } from "@/src/services/inventoryService";
 | 
					import { getInventory } from "../../services/inventoryService.ts";
 | 
				
			||||||
import { getAccountIdForRequest } from "@/src/services/loginService";
 | 
					import { getAccountIdForRequest } from "../../services/loginService.ts";
 | 
				
			||||||
import { IGuildMemberClient } from "@/src/types/guildTypes";
 | 
					import type { IGuildMemberClient } from "../../types/guildTypes.ts";
 | 
				
			||||||
import { RequestHandler } from "express";
 | 
					import type { RequestHandler } from "express";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export const getGuildContributionsController: RequestHandler = async (req, res) => {
 | 
					export const getGuildContributionsController: RequestHandler = async (req, res) => {
 | 
				
			||||||
    const accountId = await getAccountIdForRequest(req);
 | 
					    const accountId = await getAccountIdForRequest(req);
 | 
				
			||||||
 | 
				
			|||||||
@ -1,9 +1,9 @@
 | 
				
			|||||||
import { RequestHandler } from "express";
 | 
					import type { RequestHandler } from "express";
 | 
				
			||||||
import { Guild } from "@/src/models/guildModel";
 | 
					import { Guild } from "../../models/guildModel.ts";
 | 
				
			||||||
import { getAccountForRequest } from "@/src/services/loginService";
 | 
					import { getAccountForRequest } from "../../services/loginService.ts";
 | 
				
			||||||
import { logger } from "@/src/utils/logger";
 | 
					import { logger } from "../../utils/logger.ts";
 | 
				
			||||||
import { getInventory } from "@/src/services/inventoryService";
 | 
					import { getInventory } from "../../services/inventoryService.ts";
 | 
				
			||||||
import { createUniqueClanName, getGuildClient } from "@/src/services/guildService";
 | 
					import { createUniqueClanName, getGuildClient } from "../../services/guildService.ts";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export const getGuildController: RequestHandler = async (req, res) => {
 | 
					export const getGuildController: RequestHandler = async (req, res) => {
 | 
				
			||||||
    const account = await getAccountForRequest(req);
 | 
					    const account = await getAccountForRequest(req);
 | 
				
			||||||
 | 
				
			|||||||
@ -1,8 +1,8 @@
 | 
				
			|||||||
import { RequestHandler } from "express";
 | 
					import type { RequestHandler } from "express";
 | 
				
			||||||
import { Types } from "mongoose";
 | 
					import { Types } from "mongoose";
 | 
				
			||||||
import { Guild } from "@/src/models/guildModel";
 | 
					import { Guild } from "../../models/guildModel.ts";
 | 
				
			||||||
import { getDojoClient } from "@/src/services/guildService";
 | 
					import { getDojoClient } from "../../services/guildService.ts";
 | 
				
			||||||
import { Account } from "@/src/models/loginModel";
 | 
					import { Account } from "../../models/loginModel.ts";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export const getGuildDojoController: RequestHandler = async (req, res) => {
 | 
					export const getGuildDojoController: RequestHandler = async (req, res) => {
 | 
				
			||||||
    const guildId = req.query.guildId as string;
 | 
					    const guildId = req.query.guildId as string;
 | 
				
			||||||
@ -19,7 +19,7 @@ export const getGuildDojoController: RequestHandler = async (req, res) => {
 | 
				
			|||||||
            _id: new Types.ObjectId(),
 | 
					            _id: new Types.ObjectId(),
 | 
				
			||||||
            pf: "/Lotus/Levels/ClanDojo/DojoHall.level",
 | 
					            pf: "/Lotus/Levels/ClanDojo/DojoHall.level",
 | 
				
			||||||
            ppf: "",
 | 
					            ppf: "",
 | 
				
			||||||
            CompletionTime: new Date(Date.now()),
 | 
					            CompletionTime: new Date(Date.now() - 1000),
 | 
				
			||||||
            DecoCapacity: 600
 | 
					            DecoCapacity: 600
 | 
				
			||||||
        });
 | 
					        });
 | 
				
			||||||
        await guild.save();
 | 
					        await guild.save();
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										26
									
								
								src/controllers/api/getGuildEventScoreController.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										26
									
								
								src/controllers/api/getGuildEventScoreController.ts
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,26 @@
 | 
				
			|||||||
 | 
					import type { RequestHandler } from "express";
 | 
				
			||||||
 | 
					import { getAccountForRequest } from "../../services/loginService.ts";
 | 
				
			||||||
 | 
					import { getInventory } from "../../services/inventoryService.ts";
 | 
				
			||||||
 | 
					import { Guild } from "../../models/guildModel.ts";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export const getGuildEventScoreController: RequestHandler = async (req, res) => {
 | 
				
			||||||
 | 
					    const account = await getAccountForRequest(req);
 | 
				
			||||||
 | 
					    const inventory = await getInventory(account._id.toString(), "GuildId");
 | 
				
			||||||
 | 
					    const guild = await Guild.findById(inventory.GuildId);
 | 
				
			||||||
 | 
					    const goalId = req.query.goalId as string;
 | 
				
			||||||
 | 
					    if (guild && guild.GoalProgress && goalId) {
 | 
				
			||||||
 | 
					        const goal = guild.GoalProgress.find(x => x.goalId.toString() == goalId);
 | 
				
			||||||
 | 
					        if (goal) {
 | 
				
			||||||
 | 
					            res.json({
 | 
				
			||||||
 | 
					                Tier: guild.Tier,
 | 
				
			||||||
 | 
					                GoalProgress: {
 | 
				
			||||||
 | 
					                    Count: goal.Count,
 | 
				
			||||||
 | 
					                    Tag: goal.Tag,
 | 
				
			||||||
 | 
					                    _id: { $oid: goal.goalId }
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            });
 | 
				
			||||||
 | 
					            return;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    res.json({});
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
@ -1,9 +1,9 @@
 | 
				
			|||||||
import { toMongoDate } from "@/src/helpers/inventoryHelpers";
 | 
					import { toMongoDate } from "../../helpers/inventoryHelpers.ts";
 | 
				
			||||||
import { Guild } from "@/src/models/guildModel";
 | 
					import { Guild } from "../../models/guildModel.ts";
 | 
				
			||||||
import { getInventory } from "@/src/services/inventoryService";
 | 
					import { getInventory } from "../../services/inventoryService.ts";
 | 
				
			||||||
import { getAccountIdForRequest } from "@/src/services/loginService";
 | 
					import { getAccountIdForRequest } from "../../services/loginService.ts";
 | 
				
			||||||
import { IMongoDate } from "@/src/types/commonTypes";
 | 
					import type { IMongoDate } from "../../types/commonTypes.ts";
 | 
				
			||||||
import { RequestHandler } from "express";
 | 
					import type { RequestHandler } from "express";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export const getGuildLogController: RequestHandler = async (req, res) => {
 | 
					export const getGuildLogController: RequestHandler = async (req, res) => {
 | 
				
			||||||
    const accountId = await getAccountIdForRequest(req);
 | 
					    const accountId = await getAccountIdForRequest(req);
 | 
				
			||||||
 | 
				
			|||||||
@ -1,9 +1,9 @@
 | 
				
			|||||||
import { toOid } from "@/src/helpers/inventoryHelpers";
 | 
					import { toOid } from "../../helpers/inventoryHelpers.ts";
 | 
				
			||||||
import { Account, Ignore } from "@/src/models/loginModel";
 | 
					import { Account, Ignore } from "../../models/loginModel.ts";
 | 
				
			||||||
import { getAccountIdForRequest } from "@/src/services/loginService";
 | 
					import { getAccountIdForRequest } from "../../services/loginService.ts";
 | 
				
			||||||
import { IFriendInfo } from "@/src/types/friendTypes";
 | 
					import type { IFriendInfo } from "../../types/friendTypes.ts";
 | 
				
			||||||
import { parallelForeach } from "@/src/utils/async-utils";
 | 
					import { parallelForeach } from "../../utils/async-utils.ts";
 | 
				
			||||||
import { RequestHandler } from "express";
 | 
					import type { RequestHandler } from "express";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export const getIgnoredUsersController: RequestHandler = async (req, res) => {
 | 
					export const getIgnoredUsersController: RequestHandler = async (req, res) => {
 | 
				
			||||||
    const accountId = await getAccountIdForRequest(req);
 | 
					    const accountId = await getAccountIdForRequest(req);
 | 
				
			||||||
 | 
				
			|||||||
@ -1,7 +1,7 @@
 | 
				
			|||||||
import { Inventory } from "@/src/models/inventoryModels/inventoryModel";
 | 
					import { Inventory } from "../../models/inventoryModels/inventoryModel.ts";
 | 
				
			||||||
import { getAccountIdForRequest } from "@/src/services/loginService";
 | 
					import { getAccountIdForRequest } from "../../services/loginService.ts";
 | 
				
			||||||
import { generateRewardSeed } from "@/src/services/rngService";
 | 
					import { generateRewardSeed } from "../../services/rngService.ts";
 | 
				
			||||||
import { RequestHandler } from "express";
 | 
					import type { RequestHandler } from "express";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export const getNewRewardSeedController: RequestHandler = async (req, res) => {
 | 
					export const getNewRewardSeedController: RequestHandler = async (req, res) => {
 | 
				
			||||||
    const accountId = await getAccountIdForRequest(req);
 | 
					    const accountId = await getAccountIdForRequest(req);
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										62
									
								
								src/controllers/api/getPastWeeklyChallengesController.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										62
									
								
								src/controllers/api/getPastWeeklyChallengesController.ts
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,62 @@
 | 
				
			|||||||
 | 
					import type { RequestHandler } from "express";
 | 
				
			||||||
 | 
					import { getAccountIdForRequest } from "../../services/loginService.ts";
 | 
				
			||||||
 | 
					import { getInventory } from "../../services/inventoryService.ts";
 | 
				
			||||||
 | 
					import { getSeasonChallengePools, getWorldState, pushWeeklyActs } from "../../services/worldStateService.ts";
 | 
				
			||||||
 | 
					import { EPOCH, unixTimesInMs } from "../../constants/timeConstants.ts";
 | 
				
			||||||
 | 
					import type { ISeasonChallenge } from "../../types/worldStateTypes.ts";
 | 
				
			||||||
 | 
					import { ExportChallenges } from "warframe-public-export-plus";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export const getPastWeeklyChallengesController: RequestHandler = async (req, res) => {
 | 
				
			||||||
 | 
					    const accountId = await getAccountIdForRequest(req);
 | 
				
			||||||
 | 
					    const inventory = await getInventory(accountId, "SeasonChallengeHistory ChallengeProgress");
 | 
				
			||||||
 | 
					    const worldState = getWorldState(undefined);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (worldState.SeasonInfo) {
 | 
				
			||||||
 | 
					        const pools = getSeasonChallengePools(worldState.SeasonInfo.AffiliationTag);
 | 
				
			||||||
 | 
					        const nightwaveStartTimestamp = Number(worldState.SeasonInfo.Activation.$date.$numberLong);
 | 
				
			||||||
 | 
					        const nightwaveSeason = worldState.SeasonInfo.Season;
 | 
				
			||||||
 | 
					        const timeMs = worldState.Time * 1000;
 | 
				
			||||||
 | 
					        const completedChallengesIds = new Set<string>();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        inventory.SeasonChallengeHistory.forEach(challengeHistory => {
 | 
				
			||||||
 | 
					            const entryNightwaveSeason = parseInt(challengeHistory.id.slice(0, 4), 10) - 1;
 | 
				
			||||||
 | 
					            if (nightwaveSeason == entryNightwaveSeason) {
 | 
				
			||||||
 | 
					                const meta = Object.entries(ExportChallenges).find(
 | 
				
			||||||
 | 
					                    ([key]) => key.split("/").pop() === challengeHistory.challenge
 | 
				
			||||||
 | 
					                );
 | 
				
			||||||
 | 
					                if (meta) {
 | 
				
			||||||
 | 
					                    const [, challengeMeta] = meta;
 | 
				
			||||||
 | 
					                    const challengeProgress = inventory.ChallengeProgress.find(
 | 
				
			||||||
 | 
					                        c => c.Name === challengeHistory.challenge
 | 
				
			||||||
 | 
					                    );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    if (challengeProgress && challengeProgress.Progress >= (challengeMeta.requiredCount ?? 1)) {
 | 
				
			||||||
 | 
					                        completedChallengesIds.add(challengeHistory.id);
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        const PastWeeklyChallenges: ISeasonChallenge[] = [];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        let week = Math.trunc((timeMs - EPOCH) / unixTimesInMs.week) - 1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        while (EPOCH + week * unixTimesInMs.week >= nightwaveStartTimestamp && PastWeeklyChallenges.length < 3) {
 | 
				
			||||||
 | 
					            const tempActs: ISeasonChallenge[] = [];
 | 
				
			||||||
 | 
					            pushWeeklyActs(tempActs, pools, week, nightwaveStartTimestamp, nightwaveSeason);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            for (const act of tempActs) {
 | 
				
			||||||
 | 
					                if (!completedChallengesIds.has(act._id.$oid) && PastWeeklyChallenges.length < 3) {
 | 
				
			||||||
 | 
					                    if (act.Challenge.startsWith("/Lotus/Types/Challenges/Seasons/Weekly/SeasonWeeklyPermanent")) {
 | 
				
			||||||
 | 
					                        act.Permanent = true;
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                    PastWeeklyChallenges.push(act);
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            week--;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        res.json({ PastWeeklyChallenges: PastWeeklyChallenges });
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
@ -1,11 +1,9 @@
 | 
				
			|||||||
import { RequestHandler } from "express";
 | 
					import type { RequestHandler } from "express";
 | 
				
			||||||
import { config } from "@/src/services/configService";
 | 
					import { getAccountIdForRequest } from "../../services/loginService.ts";
 | 
				
			||||||
import allShipFeatures from "@/static/fixed_responses/allShipFeatures.json";
 | 
					import { createGarden, getPersonalRooms } from "../../services/personalRoomsService.ts";
 | 
				
			||||||
import { getAccountIdForRequest } from "@/src/services/loginService";
 | 
					import type { IGetShipResponse, IPersonalRoomsClient } from "../../types/personalRoomsTypes.ts";
 | 
				
			||||||
import { createGarden, getPersonalRooms } from "@/src/services/personalRoomsService";
 | 
					import { getLoadout } from "../../services/loadoutService.ts";
 | 
				
			||||||
import { IGetShipResponse, IPersonalRoomsClient } from "@/src/types/personalRoomsTypes";
 | 
					import { toOid } from "../../helpers/inventoryHelpers.ts";
 | 
				
			||||||
import { getLoadout } from "@/src/services/loadoutService";
 | 
					 | 
				
			||||||
import { toOid } from "@/src/helpers/inventoryHelpers";
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
export const getShipController: RequestHandler = async (req, res) => {
 | 
					export const getShipController: RequestHandler = async (req, res) => {
 | 
				
			||||||
    const accountId = await getAccountIdForRequest(req);
 | 
					    const accountId = await getAccountIdForRequest(req);
 | 
				
			||||||
@ -31,9 +29,5 @@ export const getShipController: RequestHandler = async (req, res) => {
 | 
				
			|||||||
        TailorShop: personalRooms.TailorShop
 | 
					        TailorShop: personalRooms.TailorShop
 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (config.unlockAllShipFeatures) {
 | 
					 | 
				
			||||||
        getShipResponse.Ship.Features = allShipFeatures;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    res.json(getShipResponse);
 | 
					    res.json(getShipResponse);
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
				
			|||||||
@ -1,8 +1,8 @@
 | 
				
			|||||||
import { RequestHandler } from "express";
 | 
					import type { RequestHandler } from "express";
 | 
				
			||||||
import { applyStandingToVendorManifest, getVendorManifestByTypeName } from "@/src/services/serversideVendorsService";
 | 
					import { applyStandingToVendorManifest, getVendorManifestByTypeName } from "../../services/serversideVendorsService.ts";
 | 
				
			||||||
import { getInventory } from "@/src/services/inventoryService";
 | 
					import { getInventory } from "../../services/inventoryService.ts";
 | 
				
			||||||
import { getAccountIdForRequest } from "@/src/services/loginService";
 | 
					import { getAccountIdForRequest } from "../../services/loginService.ts";
 | 
				
			||||||
import { config } from "@/src/services/configService";
 | 
					import { config } from "../../services/configService.ts";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export const getVendorInfoController: RequestHandler = async (req, res) => {
 | 
					export const getVendorInfoController: RequestHandler = async (req, res) => {
 | 
				
			||||||
    let manifest = getVendorManifestByTypeName(req.query.vendor as string);
 | 
					    let manifest = getVendorManifestByTypeName(req.query.vendor as string);
 | 
				
			||||||
 | 
				
			|||||||
@ -1,9 +1,9 @@
 | 
				
			|||||||
import { getJSONfromString } from "@/src/helpers/stringHelpers";
 | 
					import { getJSONfromString } from "../../helpers/stringHelpers.ts";
 | 
				
			||||||
import { crackRelic } from "@/src/helpers/relicHelper";
 | 
					import { crackRelic } from "../../helpers/relicHelper.ts";
 | 
				
			||||||
import { getInventory } from "@/src/services/inventoryService";
 | 
					import { getInventory } from "../../services/inventoryService.ts";
 | 
				
			||||||
import { getAccountIdForRequest } from "@/src/services/loginService";
 | 
					import { getAccountIdForRequest } from "../../services/loginService.ts";
 | 
				
			||||||
import { IVoidTearParticipantInfo } from "@/src/types/requestTypes";
 | 
					import type { IVoidTearParticipantInfo } from "../../types/requestTypes.ts";
 | 
				
			||||||
import { RequestHandler } from "express";
 | 
					import type { RequestHandler } from "express";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export const getVoidProjectionRewardsController: RequestHandler = async (req, res) => {
 | 
					export const getVoidProjectionRewardsController: RequestHandler = async (req, res) => {
 | 
				
			||||||
    const accountId = await getAccountIdForRequest(req);
 | 
					    const accountId = await getAccountIdForRequest(req);
 | 
				
			||||||
@ -11,7 +11,11 @@ export const getVoidProjectionRewardsController: RequestHandler = async (req, re
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    if (data.ParticipantInfo.QualifiesForReward && !data.ParticipantInfo.HaveRewardResponse) {
 | 
					    if (data.ParticipantInfo.QualifiesForReward && !data.ParticipantInfo.HaveRewardResponse) {
 | 
				
			||||||
        const inventory = await getInventory(accountId);
 | 
					        const inventory = await getInventory(accountId);
 | 
				
			||||||
        await crackRelic(inventory, data.ParticipantInfo);
 | 
					        const reward = await crackRelic(inventory, data.ParticipantInfo);
 | 
				
			||||||
 | 
					        if (!inventory.MissionRelicRewards || inventory.MissionRelicRewards.length >= data.CurrentWave) {
 | 
				
			||||||
 | 
					            inventory.MissionRelicRewards = [];
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        inventory.MissionRelicRewards.push({ ItemType: reward.type, ItemCount: reward.itemCount });
 | 
				
			||||||
        await inventory.save();
 | 
					        await inventory.save();
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -1,18 +1,19 @@
 | 
				
			|||||||
import { getJSONfromString } from "@/src/helpers/stringHelpers";
 | 
					import { getJSONfromString } from "../../helpers/stringHelpers.ts";
 | 
				
			||||||
import { Account } from "@/src/models/loginModel";
 | 
					import { Account } from "../../models/loginModel.ts";
 | 
				
			||||||
import { areFriends } from "@/src/services/friendService";
 | 
					import { areFriends } from "../../services/friendService.ts";
 | 
				
			||||||
import { createMessage } from "@/src/services/inboxService";
 | 
					import { createMessage } from "../../services/inboxService.ts";
 | 
				
			||||||
import {
 | 
					import {
 | 
				
			||||||
    combineInventoryChanges,
 | 
					    combineInventoryChanges,
 | 
				
			||||||
    getEffectiveAvatarImageType,
 | 
					    getEffectiveAvatarImageType,
 | 
				
			||||||
    getInventory,
 | 
					    getInventory,
 | 
				
			||||||
    updateCurrency
 | 
					    updateCurrency
 | 
				
			||||||
} from "@/src/services/inventoryService";
 | 
					} from "../../services/inventoryService.ts";
 | 
				
			||||||
import { getAccountForRequest, getSuffixedName } from "@/src/services/loginService";
 | 
					import { getAccountForRequest, getSuffixedName } from "../../services/loginService.ts";
 | 
				
			||||||
import { handleDailyDealPurchase, handleStoreItemAcquisition } from "@/src/services/purchaseService";
 | 
					import { handleDailyDealPurchase, handleStoreItemAcquisition } from "../../services/purchaseService.ts";
 | 
				
			||||||
import { IOid } from "@/src/types/commonTypes";
 | 
					import type { IOid } from "../../types/commonTypes.ts";
 | 
				
			||||||
import { IPurchaseParams, IPurchaseResponse, PurchaseSource } from "@/src/types/purchaseTypes";
 | 
					import type { IPurchaseParams, IPurchaseResponse } from "../../types/purchaseTypes.ts";
 | 
				
			||||||
import { RequestHandler } from "express";
 | 
					import { PurchaseSource } from "../../types/purchaseTypes.ts";
 | 
				
			||||||
 | 
					import type { RequestHandler } from "express";
 | 
				
			||||||
import { ExportBundles, ExportFlavour } from "warframe-public-export-plus";
 | 
					import { ExportBundles, ExportFlavour } from "warframe-public-export-plus";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const checkPurchaseParams = (params: IPurchaseParams): boolean => {
 | 
					const checkPurchaseParams = (params: IPurchaseParams): boolean => {
 | 
				
			||||||
 | 
				
			|||||||
@ -1,13 +1,14 @@
 | 
				
			|||||||
import { RequestHandler } from "express";
 | 
					import type { RequestHandler } from "express";
 | 
				
			||||||
import { getAccountIdForRequest } from "@/src/services/loginService";
 | 
					import { getAccountIdForRequest } from "../../services/loginService.ts";
 | 
				
			||||||
import { sendWsBroadcastTo } from "@/src/services/wsService";
 | 
					import { broadcastInventoryUpdate } from "../../services/wsService.ts";
 | 
				
			||||||
import { getJSONfromString } from "@/src/helpers/stringHelpers";
 | 
					import { getJSONfromString } from "../../helpers/stringHelpers.ts";
 | 
				
			||||||
import { addMiscItems, getInventory } from "@/src/services/inventoryService";
 | 
					import { addMiscItems, getInventory } from "../../services/inventoryService.ts";
 | 
				
			||||||
import { TEquipmentKey } from "@/src/types/inventoryTypes/inventoryTypes";
 | 
					import type { TEquipmentKey } from "../../types/inventoryTypes/inventoryTypes.ts";
 | 
				
			||||||
import { ArtifactPolarity } from "@/src/types/inventoryTypes/commonInventoryTypes";
 | 
					import type { ArtifactPolarity } from "../../types/inventoryTypes/commonInventoryTypes.ts";
 | 
				
			||||||
import { ExportRecipes } from "warframe-public-export-plus";
 | 
					import { ExportRecipes } from "warframe-public-export-plus";
 | 
				
			||||||
import { IInventoryChanges } from "@/src/types/purchaseTypes";
 | 
					import type { IInventoryChanges } from "../../types/purchaseTypes.ts";
 | 
				
			||||||
import { EquipmentFeatures, IEquipmentClient } from "@/src/types/equipmentTypes";
 | 
					import type { IEquipmentClient } from "../../types/equipmentTypes.ts";
 | 
				
			||||||
 | 
					import { EquipmentFeatures } from "../../types/equipmentTypes.ts";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
interface IGildWeaponRequest {
 | 
					interface IGildWeaponRequest {
 | 
				
			||||||
    ItemName: string;
 | 
					    ItemName: string;
 | 
				
			||||||
@ -74,5 +75,5 @@ export const gildWeaponController: RequestHandler = async (req, res) => {
 | 
				
			|||||||
        InventoryChanges: inventoryChanges,
 | 
					        InventoryChanges: inventoryChanges,
 | 
				
			||||||
        AffiliationMods: affiliationMods
 | 
					        AffiliationMods: affiliationMods
 | 
				
			||||||
    });
 | 
					    });
 | 
				
			||||||
    sendWsBroadcastTo(accountId, { update_inventory: true });
 | 
					    broadcastInventoryUpdate(req);
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
				
			|||||||
@ -1,16 +1,17 @@
 | 
				
			|||||||
import { RequestHandler } from "express";
 | 
					import type { RequestHandler } from "express";
 | 
				
			||||||
import { parseString } from "@/src/helpers/general";
 | 
					import { getJSONfromString } from "../../helpers/stringHelpers.ts";
 | 
				
			||||||
import { getJSONfromString } from "@/src/helpers/stringHelpers";
 | 
					import { getInventory } from "../../services/inventoryService.ts";
 | 
				
			||||||
import { getInventory } from "@/src/services/inventoryService";
 | 
					import { giveKeyChainItem } from "../../services/questService.ts";
 | 
				
			||||||
import { giveKeyChainItem } from "@/src/services/questService";
 | 
					import type { IKeyChainRequest } from "../../types/requestTypes.ts";
 | 
				
			||||||
import { IKeyChainRequest } from "@/src/types/requestTypes";
 | 
					import { getAccountIdForRequest } from "../../services/loginService.ts";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export const giveKeyChainTriggeredItemsController: RequestHandler = async (req, res) => {
 | 
					export const giveKeyChainTriggeredItemsController: RequestHandler = async (req, res) => {
 | 
				
			||||||
    const accountId = parseString(req.query.accountId);
 | 
					    const accountId = await getAccountIdForRequest(req);
 | 
				
			||||||
    const keyChainInfo = getJSONfromString<IKeyChainRequest>((req.body as string).toString());
 | 
					    const keyChainInfo = getJSONfromString<IKeyChainRequest>((req.body as string).toString());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    const inventory = await getInventory(accountId);
 | 
					    const inventory = await getInventory(accountId);
 | 
				
			||||||
    const inventoryChanges = await giveKeyChainItem(inventory, keyChainInfo);
 | 
					    const questKey = inventory.QuestKeys.find(qk => qk.ItemType === keyChainInfo.KeyChain)!;
 | 
				
			||||||
 | 
					    const inventoryChanges = await giveKeyChainItem(inventory, keyChainInfo, questKey);
 | 
				
			||||||
    await inventory.save();
 | 
					    await inventory.save();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    res.send(inventoryChanges);
 | 
					    res.send(inventoryChanges);
 | 
				
			||||||
 | 
				
			|||||||
Some files were not shown because too many files have changed in this diff Show More
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user