diff --git a/.github/workflows/dispatch_sdk_update.yml b/.github/workflows/dispatch_sdk_update.yml deleted file mode 100644 index 4f1abb5c4..000000000 --- a/.github/workflows/dispatch_sdk_update.yml +++ /dev/null @@ -1,26 +0,0 @@ -name: Update Immich SDK - -on: - workflow_dispatch: - push: - branches: ["main"] - -concurrency: - group: ${{ github.workflow }}-${{ github.ref }} - cancel-in-progress: true - -jobs: - update-sdk-repos: - runs-on: ubuntu-latest - if: ${{ !github.event.pull_request.head.repo.fork }} - steps: - - uses: actions/github-script@v7 - with: - github-token: ${{ secrets.GH_TOKEN }} - script: | - await github.rest.actions.createWorkflowDispatch({ - owner: 'immich-app', - repo: 'immich-sdk-typescript-axios', - workflow_id: 'build.yml', - ref: 'main' - }) diff --git a/.github/workflows/prepare-release.yml b/.github/workflows/prepare-release.yml index b98c1563a..000dbe2dd 100644 --- a/.github/workflows/prepare-release.yml +++ b/.github/workflows/prepare-release.yml @@ -74,7 +74,7 @@ jobs: name: release-apk-signed - name: Create draft release - uses: softprops/action-gh-release@v1 + uses: softprops/action-gh-release@v2 with: draft: true tag_name: ${{ env.IMMICH_VERSION }} diff --git a/.github/workflows/sdk.yml b/.github/workflows/sdk.yml new file mode 100644 index 000000000..cd3dbe2b1 --- /dev/null +++ b/.github/workflows/sdk.yml @@ -0,0 +1,31 @@ +name: Update Immich SDK + +on: + release: + types: [published] + +permissions: + packages: write + +jobs: + publish: + name: Publish `@immich/sdk` + runs-on: ubuntu-latest + defaults: + run: + working-directory: ./open-api/typescript-sdk + steps: + - uses: actions/checkout@v4 + # Setup .npmrc file to publish to npm + - uses: actions/setup-node@v4 + with: + node-version: '20.x' + registry-url: 'https://registry.npmjs.org' + - name: Install deps + run: npm ci + - name: Build + run: npm run build + - name: Publish + run: npm publish + env: + NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} diff --git a/cli/package-lock.json b/cli/package-lock.json index 38fe3c6f1..82e920bd9 100644 --- a/cli/package-lock.json +++ b/cli/package-lock.json @@ -1,12 +1,12 @@ { "name": "@immich/cli", - "version": "2.0.8", + "version": "2.1.0", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "@immich/cli", - "version": "2.0.8", + "version": "2.1.0", "license": "GNU Affero General Public License version 3", "dependencies": { "lodash-es": "^4.17.21" @@ -49,8 +49,10 @@ "version": "1.98.2", "dev": true, "license": "GNU Affero General Public License version 3", + "dependencies": { + "@oazapfts/runtime": "^1.0.2" + }, "devDependencies": { - "@oazapfts/runtime": "^1.0.0", "@types/node": "^20.11.0", "typescript": "^5.3.3" } @@ -1281,9 +1283,9 @@ } }, "node_modules/@types/node": { - "version": "20.11.24", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.11.24.tgz", - "integrity": "sha512-Kza43ewS3xoLgCEpQrsT+xRo/EJej1y0kVYGiLFE1NEODXGzTfwiC6tXTLMQskn1X4/Rjlh0MQUvx9W+L9long==", + "version": "20.11.25", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.11.25.tgz", + "integrity": "sha512-TBHyJxk2b7HceLVGFcpAUjsa5zIdsPWlR6XHfyGzd0SFu+/NFgQgMAl96MSDZgQDvJAvV6BKsFOrt6zIL09JDw==", "dev": true, "dependencies": { "undici-types": "~5.26.4" @@ -1302,16 +1304,16 @@ "dev": true }, "node_modules/@typescript-eslint/eslint-plugin": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.1.0.tgz", - "integrity": "sha512-j6vT/kCulhG5wBmGtstKeiVr1rdXE4nk+DT1k6trYkwlrvW9eOF5ZbgKnd/YR6PcM4uTEXa0h6Fcvf6X7Dxl0w==", + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.1.1.tgz", + "integrity": "sha512-zioDz623d0RHNhvx0eesUmGfIjzrk18nSBC8xewepKXbBvN/7c1qImV7Hg8TI1URTxKax7/zxfxj3Uph8Chcuw==", "dev": true, "dependencies": { "@eslint-community/regexpp": "^4.5.1", - "@typescript-eslint/scope-manager": "7.1.0", - "@typescript-eslint/type-utils": "7.1.0", - "@typescript-eslint/utils": "7.1.0", - "@typescript-eslint/visitor-keys": "7.1.0", + "@typescript-eslint/scope-manager": "7.1.1", + "@typescript-eslint/type-utils": "7.1.1", + "@typescript-eslint/utils": "7.1.1", + "@typescript-eslint/visitor-keys": "7.1.1", "debug": "^4.3.4", "graphemer": "^1.4.0", "ignore": "^5.2.4", @@ -1337,15 +1339,15 @@ } }, "node_modules/@typescript-eslint/parser": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-7.1.0.tgz", - "integrity": "sha512-V1EknKUubZ1gWFjiOZhDSNToOjs63/9O0puCgGS8aDOgpZY326fzFu15QAUjwaXzRZjf/qdsdBrckYdv9YxB8w==", + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-7.1.1.tgz", + "integrity": "sha512-ZWUFyL0z04R1nAEgr9e79YtV5LbafdOtN7yapNbn1ansMyaegl2D4bL7vHoJ4HPSc4CaLwuCVas8CVuneKzplQ==", "dev": true, "dependencies": { - "@typescript-eslint/scope-manager": "7.1.0", - "@typescript-eslint/types": "7.1.0", - "@typescript-eslint/typescript-estree": "7.1.0", - "@typescript-eslint/visitor-keys": "7.1.0", + "@typescript-eslint/scope-manager": "7.1.1", + "@typescript-eslint/types": "7.1.1", + "@typescript-eslint/typescript-estree": "7.1.1", + "@typescript-eslint/visitor-keys": "7.1.1", "debug": "^4.3.4" }, "engines": { @@ -1365,13 +1367,13 @@ } }, "node_modules/@typescript-eslint/scope-manager": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.1.0.tgz", - "integrity": "sha512-6TmN4OJiohHfoOdGZ3huuLhpiUgOGTpgXNUPJgeZOZR3DnIpdSgtt83RS35OYNNXxM4TScVlpVKC9jyQSETR1A==", + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.1.1.tgz", + "integrity": "sha512-cirZpA8bJMRb4WZ+rO6+mnOJrGFDd38WoXCEI57+CYBqta8Yc8aJym2i7vyqLL1vVYljgw0X27axkUXz32T8TA==", "dev": true, "dependencies": { - "@typescript-eslint/types": "7.1.0", - "@typescript-eslint/visitor-keys": "7.1.0" + "@typescript-eslint/types": "7.1.1", + "@typescript-eslint/visitor-keys": "7.1.1" }, "engines": { "node": "^16.0.0 || >=18.0.0" @@ -1382,13 +1384,13 @@ } }, "node_modules/@typescript-eslint/type-utils": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-7.1.0.tgz", - "integrity": "sha512-UZIhv8G+5b5skkcuhgvxYWHjk7FW7/JP5lPASMEUoliAPwIH/rxoUSQPia2cuOj9AmDZmwUl1usKm85t5VUMew==", + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-7.1.1.tgz", + "integrity": "sha512-5r4RKze6XHEEhlZnJtR3GYeCh1IueUHdbrukV2KSlLXaTjuSfeVF8mZUVPLovidCuZfbVjfhi4c0DNSa/Rdg5g==", "dev": true, "dependencies": { - "@typescript-eslint/typescript-estree": "7.1.0", - "@typescript-eslint/utils": "7.1.0", + "@typescript-eslint/typescript-estree": "7.1.1", + "@typescript-eslint/utils": "7.1.1", "debug": "^4.3.4", "ts-api-utils": "^1.0.1" }, @@ -1409,9 +1411,9 @@ } }, "node_modules/@typescript-eslint/types": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.1.0.tgz", - "integrity": "sha512-qTWjWieJ1tRJkxgZYXx6WUYtWlBc48YRxgY2JN1aGeVpkhmnopq+SUC8UEVGNXIvWH7XyuTjwALfG6bFEgCkQA==", + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.1.1.tgz", + "integrity": "sha512-KhewzrlRMrgeKm1U9bh2z5aoL4s7K3tK5DwHDn8MHv0yQfWFz/0ZR6trrIHHa5CsF83j/GgHqzdbzCXJ3crx0Q==", "dev": true, "engines": { "node": "^16.0.0 || >=18.0.0" @@ -1422,13 +1424,13 @@ } }, "node_modules/@typescript-eslint/typescript-estree": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.1.0.tgz", - "integrity": "sha512-k7MyrbD6E463CBbSpcOnwa8oXRdHzH1WiVzOipK3L5KSML92ZKgUBrTlehdi7PEIMT8k0bQixHUGXggPAlKnOQ==", + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.1.1.tgz", + "integrity": "sha512-9ZOncVSfr+sMXVxxca2OJOPagRwT0u/UHikM2Rd6L/aB+kL/QAuTnsv6MeXtjzCJYb8PzrXarypSGIPx3Jemxw==", "dev": true, "dependencies": { - "@typescript-eslint/types": "7.1.0", - "@typescript-eslint/visitor-keys": "7.1.0", + "@typescript-eslint/types": "7.1.1", + "@typescript-eslint/visitor-keys": "7.1.1", "debug": "^4.3.4", "globby": "^11.1.0", "is-glob": "^4.0.3", @@ -1474,17 +1476,17 @@ } }, "node_modules/@typescript-eslint/utils": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.1.0.tgz", - "integrity": "sha512-WUFba6PZC5OCGEmbweGpnNJytJiLG7ZvDBJJoUcX4qZYf1mGZ97mO2Mps6O2efxJcJdRNpqweCistDbZMwIVHw==", + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.1.1.tgz", + "integrity": "sha512-thOXM89xA03xAE0lW7alstvnyoBUbBX38YtY+zAUcpRPcq9EIhXPuJ0YTv948MbzmKh6e1AUszn5cBFK49Umqg==", "dev": true, "dependencies": { "@eslint-community/eslint-utils": "^4.4.0", "@types/json-schema": "^7.0.12", "@types/semver": "^7.5.0", - "@typescript-eslint/scope-manager": "7.1.0", - "@typescript-eslint/types": "7.1.0", - "@typescript-eslint/typescript-estree": "7.1.0", + "@typescript-eslint/scope-manager": "7.1.1", + "@typescript-eslint/types": "7.1.1", + "@typescript-eslint/typescript-estree": "7.1.1", "semver": "^7.5.4" }, "engines": { @@ -1499,12 +1501,12 @@ } }, "node_modules/@typescript-eslint/visitor-keys": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.1.0.tgz", - "integrity": "sha512-FhUqNWluiGNzlvnDZiXad4mZRhtghdoKW6e98GoEOYSu5cND+E39rG5KwJMUzeENwm1ztYBRqof8wMLP+wNPIA==", + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.1.1.tgz", + "integrity": "sha512-yTdHDQxY7cSoCcAtiBzVzxleJhkGB9NncSIyMYe2+OGON1ZsP9zOPws/Pqgopa65jvknOjlk/w7ulPlZ78PiLQ==", "dev": true, "dependencies": { - "@typescript-eslint/types": "7.1.0", + "@typescript-eslint/types": "7.1.1", "eslint-visitor-keys": "^3.4.1" }, "engines": { @@ -4384,9 +4386,9 @@ } }, "node_modules/typescript": { - "version": "5.3.3", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.3.3.tgz", - "integrity": "sha512-pXWcraxM0uxAS+tN0AG/BF2TyqmHO014Z070UsJ+pFvYuRSq8KH8DmWpnbXe0pEPDHXZV3FcAbJkijJ5oNEnWw==", + "version": "5.4.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.4.2.tgz", + "integrity": "sha512-+2/g0Fds1ERlP6JsakQQDXjZdZMM+rqpamFZJEKh4kwTIn3iDkgKtby0CeNd5ATNZ4Ry1ax15TMx0W2V+miizQ==", "dev": true, "bin": { "tsc": "bin/tsc", @@ -4472,9 +4474,9 @@ } }, "node_modules/vite": { - "version": "5.1.4", - "resolved": "https://registry.npmjs.org/vite/-/vite-5.1.4.tgz", - "integrity": "sha512-n+MPqzq+d9nMVTKyewqw6kSt+R3CkvF9QAKY8obiQn8g1fwTscKxyfaYnC632HtBXAQGc1Yjomphwn1dtwGAHg==", + "version": "5.1.5", + "resolved": "https://registry.npmjs.org/vite/-/vite-5.1.5.tgz", + "integrity": "sha512-BdN1xh0Of/oQafhU+FvopafUp6WaYenLU/NFoL5WyJL++GxkNfieKzBhM24H3HVsPQrlAqB7iJYTHabzaRed5Q==", "dev": true, "dependencies": { "esbuild": "^0.19.3", @@ -4748,9 +4750,9 @@ "dev": true }, "node_modules/yaml": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.4.0.tgz", - "integrity": "sha512-j9iR8g+/t0lArF4V6NE/QCfT+CO7iLqrXAHZbJdo+LfjqP1vR8Fg5bSiaq6Q2lOD1AUEVrEVIgABvBFYojJVYQ==", + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.4.1.tgz", + "integrity": "sha512-pIXzoImaqmfOrL7teGUBt/T7ZDnyeGBWyXQBvOVhLkWLN37GXv8NMLK406UY6dS51JfcQHsmcW5cJ441bHg6Lg==", "dev": true, "bin": { "yaml": "bin.mjs" @@ -5186,7 +5188,7 @@ "@immich/sdk": { "version": "file:../open-api/typescript-sdk", "requires": { - "@oazapfts/runtime": "^1.0.0", + "@oazapfts/runtime": "^1.0.2", "@types/node": "^20.11.0", "typescript": "^5.3.3" } @@ -5487,9 +5489,9 @@ } }, "@types/node": { - "version": "20.11.24", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.11.24.tgz", - "integrity": "sha512-Kza43ewS3xoLgCEpQrsT+xRo/EJej1y0kVYGiLFE1NEODXGzTfwiC6tXTLMQskn1X4/Rjlh0MQUvx9W+L9long==", + "version": "20.11.25", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.11.25.tgz", + "integrity": "sha512-TBHyJxk2b7HceLVGFcpAUjsa5zIdsPWlR6XHfyGzd0SFu+/NFgQgMAl96MSDZgQDvJAvV6BKsFOrt6zIL09JDw==", "dev": true, "requires": { "undici-types": "~5.26.4" @@ -5508,16 +5510,16 @@ "dev": true }, "@typescript-eslint/eslint-plugin": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.1.0.tgz", - "integrity": "sha512-j6vT/kCulhG5wBmGtstKeiVr1rdXE4nk+DT1k6trYkwlrvW9eOF5ZbgKnd/YR6PcM4uTEXa0h6Fcvf6X7Dxl0w==", + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.1.1.tgz", + "integrity": "sha512-zioDz623d0RHNhvx0eesUmGfIjzrk18nSBC8xewepKXbBvN/7c1qImV7Hg8TI1URTxKax7/zxfxj3Uph8Chcuw==", "dev": true, "requires": { "@eslint-community/regexpp": "^4.5.1", - "@typescript-eslint/scope-manager": "7.1.0", - "@typescript-eslint/type-utils": "7.1.0", - "@typescript-eslint/utils": "7.1.0", - "@typescript-eslint/visitor-keys": "7.1.0", + "@typescript-eslint/scope-manager": "7.1.1", + "@typescript-eslint/type-utils": "7.1.1", + "@typescript-eslint/utils": "7.1.1", + "@typescript-eslint/visitor-keys": "7.1.1", "debug": "^4.3.4", "graphemer": "^1.4.0", "ignore": "^5.2.4", @@ -5527,54 +5529,54 @@ } }, "@typescript-eslint/parser": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-7.1.0.tgz", - "integrity": "sha512-V1EknKUubZ1gWFjiOZhDSNToOjs63/9O0puCgGS8aDOgpZY326fzFu15QAUjwaXzRZjf/qdsdBrckYdv9YxB8w==", + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-7.1.1.tgz", + "integrity": "sha512-ZWUFyL0z04R1nAEgr9e79YtV5LbafdOtN7yapNbn1ansMyaegl2D4bL7vHoJ4HPSc4CaLwuCVas8CVuneKzplQ==", "dev": true, "requires": { - "@typescript-eslint/scope-manager": "7.1.0", - "@typescript-eslint/types": "7.1.0", - "@typescript-eslint/typescript-estree": "7.1.0", - "@typescript-eslint/visitor-keys": "7.1.0", + "@typescript-eslint/scope-manager": "7.1.1", + "@typescript-eslint/types": "7.1.1", + "@typescript-eslint/typescript-estree": "7.1.1", + "@typescript-eslint/visitor-keys": "7.1.1", "debug": "^4.3.4" } }, "@typescript-eslint/scope-manager": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.1.0.tgz", - "integrity": "sha512-6TmN4OJiohHfoOdGZ3huuLhpiUgOGTpgXNUPJgeZOZR3DnIpdSgtt83RS35OYNNXxM4TScVlpVKC9jyQSETR1A==", + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.1.1.tgz", + "integrity": "sha512-cirZpA8bJMRb4WZ+rO6+mnOJrGFDd38WoXCEI57+CYBqta8Yc8aJym2i7vyqLL1vVYljgw0X27axkUXz32T8TA==", "dev": true, "requires": { - "@typescript-eslint/types": "7.1.0", - "@typescript-eslint/visitor-keys": "7.1.0" + "@typescript-eslint/types": "7.1.1", + "@typescript-eslint/visitor-keys": "7.1.1" } }, "@typescript-eslint/type-utils": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-7.1.0.tgz", - "integrity": "sha512-UZIhv8G+5b5skkcuhgvxYWHjk7FW7/JP5lPASMEUoliAPwIH/rxoUSQPia2cuOj9AmDZmwUl1usKm85t5VUMew==", + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-7.1.1.tgz", + "integrity": "sha512-5r4RKze6XHEEhlZnJtR3GYeCh1IueUHdbrukV2KSlLXaTjuSfeVF8mZUVPLovidCuZfbVjfhi4c0DNSa/Rdg5g==", "dev": true, "requires": { - "@typescript-eslint/typescript-estree": "7.1.0", - "@typescript-eslint/utils": "7.1.0", + "@typescript-eslint/typescript-estree": "7.1.1", + "@typescript-eslint/utils": "7.1.1", "debug": "^4.3.4", "ts-api-utils": "^1.0.1" } }, "@typescript-eslint/types": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.1.0.tgz", - "integrity": "sha512-qTWjWieJ1tRJkxgZYXx6WUYtWlBc48YRxgY2JN1aGeVpkhmnopq+SUC8UEVGNXIvWH7XyuTjwALfG6bFEgCkQA==", + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.1.1.tgz", + "integrity": "sha512-KhewzrlRMrgeKm1U9bh2z5aoL4s7K3tK5DwHDn8MHv0yQfWFz/0ZR6trrIHHa5CsF83j/GgHqzdbzCXJ3crx0Q==", "dev": true }, "@typescript-eslint/typescript-estree": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.1.0.tgz", - "integrity": "sha512-k7MyrbD6E463CBbSpcOnwa8oXRdHzH1WiVzOipK3L5KSML92ZKgUBrTlehdi7PEIMT8k0bQixHUGXggPAlKnOQ==", + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.1.1.tgz", + "integrity": "sha512-9ZOncVSfr+sMXVxxca2OJOPagRwT0u/UHikM2Rd6L/aB+kL/QAuTnsv6MeXtjzCJYb8PzrXarypSGIPx3Jemxw==", "dev": true, "requires": { - "@typescript-eslint/types": "7.1.0", - "@typescript-eslint/visitor-keys": "7.1.0", + "@typescript-eslint/types": "7.1.1", + "@typescript-eslint/visitor-keys": "7.1.1", "debug": "^4.3.4", "globby": "^11.1.0", "is-glob": "^4.0.3", @@ -5604,27 +5606,27 @@ } }, "@typescript-eslint/utils": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.1.0.tgz", - "integrity": "sha512-WUFba6PZC5OCGEmbweGpnNJytJiLG7ZvDBJJoUcX4qZYf1mGZ97mO2Mps6O2efxJcJdRNpqweCistDbZMwIVHw==", + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.1.1.tgz", + "integrity": "sha512-thOXM89xA03xAE0lW7alstvnyoBUbBX38YtY+zAUcpRPcq9EIhXPuJ0YTv948MbzmKh6e1AUszn5cBFK49Umqg==", "dev": true, "requires": { "@eslint-community/eslint-utils": "^4.4.0", "@types/json-schema": "^7.0.12", "@types/semver": "^7.5.0", - "@typescript-eslint/scope-manager": "7.1.0", - "@typescript-eslint/types": "7.1.0", - "@typescript-eslint/typescript-estree": "7.1.0", + "@typescript-eslint/scope-manager": "7.1.1", + "@typescript-eslint/types": "7.1.1", + "@typescript-eslint/typescript-estree": "7.1.1", "semver": "^7.5.4" } }, "@typescript-eslint/visitor-keys": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.1.0.tgz", - "integrity": "sha512-FhUqNWluiGNzlvnDZiXad4mZRhtghdoKW6e98GoEOYSu5cND+E39rG5KwJMUzeENwm1ztYBRqof8wMLP+wNPIA==", + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.1.1.tgz", + "integrity": "sha512-yTdHDQxY7cSoCcAtiBzVzxleJhkGB9NncSIyMYe2+OGON1ZsP9zOPws/Pqgopa65jvknOjlk/w7ulPlZ78PiLQ==", "dev": true, "requires": { - "@typescript-eslint/types": "7.1.0", + "@typescript-eslint/types": "7.1.1", "eslint-visitor-keys": "^3.4.1" } }, @@ -7682,9 +7684,9 @@ "dev": true }, "typescript": { - "version": "5.3.3", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.3.3.tgz", - "integrity": "sha512-pXWcraxM0uxAS+tN0AG/BF2TyqmHO014Z070UsJ+pFvYuRSq8KH8DmWpnbXe0pEPDHXZV3FcAbJkijJ5oNEnWw==", + "version": "5.4.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.4.2.tgz", + "integrity": "sha512-+2/g0Fds1ERlP6JsakQQDXjZdZMM+rqpamFZJEKh4kwTIn3iDkgKtby0CeNd5ATNZ4Ry1ax15TMx0W2V+miizQ==", "dev": true }, "ufo": { @@ -7740,9 +7742,9 @@ } }, "vite": { - "version": "5.1.4", - "resolved": "https://registry.npmjs.org/vite/-/vite-5.1.4.tgz", - "integrity": "sha512-n+MPqzq+d9nMVTKyewqw6kSt+R3CkvF9QAKY8obiQn8g1fwTscKxyfaYnC632HtBXAQGc1Yjomphwn1dtwGAHg==", + "version": "5.1.5", + "resolved": "https://registry.npmjs.org/vite/-/vite-5.1.5.tgz", + "integrity": "sha512-BdN1xh0Of/oQafhU+FvopafUp6WaYenLU/NFoL5WyJL++GxkNfieKzBhM24H3HVsPQrlAqB7iJYTHabzaRed5Q==", "dev": true, "requires": { "esbuild": "^0.19.3", @@ -7880,9 +7882,9 @@ "dev": true }, "yaml": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.4.0.tgz", - "integrity": "sha512-j9iR8g+/t0lArF4V6NE/QCfT+CO7iLqrXAHZbJdo+LfjqP1vR8Fg5bSiaq6Q2lOD1AUEVrEVIgABvBFYojJVYQ==", + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.4.1.tgz", + "integrity": "sha512-pIXzoImaqmfOrL7teGUBt/T7ZDnyeGBWyXQBvOVhLkWLN37GXv8NMLK406UY6dS51JfcQHsmcW5cJ441bHg6Lg==", "dev": true }, "yocto-queue": { diff --git a/cli/package.json b/cli/package.json index 630add5b0..b76c24f94 100644 --- a/cli/package.json +++ b/cli/package.json @@ -1,6 +1,6 @@ { "name": "@immich/cli", - "version": "2.0.8", + "version": "2.1.0", "description": "Command Line Interface (CLI) for Immich", "type": "module", "exports": "./dist/index.js", diff --git a/cli/src/index.ts b/cli/src/index.ts index 1aab0386a..e9485190a 100644 --- a/cli/src/index.ts +++ b/cli/src/index.ts @@ -44,7 +44,7 @@ program .default(false), ) .addOption( - new Option('-c, --concurrency', 'Number of assets to upload at the same time') + new Option('-c, --concurrency ', 'Number of assets to upload at the same time') .env('IMMICH_UPLOAD_CONCURRENCY') .default(4), ) diff --git a/design/immich-text-right.png b/design/immich-text-light.png similarity index 100% rename from design/immich-text-right.png rename to design/immich-text-light.png diff --git a/docker/docker-compose.dev.yml b/docker/docker-compose.dev.yml index d344329a5..2541a1a20 100644 --- a/docker/docker-compose.dev.yml +++ b/docker/docker-compose.dev.yml @@ -114,6 +114,29 @@ services: - ${UPLOAD_LOCATION}/postgres:/var/lib/postgresql/data ports: - 5432:5432 + + # set IMMICH_METRICS=true in .env to enable metrics + # immich-prometheus: + # container_name: immich_prometheus + # ports: + # - 9090:9090 + # image: prom/prometheus + # volumes: + # - ./prometheus.yml:/etc/prometheus/prometheus.yml + # - prometheus-data:/prometheus + + # first login uses admin/admin + # add data source for http://immich-prometheus:9090 to get started + # immich-grafana: + # container_name: immich_grafana + # command: ['./run.sh', '-disable-reporting'] + # ports: + # - 3000:3000 + # image: grafana/grafana:10.3.3-ubuntu + # volumes: + # - grafana-data:/var/lib/grafana volumes: model-cache: + prometheus-data: + grafana-data: diff --git a/docker/docker-compose.prod.yml b/docker/docker-compose.prod.yml index b0a19274d..4d418a0c2 100644 --- a/docker/docker-compose.prod.yml +++ b/docker/docker-compose.prod.yml @@ -73,5 +73,28 @@ services: ports: - 5432:5432 + # set IMMICH_METRICS=true in .env to enable metrics + immich-prometheus: + container_name: immich_prometheus + ports: + - 9090:9090 + image: prom/prometheus + volumes: + - ./prometheus.yml:/etc/prometheus/prometheus.yml + - prometheus-data:/prometheus + + # first login uses admin/admin + # add data source for http://immich-prometheus:9090 to get started + immich-grafana: + container_name: immich_grafana + command: ['./run.sh', '-disable-reporting'] + ports: + - 3000:3000 + image: grafana/grafana:10.4.0-ubuntu@sha256:c1f582b7cc4c1b9805d187b5600ce7879550a12ef6d29571da133c3d3fc67a9c + volumes: + - grafana-data:/var/lib/grafana + volumes: model-cache: + prometheus-data: + grafana-data: diff --git a/docker/prometheus.yml b/docker/prometheus.yml new file mode 100644 index 000000000..e25bb7db6 --- /dev/null +++ b/docker/prometheus.yml @@ -0,0 +1,12 @@ +global: + scrape_interval: 15s + evaluation_interval: 15s + +scrape_configs: + - job_name: immich_server + static_configs: + - targets: ['immich-server:8081'] + + - job_name: immich_microservices + static_configs: + - targets: ['immich-microservices:8081'] diff --git a/docs/docs/administration/backup-and-restore.md b/docs/docs/administration/backup-and-restore.md index a37b1bd8a..6d7ee6f15 100644 --- a/docs/docs/administration/backup-and-restore.md +++ b/docs/docs/administration/backup-and-restore.md @@ -101,7 +101,7 @@ Some storage locations are impacted by the Storage Template. See below for more :::note -`UPLOAD_LOCATION/library` folder is not used by default on new machines running version 1.92.0. These are if the system administrator activated the storage template engine, for [more info](https://github.com/immich-app/immich/releases#:~:text=the%20partner%E2%80%99s%20assets.-,Hardening%20storage%20template,-We%20have%20further). +`UPLOAD_LOCATION/library` folder is not used by default on new machines running version 1.92.0. These are if the system administrator activated the storage template engine, for [more info](https://github.com/immich-app/immich/releases/tag/v1.92.0#:~:text=the%20partner%E2%80%99s%20assets.-,Hardening%20storage%20template). ::: **1. User-Specific Folders:** diff --git a/docs/docs/administration/server-commands.md b/docs/docs/administration/server-commands.md index fc235f5a5..2594da44b 100644 --- a/docs/docs/administration/server-commands.md +++ b/docs/docs/administration/server-commands.md @@ -8,6 +8,8 @@ The `immich-server` docker image comes preinstalled with an administrative CLI ( | `reset-admin-password` | Reset the password for the admin user | | `disable-password-login` | Disable password login | | `enable-password-login` | Enable password login | +| `enable-oauth-login` | Enable OAuth login | +| `disable-oauth-login` | Disable OAuth login | | `list-users` | List Immich users | ## How to run a command @@ -36,13 +38,27 @@ immich-admin disable-password-login Password login has been disabled. ``` -Enabled Password Login +Enable Password Login ``` immich-admin enable-password-login Password login has been enabled. ``` +Enable OAuth login + +``` +immich-admin enable-oauth-login +OAuth login has been enabled. +``` + +Disable OAuth login + +``` +immich-admin disable-oauth-login +OAuth login has been disabled. +``` + List Users ``` diff --git a/docs/docs/features/automatic-backup.md b/docs/docs/features/automatic-backup.md index b4b3e1fb0..81444d9f3 100644 --- a/docs/docs/features/automatic-backup.md +++ b/docs/docs/features/automatic-backup.md @@ -10,7 +10,7 @@ If foreground backup is enabled: whenever the app is opened or resumed, it will ## Background backup -Background backup is available thanks to the contribution effort of [@zoodyy](https://github.com/zoodyy) and [@martyfuhry](https://github.com/martyfuhry). +Background backup is available thanks to the contribution effort of [@fyfrey](https://github.com/fyfrey) and [@martyfuhry](https://github.com/martyfuhry). If background backup is enabled. The app will periodically check if there are any new photos or videos in the selected album(s) to be uploaded to the cloud. If there are, it will upload them to the cloud in the background. diff --git a/docs/docs/guides/template-backup-script.md b/docs/docs/guides/template-backup-script.md index 51ae4e932..cd43d660b 100644 --- a/docs/docs/guides/template-backup-script.md +++ b/docs/docs/guides/template-backup-script.md @@ -27,11 +27,11 @@ borg init --encryption=none "$BACKUP_PATH/immich-borg" REMOTE_HOST="remote_host@IP" REMOTE_BACKUP_PATH="/path/to/remote/backup/directory" -ssh "$REMOTE_HOST" "mkdir $REMOTE_BACKUP_PATH/immich-borg" -ssh "$REMOTE_HOST" "borg init --encryption=none $REMOTE_BACKUP_PATH/immich-borg" +ssh "$REMOTE_HOST" "mkdir \"$REMOTE_BACKUP_PATH\"/immich-borg" +ssh "$REMOTE_HOST" "borg init --encryption=none \"$REMOTE_BACKUP_PATH\"/immich-borg" ``` -Edit the following script as necessary and add it to your crontab. Note that this script assumes there are no spaces in your paths. If there are spaces, enclose the paths in double quotes. +Edit the following script as necessary and add it to your crontab. Note that this script assumes there are no `:`, `@`, or `"` characters in your paths. If these characters exist, you will need to escape and/or rename the paths. ```bash title='Borg backup template' #!/bin/sh @@ -46,18 +46,20 @@ REMOTE_BACKUP_PATH="/path/to/remote/backup/directory" ### Local # Backup Immich database -docker exec -t immich_postgres pg_dumpall -c -U postgres | /usr/bin/gzip > $UPLOAD_LOCATION/database-backup/immich-database.sql.gz +docker exec -t immich_postgres pg_dumpall -c -U postgres > "$UPLOAD_LOCATION"/database-backup/immich-database.sql +# For deduplicating backup programs such as Borg or Restic, compressing the content can increase backup size by making it harder to deduplicate. If you are using a different program or still prefer to compress, you can use the following command instead: +# docker exec -t immich_postgres pg_dumpall -c -U postgres | /usr/bin/gzip --rsyncable > "$UPLOAD_LOCATION"/database-backup/immich-database.sql.gz ### Append to local Borg repository -borg create $BACKUP_PATH/immich-borg::{now} $UPLOAD_LOCATION --exclude $UPLOAD_LOCATION/thumbs/ --exclude $UPLOAD_LOCATION/encoded-video/ -borg prune --keep-weekly=4 --keep-monthly=3 $BACKUP_PATH/immich-borg -borg compact $BACKUP_PATH/immich-borg +borg create "$BACKUP_PATH/immich-borg::{now}" "$UPLOAD_LOCATION" --exclude "$UPLOAD_LOCATION"/thumbs/ --exclude "$UPLOAD_LOCATION"/encoded-video/ +borg prune --keep-weekly=4 --keep-monthly=3 "$BACKUP_PATH"/immich-borg +borg compact "$BACKUP_PATH"/immich-borg ### Append to remote Borg repository -borg create $REMOTE_HOST:$REMOTE_BACKUP_PATH/immich-borg::{now} $UPLOAD_LOCATION --exclude $UPLOAD_LOCATION/thumbs/ --exclude $UPLOAD_LOCATION/encoded-video/ -borg prune --keep-weekly=4 --keep-monthly=3 $REMOTE_HOST:$REMOTE_BACKUP_PATH/immich-borg -borg compact $REMOTE_HOST:$REMOTE_BACKUP_PATH/immich-borg +borg create "$REMOTE_HOST:$REMOTE_BACKUP_PATH/immich-borg::{now}" "$UPLOAD_LOCATION" --exclude "$UPLOAD_LOCATION"/thumbs/ --exclude "$UPLOAD_LOCATION"/encoded-video/ +borg prune --keep-weekly=4 --keep-monthly=3 "$REMOTE_HOST:$REMOTE_BACKUP_PATH"/immich-borg +borg compact "$REMOTE_HOST:$REMOTE_BACKUP_PATH"/immich-borg ``` ### Restoring @@ -67,7 +69,7 @@ To restore from a backup, use the `borg mount` command. ```bash title='Restore from local backup' BACKUP_PATH="/path/to/local/backup/directory" mkdir /tmp/immich-mountpoint -borg mount $BACKUP_PATH/immich-borg /tmp/immich-mountpoint +borg mount "$BACKUP_PATH"/immich-borg /tmp/immich-mountpoint cd /tmp/immich-mountpoint ``` @@ -75,7 +77,7 @@ cd /tmp/immich-mountpoint REMOTE_HOST="remote_host@IP" REMOTE_BACKUP_PATH="/path/to/remote/backup/directory" mkdir /tmp/immich-mountpoint -borg mount $REMOTE_HOST:$REMOTE_BACKUP_PATH/immich-borg /tmp/immich-mountpoint +borg mount "$REMOTE_HOST:$REMOTE_BACKUP_PATH"/immich-borg /tmp/immich-mountpoint cd /tmp/immich-mountpoint ``` diff --git a/docs/docs/install/config-file.md b/docs/docs/install/config-file.md index 0d7c8dafc..9a1d1acb1 100644 --- a/docs/docs/install/config-file.md +++ b/docs/docs/install/config-file.md @@ -4,7 +4,7 @@ A config file can be provided as an alternative to the UI configuration. ### Step 1 - Create a new config file -In JSON format, create a new config file (e.g. `immich.config`) and put it in a location that can be accessed by Immich. +In JSON format, create a new config file (e.g. `immich.json`) and put it in a location that can be accessed by Immich. The default configuration looks like this: ```json @@ -14,7 +14,9 @@ The default configuration looks like this: "threads": 0, "preset": "ultrafast", "targetVideoCodec": "h264", + "acceptedVideoCodecs": ["h264"], "targetAudioCodec": "aac", + "acceptedAudioCodecs": ["aac", "mp3", "libopus"], "targetResolution": "720", "maxBitrate": "0", "bframes": -1, @@ -24,6 +26,7 @@ The default configuration looks like this: "temporalAQ": false, "cqMode": "auto", "twoPass": false, + "preferredHwDevice": "auto", "transcode": "required", "tonemap": "hable", "accel": "disabled" @@ -38,7 +41,7 @@ The default configuration looks like this: "metadataExtraction": { "concurrency": 5 }, - "recognizeFaces": { + "faceDetection": { "concurrency": 2 }, "search": { @@ -50,9 +53,6 @@ The default configuration looks like this: "library": { "concurrency": 5 }, - "storageTemplateMigration": { - "concurrency": 5 - }, "migration": { "concurrency": 5 }, @@ -110,6 +110,8 @@ The default configuration looks like this: "enabled": true }, "storageTemplate": { + "enabled": false, + "hashVerificationEnabled": true, "template": "{{y}}/{{y}}-{{MM}}-{{dd}}/{{filename}}" }, "thumbnail": { @@ -141,6 +143,13 @@ The default configuration looks like this: "usePolling": false, "interval": 10000 } + }, + "server": { + "externalDomain": "", + "loginPageMessage": "" + }, + "user": { + "deleteDelay": 7 } } ``` @@ -154,3 +163,7 @@ So you can just grab it from there, paste it into a file and you're pretty much In your `.env` file, set the variable `IMMICH_CONFIG_FILE` to the path of your config. For more information, refer to the [Environment Variables](/docs/install/environment-variables.md) section. + +:::tip +YAML-formatted config files are also supported. +::: diff --git a/docs/package-lock.json b/docs/package-lock.json index 9a55af7f5..9fbcc56a4 100644 --- a/docs/package-lock.json +++ b/docs/package-lock.json @@ -4264,9 +4264,9 @@ } }, "node_modules/autoprefixer": { - "version": "10.4.17", - "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.17.tgz", - "integrity": "sha512-/cpVNRLSfhOtcGflT13P2794gVSgmPgTR+erw5ifnMLZb0UnSlkK4tquLmkd3BhA+nLo5tX8Cu0upUsGKvKbmg==", + "version": "10.4.18", + "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.18.tgz", + "integrity": "sha512-1DKbDfsr6KUElM6wg+0zRNkB/Q7WcKYAaK+pzXn+Xqmszm/5Xa9coeNdtP88Vi+dPzZnMjhge8GIV49ZQkDa+g==", "funding": [ { "type": "opencollective", @@ -4282,8 +4282,8 @@ } ], "dependencies": { - "browserslist": "^4.22.2", - "caniuse-lite": "^1.0.30001578", + "browserslist": "^4.23.0", + "caniuse-lite": "^1.0.30001591", "fraction.js": "^4.3.7", "normalize-range": "^0.1.2", "picocolors": "^1.0.0", @@ -4565,9 +4565,9 @@ } }, "node_modules/browserslist": { - "version": "4.22.2", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.22.2.tgz", - "integrity": "sha512-0UgcrvQmBDvZHFGdYUehrCNIazki7/lUP3kkoi/r3YB2amZbFM9J43ZRkJTXBUZK4gmx56+Sqk9+Vs9mwZx9+A==", + "version": "4.23.0", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.23.0.tgz", + "integrity": "sha512-QW8HiM1shhT2GuzkvklfjcKDiWFXHOeFCIA/huJPwHsslwcydgk7X+z2zXpEijP98UCY7HbubZt5J2Zgvf0CaQ==", "funding": [ { "type": "opencollective", @@ -4583,8 +4583,8 @@ } ], "dependencies": { - "caniuse-lite": "^1.0.30001565", - "electron-to-chromium": "^1.4.601", + "caniuse-lite": "^1.0.30001587", + "electron-to-chromium": "^1.4.668", "node-releases": "^2.0.14", "update-browserslist-db": "^1.0.13" }, @@ -4728,9 +4728,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001580", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001580.tgz", - "integrity": "sha512-mtj5ur2FFPZcCEpXFy8ADXbDACuNFXg6mxVDqp7tqooX6l3zwm+d8EPoeOSIFRDvHs8qu7/SLFOGniULkcH2iA==", + "version": "1.0.30001597", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001597.tgz", + "integrity": "sha512-7LjJvmQU6Sj7bL0j5b5WY/3n7utXUJvAe1lxhsHDbLmwX9mdL86Yjtr+5SRCyf8qME4M7pU2hswj0FpyBVCv9w==", "funding": [ { "type": "opencollective", @@ -6348,9 +6348,9 @@ "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==" }, "node_modules/electron-to-chromium": { - "version": "1.4.647", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.647.tgz", - "integrity": "sha512-Z/fTNGwc45WrYQhPaEcz5tAJuZZ8G7S/DBnhS6Kgp4BxnS40Z/HqlJ0hHg3Z79IGVzuVartIlTcjw/cQbPLgOw==" + "version": "1.4.701", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.701.tgz", + "integrity": "sha512-K3WPQ36bUOtXg/1+69bFlFOvdSm0/0bGqmsfPDLRXLanoKXdA+pIWuf/VbA9b+2CwBFuONgl4NEz4OEm+OJOKA==" }, "node_modules/emoji-regex": { "version": "9.2.2", @@ -16141,9 +16141,9 @@ } }, "node_modules/typescript": { - "version": "5.3.3", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.3.3.tgz", - "integrity": "sha512-pXWcraxM0uxAS+tN0AG/BF2TyqmHO014Z070UsJ+pFvYuRSq8KH8DmWpnbXe0pEPDHXZV3FcAbJkijJ5oNEnWw==", + "version": "5.4.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.4.2.tgz", + "integrity": "sha512-+2/g0Fds1ERlP6JsakQQDXjZdZMM+rqpamFZJEKh4kwTIn3iDkgKtby0CeNd5ATNZ4Ry1ax15TMx0W2V+miizQ==", "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" diff --git a/docs/src/pages/milestones.tsx b/docs/src/pages/milestones.tsx index e672e0326..ea00f486c 100644 --- a/docs/src/pages/milestones.tsx +++ b/docs/src/pages/milestones.tsx @@ -558,7 +558,7 @@ const items: Item[] = [ title: 'Dark Mode (Web)', description: 'Dark mode on the web.', release: 'v1.32.0', - tag: ' v1.32.0_50-dev', + tag: 'v1.32.0_50-dev', date: new Date(2022, 9, 14), dateType: DateType.RELEASE, }, @@ -621,7 +621,7 @@ const items: Item[] = [ title: 'View Exif', description: 'View metadata about assets.', release: 'v1.3.0', - tag: 'V1.3.0-dev ', + tag: 'v1.3.0-dev ', date: new Date(2022, 2, 22), dateType: DateType.RELEASE, }, @@ -630,7 +630,7 @@ const items: Item[] = [ title: 'Multi Select', description: 'Select and execute actions on multiple assets at the same time.', release: 'v1.2.0', - tag: 'V0.2-dev ', + tag: 'v0.2-dev ', date: new Date(2022, 1, 8), dateType: DateType.RELEASE, }, diff --git a/e2e/docker-compose.yml b/e2e/docker-compose.yml index 6e2d4b78d..7cda6a12c 100644 --- a/e2e/docker-compose.yml +++ b/e2e/docker-compose.yml @@ -14,6 +14,7 @@ x-server-build: &server-common - DB_DATABASE_NAME=immich - REDIS_HOSTNAME=redis - IMMICH_MACHINE_LEARNING_ENABLED=false + - IMMICH_METRICS=true volumes: - upload:/usr/src/app/upload - ../server/test/assets:/data/assets diff --git a/e2e/package-lock.json b/e2e/package-lock.json index f3d06eacc..f94958113 100644 --- a/e2e/package-lock.json +++ b/e2e/package-lock.json @@ -38,7 +38,7 @@ }, "../cli": { "name": "@immich/cli", - "version": "2.0.8", + "version": "2.1.0", "dev": true, "license": "GNU Affero General Public License version 3", "dependencies": { @@ -82,8 +82,10 @@ "version": "1.98.2", "dev": true, "license": "GNU Affero General Public License version 3", + "dependencies": { + "@oazapfts/runtime": "^1.0.2" + }, "devDependencies": { - "@oazapfts/runtime": "^1.0.0", "@types/node": "^20.11.0", "typescript": "^5.3.3" } @@ -1155,9 +1157,9 @@ "dev": true }, "node_modules/@types/node": { - "version": "20.11.24", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.11.24.tgz", - "integrity": "sha512-Kza43ewS3xoLgCEpQrsT+xRo/EJej1y0kVYGiLFE1NEODXGzTfwiC6tXTLMQskn1X4/Rjlh0MQUvx9W+L9long==", + "version": "20.11.25", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.11.25.tgz", + "integrity": "sha512-TBHyJxk2b7HceLVGFcpAUjsa5zIdsPWlR6XHfyGzd0SFu+/NFgQgMAl96MSDZgQDvJAvV6BKsFOrt6zIL09JDw==", "dev": true, "dependencies": { "undici-types": "~5.26.4" @@ -4795,9 +4797,9 @@ } }, "node_modules/typescript": { - "version": "5.3.3", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.3.3.tgz", - "integrity": "sha512-pXWcraxM0uxAS+tN0AG/BF2TyqmHO014Z070UsJ+pFvYuRSq8KH8DmWpnbXe0pEPDHXZV3FcAbJkijJ5oNEnWw==", + "version": "5.4.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.4.2.tgz", + "integrity": "sha512-+2/g0Fds1ERlP6JsakQQDXjZdZMM+rqpamFZJEKh4kwTIn3iDkgKtby0CeNd5ATNZ4Ry1ax15TMx0W2V+miizQ==", "dev": true, "bin": { "tsc": "bin/tsc", diff --git a/e2e/src/cli/specs/upload.e2e-spec.ts b/e2e/src/cli/specs/upload.e2e-spec.ts index 27362ef23..bc4382f98 100644 --- a/e2e/src/cli/specs/upload.e2e-spec.ts +++ b/e2e/src/cli/specs/upload.e2e-spec.ts @@ -142,4 +142,42 @@ describe(`immich upload`, () => { expect(assets.length).toBe(9); }); }); + + describe('immich upload --concurrency ', () => { + it('should work', async () => { + const { stderr, stdout, exitCode } = await immichCli([ + 'upload', + `${testAssetDir}/albums/nature/`, + '--concurrency', + '2', + ]); + + expect(stderr).toBe(''); + expect(stdout.split('\n')).toEqual( + expect.arrayContaining([expect.stringContaining('Successfully uploaded 9 assets')]), + ); + expect(exitCode).toBe(0); + + const assets = await getAllAssets({}, { headers: asKeyAuth(key) }); + expect(assets.length).toBe(9); + }); + + it('should reject string argument', async () => { + const { stderr, exitCode } = await immichCli([ + 'upload', + `${testAssetDir}/albums/nature/`, + '--concurrency string', + ]); + + expect(stderr).toContain('unknown option'); + expect(exitCode).not.toBe(0); + }); + + it('should reject command without number', async () => { + const { stderr, exitCode } = await immichCli(['upload', `${testAssetDir}/albums/nature/`, '--concurrency']); + + expect(stderr).toContain('argument missing'); + expect(exitCode).not.toBe(0); + }); + }); }); diff --git a/machine-learning/poetry.lock b/machine-learning/poetry.lock index ac5dfd2bf..955a64f8e 100644 --- a/machine-learning/poetry.lock +++ b/machine-learning/poetry.lock @@ -1274,13 +1274,13 @@ socks = ["socksio (==1.*)"] [[package]] name = "huggingface-hub" -version = "0.21.3" +version = "0.21.4" description = "Client library to download and publish models, datasets and other repos on the huggingface.co hub" optional = false python-versions = ">=3.8.0" files = [ - {file = "huggingface_hub-0.21.3-py3-none-any.whl", hash = "sha256:b183144336fdf2810a8c109822e0bb6ef1fd61c65da6fb60e8c3f658b7144016"}, - {file = "huggingface_hub-0.21.3.tar.gz", hash = "sha256:26a15b604e4fc7bad37c467b76456543ec849386cbca9cd7e1e135f53e500423"}, + {file = "huggingface_hub-0.21.4-py3-none-any.whl", hash = "sha256:df37c2c37fc6c82163cdd8a67ede261687d80d1e262526d6c0ce73b6b3630a7b"}, + {file = "huggingface_hub-0.21.4.tar.gz", hash = "sha256:e1f4968c93726565a80edf6dc309763c7b546d0cfe79aa221206034d50155531"}, ] [package.dependencies] @@ -2843,28 +2843,28 @@ files = [ [[package]] name = "ruff" -version = "0.3.0" +version = "0.3.2" description = "An extremely fast Python linter and code formatter, written in Rust." optional = false python-versions = ">=3.7" files = [ - {file = "ruff-0.3.0-py3-none-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:7deb528029bacf845bdbb3dbb2927d8ef9b4356a5e731b10eef171e3f0a85944"}, - {file = "ruff-0.3.0-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:e1e0d4381ca88fb2b73ea0766008e703f33f460295de658f5467f6f229658c19"}, - {file = "ruff-0.3.0-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2f7dbba46e2827dfcb0f0cc55fba8e96ba7c8700e0a866eb8cef7d1d66c25dcb"}, - {file = "ruff-0.3.0-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:23dbb808e2f1d68eeadd5f655485e235c102ac6f12ad31505804edced2a5ae77"}, - {file = "ruff-0.3.0-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3ef655c51f41d5fa879f98e40c90072b567c666a7114fa2d9fe004dffba00932"}, - {file = "ruff-0.3.0-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:d0d3d7ef3d4f06433d592e5f7d813314a34601e6c5be8481cccb7fa760aa243e"}, - {file = "ruff-0.3.0-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b08b356d06a792e49a12074b62222f9d4ea2a11dca9da9f68163b28c71bf1dd4"}, - {file = "ruff-0.3.0-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9343690f95710f8cf251bee1013bf43030072b9f8d012fbed6ad702ef70d360a"}, - {file = "ruff-0.3.0-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a1f3ed501a42f60f4dedb7805fa8d4534e78b4e196f536bac926f805f0743d49"}, - {file = "ruff-0.3.0-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:cc30a9053ff2f1ffb505a585797c23434d5f6c838bacfe206c0e6cf38c921a1e"}, - {file = "ruff-0.3.0-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:5da894a29ec018a8293d3d17c797e73b374773943e8369cfc50495573d396933"}, - {file = "ruff-0.3.0-py3-none-musllinux_1_2_i686.whl", hash = "sha256:755c22536d7f1889be25f2baf6fedd019d0c51d079e8417d4441159f3bcd30c2"}, - {file = "ruff-0.3.0-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:dd73fe7f4c28d317855da6a7bc4aa29a1500320818dd8f27df95f70a01b8171f"}, - {file = "ruff-0.3.0-py3-none-win32.whl", hash = "sha256:19eacceb4c9406f6c41af806418a26fdb23120dfe53583df76d1401c92b7c14b"}, - {file = "ruff-0.3.0-py3-none-win_amd64.whl", hash = "sha256:128265876c1d703e5f5e5a4543bd8be47c73a9ba223fd3989d4aa87dd06f312f"}, - {file = "ruff-0.3.0-py3-none-win_arm64.whl", hash = "sha256:e3a4a6d46aef0a84b74fcd201a4401ea9a6cd85614f6a9435f2d33dd8cefbf83"}, - {file = "ruff-0.3.0.tar.gz", hash = "sha256:0886184ba2618d815067cf43e005388967b67ab9c80df52b32ec1152ab49f53a"}, + {file = "ruff-0.3.2-py3-none-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:77f2612752e25f730da7421ca5e3147b213dca4f9a0f7e0b534e9562c5441f01"}, + {file = "ruff-0.3.2-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:9966b964b2dd1107797be9ca7195002b874424d1d5472097701ae8f43eadef5d"}, + {file = "ruff-0.3.2-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b83d17ff166aa0659d1e1deaf9f2f14cbe387293a906de09bc4860717eb2e2da"}, + {file = "ruff-0.3.2-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:bb875c6cc87b3703aeda85f01c9aebdce3d217aeaca3c2e52e38077383f7268a"}, + {file = "ruff-0.3.2-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:be75e468a6a86426430373d81c041b7605137a28f7014a72d2fc749e47f572aa"}, + {file = "ruff-0.3.2-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:967978ac2d4506255e2f52afe70dda023fc602b283e97685c8447d036863a302"}, + {file = "ruff-0.3.2-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1231eacd4510f73222940727ac927bc5d07667a86b0cbe822024dd00343e77e9"}, + {file = "ruff-0.3.2-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2c6d613b19e9a8021be2ee1d0e27710208d1603b56f47203d0abbde906929a9b"}, + {file = "ruff-0.3.2-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c8439338a6303585d27b66b4626cbde89bb3e50fa3cae86ce52c1db7449330a7"}, + {file = "ruff-0.3.2-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:de8b480d8379620cbb5ea466a9e53bb467d2fb07c7eca54a4aa8576483c35d36"}, + {file = "ruff-0.3.2-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:b74c3de9103bd35df2bb05d8b2899bf2dbe4efda6474ea9681280648ec4d237d"}, + {file = "ruff-0.3.2-py3-none-musllinux_1_2_i686.whl", hash = "sha256:f380be9fc15a99765c9cf316b40b9da1f6ad2ab9639e551703e581a5e6da6745"}, + {file = "ruff-0.3.2-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:0ac06a3759c3ab9ef86bbeca665d31ad3aa9a4b1c17684aadb7e61c10baa0df4"}, + {file = "ruff-0.3.2-py3-none-win32.whl", hash = "sha256:9bd640a8f7dd07a0b6901fcebccedadeb1a705a50350fb86b4003b805c81385a"}, + {file = "ruff-0.3.2-py3-none-win_amd64.whl", hash = "sha256:0c1bdd9920cab5707c26c8b3bf33a064a4ca7842d91a99ec0634fec68f9f4037"}, + {file = "ruff-0.3.2-py3-none-win_arm64.whl", hash = "sha256:5f65103b1d76e0d600cabd577b04179ff592064eaa451a70a81085930e907d0b"}, + {file = "ruff-0.3.2.tar.gz", hash = "sha256:fa78ec9418eb1ca3db392811df3376b46471ae93792a81af2d1cbb0e5dcb5142"}, ] [[package]] diff --git a/machine-learning/start.sh b/machine-learning/start.sh index 082bf205c..d4a971f0c 100755 --- a/machine-learning/start.sh +++ b/machine-learning/start.sh @@ -4,7 +4,7 @@ lib_path="/usr/lib/$(arch)-linux-gnu/libmimalloc.so.2" export LD_PRELOAD="$lib_path" export LD_BIND_NOW=1 -: "${MACHINE_LEARNING_HOST:=0.0.0.0}" +: "${MACHINE_LEARNING_HOST:=[::]}" : "${MACHINE_LEARNING_PORT:=3003}" : "${MACHINE_LEARNING_WORKERS:=1}" : "${MACHINE_LEARNING_WORKER_TIMEOUT:=120}" diff --git a/mobile/analysis_options.yaml b/mobile/analysis_options.yaml index 0b08791dc..fe5729fc6 100644 --- a/mobile/analysis_options.yaml +++ b/mobile/analysis_options.yaml @@ -34,7 +34,6 @@ linter: analyzer: exclude: - openapi/** - - openapi/test/** - lib/generated_plugin_registrant.dart plugins: diff --git a/mobile/android/app/src/main/res/drawable-hdpi/android12splash.png b/mobile/android/app/src/main/res/drawable-hdpi/android12splash.png index 98499dc3e..051d1bd7a 100644 Binary files a/mobile/android/app/src/main/res/drawable-hdpi/android12splash.png and b/mobile/android/app/src/main/res/drawable-hdpi/android12splash.png differ diff --git a/mobile/android/app/src/main/res/drawable-hdpi/ic_launcher_foreground.png b/mobile/android/app/src/main/res/drawable-hdpi/ic_launcher_foreground.png new file mode 100644 index 000000000..5b91b2258 Binary files /dev/null and b/mobile/android/app/src/main/res/drawable-hdpi/ic_launcher_foreground.png differ diff --git a/mobile/android/app/src/main/res/drawable-hdpi/notification_icon.png b/mobile/android/app/src/main/res/drawable-hdpi/notification_icon.png index eab14a83e..9c2921c5e 100644 Binary files a/mobile/android/app/src/main/res/drawable-hdpi/notification_icon.png and b/mobile/android/app/src/main/res/drawable-hdpi/notification_icon.png differ diff --git a/mobile/android/app/src/main/res/drawable-hdpi/splash.png b/mobile/android/app/src/main/res/drawable-hdpi/splash.png index bae50bb02..787d65636 100644 Binary files a/mobile/android/app/src/main/res/drawable-hdpi/splash.png and b/mobile/android/app/src/main/res/drawable-hdpi/splash.png differ diff --git a/mobile/android/app/src/main/res/drawable-mdpi/android12splash.png b/mobile/android/app/src/main/res/drawable-mdpi/android12splash.png index 8b7e4f964..bb379c1a7 100644 Binary files a/mobile/android/app/src/main/res/drawable-mdpi/android12splash.png and b/mobile/android/app/src/main/res/drawable-mdpi/android12splash.png differ diff --git a/mobile/android/app/src/main/res/drawable-mdpi/ic_launcher_foreground.png b/mobile/android/app/src/main/res/drawable-mdpi/ic_launcher_foreground.png new file mode 100644 index 000000000..18470610c Binary files /dev/null and b/mobile/android/app/src/main/res/drawable-mdpi/ic_launcher_foreground.png differ diff --git a/mobile/android/app/src/main/res/drawable-mdpi/notification_icon.png b/mobile/android/app/src/main/res/drawable-mdpi/notification_icon.png index 29b3f5234..9d76aa0b2 100644 Binary files a/mobile/android/app/src/main/res/drawable-mdpi/notification_icon.png and b/mobile/android/app/src/main/res/drawable-mdpi/notification_icon.png differ diff --git a/mobile/android/app/src/main/res/drawable-mdpi/splash.png b/mobile/android/app/src/main/res/drawable-mdpi/splash.png index 8e81b09b6..9686187c0 100644 Binary files a/mobile/android/app/src/main/res/drawable-mdpi/splash.png and b/mobile/android/app/src/main/res/drawable-mdpi/splash.png differ diff --git a/mobile/android/app/src/main/res/drawable-night-hdpi/android12splash.png b/mobile/android/app/src/main/res/drawable-night-hdpi/android12splash.png index 98499dc3e..051d1bd7a 100644 Binary files a/mobile/android/app/src/main/res/drawable-night-hdpi/android12splash.png and b/mobile/android/app/src/main/res/drawable-night-hdpi/android12splash.png differ diff --git a/mobile/android/app/src/main/res/drawable-night-mdpi/android12splash.png b/mobile/android/app/src/main/res/drawable-night-mdpi/android12splash.png index 8b7e4f964..bb379c1a7 100644 Binary files a/mobile/android/app/src/main/res/drawable-night-mdpi/android12splash.png and b/mobile/android/app/src/main/res/drawable-night-mdpi/android12splash.png differ diff --git a/mobile/android/app/src/main/res/drawable-night-v21/background.png b/mobile/android/app/src/main/res/drawable-night-v21/background.png index 1b5df34e7..71e9c817e 100644 Binary files a/mobile/android/app/src/main/res/drawable-night-v21/background.png and b/mobile/android/app/src/main/res/drawable-night-v21/background.png differ diff --git a/mobile/android/app/src/main/res/drawable-night-xhdpi/android12splash.png b/mobile/android/app/src/main/res/drawable-night-xhdpi/android12splash.png index 86e4a379f..b7ba46b25 100644 Binary files a/mobile/android/app/src/main/res/drawable-night-xhdpi/android12splash.png and b/mobile/android/app/src/main/res/drawable-night-xhdpi/android12splash.png differ diff --git a/mobile/android/app/src/main/res/drawable-night-xxhdpi/android12splash.png b/mobile/android/app/src/main/res/drawable-night-xxhdpi/android12splash.png index e5445c251..506869c1b 100644 Binary files a/mobile/android/app/src/main/res/drawable-night-xxhdpi/android12splash.png and b/mobile/android/app/src/main/res/drawable-night-xxhdpi/android12splash.png differ diff --git a/mobile/android/app/src/main/res/drawable-night-xxxhdpi/android12splash.png b/mobile/android/app/src/main/res/drawable-night-xxxhdpi/android12splash.png index 2336e479a..014bdc143 100644 Binary files a/mobile/android/app/src/main/res/drawable-night-xxxhdpi/android12splash.png and b/mobile/android/app/src/main/res/drawable-night-xxxhdpi/android12splash.png differ diff --git a/mobile/android/app/src/main/res/drawable-night/background.png b/mobile/android/app/src/main/res/drawable-night/background.png index 1b5df34e7..71e9c817e 100644 Binary files a/mobile/android/app/src/main/res/drawable-night/background.png and b/mobile/android/app/src/main/res/drawable-night/background.png differ diff --git a/mobile/android/app/src/main/res/drawable-v21/background.png b/mobile/android/app/src/main/res/drawable-v21/background.png index 649393cb5..a8cb4d717 100644 Binary files a/mobile/android/app/src/main/res/drawable-v21/background.png and b/mobile/android/app/src/main/res/drawable-v21/background.png differ diff --git a/mobile/android/app/src/main/res/drawable-xhdpi/android12splash.png b/mobile/android/app/src/main/res/drawable-xhdpi/android12splash.png index 86e4a379f..b7ba46b25 100644 Binary files a/mobile/android/app/src/main/res/drawable-xhdpi/android12splash.png and b/mobile/android/app/src/main/res/drawable-xhdpi/android12splash.png differ diff --git a/mobile/android/app/src/main/res/drawable-xhdpi/ic_launcher_foreground.png b/mobile/android/app/src/main/res/drawable-xhdpi/ic_launcher_foreground.png new file mode 100644 index 000000000..f0d6d66ac Binary files /dev/null and b/mobile/android/app/src/main/res/drawable-xhdpi/ic_launcher_foreground.png differ diff --git a/mobile/android/app/src/main/res/drawable-xhdpi/notification_icon.png b/mobile/android/app/src/main/res/drawable-xhdpi/notification_icon.png index 3575d7998..ea1d6ed6f 100644 Binary files a/mobile/android/app/src/main/res/drawable-xhdpi/notification_icon.png and b/mobile/android/app/src/main/res/drawable-xhdpi/notification_icon.png differ diff --git a/mobile/android/app/src/main/res/drawable-xhdpi/splash.png b/mobile/android/app/src/main/res/drawable-xhdpi/splash.png index d0cfcc422..00e6c61e7 100644 Binary files a/mobile/android/app/src/main/res/drawable-xhdpi/splash.png and b/mobile/android/app/src/main/res/drawable-xhdpi/splash.png differ diff --git a/mobile/android/app/src/main/res/drawable-xxhdpi/android12splash.png b/mobile/android/app/src/main/res/drawable-xxhdpi/android12splash.png index e5445c251..506869c1b 100644 Binary files a/mobile/android/app/src/main/res/drawable-xxhdpi/android12splash.png and b/mobile/android/app/src/main/res/drawable-xxhdpi/android12splash.png differ diff --git a/mobile/android/app/src/main/res/drawable-xxhdpi/ic_launcher_foreground.png b/mobile/android/app/src/main/res/drawable-xxhdpi/ic_launcher_foreground.png new file mode 100644 index 000000000..6eb60e8b7 Binary files /dev/null and b/mobile/android/app/src/main/res/drawable-xxhdpi/ic_launcher_foreground.png differ diff --git a/mobile/android/app/src/main/res/drawable-xxhdpi/notification_icon.png b/mobile/android/app/src/main/res/drawable-xxhdpi/notification_icon.png index bf5672b61..fc3a8c5de 100644 Binary files a/mobile/android/app/src/main/res/drawable-xxhdpi/notification_icon.png and b/mobile/android/app/src/main/res/drawable-xxhdpi/notification_icon.png differ diff --git a/mobile/android/app/src/main/res/drawable-xxhdpi/splash.png b/mobile/android/app/src/main/res/drawable-xxhdpi/splash.png index 4ba88c62a..e87b8694f 100644 Binary files a/mobile/android/app/src/main/res/drawable-xxhdpi/splash.png and b/mobile/android/app/src/main/res/drawable-xxhdpi/splash.png differ diff --git a/mobile/android/app/src/main/res/drawable-xxxhdpi/android12splash.png b/mobile/android/app/src/main/res/drawable-xxxhdpi/android12splash.png index 2336e479a..014bdc143 100644 Binary files a/mobile/android/app/src/main/res/drawable-xxxhdpi/android12splash.png and b/mobile/android/app/src/main/res/drawable-xxxhdpi/android12splash.png differ diff --git a/mobile/android/app/src/main/res/drawable-xxxhdpi/ic_launcher_foreground.png b/mobile/android/app/src/main/res/drawable-xxxhdpi/ic_launcher_foreground.png new file mode 100644 index 000000000..c8842b651 Binary files /dev/null and b/mobile/android/app/src/main/res/drawable-xxxhdpi/ic_launcher_foreground.png differ diff --git a/mobile/android/app/src/main/res/drawable-xxxhdpi/notification_icon.png b/mobile/android/app/src/main/res/drawable-xxxhdpi/notification_icon.png index c45e0d6e9..eda791487 100644 Binary files a/mobile/android/app/src/main/res/drawable-xxxhdpi/notification_icon.png and b/mobile/android/app/src/main/res/drawable-xxxhdpi/notification_icon.png differ diff --git a/mobile/android/app/src/main/res/drawable-xxxhdpi/splash.png b/mobile/android/app/src/main/res/drawable-xxxhdpi/splash.png index 117320218..bddbad827 100644 Binary files a/mobile/android/app/src/main/res/drawable-xxxhdpi/splash.png and b/mobile/android/app/src/main/res/drawable-xxxhdpi/splash.png differ diff --git a/mobile/android/app/src/main/res/drawable/background.png b/mobile/android/app/src/main/res/drawable/background.png index 649393cb5..a8cb4d717 100644 Binary files a/mobile/android/app/src/main/res/drawable/background.png and b/mobile/android/app/src/main/res/drawable/background.png differ diff --git a/mobile/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml b/mobile/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml index 1084c2408..5f349f7f4 100644 --- a/mobile/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml +++ b/mobile/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml @@ -1,6 +1,5 @@ - - - - \ No newline at end of file + + + diff --git a/mobile/android/app/src/main/res/mipmap-hdpi/ic_launcher.png b/mobile/android/app/src/main/res/mipmap-hdpi/ic_launcher.png index 4d6c70d14..85d3df61e 100644 Binary files a/mobile/android/app/src/main/res/mipmap-hdpi/ic_launcher.png and b/mobile/android/app/src/main/res/mipmap-hdpi/ic_launcher.png differ diff --git a/mobile/android/app/src/main/res/mipmap-mdpi/ic_launcher.png b/mobile/android/app/src/main/res/mipmap-mdpi/ic_launcher.png index 0a9d07b32..749bb343a 100644 Binary files a/mobile/android/app/src/main/res/mipmap-mdpi/ic_launcher.png and b/mobile/android/app/src/main/res/mipmap-mdpi/ic_launcher.png differ diff --git a/mobile/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png b/mobile/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png index 661fe7792..7fd792179 100644 Binary files a/mobile/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png and b/mobile/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png differ diff --git a/mobile/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/mobile/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png index b980adbf5..964e50673 100644 Binary files a/mobile/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png and b/mobile/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png differ diff --git a/mobile/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/mobile/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png index 08e57d7e8..26c3250d0 100644 Binary files a/mobile/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png and b/mobile/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png differ diff --git a/mobile/android/app/src/main/res/values-night-v31/styles.xml b/mobile/android/app/src/main/res/values-night-v31/styles.xml index 8e51f7679..c4a573dfe 100644 --- a/mobile/android/app/src/main/res/values-night-v31/styles.xml +++ b/mobile/android/app/src/main/res/values-night-v31/styles.xml @@ -4,6 +4,7 @@ - - - - - - - - - - - - - - - - - - - + + + + + + + diff --git a/mobile/assets/immich-splash-android12.png b/mobile/assets/immich-splash-android12.png index a4fd2fb0d..3a7f71ae3 100644 Binary files a/mobile/assets/immich-splash-android12.png and b/mobile/assets/immich-splash-android12.png differ diff --git a/mobile/assets/immich-splash.png b/mobile/assets/immich-splash.png index e7767cc3d..49035b27f 100644 Binary files a/mobile/assets/immich-splash.png and b/mobile/assets/immich-splash.png differ diff --git a/mobile/assets/immich-text-dark.png b/mobile/assets/immich-text-dark.png new file mode 100644 index 000000000..215687af8 Binary files /dev/null and b/mobile/assets/immich-text-dark.png differ diff --git a/mobile/assets/immich-text-light.png b/mobile/assets/immich-text-light.png new file mode 100644 index 000000000..478158d39 Binary files /dev/null and b/mobile/assets/immich-text-light.png differ diff --git a/mobile/flutter_native_splash.yaml b/mobile/flutter_native_splash.yaml index 2fcbc1f14..1b290fbfa 100644 --- a/mobile/flutter_native_splash.yaml +++ b/mobile/flutter_native_splash.yaml @@ -10,7 +10,7 @@ flutter_native_splash: # of your splash screen to a solid color. Use background_image to set the background of your # splash screen to a png image. This is useful for gradients. The image will be stretch to the # size of the app. Only one parameter can be used, color and background_image cannot both be set. - #background_image: "assets/immich-logo-no-outline.png" + #background_image: "assets/immich-logo.png" color: "#f6f8fe" # Optional parameters are listed below. To enable a parameter, uncomment the line by removing diff --git a/mobile/ios/Podfile.lock b/mobile/ios/Podfile.lock index a9ac5b338..6081988b7 100644 --- a/mobile/ios/Podfile.lock +++ b/mobile/ios/Podfile.lock @@ -180,4 +180,4 @@ SPEC CHECKSUMS: PODFILE CHECKSUM: 64c9b5291666c0ca3caabdfe9865c141ac40321d -COCOAPODS: 1.12.1 +COCOAPODS: 1.11.3 diff --git a/mobile/ios/Runner.xcodeproj/project.pbxproj b/mobile/ios/Runner.xcodeproj/project.pbxproj index dcfe3dc85..5f44646ec 100644 --- a/mobile/ios/Runner.xcodeproj/project.pbxproj +++ b/mobile/ios/Runner.xcodeproj/project.pbxproj @@ -171,6 +171,7 @@ 97C146E61CF9000F007C117D /* Project object */ = { isa = PBXProject; attributes = { + BuildIndependentTargetsInParallel = YES; LastUpgradeCheck = 1430; ORGANIZATIONNAME = ""; TargetAttributes = { @@ -323,6 +324,7 @@ isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; CLANG_ANALYZER_NONNULL = YES; CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; CLANG_CXX_LIBRARY = "libc++"; @@ -342,6 +344,7 @@ CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; CLANG_WARN_STRICT_PROTOTYPES = YES; CLANG_WARN_SUSPICIOUS_MOVE = YES; @@ -352,6 +355,7 @@ DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; ENABLE_NS_ASSERTIONS = NO; ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_USER_SCRIPT_SANDBOXING = NO; GCC_C_LANGUAGE_STANDARD = gnu99; GCC_NO_COMMON_BLOCKS = YES; GCC_WARN_64_TO_32_BIT_CONVERSION = YES; @@ -402,6 +406,7 @@ isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = AppIcon; CLANG_ANALYZER_NONNULL = YES; CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; CLANG_CXX_LIBRARY = "libc++"; @@ -421,6 +426,7 @@ CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; CLANG_WARN_STRICT_PROTOTYPES = YES; CLANG_WARN_SUSPICIOUS_MOVE = YES; @@ -431,6 +437,7 @@ DEBUG_INFORMATION_FORMAT = dwarf; ENABLE_STRICT_OBJC_MSGSEND = YES; ENABLE_TESTABILITY = YES; + ENABLE_USER_SCRIPT_SANDBOXING = NO; GCC_C_LANGUAGE_STANDARD = gnu99; GCC_DYNAMIC_NO_PIC = NO; GCC_NO_COMMON_BLOCKS = YES; @@ -458,6 +465,7 @@ isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = AppIcon; CLANG_ANALYZER_NONNULL = YES; CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; CLANG_CXX_LIBRARY = "libc++"; @@ -477,6 +485,7 @@ CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; CLANG_WARN_STRICT_PROTOTYPES = YES; CLANG_WARN_SUSPICIOUS_MOVE = YES; @@ -487,6 +496,7 @@ DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; ENABLE_NS_ASSERTIONS = NO; ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_USER_SCRIPT_SANDBOXING = NO; GCC_C_LANGUAGE_STANDARD = gnu99; GCC_NO_COMMON_BLOCKS = YES; GCC_WARN_64_TO_32_BIT_CONVERSION = YES; diff --git a/mobile/ios/Runner/Assets.xcassets/AppIcon.appiconset/100.png b/mobile/ios/Runner/Assets.xcassets/AppIcon.appiconset/100.png index 9923b59b1..7410611a1 100644 Binary files a/mobile/ios/Runner/Assets.xcassets/AppIcon.appiconset/100.png and b/mobile/ios/Runner/Assets.xcassets/AppIcon.appiconset/100.png differ diff --git a/mobile/ios/Runner/Assets.xcassets/AppIcon.appiconset/102.png b/mobile/ios/Runner/Assets.xcassets/AppIcon.appiconset/102.png new file mode 100644 index 000000000..fdc691876 Binary files /dev/null and b/mobile/ios/Runner/Assets.xcassets/AppIcon.appiconset/102.png differ diff --git a/mobile/ios/Runner/Assets.xcassets/AppIcon.appiconset/1024.png b/mobile/ios/Runner/Assets.xcassets/AppIcon.appiconset/1024.png index 027439fa0..68315df16 100644 Binary files a/mobile/ios/Runner/Assets.xcassets/AppIcon.appiconset/1024.png and b/mobile/ios/Runner/Assets.xcassets/AppIcon.appiconset/1024.png differ diff --git a/mobile/ios/Runner/Assets.xcassets/AppIcon.appiconset/114.png b/mobile/ios/Runner/Assets.xcassets/AppIcon.appiconset/114.png index c5d873221..6477a0347 100644 Binary files a/mobile/ios/Runner/Assets.xcassets/AppIcon.appiconset/114.png and b/mobile/ios/Runner/Assets.xcassets/AppIcon.appiconset/114.png differ diff --git a/mobile/ios/Runner/Assets.xcassets/AppIcon.appiconset/120.png b/mobile/ios/Runner/Assets.xcassets/AppIcon.appiconset/120.png index 22e7c868c..cb0b8b233 100644 Binary files a/mobile/ios/Runner/Assets.xcassets/AppIcon.appiconset/120.png and b/mobile/ios/Runner/Assets.xcassets/AppIcon.appiconset/120.png differ diff --git a/mobile/ios/Runner/Assets.xcassets/AppIcon.appiconset/128.png b/mobile/ios/Runner/Assets.xcassets/AppIcon.appiconset/128.png index ffb9850da..fd3f25c8b 100644 Binary files a/mobile/ios/Runner/Assets.xcassets/AppIcon.appiconset/128.png and b/mobile/ios/Runner/Assets.xcassets/AppIcon.appiconset/128.png differ diff --git a/mobile/ios/Runner/Assets.xcassets/AppIcon.appiconset/144.png b/mobile/ios/Runner/Assets.xcassets/AppIcon.appiconset/144.png index a8a56ba51..0352e1c29 100644 Binary files a/mobile/ios/Runner/Assets.xcassets/AppIcon.appiconset/144.png and b/mobile/ios/Runner/Assets.xcassets/AppIcon.appiconset/144.png differ diff --git a/mobile/ios/Runner/Assets.xcassets/AppIcon.appiconset/152.png b/mobile/ios/Runner/Assets.xcassets/AppIcon.appiconset/152.png index c499f4a8a..5cfe315e6 100644 Binary files a/mobile/ios/Runner/Assets.xcassets/AppIcon.appiconset/152.png and b/mobile/ios/Runner/Assets.xcassets/AppIcon.appiconset/152.png differ diff --git a/mobile/ios/Runner/Assets.xcassets/AppIcon.appiconset/16.png b/mobile/ios/Runner/Assets.xcassets/AppIcon.appiconset/16.png index aef74574e..be71bdffe 100644 Binary files a/mobile/ios/Runner/Assets.xcassets/AppIcon.appiconset/16.png and b/mobile/ios/Runner/Assets.xcassets/AppIcon.appiconset/16.png differ diff --git a/mobile/ios/Runner/Assets.xcassets/AppIcon.appiconset/167.png b/mobile/ios/Runner/Assets.xcassets/AppIcon.appiconset/167.png index 1be420435..92fa603e4 100644 Binary files a/mobile/ios/Runner/Assets.xcassets/AppIcon.appiconset/167.png and b/mobile/ios/Runner/Assets.xcassets/AppIcon.appiconset/167.png differ diff --git a/mobile/ios/Runner/Assets.xcassets/AppIcon.appiconset/172.png b/mobile/ios/Runner/Assets.xcassets/AppIcon.appiconset/172.png index ae36f630f..55ef6fd65 100644 Binary files a/mobile/ios/Runner/Assets.xcassets/AppIcon.appiconset/172.png and b/mobile/ios/Runner/Assets.xcassets/AppIcon.appiconset/172.png differ diff --git a/mobile/ios/Runner/Assets.xcassets/AppIcon.appiconset/180.png b/mobile/ios/Runner/Assets.xcassets/AppIcon.appiconset/180.png index 45c25a7d0..223738d84 100644 Binary files a/mobile/ios/Runner/Assets.xcassets/AppIcon.appiconset/180.png and b/mobile/ios/Runner/Assets.xcassets/AppIcon.appiconset/180.png differ diff --git a/mobile/ios/Runner/Assets.xcassets/AppIcon.appiconset/196.png b/mobile/ios/Runner/Assets.xcassets/AppIcon.appiconset/196.png index 428e4568d..6beb14060 100644 Binary files a/mobile/ios/Runner/Assets.xcassets/AppIcon.appiconset/196.png and b/mobile/ios/Runner/Assets.xcassets/AppIcon.appiconset/196.png differ diff --git a/mobile/ios/Runner/Assets.xcassets/AppIcon.appiconset/20.png b/mobile/ios/Runner/Assets.xcassets/AppIcon.appiconset/20.png index b852aba7a..290b0e500 100644 Binary files a/mobile/ios/Runner/Assets.xcassets/AppIcon.appiconset/20.png and b/mobile/ios/Runner/Assets.xcassets/AppIcon.appiconset/20.png differ diff --git a/mobile/ios/Runner/Assets.xcassets/AppIcon.appiconset/216.png b/mobile/ios/Runner/Assets.xcassets/AppIcon.appiconset/216.png index da1fab772..0cd0958f1 100644 Binary files a/mobile/ios/Runner/Assets.xcassets/AppIcon.appiconset/216.png and b/mobile/ios/Runner/Assets.xcassets/AppIcon.appiconset/216.png differ diff --git a/mobile/ios/Runner/Assets.xcassets/AppIcon.appiconset/256.png b/mobile/ios/Runner/Assets.xcassets/AppIcon.appiconset/256.png index 8f6069e84..f953bf98d 100644 Binary files a/mobile/ios/Runner/Assets.xcassets/AppIcon.appiconset/256.png and b/mobile/ios/Runner/Assets.xcassets/AppIcon.appiconset/256.png differ diff --git a/mobile/ios/Runner/Assets.xcassets/AppIcon.appiconset/29.png b/mobile/ios/Runner/Assets.xcassets/AppIcon.appiconset/29.png index 0435b40ec..f657572a8 100644 Binary files a/mobile/ios/Runner/Assets.xcassets/AppIcon.appiconset/29.png and b/mobile/ios/Runner/Assets.xcassets/AppIcon.appiconset/29.png differ diff --git a/mobile/ios/Runner/Assets.xcassets/AppIcon.appiconset/32.png b/mobile/ios/Runner/Assets.xcassets/AppIcon.appiconset/32.png index 820e5b461..b90be3463 100644 Binary files a/mobile/ios/Runner/Assets.xcassets/AppIcon.appiconset/32.png and b/mobile/ios/Runner/Assets.xcassets/AppIcon.appiconset/32.png differ diff --git a/mobile/ios/Runner/Assets.xcassets/AppIcon.appiconset/40.png b/mobile/ios/Runner/Assets.xcassets/AppIcon.appiconset/40.png index 773d875cc..d4da3d2c8 100644 Binary files a/mobile/ios/Runner/Assets.xcassets/AppIcon.appiconset/40.png and b/mobile/ios/Runner/Assets.xcassets/AppIcon.appiconset/40.png differ diff --git a/mobile/ios/Runner/Assets.xcassets/AppIcon.appiconset/48.png b/mobile/ios/Runner/Assets.xcassets/AppIcon.appiconset/48.png index d512f32d1..31bf03f16 100644 Binary files a/mobile/ios/Runner/Assets.xcassets/AppIcon.appiconset/48.png and b/mobile/ios/Runner/Assets.xcassets/AppIcon.appiconset/48.png differ diff --git a/mobile/ios/Runner/Assets.xcassets/AppIcon.appiconset/50.png b/mobile/ios/Runner/Assets.xcassets/AppIcon.appiconset/50.png index de3f8fac0..aabe91e42 100644 Binary files a/mobile/ios/Runner/Assets.xcassets/AppIcon.appiconset/50.png and b/mobile/ios/Runner/Assets.xcassets/AppIcon.appiconset/50.png differ diff --git a/mobile/ios/Runner/Assets.xcassets/AppIcon.appiconset/512.png b/mobile/ios/Runner/Assets.xcassets/AppIcon.appiconset/512.png index cca8509f2..9ffc996bf 100644 Binary files a/mobile/ios/Runner/Assets.xcassets/AppIcon.appiconset/512.png and b/mobile/ios/Runner/Assets.xcassets/AppIcon.appiconset/512.png differ diff --git a/mobile/ios/Runner/Assets.xcassets/AppIcon.appiconset/55.png b/mobile/ios/Runner/Assets.xcassets/AppIcon.appiconset/55.png index 400dc6c9d..7e6c272f7 100644 Binary files a/mobile/ios/Runner/Assets.xcassets/AppIcon.appiconset/55.png and b/mobile/ios/Runner/Assets.xcassets/AppIcon.appiconset/55.png differ diff --git a/mobile/ios/Runner/Assets.xcassets/AppIcon.appiconset/57.png b/mobile/ios/Runner/Assets.xcassets/AppIcon.appiconset/57.png index 10587f2fd..776f6cdb3 100644 Binary files a/mobile/ios/Runner/Assets.xcassets/AppIcon.appiconset/57.png and b/mobile/ios/Runner/Assets.xcassets/AppIcon.appiconset/57.png differ diff --git a/mobile/ios/Runner/Assets.xcassets/AppIcon.appiconset/58.png b/mobile/ios/Runner/Assets.xcassets/AppIcon.appiconset/58.png index 8063164e6..61cf91efd 100644 Binary files a/mobile/ios/Runner/Assets.xcassets/AppIcon.appiconset/58.png and b/mobile/ios/Runner/Assets.xcassets/AppIcon.appiconset/58.png differ diff --git a/mobile/ios/Runner/Assets.xcassets/AppIcon.appiconset/60.png b/mobile/ios/Runner/Assets.xcassets/AppIcon.appiconset/60.png index 8186ed100..bc08a2659 100644 Binary files a/mobile/ios/Runner/Assets.xcassets/AppIcon.appiconset/60.png and b/mobile/ios/Runner/Assets.xcassets/AppIcon.appiconset/60.png differ diff --git a/mobile/ios/Runner/Assets.xcassets/AppIcon.appiconset/64.png b/mobile/ios/Runner/Assets.xcassets/AppIcon.appiconset/64.png index 004851109..71af65a43 100644 Binary files a/mobile/ios/Runner/Assets.xcassets/AppIcon.appiconset/64.png and b/mobile/ios/Runner/Assets.xcassets/AppIcon.appiconset/64.png differ diff --git a/mobile/ios/Runner/Assets.xcassets/AppIcon.appiconset/66.png b/mobile/ios/Runner/Assets.xcassets/AppIcon.appiconset/66.png new file mode 100644 index 000000000..9891293ce Binary files /dev/null and b/mobile/ios/Runner/Assets.xcassets/AppIcon.appiconset/66.png differ diff --git a/mobile/ios/Runner/Assets.xcassets/AppIcon.appiconset/72.png b/mobile/ios/Runner/Assets.xcassets/AppIcon.appiconset/72.png index d2fd11d1b..e9f403101 100644 Binary files a/mobile/ios/Runner/Assets.xcassets/AppIcon.appiconset/72.png and b/mobile/ios/Runner/Assets.xcassets/AppIcon.appiconset/72.png differ diff --git a/mobile/ios/Runner/Assets.xcassets/AppIcon.appiconset/76.png b/mobile/ios/Runner/Assets.xcassets/AppIcon.appiconset/76.png index 93d868e1c..9185ca516 100644 Binary files a/mobile/ios/Runner/Assets.xcassets/AppIcon.appiconset/76.png and b/mobile/ios/Runner/Assets.xcassets/AppIcon.appiconset/76.png differ diff --git a/mobile/ios/Runner/Assets.xcassets/AppIcon.appiconset/80.png b/mobile/ios/Runner/Assets.xcassets/AppIcon.appiconset/80.png index aec01e484..2bb5e811f 100644 Binary files a/mobile/ios/Runner/Assets.xcassets/AppIcon.appiconset/80.png and b/mobile/ios/Runner/Assets.xcassets/AppIcon.appiconset/80.png differ diff --git a/mobile/ios/Runner/Assets.xcassets/AppIcon.appiconset/87.png b/mobile/ios/Runner/Assets.xcassets/AppIcon.appiconset/87.png index f0a86953f..8aa25d730 100644 Binary files a/mobile/ios/Runner/Assets.xcassets/AppIcon.appiconset/87.png and b/mobile/ios/Runner/Assets.xcassets/AppIcon.appiconset/87.png differ diff --git a/mobile/ios/Runner/Assets.xcassets/AppIcon.appiconset/88.png b/mobile/ios/Runner/Assets.xcassets/AppIcon.appiconset/88.png index b154d30df..a3442ae29 100644 Binary files a/mobile/ios/Runner/Assets.xcassets/AppIcon.appiconset/88.png and b/mobile/ios/Runner/Assets.xcassets/AppIcon.appiconset/88.png differ diff --git a/mobile/ios/Runner/Assets.xcassets/AppIcon.appiconset/92.png b/mobile/ios/Runner/Assets.xcassets/AppIcon.appiconset/92.png new file mode 100644 index 000000000..7089a8c76 Binary files /dev/null and b/mobile/ios/Runner/Assets.xcassets/AppIcon.appiconset/92.png differ diff --git a/mobile/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json b/mobile/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json index f78687a21..ffab2548e 100644 --- a/mobile/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json +++ b/mobile/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -1,344 +1 @@ -{ - "images" : [ - { - "filename" : "40.png", - "idiom" : "iphone", - "scale" : "2x", - "size" : "20x20" - }, - { - "filename" : "60.png", - "idiom" : "iphone", - "scale" : "3x", - "size" : "20x20" - }, - { - "filename" : "29.png", - "idiom" : "iphone", - "scale" : "1x", - "size" : "29x29" - }, - { - "filename" : "58.png", - "idiom" : "iphone", - "scale" : "2x", - "size" : "29x29" - }, - { - "filename" : "87.png", - "idiom" : "iphone", - "scale" : "3x", - "size" : "29x29" - }, - { - "filename" : "80.png", - "idiom" : "iphone", - "scale" : "2x", - "size" : "40x40" - }, - { - "filename" : "120.png", - "idiom" : "iphone", - "scale" : "3x", - "size" : "40x40" - }, - { - "filename" : "57.png", - "idiom" : "iphone", - "scale" : "1x", - "size" : "57x57" - }, - { - "filename" : "114.png", - "idiom" : "iphone", - "scale" : "2x", - "size" : "57x57" - }, - { - "filename" : "120.png", - "idiom" : "iphone", - "scale" : "2x", - "size" : "60x60" - }, - { - "filename" : "180.png", - "idiom" : "iphone", - "scale" : "3x", - "size" : "60x60" - }, - { - "filename" : "20.png", - "idiom" : "ipad", - "scale" : "1x", - "size" : "20x20" - }, - { - "filename" : "40.png", - "idiom" : "ipad", - "scale" : "2x", - "size" : "20x20" - }, - { - "filename" : "29.png", - "idiom" : "ipad", - "scale" : "1x", - "size" : "29x29" - }, - { - "filename" : "58.png", - "idiom" : "ipad", - "scale" : "2x", - "size" : "29x29" - }, - { - "filename" : "40.png", - "idiom" : "ipad", - "scale" : "1x", - "size" : "40x40" - }, - { - "filename" : "80.png", - "idiom" : "ipad", - "scale" : "2x", - "size" : "40x40" - }, - { - "filename" : "50.png", - "idiom" : "ipad", - "scale" : "1x", - "size" : "50x50" - }, - { - "filename" : "100.png", - "idiom" : "ipad", - "scale" : "2x", - "size" : "50x50" - }, - { - "filename" : "72.png", - "idiom" : "ipad", - "scale" : "1x", - "size" : "72x72" - }, - { - "filename" : "144.png", - "idiom" : "ipad", - "scale" : "2x", - "size" : "72x72" - }, - { - "filename" : "76.png", - "idiom" : "ipad", - "scale" : "1x", - "size" : "76x76" - }, - { - "filename" : "152.png", - "idiom" : "ipad", - "scale" : "2x", - "size" : "76x76" - }, - { - "filename" : "167.png", - "idiom" : "ipad", - "scale" : "2x", - "size" : "83.5x83.5" - }, - { - "filename" : "1024.png", - "idiom" : "ios-marketing", - "scale" : "1x", - "size" : "1024x1024" - }, - { - "filename" : "16.png", - "idiom" : "mac", - "scale" : "1x", - "size" : "16x16" - }, - { - "filename" : "32.png", - "idiom" : "mac", - "scale" : "2x", - "size" : "16x16" - }, - { - "filename" : "32.png", - "idiom" : "mac", - "scale" : "1x", - "size" : "32x32" - }, - { - "filename" : "64.png", - "idiom" : "mac", - "scale" : "2x", - "size" : "32x32" - }, - { - "filename" : "128.png", - "idiom" : "mac", - "scale" : "1x", - "size" : "128x128" - }, - { - "filename" : "256.png", - "idiom" : "mac", - "scale" : "2x", - "size" : "128x128" - }, - { - "filename" : "256.png", - "idiom" : "mac", - "scale" : "1x", - "size" : "256x256" - }, - { - "filename" : "512.png", - "idiom" : "mac", - "scale" : "2x", - "size" : "256x256" - }, - { - "filename" : "512.png", - "idiom" : "mac", - "scale" : "1x", - "size" : "512x512" - }, - { - "filename" : "1024.png", - "idiom" : "mac", - "scale" : "2x", - "size" : "512x512" - }, - { - "filename" : "48.png", - "idiom" : "watch", - "role" : "notificationCenter", - "scale" : "2x", - "size" : "24x24", - "subtype" : "38mm" - }, - { - "filename" : "55.png", - "idiom" : "watch", - "role" : "notificationCenter", - "scale" : "2x", - "size" : "27.5x27.5", - "subtype" : "42mm" - }, - { - "filename" : "58.png", - "idiom" : "watch", - "role" : "companionSettings", - "scale" : "2x", - "size" : "29x29" - }, - { - "filename" : "87.png", - "idiom" : "watch", - "role" : "companionSettings", - "scale" : "3x", - "size" : "29x29" - }, - { - "idiom" : "watch", - "role" : "notificationCenter", - "scale" : "2x", - "size" : "33x33", - "subtype" : "45mm" - }, - { - "filename" : "80.png", - "idiom" : "watch", - "role" : "appLauncher", - "scale" : "2x", - "size" : "40x40", - "subtype" : "38mm" - }, - { - "filename" : "88.png", - "idiom" : "watch", - "role" : "appLauncher", - "scale" : "2x", - "size" : "44x44", - "subtype" : "40mm" - }, - { - "idiom" : "watch", - "role" : "appLauncher", - "scale" : "2x", - "size" : "46x46", - "subtype" : "41mm" - }, - { - "filename" : "100.png", - "idiom" : "watch", - "role" : "appLauncher", - "scale" : "2x", - "size" : "50x50", - "subtype" : "44mm" - }, - { - "idiom" : "watch", - "role" : "appLauncher", - "scale" : "2x", - "size" : "51x51", - "subtype" : "45mm" - }, - { - "idiom" : "watch", - "role" : "appLauncher", - "scale" : "2x", - "size" : "54x54", - "subtype" : "49mm" - }, - { - "filename" : "172.png", - "idiom" : "watch", - "role" : "quickLook", - "scale" : "2x", - "size" : "86x86", - "subtype" : "38mm" - }, - { - "filename" : "196.png", - "idiom" : "watch", - "role" : "quickLook", - "scale" : "2x", - "size" : "98x98", - "subtype" : "42mm" - }, - { - "filename" : "216.png", - "idiom" : "watch", - "role" : "quickLook", - "scale" : "2x", - "size" : "108x108", - "subtype" : "44mm" - }, - { - "idiom" : "watch", - "role" : "quickLook", - "scale" : "2x", - "size" : "117x117", - "subtype" : "45mm" - }, - { - "idiom" : "watch", - "role" : "quickLook", - "scale" : "2x", - "size" : "129x129", - "subtype" : "49mm" - }, - { - "filename" : "1024.png", - "idiom" : "watch-marketing", - "scale" : "1x", - "size" : "1024x1024" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - } -} +{"images":[{"size":"60x60","expected-size":"180","filename":"180.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"iphone","scale":"3x"},{"size":"40x40","expected-size":"80","filename":"80.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"iphone","scale":"2x"},{"size":"40x40","expected-size":"120","filename":"120.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"iphone","scale":"3x"},{"size":"60x60","expected-size":"120","filename":"120.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"iphone","scale":"2x"},{"size":"57x57","expected-size":"57","filename":"57.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"iphone","scale":"1x"},{"size":"29x29","expected-size":"58","filename":"58.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"iphone","scale":"2x"},{"size":"29x29","expected-size":"29","filename":"29.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"iphone","scale":"1x"},{"size":"29x29","expected-size":"87","filename":"87.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"iphone","scale":"3x"},{"size":"57x57","expected-size":"114","filename":"114.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"iphone","scale":"2x"},{"size":"20x20","expected-size":"40","filename":"40.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"iphone","scale":"2x"},{"size":"20x20","expected-size":"60","filename":"60.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"iphone","scale":"3x"},{"size":"1024x1024","filename":"1024.png","expected-size":"1024","idiom":"ios-marketing","folder":"Assets.xcassets/AppIcon.appiconset/","scale":"1x"},{"size":"40x40","expected-size":"80","filename":"80.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"ipad","scale":"2x"},{"size":"72x72","expected-size":"72","filename":"72.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"ipad","scale":"1x"},{"size":"76x76","expected-size":"152","filename":"152.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"ipad","scale":"2x"},{"size":"50x50","expected-size":"100","filename":"100.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"ipad","scale":"2x"},{"size":"29x29","expected-size":"58","filename":"58.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"ipad","scale":"2x"},{"size":"76x76","expected-size":"76","filename":"76.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"ipad","scale":"1x"},{"size":"29x29","expected-size":"29","filename":"29.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"ipad","scale":"1x"},{"size":"50x50","expected-size":"50","filename":"50.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"ipad","scale":"1x"},{"size":"72x72","expected-size":"144","filename":"144.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"ipad","scale":"2x"},{"size":"40x40","expected-size":"40","filename":"40.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"ipad","scale":"1x"},{"size":"83.5x83.5","expected-size":"167","filename":"167.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"ipad","scale":"2x"},{"size":"20x20","expected-size":"20","filename":"20.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"ipad","scale":"1x"},{"size":"20x20","expected-size":"40","filename":"40.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"ipad","scale":"2x"},{"idiom":"watch","filename":"172.png","folder":"Assets.xcassets/AppIcon.appiconset/","subtype":"38mm","scale":"2x","size":"86x86","expected-size":"172","role":"quickLook"},{"idiom":"watch","filename":"80.png","folder":"Assets.xcassets/AppIcon.appiconset/","subtype":"38mm","scale":"2x","size":"40x40","expected-size":"80","role":"appLauncher"},{"idiom":"watch","filename":"88.png","folder":"Assets.xcassets/AppIcon.appiconset/","subtype":"40mm","scale":"2x","size":"44x44","expected-size":"88","role":"appLauncher"},{"idiom":"watch","filename":"102.png","folder":"Assets.xcassets/AppIcon.appiconset/","subtype":"41mm","scale":"2x","size":"45x45","expected-size":"102","role":"appLauncher"},{"idiom":"watch","filename":"92.png","folder":"Assets.xcassets/AppIcon.appiconset/","subtype":"41mm","scale":"2x","size":"46x46","expected-size":"92","role":"appLauncher"},{"idiom":"watch","filename":"100.png","folder":"Assets.xcassets/AppIcon.appiconset/","subtype":"44mm","scale":"2x","size":"50x50","expected-size":"100","role":"appLauncher"},{"idiom":"watch","filename":"196.png","folder":"Assets.xcassets/AppIcon.appiconset/","subtype":"42mm","scale":"2x","size":"98x98","expected-size":"196","role":"quickLook"},{"idiom":"watch","filename":"216.png","folder":"Assets.xcassets/AppIcon.appiconset/","subtype":"44mm","scale":"2x","size":"108x108","expected-size":"216","role":"quickLook"},{"idiom":"watch","filename":"48.png","folder":"Assets.xcassets/AppIcon.appiconset/","subtype":"38mm","scale":"2x","size":"24x24","expected-size":"48","role":"notificationCenter"},{"idiom":"watch","filename":"55.png","folder":"Assets.xcassets/AppIcon.appiconset/","subtype":"42mm","scale":"2x","size":"27.5x27.5","expected-size":"55","role":"notificationCenter"},{"idiom":"watch","filename":"66.png","folder":"Assets.xcassets/AppIcon.appiconset/","subtype":"45mm","scale":"2x","size":"33x33","expected-size":"66","role":"notificationCenter"},{"size":"29x29","expected-size":"87","filename":"87.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"watch","role":"companionSettings","scale":"3x"},{"size":"29x29","expected-size":"58","filename":"58.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"watch","role":"companionSettings","scale":"2x"},{"size":"1024x1024","expected-size":"1024","filename":"1024.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"watch-marketing","scale":"1x"},{"size":"128x128","expected-size":"128","filename":"128.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"mac","scale":"1x"},{"size":"256x256","expected-size":"256","filename":"256.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"mac","scale":"1x"},{"size":"128x128","expected-size":"256","filename":"256.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"mac","scale":"2x"},{"size":"256x256","expected-size":"512","filename":"512.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"mac","scale":"2x"},{"size":"32x32","expected-size":"32","filename":"32.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"mac","scale":"1x"},{"size":"512x512","expected-size":"512","filename":"512.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"mac","scale":"1x"},{"size":"16x16","expected-size":"16","filename":"16.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"mac","scale":"1x"},{"size":"16x16","expected-size":"32","filename":"32.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"mac","scale":"2x"},{"size":"32x32","expected-size":"64","filename":"64.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"mac","scale":"2x"},{"size":"512x512","expected-size":"1024","filename":"1024.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"mac","scale":"2x"}]} \ No newline at end of file diff --git a/mobile/ios/Runner/Assets.xcassets/LaunchBackground.imageset/background.png b/mobile/ios/Runner/Assets.xcassets/LaunchBackground.imageset/background.png index 649393cb5..a8cb4d717 100644 Binary files a/mobile/ios/Runner/Assets.xcassets/LaunchBackground.imageset/background.png and b/mobile/ios/Runner/Assets.xcassets/LaunchBackground.imageset/background.png differ diff --git a/mobile/ios/Runner/Assets.xcassets/LaunchBackground.imageset/darkbackground.png b/mobile/ios/Runner/Assets.xcassets/LaunchBackground.imageset/darkbackground.png index 1b5df34e7..71e9c817e 100644 Binary files a/mobile/ios/Runner/Assets.xcassets/LaunchBackground.imageset/darkbackground.png and b/mobile/ios/Runner/Assets.xcassets/LaunchBackground.imageset/darkbackground.png differ diff --git a/mobile/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png b/mobile/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png index 8e81b09b6..9686187c0 100644 Binary files a/mobile/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png and b/mobile/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png differ diff --git a/mobile/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png b/mobile/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png index d0cfcc422..00e6c61e7 100644 Binary files a/mobile/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png and b/mobile/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png differ diff --git a/mobile/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png b/mobile/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png index 4ba88c62a..e87b8694f 100644 Binary files a/mobile/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png and b/mobile/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png differ diff --git a/mobile/ios/Runner/Info.plist b/mobile/ios/Runner/Info.plist index 310133e0b..a750a446b 100644 --- a/mobile/ios/Runner/Info.plist +++ b/mobile/ios/Runner/Info.plist @@ -1,121 +1,121 @@ - - BGTaskSchedulerPermittedIdentifiers - - app.alextran.immich.backgroundFetch - app.alextran.immich.backgroundProcessing - - CADisableMinimumFrameDurationOnPhone - - CFBundleDevelopmentRegion - $(DEVELOPMENT_LANGUAGE) - CFBundleDisplayName - Immich - CFBundleExecutable - $(EXECUTABLE_NAME) - CFBundleIdentifier - $(PRODUCT_BUNDLE_IDENTIFIER) - CFBundleInfoDictionaryVersion - 6.0 - CFBundleLocalizations - - en - de - da - it - es - vi - fr - ja - pl - fi - pt - cs - uk - ru - zh - sk - nl - nb - sv - mn - ko - sr - hi - ca - hu - lv - th - sl - - CFBundleName - immich_mobile - CFBundlePackageType - APPL - CFBundleShortVersionString - 1.98.2 - CFBundleSignature - ???? - CFBundleVersion - 144 - FLTEnableImpeller - - ITSAppUsesNonExemptEncryption - - LSApplicationQueriesSchemes - - https - - LSRequiresIPhoneOS - - MGLMapboxMetricsEnabledSettingShownInApp - - NSAppTransportSecurity - - NSAllowsArbitraryLoads - - - NSCameraUsageDescription - We need to access the camera to let you take beautiful video using this app - NSLocationWhenInUseUsageDescription - Enable location setting to show position of assets on map - NSMicrophoneUsageDescription - We need to access the microphone to let you take beautiful video using this app - NSPhotoLibraryAddUsageDescription - We need to manage backup your photos album - NSPhotoLibraryUsageDescription - We need to manage backup your photos album - UIApplicationSupportsIndirectInputEvents - - UIBackgroundModes - - fetch - processing - - UILaunchStoryboardName - LaunchScreen - UIMainStoryboardFile - Main - UIStatusBarHidden - - UISupportedInterfaceOrientations - - UIInterfaceOrientationPortrait - UIInterfaceOrientationLandscapeLeft - UIInterfaceOrientationLandscapeRight - - UISupportedInterfaceOrientations~ipad - - UIInterfaceOrientationPortrait - UIInterfaceOrientationPortraitUpsideDown - UIInterfaceOrientationLandscapeLeft - UIInterfaceOrientationLandscapeRight - - UIViewControllerBasedStatusBarAppearance - - io.flutter.embedded_views_preview - - - \ No newline at end of file + + BGTaskSchedulerPermittedIdentifiers + + app.alextran.immich.backgroundFetch + app.alextran.immich.backgroundProcessing + + CADisableMinimumFrameDurationOnPhone + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleDisplayName + Immich + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleLocalizations + + en + de + da + it + es + vi + fr + ja + pl + fi + pt + cs + uk + ru + zh + sk + nl + nb + sv + mn + ko + sr + hi + ca + hu + lv + th + sl + + CFBundleName + immich_mobile + CFBundlePackageType + APPL + CFBundleShortVersionString + 1.98.2 + CFBundleSignature + ???? + CFBundleVersion + 144 + FLTEnableImpeller + + ITSAppUsesNonExemptEncryption + + LSApplicationQueriesSchemes + + https + + LSRequiresIPhoneOS + + MGLMapboxMetricsEnabledSettingShownInApp + + NSAppTransportSecurity + + NSAllowsArbitraryLoads + + + NSCameraUsageDescription + We need to access the camera to let you take beautiful video using this app + NSLocationWhenInUseUsageDescription + Enable location setting to show position of assets on map + NSMicrophoneUsageDescription + We need to access the microphone to let you take beautiful video using this app + NSPhotoLibraryAddUsageDescription + We need to manage backup your photos album + NSPhotoLibraryUsageDescription + We need to manage backup your photos album + UIApplicationSupportsIndirectInputEvents + + UIBackgroundModes + + fetch + processing + + UILaunchStoryboardName + LaunchScreen + UIMainStoryboardFile + Main + UIStatusBarHidden + + UISupportedInterfaceOrientations + + UIInterfaceOrientationPortrait + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + UISupportedInterfaceOrientations~ipad + + UIInterfaceOrientationPortrait + UIInterfaceOrientationPortraitUpsideDown + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + UIViewControllerBasedStatusBarAppearance + + io.flutter.embedded_views_preview + + + diff --git a/mobile/lib/modules/album/views/library_page.dart b/mobile/lib/modules/album/views/library_page.dart index 4a0f57ab5..b8b1b6b39 100644 --- a/mobile/lib/modules/album/views/library_page.dart +++ b/mobile/lib/modules/album/views/library_page.dart @@ -194,9 +194,10 @@ class LibraryPage extends HookConsumerWidget { ? InkWell( onTap: () => context.pushRoute(const TrashRoute()), borderRadius: const BorderRadius.all(Radius.circular(12)), - child: const Icon( + child: Icon( Icons.delete_rounded, size: 25, + semanticLabel: 'profile_drawer_trash'.tr(), ), ) : null; diff --git a/mobile/lib/modules/album/views/sharing_page.dart b/mobile/lib/modules/album/views/sharing_page.dart index e6b2ade6b..44a7faee4 100644 --- a/mobile/lib/modules/album/views/sharing_page.dart +++ b/mobile/lib/modules/album/views/sharing_page.dart @@ -212,9 +212,10 @@ class SharingPage extends HookConsumerWidget { return InkWell( onTap: () => context.pushRoute(const PartnerRoute()), borderRadius: const BorderRadius.all(Radius.circular(12)), - child: const Icon( + child: Icon( Icons.swap_horizontal_circle_rounded, size: 25, + semanticLabel: 'partner_page_title'.tr(), ), ); } diff --git a/mobile/lib/modules/asset_viewer/image_providers/immich_local_thumbnail_provider.dart b/mobile/lib/modules/asset_viewer/image_providers/immich_local_thumbnail_provider.dart index bb86cfafd..0c97ab01c 100644 --- a/mobile/lib/modules/asset_viewer/image_providers/immich_local_thumbnail_provider.dart +++ b/mobile/lib/modules/asset_viewer/image_providers/immich_local_thumbnail_provider.dart @@ -10,7 +10,8 @@ import 'package:photo_manager/photo_manager.dart'; /// The local image provider for an asset /// Only viable -class ImmichLocalThumbnailProvider extends ImageProvider { +class ImmichLocalThumbnailProvider + extends ImageProvider { final Asset asset; final int height; final int width; @@ -24,15 +25,20 @@ class ImmichLocalThumbnailProvider extends ImageProvider { /// Converts an [ImageProvider]'s settings plus an [ImageConfiguration] to a key /// that describes the precise image to load. @override - Future obtainKey(ImageConfiguration configuration) { - return SynchronousFuture(asset); + Future obtainKey( + ImageConfiguration configuration, + ) { + return SynchronousFuture(this); } @override - ImageStreamCompleter loadImage(Asset key, ImageDecoderCallback decode) { + ImageStreamCompleter loadImage( + ImmichLocalThumbnailProvider key, + ImageDecoderCallback decode, + ) { final chunkEvents = StreamController(); return MultiImageStreamCompleter( - codec: _codec(key, decode, chunkEvents), + codec: _codec(key.asset, decode, chunkEvents), scale: 1.0, chunkEvents: chunkEvents.stream, informationCollector: () sync* { diff --git a/mobile/lib/modules/asset_viewer/providers/asset_people.provider.g.dart b/mobile/lib/modules/asset_viewer/providers/asset_people.provider.g.dart index 449d5b6c8..df6ee779c 100644 --- a/mobile/lib/modules/asset_viewer/providers/asset_people.provider.g.dart +++ b/mobile/lib/modules/asset_viewer/providers/asset_people.provider.g.dart @@ -7,7 +7,7 @@ part of 'asset_people.provider.dart'; // ************************************************************************** String _$assetPeopleNotifierHash() => - r'192a4ee188f781000fe43f1675c49e1081ccc631'; + r'9835b180984a750c91e923e7b64dbda94f6d7574'; /// Copied from Dart SDK class _SystemHash { @@ -34,7 +34,7 @@ abstract class _$AssetPeopleNotifier extends BuildlessAutoDisposeAsyncNotifier< List> { late final Asset asset; - Future> build( + FutureOr> build( Asset asset, ); } @@ -127,7 +127,7 @@ class AssetPeopleNotifierProvider extends AutoDisposeAsyncNotifierProviderImpl< final Asset asset; @override - Future> runNotifierBuild( + FutureOr> runNotifierBuild( covariant AssetPeopleNotifier notifier, ) { return notifier.build( diff --git a/mobile/lib/modules/asset_viewer/providers/video_player_controller_provider.g.dart b/mobile/lib/modules/asset_viewer/providers/video_player_controller_provider.g.dart index a9b287e95..e447304b3 100644 --- a/mobile/lib/modules/asset_viewer/providers/video_player_controller_provider.g.dart +++ b/mobile/lib/modules/asset_viewer/providers/video_player_controller_provider.g.dart @@ -7,7 +7,7 @@ part of 'video_player_controller_provider.dart'; // ************************************************************************** String _$videoPlayerControllerHash() => - r'72b45de66542021717807655e25ec92d78d80eec'; + r'40b31f7b1a73fab84c311b0f06bedf5322143cd9'; /// Copied from Dart SDK class _SystemHash { diff --git a/mobile/lib/modules/backup/providers/backup_verification.provider.dart b/mobile/lib/modules/backup/providers/backup_verification.provider.dart new file mode 100644 index 000000000..1cc537913 --- /dev/null +++ b/mobile/lib/modules/backup/providers/backup_verification.provider.dart @@ -0,0 +1,109 @@ +import 'dart:async'; + +import 'package:connectivity_plus/connectivity_plus.dart'; +import 'package:flutter/material.dart'; +import 'package:immich_mobile/modules/backup/providers/backup.provider.dart'; +import 'package:immich_mobile/modules/backup/services/backup_verification.service.dart'; +import 'package:immich_mobile/shared/models/asset.dart'; +import 'package:immich_mobile/shared/providers/asset.provider.dart'; +import 'package:immich_mobile/shared/ui/confirm_dialog.dart'; +import 'package:immich_mobile/shared/ui/immich_toast.dart'; +import 'package:riverpod_annotation/riverpod_annotation.dart'; +import 'package:wakelock_plus/wakelock_plus.dart'; + +part 'backup_verification.provider.g.dart'; + +@riverpod +class BackupVerification extends _$BackupVerification { + @override + bool build() => false; + + void performBackupCheck(BuildContext context) async { + try { + state = true; + final backupState = ref.read(backupProvider); + + if (backupState.allUniqueAssets.length > + backupState.selectedAlbumsBackupAssetsIds.length) { + if (context.mounted) { + ImmichToast.show( + context: context, + msg: "Backup all assets before starting this check!", + toastType: ToastType.error, + ); + } + return; + } + final connection = await Connectivity().checkConnectivity(); + if (connection != ConnectivityResult.wifi) { + if (context.mounted) { + ImmichToast.show( + context: context, + msg: "Make sure to be connected to unmetered Wi-Fi", + toastType: ToastType.error, + ); + } + return; + } + WakelockPlus.enable(); + + const limit = 100; + final toDelete = await ref + .read(backupVerificationServiceProvider) + .findWronglyBackedUpAssets(limit: limit); + if (toDelete.isEmpty) { + if (context.mounted) { + ImmichToast.show( + context: context, + msg: "Did not find any corrupt asset backups!", + toastType: ToastType.success, + ); + } + } else { + if (context.mounted) { + await showDialog( + context: context, + builder: (ctx) => ConfirmDialog( + onOk: () => _performDeletion(context, toDelete), + title: "Corrupt backups!", + ok: "Delete", + content: + "Found ${toDelete.length} (max $limit at once) corrupt asset backups. " + "Run the check again to find more.\n" + "Do you want to delete the corrupt asset backups now?", + ), + ); + } + } + } finally { + WakelockPlus.disable(); + state = false; + } + } + + Future _performDeletion( + BuildContext context, + List assets, + ) async { + try { + state = true; + if (context.mounted) { + ImmichToast.show( + context: context, + msg: "Deleting ${assets.length} assets on the server...", + ); + } + await ref.read(assetProvider.notifier).deleteAssets(assets, force: true); + if (context.mounted) { + ImmichToast.show( + context: context, + msg: "Deleted ${assets.length} assets on the server. " + "You can now start a manual backup", + toastType: ToastType.success, + ); + } + } finally { + state = false; + } + } +} diff --git a/mobile/lib/modules/backup/providers/backup_verification.provider.g.dart b/mobile/lib/modules/backup/providers/backup_verification.provider.g.dart new file mode 100644 index 000000000..f222c9bd8 --- /dev/null +++ b/mobile/lib/modules/backup/providers/backup_verification.provider.g.dart @@ -0,0 +1,27 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'backup_verification.provider.dart'; + +// ************************************************************************** +// RiverpodGenerator +// ************************************************************************** + +String _$backupVerificationHash() => + r'b691e0cc27856eef189258d3c102cc73ce4812a4'; + +/// See also [BackupVerification]. +@ProviderFor(BackupVerification) +final backupVerificationProvider = + AutoDisposeNotifierProvider.internal( + BackupVerification.new, + name: r'backupVerificationProvider', + debugGetCreateSourceHash: const bool.fromEnvironment('dart.vm.product') + ? null + : _$backupVerificationHash, + dependencies: null, + allTransitiveDependencies: null, +); + +typedef _$BackupVerification = AutoDisposeNotifier; +// ignore_for_file: type=lint +// ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member, invalid_use_of_visible_for_testing_member diff --git a/mobile/lib/modules/backup/ui/album_info_card.dart b/mobile/lib/modules/backup/ui/album_info_card.dart index b962fbe05..0008c0a9e 100644 --- a/mobile/lib/modules/backup/ui/album_info_card.dart +++ b/mobile/lib/modules/backup/ui/album_info_card.dart @@ -142,7 +142,7 @@ class AlbumInfoCard extends HookConsumerWidget { image: imageData != null ? MemoryImage(imageData!) : const AssetImage( - 'assets/immich-logo-no-outline.png', + 'assets/immich-logo.png', ) as ImageProvider, fit: BoxFit.cover, ), diff --git a/mobile/lib/modules/backup/ui/album_info_list_tile.dart b/mobile/lib/modules/backup/ui/album_info_list_tile.dart index 484577f8c..c87bec09a 100644 --- a/mobile/lib/modules/backup/ui/album_info_list_tile.dart +++ b/mobile/lib/modules/backup/ui/album_info_list_tile.dart @@ -117,7 +117,7 @@ class AlbumInfoListTile extends HookConsumerWidget { image: imageData != null ? MemoryImage(imageData!) : const AssetImage( - 'assets/immich-logo-no-outline.png', + 'assets/immich-logo.png', ) as ImageProvider, fit: BoxFit.cover, ), diff --git a/mobile/lib/modules/backup/views/backup_options_page.dart b/mobile/lib/modules/backup/views/backup_options_page.dart index 8144f1b8e..b37ded6a6 100644 --- a/mobile/lib/modules/backup/views/backup_options_page.dart +++ b/mobile/lib/modules/backup/views/backup_options_page.dart @@ -1,487 +1,12 @@ -import 'dart:io'; - import 'package:auto_route/auto_route.dart'; -import 'package:connectivity_plus/connectivity_plus.dart'; -import 'package:easy_localization/easy_localization.dart'; import 'package:flutter/material.dart'; -import 'package:flutter_hooks/flutter_hooks.dart'; -import 'package:hooks_riverpod/hooks_riverpod.dart'; -import 'package:immich_mobile/extensions/build_context_extensions.dart'; -import 'package:immich_mobile/modules/backup/background_service/background.service.dart'; -import 'package:immich_mobile/modules/backup/models/backup_state.model.dart'; -import 'package:immich_mobile/modules/backup/providers/backup.provider.dart'; -import 'package:immich_mobile/modules/backup/providers/ios_background_settings.provider.dart'; -import 'package:immich_mobile/modules/backup/services/backup_verification.service.dart'; -import 'package:immich_mobile/modules/backup/ui/ios_debug_info_tile.dart'; -import 'package:immich_mobile/modules/settings/providers/app_settings.provider.dart'; -import 'package:immich_mobile/modules/settings/services/app_settings.service.dart'; -import 'package:immich_mobile/shared/models/asset.dart'; -import 'package:immich_mobile/shared/providers/asset.provider.dart'; -import 'package:immich_mobile/shared/ui/confirm_dialog.dart'; -import 'package:immich_mobile/shared/ui/immich_toast.dart'; -import 'package:permission_handler/permission_handler.dart'; -import 'package:url_launcher/url_launcher.dart'; -import 'package:wakelock_plus/wakelock_plus.dart'; +import 'package:immich_mobile/modules/settings/ui/backup_settings/backup_settings.dart'; @RoutePage() -class BackupOptionsPage extends HookConsumerWidget { +class BackupOptionsPage extends StatelessWidget { const BackupOptionsPage({super.key}); @override - Widget build(BuildContext context, WidgetRef ref) { - BackUpState backupState = ref.watch(backupProvider); - final settings = ref.watch(iOSBackgroundSettingsProvider.notifier).settings; - final settingsService = ref.watch(appSettingsServiceProvider); - final showBackupFix = Platform.isAndroid && - settingsService.getSetting(AppSettingsEnum.advancedTroubleshooting); - final ignoreIcloudAssets = useState( - settingsService.getSetting(AppSettingsEnum.ignoreIcloudAssets), - ); - final appRefreshDisabled = - Platform.isIOS && settings?.appRefreshEnabled != true; - final checkInProgress = useState(false); - - Future performDeletion(List assets) async { - try { - checkInProgress.value = true; - ImmichToast.show( - context: context, - msg: "Deleting ${assets.length} assets on the server...", - ); - await ref - .read(assetProvider.notifier) - .deleteAssets(assets, force: true); - ImmichToast.show( - context: context, - msg: "Deleted ${assets.length} assets on the server. " - "You can now start a manual backup", - toastType: ToastType.success, - ); - } finally { - checkInProgress.value = false; - } - } - - void performBackupCheck() async { - try { - checkInProgress.value = true; - if (backupState.allUniqueAssets.length > - backupState.selectedAlbumsBackupAssetsIds.length) { - ImmichToast.show( - context: context, - msg: "Backup all assets before starting this check!", - toastType: ToastType.error, - ); - return; - } - final connection = await Connectivity().checkConnectivity(); - if (connection != ConnectivityResult.wifi) { - ImmichToast.show( - context: context, - msg: "Make sure to be connected to unmetered Wi-Fi", - toastType: ToastType.error, - ); - return; - } - WakelockPlus.enable(); - const limit = 100; - final toDelete = await ref - .read(backupVerificationServiceProvider) - .findWronglyBackedUpAssets(limit: limit); - if (toDelete.isEmpty) { - ImmichToast.show( - context: context, - msg: "Did not find any corrupt asset backups!", - toastType: ToastType.success, - ); - } else { - await showDialog( - context: context, - builder: (context) => ConfirmDialog( - onOk: () => performDeletion(toDelete), - title: "Corrupt backups!", - ok: "Delete", - content: - "Found ${toDelete.length} (max $limit at once) corrupt asset backups. " - "Run the check again to find more.\n" - "Do you want to delete the corrupt asset backups now?", - ), - ); - } - } finally { - WakelockPlus.disable(); - checkInProgress.value = false; - } - } - - Widget buildCheckCorruptBackups() { - return ListTile( - leading: Icon( - Icons.warning_rounded, - color: context.primaryColor, - ), - title: const Text( - "Check for corrupt asset backups", - style: TextStyle(fontWeight: FontWeight.bold, fontSize: 14), - ), - isThreeLine: true, - subtitle: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - const Text("Run this check only over Wi-Fi and once all assets " - "have been backed-up. The procedure might take a few minutes."), - ElevatedButton( - onPressed: checkInProgress.value ? null : performBackupCheck, - child: checkInProgress.value - ? const CircularProgressIndicator() - : const Text("Perform check"), - ), - ], - ), - ); - } - - void showErrorToUser(String msg) { - final snackBar = SnackBar( - content: Text( - msg.tr(), - style: context.textTheme.bodyLarge?.copyWith( - color: context.primaryColor, - ), - ), - backgroundColor: Colors.red, - ); - ScaffoldMessenger.of(context).showSnackBar(snackBar); - } - - void showBatteryOptimizationInfoToUser() { - showDialog( - context: context, - barrierDismissible: false, - builder: (BuildContext context) { - return AlertDialog( - title: const Text( - 'backup_controller_page_background_battery_info_title', - ).tr(), - content: SingleChildScrollView( - child: const Text( - 'backup_controller_page_background_battery_info_message', - ).tr(), - ), - actions: [ - ElevatedButton( - onPressed: () => launchUrl( - Uri.parse('https://dontkillmyapp.com'), - mode: LaunchMode.externalApplication, - ), - child: const Text( - "backup_controller_page_background_battery_info_link", - style: TextStyle(fontWeight: FontWeight.bold, fontSize: 12), - ).tr(), - ), - ElevatedButton( - child: const Text( - 'backup_controller_page_background_battery_info_ok', - style: TextStyle(fontWeight: FontWeight.bold, fontSize: 12), - ).tr(), - onPressed: () { - context.pop(); - }, - ), - ], - ); - }, - ); - } - - Widget buildBackgroundBackupController() { - final bool isBackgroundEnabled = backupState.backgroundBackup; - final bool isWifiRequired = backupState.backupRequireWifi; - final bool isChargingRequired = backupState.backupRequireCharging; - final Color activeColor = context.primaryColor; - - String formatBackupDelaySliderValue(double v) { - if (v == 0.0) { - return 'setting_notifications_notify_seconds'.tr(args: const ['5']); - } else if (v == 1.0) { - return 'setting_notifications_notify_seconds'.tr(args: const ['30']); - } else if (v == 2.0) { - return 'setting_notifications_notify_minutes'.tr(args: const ['2']); - } else { - return 'setting_notifications_notify_minutes'.tr(args: const ['10']); - } - } - - int backupDelayToMilliseconds(double v) { - if (v == 0.0) { - return 5000; - } else if (v == 1.0) { - return 30000; - } else if (v == 2.0) { - return 120000; - } else { - return 600000; - } - } - - double backupDelayToSliderValue(int ms) { - if (ms == 5000) { - return 0.0; - } else if (ms == 30000) { - return 1.0; - } else if (ms == 120000) { - return 2.0; - } else { - return 3.0; - } - } - - final triggerDelay = - useState(backupDelayToSliderValue(backupState.backupTriggerDelay)); - - return Column( - children: [ - ListTile( - isThreeLine: true, - leading: isBackgroundEnabled - ? Icon( - Icons.cloud_sync_rounded, - color: activeColor, - ) - : const Icon(Icons.cloud_sync_rounded), - title: Text( - isBackgroundEnabled - ? "backup_controller_page_background_is_on" - : "backup_controller_page_background_is_off", - style: context.textTheme.titleSmall, - ).tr(), - subtitle: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - if (!isBackgroundEnabled) - Padding( - padding: const EdgeInsets.symmetric(vertical: 8.0), - child: const Text( - "backup_controller_page_background_description", - ).tr(), - ), - if (isBackgroundEnabled) - SwitchListTile.adaptive( - title: const Text("backup_controller_page_background_wifi") - .tr(), - secondary: Icon( - Icons.wifi, - color: isWifiRequired ? activeColor : null, - ), - dense: true, - activeColor: activeColor, - value: isWifiRequired, - onChanged: (isChecked) => ref - .read(backupProvider.notifier) - .configureBackgroundBackup( - requireWifi: isChecked, - onError: showErrorToUser, - onBatteryInfo: showBatteryOptimizationInfoToUser, - ), - ), - if (isBackgroundEnabled) - SwitchListTile.adaptive( - title: - const Text("backup_controller_page_background_charging") - .tr(), - secondary: Icon( - Icons.charging_station, - color: isChargingRequired ? activeColor : null, - ), - dense: true, - activeColor: activeColor, - value: isChargingRequired, - onChanged: (isChecked) => ref - .read(backupProvider.notifier) - .configureBackgroundBackup( - requireCharging: isChecked, - onError: showErrorToUser, - onBatteryInfo: showBatteryOptimizationInfoToUser, - ), - ), - if (isBackgroundEnabled && Platform.isAndroid) - ListTile( - isThreeLine: false, - dense: true, - title: const Text( - 'backup_controller_page_background_delay', - style: TextStyle( - fontWeight: FontWeight.bold, - ), - ).tr( - args: [formatBackupDelaySliderValue(triggerDelay.value)], - ), - subtitle: Slider( - value: triggerDelay.value, - onChanged: (double v) => triggerDelay.value = v, - onChangeEnd: (double v) => ref - .read(backupProvider.notifier) - .configureBackgroundBackup( - triggerDelay: backupDelayToMilliseconds(v), - onError: showErrorToUser, - onBatteryInfo: showBatteryOptimizationInfoToUser, - ), - max: 3.0, - divisions: 3, - label: formatBackupDelaySliderValue(triggerDelay.value), - activeColor: context.primaryColor, - ), - ), - ElevatedButton( - onPressed: () => ref - .read(backupProvider.notifier) - .configureBackgroundBackup( - enabled: !isBackgroundEnabled, - onError: showErrorToUser, - onBatteryInfo: showBatteryOptimizationInfoToUser, - ), - child: Text( - isBackgroundEnabled - ? "backup_controller_page_background_turn_off" - : "backup_controller_page_background_turn_on", - style: context.textTheme.labelLarge?.copyWith( - color: context.isDarkTheme ? Colors.black : Colors.white, - ), - ).tr(), - ), - ], - ), - ), - if (isBackgroundEnabled && Platform.isIOS) - FutureBuilder( - future: ref - .read(backgroundServiceProvider) - .getIOSBackgroundAppRefreshEnabled(), - builder: (context, snapshot) { - final enabled = snapshot.data; - // If it's not enabled, show them some kind of alert that says - // background refresh is not enabled - if (enabled != null && !enabled) {} - // If it's enabled, no need to bother them - return Container(); - }, - ), - if (Platform.isIOS && isBackgroundEnabled && settings != null) - IosDebugInfoTile( - settings: settings, - ), - ], - ); - } - - Widget buildBackgroundAppRefreshWarning() { - return ListTile( - isThreeLine: true, - leading: const Icon( - Icons.task_outlined, - ), - title: const Text( - 'backup_controller_page_background_app_refresh_disabled_title', - style: TextStyle( - fontWeight: FontWeight.bold, - fontSize: 14, - ), - ).tr(), - subtitle: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Padding( - padding: const EdgeInsets.symmetric(vertical: 8.0), - child: const Text( - 'backup_controller_page_background_app_refresh_disabled_content', - ).tr(), - ), - ElevatedButton( - onPressed: () => openAppSettings(), - child: const Text( - 'backup_controller_page_background_app_refresh_enable_button_text', - style: TextStyle( - fontWeight: FontWeight.bold, - fontSize: 12, - ), - ).tr(), - ), - ], - ), - ); - } - - ListTile buildAutoBackupController() { - final isAutoBackup = backupState.autoBackup; - final backUpOption = isAutoBackup - ? "backup_controller_page_status_on".tr() - : "backup_controller_page_status_off".tr(); - final backupBtnText = isAutoBackup - ? "backup_controller_page_turn_off".tr() - : "backup_controller_page_turn_on".tr(); - return ListTile( - isThreeLine: true, - leading: isAutoBackup - ? Icon( - Icons.cloud_done_rounded, - color: context.primaryColor, - ) - : const Icon(Icons.cloud_off_rounded), - title: Text( - backUpOption, - style: context.textTheme.titleSmall, - ), - subtitle: Padding( - padding: const EdgeInsets.symmetric(vertical: 8.0), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - if (!isAutoBackup) - const Text( - "backup_controller_page_desc_backup", - ).tr(), - Padding( - padding: const EdgeInsets.only(top: 8.0), - child: ElevatedButton( - onPressed: () => ref - .read(backupProvider.notifier) - .setAutoBackup(!isAutoBackup), - child: Text( - backupBtnText, - style: context.textTheme.labelLarge?.copyWith( - color: context.isDarkTheme ? Colors.black : Colors.white, - ), - ), - ), - ), - ], - ), - ), - ); - } - - void switchChanged(bool value) { - settingsService.setSetting(AppSettingsEnum.ignoreIcloudAssets, value); - ignoreIcloudAssets.value = value; - ref.invalidate(appSettingsServiceProvider); - } - - buildIgnoreIcloudAssetSetting() { - return [ - const Divider(), - SwitchListTile.adaptive( - title: const Text( - "Ignore iCloud photos", - style: TextStyle(fontWeight: FontWeight.bold), - ), - subtitle: const Text( - "Photos that are stored on iCloud will not be uploaded to the Immich server", - ), - value: ignoreIcloudAssets.value, - onChanged: switchChanged, - ), - ]; - } - + Widget build(BuildContext context) { return Scaffold( appBar: AppBar( elevation: 0, @@ -496,26 +21,7 @@ class BackupOptionsPage extends HookConsumerWidget { ), ), ), - body: Padding( - padding: const EdgeInsets.symmetric(horizontal: 16.0, vertical: 32.0), - child: ListView( - children: [ - buildAutoBackupController(), - const Divider(), - AnimatedSwitcher( - duration: const Duration(milliseconds: 500), - child: Platform.isIOS - ? (appRefreshDisabled - ? buildBackgroundAppRefreshWarning() - : buildBackgroundBackupController()) - : buildBackgroundBackupController(), - ), - if (Platform.isIOS) ...buildIgnoreIcloudAssetSetting(), - if (showBackupFix) const Divider(), - if (showBackupFix) buildCheckCorruptBackups(), - ], - ), - ), + body: const BackupSettings(), ); } } diff --git a/mobile/lib/modules/login/ui/login_form.dart b/mobile/lib/modules/login/ui/login_form.dart index 4c8a12bb2..5c7049a4e 100644 --- a/mobile/lib/modules/login/ui/login_form.dart +++ b/mobile/lib/modules/login/ui/login_form.dart @@ -402,7 +402,10 @@ class LoginForm extends HookConsumerWidget { ), ), ), - const ImmichTitleText(), + const Padding( + padding: EdgeInsets.only(top: 8.0, bottom: 16), + child: ImmichTitleText(), + ), ], ), const SizedBox(height: 18), diff --git a/mobile/lib/modules/login/views/login_page.dart b/mobile/lib/modules/login/views/login_page.dart index cb679fa1f..8593c1ee3 100644 --- a/mobile/lib/modules/login/views/login_page.dart +++ b/mobile/lib/modules/login/views/login_page.dart @@ -29,36 +29,38 @@ class LoginPage extends HookConsumerWidget { return Scaffold( body: const LoginForm(), - bottomNavigationBar: Padding( - padding: const EdgeInsets.only(bottom: 16.0), - child: SizedBox( - height: 50, - child: Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Text( - 'v${appVersion.value}', - style: const TextStyle( - color: Colors.grey, - fontWeight: FontWeight.bold, - fontFamily: "Inconsolata", - ), - ), - const Text(' '), - GestureDetector( - child: Text( - 'Logs', - style: TextStyle( - color: context.primaryColor, + bottomNavigationBar: SafeArea( + child: Padding( + padding: const EdgeInsets.only(bottom: 16.0), + child: SizedBox( + height: 50, + child: Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Text( + 'v${appVersion.value}', + style: const TextStyle( + color: Colors.grey, fontWeight: FontWeight.bold, fontFamily: "Inconsolata", ), ), - onTap: () { - context.pushRoute(const AppLogRoute()); - }, - ), - ], + const Text(' '), + GestureDetector( + child: Text( + 'Logs', + style: TextStyle( + color: context.primaryColor, + fontWeight: FontWeight.bold, + fontFamily: "Inconsolata", + ), + ), + onTap: () { + context.pushRoute(const AppLogRoute()); + }, + ), + ], + ), ), ), ), diff --git a/mobile/lib/modules/memories/views/memory_page.dart b/mobile/lib/modules/memories/views/memory_page.dart index d06bb959e..aa968303b 100644 --- a/mobile/lib/modules/memories/views/memory_page.dart +++ b/mobile/lib/modules/memories/views/memory_page.dart @@ -39,11 +39,13 @@ class MemoryPage extends HookConsumerWidget { /// The main vertically scrolling page controller with each list of memories final memoryPageController = usePageController(initialPage: memoryIndex); - // The Page Controller that scrolls horizontally with all of the assets useEffect(() { // Memories is an immersive activity SystemChrome.setEnabledSystemUIMode(SystemUiMode.immersive); - return null; + return () { + // Clean up to normal edge to edge when we are done + SystemChrome.setEnabledSystemUIMode(SystemUiMode.edgeToEdge); + }; }); toNextMemory() { @@ -159,127 +161,121 @@ class MemoryPage extends HookConsumerWidget { }, child: Scaffold( backgroundColor: bgColor, - body: PopScope( - onPopInvoked: (didPop) { - // Remove immersive mode and go back to normal mode - SystemChrome.setEnabledSystemUIMode(SystemUiMode.edgeToEdge); - }, - child: SafeArea( - child: PageView.builder( - physics: const BouncingScrollPhysics( - parent: AlwaysScrollableScrollPhysics(), - ), - scrollDirection: Axis.vertical, - controller: memoryPageController, - onPageChanged: (pageNumber) { - HapticFeedback.mediumImpact(); - if (pageNumber < memories.length) { - currentMemoryIndex.value = pageNumber; - currentMemory.value = memories[pageNumber]; - } + body: SafeArea( + child: PageView.builder( + physics: const BouncingScrollPhysics( + parent: AlwaysScrollableScrollPhysics(), + ), + scrollDirection: Axis.vertical, + controller: memoryPageController, + onPageChanged: (pageNumber) { + HapticFeedback.mediumImpact(); + if (pageNumber < memories.length) { + currentMemoryIndex.value = pageNumber; + currentMemory.value = memories[pageNumber]; + } - currentAssetPage.value = 0; + currentAssetPage.value = 0; - updateProgressText(); - }, - itemCount: memories.length + 1, - itemBuilder: (context, mIndex) { - // Build last page - if (mIndex == memories.length) { - return MemoryEpilogue( - onStartOver: () => memoryPageController.animateToPage( - 0, - duration: const Duration(seconds: 1), - curve: Curves.easeInOut, + updateProgressText(); + }, + itemCount: memories.length + 1, + itemBuilder: (context, mIndex) { + // Build last page + if (mIndex == memories.length) { + return MemoryEpilogue( + onStartOver: () => memoryPageController.animateToPage( + 0, + duration: const Duration(seconds: 1), + curve: Curves.easeInOut, + ), + ); + } + // Build horizontal page + final assetController = memoryAssetPageControllers[mIndex]; + return Column( + children: [ + Padding( + padding: const EdgeInsets.only( + left: 24.0, + right: 24.0, + top: 8.0, + bottom: 2.0, ), - ); - } - // Build horizontal page - final assetController = memoryAssetPageControllers[mIndex]; - return Column( - children: [ - Padding( - padding: const EdgeInsets.only( - left: 24.0, - right: 24.0, - top: 8.0, - bottom: 2.0, - ), - child: AnimatedBuilder( - animation: assetController, - builder: (context, child) { - double value = 0.0; - if (assetController.hasClients) { - // We can only access [page] if this has clients - value = assetController.page ?? 0; - } - return MemoryProgressIndicator( - ticks: memories[mIndex].assets.length, - value: (value + 1) / memories[mIndex].assets.length, - ); - }, - ), + child: AnimatedBuilder( + animation: assetController, + builder: (context, child) { + double value = 0.0; + if (assetController.hasClients) { + // We can only access [page] if this has clients + value = assetController.page ?? 0; + } + return MemoryProgressIndicator( + ticks: memories[mIndex].assets.length, + value: (value + 1) / memories[mIndex].assets.length, + ); + }, ), - Expanded( - child: Stack( - children: [ - PageView.builder( - physics: const BouncingScrollPhysics( - parent: AlwaysScrollableScrollPhysics(), - ), - controller: assetController, - onPageChanged: onAssetChanged, - scrollDirection: Axis.horizontal, - itemCount: memories[mIndex].assets.length, - itemBuilder: (context, index) { - final asset = memories[mIndex].assets[index]; - return GestureDetector( - behavior: HitTestBehavior.translucent, - onTap: () { - toNextAsset(index); - }, - child: Container( - color: Colors.black, - child: MemoryCard( - asset: asset, - title: memories[mIndex].title, - showTitle: index == 0, - ), + ), + Expanded( + child: Stack( + children: [ + PageView.builder( + physics: const BouncingScrollPhysics( + parent: AlwaysScrollableScrollPhysics(), + ), + controller: assetController, + onPageChanged: onAssetChanged, + scrollDirection: Axis.horizontal, + itemCount: memories[mIndex].assets.length, + itemBuilder: (context, index) { + final asset = memories[mIndex].assets[index]; + return GestureDetector( + behavior: HitTestBehavior.translucent, + onTap: () { + toNextAsset(index); + }, + child: Container( + color: Colors.black, + child: MemoryCard( + asset: asset, + title: memories[mIndex].title, + showTitle: index == 0, ), + ), + ); + }, + ), + Positioned( + top: 8, + left: 8, + child: MaterialButton( + minWidth: 0, + onPressed: () { + // auto_route doesn't invoke pop scope, so + // turn off full screen mode here + // https://github.com/Milad-Akarie/auto_route_library/issues/1799 + context.popRoute(); + SystemChrome.setEnabledSystemUIMode( + SystemUiMode.edgeToEdge, ); }, - ), - Positioned( - top: 8, - left: 8, - child: MaterialButton( - minWidth: 0, - onPressed: () { - // auto_route doesn't invoke pop scope, so - // turn off full screen mode here - // https://github.com/Milad-Akarie/auto_route_library/issues/1799 - context.popRoute(); - SystemChrome.setEnabledSystemUIMode( - SystemUiMode.edgeToEdge, - ); - }, - shape: const CircleBorder(), - color: Colors.white.withOpacity(0.2), - elevation: 0, - child: const Icon( - Icons.close_rounded, - color: Colors.white, - ), + shape: const CircleBorder(), + color: Colors.white.withOpacity(0.2), + elevation: 0, + child: const Icon( + Icons.close_rounded, + color: Colors.white, ), ), - ], - ), + ), + ], ), - MemoryBottomInfo(memory: memories[mIndex]), - ], - ); - }, - ), + ), + MemoryBottomInfo(memory: memories[mIndex]), + ], + ); + }, ), ), ), diff --git a/mobile/lib/modules/settings/models/store_model_here.txt b/mobile/lib/modules/settings/models/store_model_here.txt deleted file mode 100644 index e69de29bb..000000000 diff --git a/mobile/lib/modules/settings/ui/advanced_settings.dart b/mobile/lib/modules/settings/ui/advanced_settings.dart new file mode 100644 index 000000000..65089ac5b --- /dev/null +++ b/mobile/lib/modules/settings/ui/advanced_settings.dart @@ -0,0 +1,69 @@ +import 'dart:io'; +import 'package:easy_localization/easy_localization.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_hooks/flutter_hooks.dart' hide Store; +import 'package:immich_mobile/modules/settings/ui/local_storage_settings.dart'; +import 'package:immich_mobile/modules/settings/ui/settings_slider_list_tile.dart'; +import 'package:immich_mobile/modules/settings/ui/settings_sub_page_scaffold.dart'; +import 'package:immich_mobile/modules/settings/ui/settings_switch_list_tile.dart'; +import 'package:immich_mobile/modules/settings/utils/app_settings_update_hook.dart'; +import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:immich_mobile/modules/settings/services/app_settings.service.dart'; +import 'package:immich_mobile/shared/providers/user.provider.dart'; +import 'package:immich_mobile/shared/services/immich_logger.service.dart'; +import 'package:immich_mobile/utils/http_ssl_cert_override.dart'; +import 'package:logging/logging.dart'; + +class AdvancedSettings extends HookConsumerWidget { + const AdvancedSettings({super.key}); + @override + Widget build(BuildContext context, WidgetRef ref) { + bool isLoggedIn = ref.read(currentUserProvider) != null; + + final advancedTroubleshooting = + useAppSettingsState(AppSettingsEnum.advancedTroubleshooting); + final levelId = useAppSettingsState(AppSettingsEnum.logLevel); + final preferRemote = useAppSettingsState(AppSettingsEnum.preferRemoteImage); + final allowSelfSignedSSLCert = + useAppSettingsState(AppSettingsEnum.allowSelfSignedSSLCert); + + final logLevel = Level.LEVELS[levelId.value].name; + + useValueChanged( + levelId.value, + (_, __) => ImmichLogger().level = Level.LEVELS[levelId.value], + ); + + final advancedSettings = [ + SettingsSwitchListTile( + enabled: true, + valueNotifier: advancedTroubleshooting, + title: "advanced_settings_troubleshooting_title".tr(), + subtitle: "advanced_settings_troubleshooting_subtitle".tr(), + ), + SettingsSliderListTile( + text: "advanced_settings_log_level_title".tr(args: [logLevel]), + valueNotifier: levelId, + maxValue: 8, + minValue: 1, + noDivisons: 7, + label: logLevel, + ), + SettingsSwitchListTile( + valueNotifier: preferRemote, + title: "advanced_settings_prefer_remote_title".tr(), + subtitle: "advanced_settings_prefer_remote_subtitle".tr(), + ), + const LocalStorageSettings(), + SettingsSwitchListTile( + enabled: !isLoggedIn, + valueNotifier: allowSelfSignedSSLCert, + title: "advanced_settings_self_signed_ssl_title".tr(), + subtitle: "advanced_settings_self_signed_ssl_subtitle".tr(), + onChanged: (_) => HttpOverrides.global = HttpSSLCertOverride(), + ), + ]; + + return SettingsSubPageScaffold(settings: advancedSettings); + } +} diff --git a/mobile/lib/modules/settings/ui/advanced_settings/advanced_settings.dart b/mobile/lib/modules/settings/ui/advanced_settings/advanced_settings.dart deleted file mode 100644 index d0397fe5a..000000000 --- a/mobile/lib/modules/settings/ui/advanced_settings/advanced_settings.dart +++ /dev/null @@ -1,108 +0,0 @@ -import 'dart:io'; -import 'package:easy_localization/easy_localization.dart'; -import 'package:flutter/material.dart'; -import 'package:flutter_hooks/flutter_hooks.dart' show useEffect, useState; -import 'package:immich_mobile/extensions/build_context_extensions.dart'; -import 'package:immich_mobile/shared/models/store.dart'; -import 'package:hooks_riverpod/hooks_riverpod.dart'; -import 'package:immich_mobile/modules/settings/providers/app_settings.provider.dart'; -import 'package:immich_mobile/modules/settings/services/app_settings.service.dart'; -import 'package:immich_mobile/modules/settings/ui/settings_switch_list_tile.dart'; -import 'package:immich_mobile/shared/services/immich_logger.service.dart'; -import 'package:immich_mobile/utils/http_ssl_cert_override.dart'; -import 'package:logging/logging.dart'; - -class AdvancedSettings extends HookConsumerWidget { - const AdvancedSettings({super.key}); - @override - Widget build(BuildContext context, WidgetRef ref) { - bool isLoggedIn = Store.tryGet(StoreKey.currentUser) != null; - final appSettingService = ref.watch(appSettingsServiceProvider); - final isEnabled = - useState(AppSettingsEnum.advancedTroubleshooting.defaultValue); - final levelId = useState(AppSettingsEnum.logLevel.defaultValue); - final preferRemote = - useState(AppSettingsEnum.preferRemoteImage.defaultValue); - final allowSelfSignedSSLCert = - useState(AppSettingsEnum.allowSelfSignedSSLCert.defaultValue); - - useEffect( - () { - isEnabled.value = appSettingService.getSetting( - AppSettingsEnum.advancedTroubleshooting, - ); - levelId.value = appSettingService.getSetting(AppSettingsEnum.logLevel); - preferRemote.value = - appSettingService.getSetting(AppSettingsEnum.preferRemoteImage); - allowSelfSignedSSLCert.value = appSettingService - .getSetting(AppSettingsEnum.allowSelfSignedSSLCert); - return null; - }, - [], - ); - - final logLevel = Level.LEVELS[levelId.value].name; - - return ExpansionTile( - textColor: context.primaryColor, - title: Text( - "advanced_settings_tile_title", - style: context.textTheme.titleMedium, - ).tr(), - subtitle: const Text( - "advanced_settings_tile_subtitle", - ).tr(), - children: [ - SettingsSwitchListTile( - enabled: true, - appSettingService: appSettingService, - valueNotifier: isEnabled, - settingsEnum: AppSettingsEnum.advancedTroubleshooting, - title: "advanced_settings_troubleshooting_title".tr(), - subtitle: "advanced_settings_troubleshooting_subtitle".tr(), - ), - ListTile( - dense: true, - title: const Text( - "advanced_settings_log_level_title", - style: TextStyle(fontWeight: FontWeight.bold), - ).tr(args: [logLevel]), - subtitle: Slider( - value: levelId.value.toDouble(), - onChanged: (double v) => levelId.value = v.toInt(), - onChangeEnd: (double v) { - appSettingService.setSetting( - AppSettingsEnum.logLevel, - v.toInt(), - ); - ImmichLogger().level = Level.LEVELS[v.toInt()]; - }, - max: 8, - min: 1.0, - divisions: 7, - label: logLevel, - activeColor: context.primaryColor, - ), - ), - SettingsSwitchListTile( - appSettingService: appSettingService, - valueNotifier: preferRemote, - settingsEnum: AppSettingsEnum.preferRemoteImage, - title: "advanced_settings_prefer_remote_title".tr(), - subtitle: "advanced_settings_prefer_remote_subtitle".tr(), - ), - SettingsSwitchListTile( - enabled: !isLoggedIn, - appSettingService: appSettingService, - valueNotifier: allowSelfSignedSSLCert, - settingsEnum: AppSettingsEnum.allowSelfSignedSSLCert, - title: "advanced_settings_self_signed_ssl_title".tr(), - subtitle: "advanced_settings_self_signed_ssl_subtitle".tr(), - onChanged: (value) { - HttpOverrides.global = HttpSSLCertOverride(); - }, - ), - ], - ); - } -} diff --git a/mobile/lib/modules/settings/ui/asset_list_settings/asset_list_group_settings.dart b/mobile/lib/modules/settings/ui/asset_list_settings/asset_list_group_settings.dart new file mode 100644 index 000000000..8595973f2 --- /dev/null +++ b/mobile/lib/modules/settings/ui/asset_list_settings/asset_list_group_settings.dart @@ -0,0 +1,53 @@ +import 'package:easy_localization/easy_localization.dart'; +import 'package:flutter/material.dart'; +import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:immich_mobile/modules/home/ui/asset_grid/asset_grid_data_structure.dart'; +import 'package:immich_mobile/modules/settings/providers/app_settings.provider.dart'; +import 'package:immich_mobile/modules/settings/services/app_settings.service.dart'; +import 'package:immich_mobile/modules/settings/ui/settings_radio_list_tile.dart'; +import 'package:immich_mobile/modules/settings/ui/settings_sub_title.dart'; +import 'package:immich_mobile/modules/settings/utils/app_settings_update_hook.dart'; + +class GroupSettings extends HookConsumerWidget { + const GroupSettings({ + super.key, + }); + + @override + Widget build(BuildContext context, WidgetRef ref) { + final groupByIndex = useAppSettingsState(AppSettingsEnum.groupAssetsBy); + final groupBy = GroupAssetsBy.values[groupByIndex.value]; + + void changeGroupValue(GroupAssetsBy? value) { + if (value != null) { + groupByIndex.value = value.index; + ref.invalidate(appSettingsServiceProvider); + } + } + + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + SettingsSubTitle(title: "asset_list_group_by_sub_title".tr()), + SettingsRadioListTile( + groups: [ + SettingsRadioGroup( + title: 'asset_list_layout_settings_group_by_month_day'.tr(), + value: GroupAssetsBy.day, + ), + SettingsRadioGroup( + title: 'asset_list_layout_settings_group_by_month'.tr(), + value: GroupAssetsBy.month, + ), + SettingsRadioGroup( + title: 'asset_list_layout_settings_group_automatically'.tr(), + value: GroupAssetsBy.auto, + ), + ], + groupBy: groupBy, + onRadioChanged: changeGroupValue, + ), + ], + ); + } +} diff --git a/mobile/lib/modules/settings/ui/asset_list_settings/asset_list_layout_settings.dart b/mobile/lib/modules/settings/ui/asset_list_settings/asset_list_layout_settings.dart index 5ac22e131..099d091e2 100644 --- a/mobile/lib/modules/settings/ui/asset_list_settings/asset_list_layout_settings.dart +++ b/mobile/lib/modules/settings/ui/asset_list_settings/asset_list_layout_settings.dart @@ -1,11 +1,12 @@ import 'package:easy_localization/easy_localization.dart'; import 'package:flutter/material.dart'; -import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; -import 'package:immich_mobile/extensions/build_context_extensions.dart'; -import 'package:immich_mobile/modules/home/ui/asset_grid/asset_grid_data_structure.dart'; import 'package:immich_mobile/modules/settings/providers/app_settings.provider.dart'; import 'package:immich_mobile/modules/settings/services/app_settings.service.dart'; +import 'package:immich_mobile/modules/settings/ui/settings_slider_list_tile.dart'; +import 'package:immich_mobile/modules/settings/ui/settings_sub_title.dart'; +import 'package:immich_mobile/modules/settings/ui/settings_switch_list_tile.dart'; +import 'package:immich_mobile/modules/settings/utils/app_settings_update_hook.dart'; class LayoutSettings extends HookConsumerWidget { const LayoutSettings({ @@ -14,96 +15,27 @@ class LayoutSettings extends HookConsumerWidget { @override Widget build(BuildContext context, WidgetRef ref) { - final appSettingService = ref.watch(appSettingsServiceProvider); - - final useDynamicLayout = useState(true); - final groupBy = useState(GroupAssetsBy.day); - - void switchChanged(bool value) { - appSettingService.setSetting(AppSettingsEnum.dynamicLayout, value); - useDynamicLayout.value = value; - ref.invalidate(appSettingsServiceProvider); - } - - void changeGroupValue(GroupAssetsBy? value) { - if (value != null) { - appSettingService.setSetting( - AppSettingsEnum.groupAssetsBy, - value.index, - ); - groupBy.value = value; - ref.invalidate(appSettingsServiceProvider); - } - } - - useEffect( - () { - useDynamicLayout.value = - appSettingService.getSetting(AppSettingsEnum.dynamicLayout); - groupBy.value = GroupAssetsBy.values[ - appSettingService.getSetting(AppSettingsEnum.groupAssetsBy)]; - - return null; - }, - [], - ); + final useDynamicLayout = useAppSettingsState(AppSettingsEnum.dynamicLayout); + final tilesPerRow = useAppSettingsState(AppSettingsEnum.tilesPerRow); return Column( + crossAxisAlignment: CrossAxisAlignment.start, children: [ - SwitchListTile.adaptive( - activeColor: context.primaryColor, - title: Text( - "asset_list_layout_settings_dynamic_layout_title", - style: context.textTheme.labelLarge, - ).tr(), - onChanged: switchChanged, - value: useDynamicLayout.value, + SettingsSubTitle(title: "asset_list_layout_sub_title".tr()), + SettingsSwitchListTile( + valueNotifier: useDynamicLayout, + title: "asset_list_layout_settings_dynamic_layout_title".tr(), + onChanged: (_) => ref.invalidate(appSettingsServiceProvider), ), - const Divider( - indent: 18, - endIndent: 18, - ), - ListTile( - title: const Text( - "asset_list_layout_settings_group_by", - style: TextStyle( - fontSize: 16, - fontWeight: FontWeight.bold, - ), - ).tr(), - ), - RadioListTile( - activeColor: context.primaryColor, - title: Text( - "asset_list_layout_settings_group_by_month_day", - style: context.textTheme.labelLarge, - ).tr(), - value: GroupAssetsBy.day, - groupValue: groupBy.value, - onChanged: changeGroupValue, - controlAffinity: ListTileControlAffinity.trailing, - ), - RadioListTile( - activeColor: context.primaryColor, - title: Text( - "asset_list_layout_settings_group_by_month", - style: context.textTheme.labelLarge, - ).tr(), - value: GroupAssetsBy.month, - groupValue: groupBy.value, - onChanged: changeGroupValue, - controlAffinity: ListTileControlAffinity.trailing, - ), - RadioListTile( - activeColor: context.primaryColor, - title: Text( - "asset_list_layout_settings_group_automatically", - style: context.textTheme.labelLarge, - ).tr(), - value: GroupAssetsBy.auto, - groupValue: groupBy.value, - onChanged: changeGroupValue, - controlAffinity: ListTileControlAffinity.trailing, + SettingsSliderListTile( + valueNotifier: tilesPerRow, + text: 'theme_setting_asset_list_tiles_per_row_title' + .tr(args: ["${tilesPerRow.value}"]), + label: "${tilesPerRow.value}", + maxValue: 6, + minValue: 2, + noDivisons: 4, + onChangeEnd: (_) => ref.invalidate(appSettingsServiceProvider), ), ], ); diff --git a/mobile/lib/modules/settings/ui/asset_list_settings/asset_list_settings.dart b/mobile/lib/modules/settings/ui/asset_list_settings/asset_list_settings.dart index a2ad73ec8..82a64dc3e 100644 --- a/mobile/lib/modules/settings/ui/asset_list_settings/asset_list_settings.dart +++ b/mobile/lib/modules/settings/ui/asset_list_settings/asset_list_settings.dart @@ -1,31 +1,37 @@ import 'package:easy_localization/easy_localization.dart'; import 'package:flutter/material.dart'; -import 'package:immich_mobile/extensions/build_context_extensions.dart'; -import 'package:immich_mobile/modules/settings/ui/asset_list_settings/asset_list_layout_settings.dart'; -import 'package:immich_mobile/modules/settings/ui/asset_list_settings/asset_list_storage_indicator.dart'; -import 'asset_list_tiles_per_row.dart'; +import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:immich_mobile/modules/settings/providers/app_settings.provider.dart'; +import 'package:immich_mobile/modules/settings/services/app_settings.service.dart'; +import 'package:immich_mobile/modules/settings/ui/asset_list_settings/asset_list_group_settings.dart'; +import 'package:immich_mobile/modules/settings/ui/settings_sub_page_scaffold.dart'; +import 'package:immich_mobile/modules/settings/ui/settings_switch_list_tile.dart'; +import 'package:immich_mobile/modules/settings/utils/app_settings_update_hook.dart'; +import 'asset_list_layout_settings.dart'; -class AssetListSettings extends StatelessWidget { +class AssetListSettings extends HookConsumerWidget { const AssetListSettings({ super.key, }); @override - Widget build(BuildContext context) { - return ExpansionTile( - textColor: context.primaryColor, - title: Text( - 'asset_list_settings_title', - style: context.textTheme.titleMedium, - ).tr(), - subtitle: const Text( - 'asset_list_settings_subtitle', - ).tr(), - children: const [ - TilesPerRow(), - StorageIndicator(), - LayoutSettings(), - ], + Widget build(BuildContext context, WidgetRef ref) { + final showStorageIndicator = + useAppSettingsState(AppSettingsEnum.storageIndicator); + + final assetListSetting = [ + SettingsSwitchListTile( + valueNotifier: showStorageIndicator, + title: 'theme_setting_asset_list_storage_indicator_title'.tr(), + onChanged: (_) => ref.invalidate(appSettingsServiceProvider), + ), + const LayoutSettings(), + const GroupSettings(), + ]; + + return SettingsSubPageScaffold( + settings: assetListSetting, + showDivider: true, ); } } diff --git a/mobile/lib/modules/settings/ui/asset_list_settings/asset_list_storage_indicator.dart b/mobile/lib/modules/settings/ui/asset_list_settings/asset_list_storage_indicator.dart deleted file mode 100644 index 866e0a08f..000000000 --- a/mobile/lib/modules/settings/ui/asset_list_settings/asset_list_storage_indicator.dart +++ /dev/null @@ -1,46 +0,0 @@ -import 'package:easy_localization/easy_localization.dart'; -import 'package:flutter/material.dart'; -import 'package:flutter_hooks/flutter_hooks.dart'; -import 'package:hooks_riverpod/hooks_riverpod.dart'; -import 'package:immich_mobile/extensions/build_context_extensions.dart'; -import 'package:immich_mobile/modules/settings/providers/app_settings.provider.dart'; -import 'package:immich_mobile/modules/settings/services/app_settings.service.dart'; - -class StorageIndicator extends HookConsumerWidget { - const StorageIndicator({ - super.key, - }); - - @override - Widget build(BuildContext context, WidgetRef ref) { - final appSettingService = ref.watch(appSettingsServiceProvider); - - final showStorageIndicator = useState(true); - - void switchChanged(bool value) { - appSettingService.setSetting(AppSettingsEnum.storageIndicator, value); - showStorageIndicator.value = value; - ref.invalidate(appSettingsServiceProvider); - } - - useEffect( - () { - showStorageIndicator.value = appSettingService - .getSetting(AppSettingsEnum.storageIndicator); - - return null; - }, - [], - ); - - return SwitchListTile.adaptive( - activeColor: context.primaryColor, - title: Text( - "theme_setting_asset_list_storage_indicator_title", - style: context.textTheme.labelLarge, - ).tr(), - onChanged: switchChanged, - value: showStorageIndicator.value, - ); - } -} diff --git a/mobile/lib/modules/settings/ui/asset_list_settings/asset_list_tiles_per_row.dart b/mobile/lib/modules/settings/ui/asset_list_settings/asset_list_tiles_per_row.dart deleted file mode 100644 index 23690f907..000000000 --- a/mobile/lib/modules/settings/ui/asset_list_settings/asset_list_tiles_per_row.dart +++ /dev/null @@ -1,57 +0,0 @@ -import 'package:easy_localization/easy_localization.dart'; -import 'package:flutter/material.dart'; -import 'package:flutter_hooks/flutter_hooks.dart'; -import 'package:hooks_riverpod/hooks_riverpod.dart'; -import 'package:immich_mobile/extensions/build_context_extensions.dart'; -import 'package:immich_mobile/modules/settings/providers/app_settings.provider.dart'; -import 'package:immich_mobile/modules/settings/services/app_settings.service.dart'; - -class TilesPerRow extends HookConsumerWidget { - const TilesPerRow({ - super.key, - }); - - @override - Widget build(BuildContext context, WidgetRef ref) { - final appSettingService = ref.watch(appSettingsServiceProvider); - - final itemsValue = useState(4.0); - - void sliderChanged(double value) { - appSettingService.setSetting(AppSettingsEnum.tilesPerRow, value.toInt()); - itemsValue.value = value; - ref.invalidate(appSettingsServiceProvider); - } - - useEffect( - () { - int tilesPerRow = - appSettingService.getSetting(AppSettingsEnum.tilesPerRow); - itemsValue.value = tilesPerRow.toDouble(); - return null; - }, - [], - ); - - return Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - ListTile( - title: Text( - "theme_setting_asset_list_tiles_per_row_title", - style: context.textTheme.labelLarge, - ).tr(args: ["${itemsValue.value.toInt()}"]), - ), - Slider( - onChanged: sliderChanged, - value: itemsValue.value, - min: 2, - max: 6, - divisions: 4, - label: "${itemsValue.value.toInt()}", - activeColor: context.primaryColor, - ), - ], - ); - } -} diff --git a/mobile/lib/modules/settings/ui/backup_settings/background_settings.dart b/mobile/lib/modules/settings/ui/backup_settings/background_settings.dart new file mode 100644 index 000000000..73f7d120c --- /dev/null +++ b/mobile/lib/modules/settings/ui/backup_settings/background_settings.dart @@ -0,0 +1,234 @@ +import 'dart:io'; + +import 'package:easy_localization/easy_localization.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_hooks/flutter_hooks.dart'; +import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:immich_mobile/extensions/build_context_extensions.dart'; +import 'package:immich_mobile/modules/backup/providers/backup.provider.dart'; +import 'package:immich_mobile/modules/backup/providers/ios_background_settings.provider.dart'; +import 'package:immich_mobile/modules/backup/ui/ios_debug_info_tile.dart'; +import 'package:immich_mobile/modules/settings/ui/settings_button_list_tile.dart'; +import 'package:immich_mobile/modules/settings/ui/settings_slider_list_tile.dart'; +import 'package:immich_mobile/modules/settings/ui/settings_switch_list_tile.dart'; +import 'package:permission_handler/permission_handler.dart'; +import 'package:url_launcher/url_launcher.dart'; + +class BackgroundBackupSettings extends ConsumerWidget { + const BackgroundBackupSettings({super.key}); + + @override + Widget build(BuildContext context, WidgetRef ref) { + final isBackgroundEnabled = + ref.watch(backupProvider.select((s) => s.backgroundBackup)); + final iosSettings = ref.watch(iOSBackgroundSettingsProvider); + + void showErrorToUser(String msg) { + final snackBar = SnackBar( + content: Text( + msg.tr(), + style: context.textTheme.bodyLarge?.copyWith( + color: context.primaryColor, + ), + ), + backgroundColor: Colors.red, + ); + ScaffoldMessenger.of(context).showSnackBar(snackBar); + } + + void showBatteryOptimizationInfoToUser() { + showDialog( + context: context, + barrierDismissible: false, + builder: (BuildContext ctx) { + return AlertDialog( + title: const Text( + 'backup_controller_page_background_battery_info_title', + ).tr(), + content: SingleChildScrollView( + child: const Text( + 'backup_controller_page_background_battery_info_message', + ).tr(), + ), + actions: [ + ElevatedButton( + onPressed: () => launchUrl( + Uri.parse('https://dontkillmyapp.com'), + mode: LaunchMode.externalApplication, + ), + child: const Text( + "backup_controller_page_background_battery_info_link", + style: TextStyle(fontWeight: FontWeight.bold, fontSize: 12), + ).tr(), + ), + ElevatedButton( + child: const Text( + 'backup_controller_page_background_battery_info_ok', + style: TextStyle(fontWeight: FontWeight.bold, fontSize: 12), + ).tr(), + onPressed: () => ctx.pop(), + ), + ], + ); + }, + ); + } + + if (!isBackgroundEnabled) { + return SettingsButtonListTile( + icon: Icons.cloud_sync_outlined, + title: 'backup_controller_page_background_is_off'.tr(), + subtileText: 'backup_controller_page_background_description'.tr(), + buttonText: 'backup_controller_page_background_turn_on'.tr(), + onButtonTap: () => + ref.read(backupProvider.notifier).configureBackgroundBackup( + enabled: true, + onError: showErrorToUser, + onBatteryInfo: showBatteryOptimizationInfoToUser, + ), + ); + } + + return Column( + children: [ + if (!Platform.isIOS || iosSettings?.appRefreshEnabled == true) + _BackgroundSettingsEnabled( + onError: showErrorToUser, + onBatteryInfo: showBatteryOptimizationInfoToUser, + ), + if (Platform.isIOS && iosSettings?.appRefreshEnabled != true) + _IOSBackgroundRefreshDisabled(), + if (Platform.isIOS && iosSettings != null) + IosDebugInfoTile(settings: iosSettings), + ], + ); + } +} + +class _IOSBackgroundRefreshDisabled extends StatelessWidget { + @override + Widget build(BuildContext context) { + return SettingsButtonListTile( + icon: Icons.task_outlined, + title: + 'backup_controller_page_background_app_refresh_disabled_title'.tr(), + subtileText: + 'backup_controller_page_background_app_refresh_disabled_content'.tr(), + buttonText: + 'backup_controller_page_background_app_refresh_enable_button_text' + .tr(), + onButtonTap: () => openAppSettings(), + ); + } +} + +class _BackgroundSettingsEnabled extends HookConsumerWidget { + final void Function(String msg) onError; + final void Function() onBatteryInfo; + + const _BackgroundSettingsEnabled({ + required this.onError, + required this.onBatteryInfo, + }); + + @override + Widget build(BuildContext context, WidgetRef ref) { + final isWifiRequired = + ref.watch(backupProvider.select((s) => s.backupRequireWifi)); + final isWifiRequiredNotifier = useValueNotifier(isWifiRequired); + useValueChanged( + isWifiRequired, + (_, __) => WidgetsBinding.instance.addPostFrameCallback( + (_) => isWifiRequiredNotifier.value = isWifiRequired, + ), + ); + + final isChargingRequired = + ref.watch(backupProvider.select((s) => s.backupRequireCharging)); + final isChargingRequiredNotifier = useValueNotifier(isChargingRequired); + useValueChanged( + isChargingRequired, + (_, __) => WidgetsBinding.instance.addPostFrameCallback( + (_) => isChargingRequiredNotifier.value = isChargingRequired, + ), + ); + + int backupDelayToSliderValue(int ms) => switch (ms) { + 5000 => 0, + 30000 => 1, + 120000 => 2, + _ => 3, + }; + + int backupDelayToMilliseconds(int v) => + switch (v) { 0 => 5000, 1 => 30000, 2 => 120000, _ => 600000 }; + + String formatBackupDelaySliderValue(int v) => switch (v) { + 0 => 'setting_notifications_notify_seconds'.tr(args: const ['5']), + 1 => 'setting_notifications_notify_seconds'.tr(args: const ['30']), + 2 => 'setting_notifications_notify_minutes'.tr(args: const ['2']), + _ => 'setting_notifications_notify_minutes'.tr(args: const ['10']), + }; + + final backupTriggerDelay = + ref.watch(backupProvider.select((s) => s.backupTriggerDelay)); + final triggerDelay = useState(backupDelayToSliderValue(backupTriggerDelay)); + useValueChanged( + triggerDelay.value, + (_, __) => ref.read(backupProvider.notifier).configureBackgroundBackup( + triggerDelay: backupDelayToMilliseconds(triggerDelay.value), + onError: onError, + onBatteryInfo: onBatteryInfo, + ), + ); + + return SettingsButtonListTile( + icon: Icons.cloud_sync_rounded, + iconColor: context.primaryColor, + title: 'backup_controller_page_background_is_on'.tr(), + buttonText: 'backup_controller_page_background_turn_off'.tr(), + onButtonTap: () => + ref.read(backupProvider.notifier).configureBackgroundBackup( + enabled: false, + onError: onError, + onBatteryInfo: onBatteryInfo, + ), + subtitle: Column( + children: [ + SettingsSwitchListTile( + valueNotifier: isWifiRequiredNotifier, + title: 'backup_controller_page_background_wifi'.tr(), + icon: Icons.wifi, + onChanged: (enabled) => + ref.read(backupProvider.notifier).configureBackgroundBackup( + requireWifi: enabled, + onError: onError, + onBatteryInfo: onBatteryInfo, + ), + ), + SettingsSwitchListTile( + valueNotifier: isChargingRequiredNotifier, + title: 'backup_controller_page_background_charging'.tr(), + icon: Icons.charging_station, + onChanged: (enabled) => + ref.read(backupProvider.notifier).configureBackgroundBackup( + requireCharging: enabled, + onError: onError, + onBatteryInfo: onBatteryInfo, + ), + ), + if (Platform.isAndroid) + SettingsSliderListTile( + valueNotifier: triggerDelay, + text: 'backup_controller_page_background_delay'.tr( + args: [formatBackupDelaySliderValue(triggerDelay.value)], + ), + maxValue: 3.0, + noDivisons: 3, + label: formatBackupDelaySliderValue(triggerDelay.value), + ), + ], + ), + ); + } +} diff --git a/mobile/lib/modules/settings/ui/backup_settings/backup_settings.dart b/mobile/lib/modules/settings/ui/backup_settings/backup_settings.dart new file mode 100644 index 000000000..e095c8d05 --- /dev/null +++ b/mobile/lib/modules/settings/ui/backup_settings/backup_settings.dart @@ -0,0 +1,68 @@ +import 'dart:io'; + +import 'package:flutter/material.dart'; +import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:immich_mobile/modules/backup/providers/backup_verification.provider.dart'; +import 'package:immich_mobile/modules/settings/services/app_settings.service.dart'; +import 'package:immich_mobile/modules/settings/ui/backup_settings/background_settings.dart'; +import 'package:immich_mobile/modules/settings/ui/backup_settings/foreground_settings.dart'; +import 'package:immich_mobile/modules/settings/ui/settings_button_list_tile.dart'; +import 'package:immich_mobile/modules/settings/ui/settings_sub_page_scaffold.dart'; +import 'package:immich_mobile/modules/settings/ui/settings_switch_list_tile.dart'; +import 'package:immich_mobile/modules/settings/utils/app_settings_update_hook.dart'; +import 'package:immich_mobile/shared/ui/immich_loading_indicator.dart'; + +class BackupSettings extends HookConsumerWidget { + const BackupSettings({ + super.key, + }); + + @override + Widget build(BuildContext context, WidgetRef ref) { + final ignoreIcloudAssets = + useAppSettingsState(AppSettingsEnum.ignoreIcloudAssets); + final isAdvancedTroubleshooting = + useAppSettingsState(AppSettingsEnum.advancedTroubleshooting); + final isCorruptCheckInProgress = ref.watch(backupVerificationProvider); + + final backupSettings = [ + const ForegroundBackupSettings(), + const BackgroundBackupSettings(), + if (Platform.isIOS) + SettingsSwitchListTile( + valueNotifier: ignoreIcloudAssets, + title: 'Ignore iCloud photos', + subtitle: + 'Photos that are stored on iCloud will not be uploaded to the Immich server', + ), + if (Platform.isAndroid && isAdvancedTroubleshooting.value) + SettingsButtonListTile( + icon: Icons.warning_rounded, + title: 'Check for corrupt asset backups', + subtitle: isCorruptCheckInProgress + ? const Column( + children: [ + SizedBox(height: 20), + Center(child: ImmichLoadingIndicator()), + SizedBox(height: 20), + ], + ) + : null, + subtileText: !isCorruptCheckInProgress + ? 'Run this check only over Wi-Fi and once all assets have been backed-up. The procedure might take a few minutes.' + : null, + buttonText: 'Perform check', + onButtonTap: !isCorruptCheckInProgress + ? () => ref + .read(backupVerificationProvider.notifier) + .performBackupCheck(context) + : null, + ), + ]; + + return SettingsSubPageScaffold( + settings: backupSettings, + showDivider: true, + ); + } +} diff --git a/mobile/lib/modules/settings/ui/backup_settings/foreground_settings.dart b/mobile/lib/modules/settings/ui/backup_settings/foreground_settings.dart new file mode 100644 index 000000000..684fc95f2 --- /dev/null +++ b/mobile/lib/modules/settings/ui/backup_settings/foreground_settings.dart @@ -0,0 +1,36 @@ +import 'package:easy_localization/easy_localization.dart'; +import 'package:flutter/material.dart'; +import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:immich_mobile/extensions/build_context_extensions.dart'; +import 'package:immich_mobile/modules/backup/providers/backup.provider.dart'; +import 'package:immich_mobile/modules/settings/ui/settings_button_list_tile.dart'; + +class ForegroundBackupSettings extends ConsumerWidget { + const ForegroundBackupSettings({super.key}); + + @override + Widget build(BuildContext context, WidgetRef ref) { + final isAutoBackup = ref.watch(backupProvider.select((s) => s.autoBackup)); + + void onButtonTap() => + ref.read(backupProvider.notifier).setAutoBackup(!isAutoBackup); + + if (isAutoBackup) { + return SettingsButtonListTile( + icon: Icons.cloud_done_rounded, + iconColor: context.primaryColor, + title: 'backup_controller_page_status_on'.tr(), + buttonText: 'backup_controller_page_turn_off'.tr(), + onButtonTap: onButtonTap, + ); + } + + return SettingsButtonListTile( + icon: Icons.cloud_off_rounded, + title: 'backup_controller_page_status_off'.tr(), + subtileText: 'backup_controller_page_desc_backup'.tr(), + buttonText: 'backup_controller_page_turn_on'.tr(), + onButtonTap: onButtonTap, + ); + } +} diff --git a/mobile/lib/modules/settings/ui/image_viewer_quality_setting.dart b/mobile/lib/modules/settings/ui/image_viewer_quality_setting.dart new file mode 100644 index 000000000..21753ef54 --- /dev/null +++ b/mobile/lib/modules/settings/ui/image_viewer_quality_setting.dart @@ -0,0 +1,41 @@ +import 'package:easy_localization/easy_localization.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_hooks/flutter_hooks.dart'; +import 'package:immich_mobile/extensions/build_context_extensions.dart'; +import 'package:immich_mobile/modules/settings/services/app_settings.service.dart'; +import 'package:immich_mobile/modules/settings/ui/settings_sub_page_scaffold.dart'; +import 'package:immich_mobile/modules/settings/ui/settings_switch_list_tile.dart'; +import 'package:immich_mobile/modules/settings/utils/app_settings_update_hook.dart'; + +class ImageViewerQualitySetting extends HookWidget { + const ImageViewerQualitySetting({ + super.key, + }); + + @override + Widget build(BuildContext context) { + final isPreview = useAppSettingsState(AppSettingsEnum.loadPreview); + final isOriginal = useAppSettingsState(AppSettingsEnum.loadOriginal); + + final viewerSettings = [ + ListTile( + title: Text( + 'setting_image_viewer_help', + style: context.textTheme.bodyMedium, + ).tr(), + ), + SettingsSwitchListTile( + valueNotifier: isPreview, + title: "setting_image_viewer_preview_title".tr(), + subtitle: "setting_image_viewer_preview_subtitle".tr(), + ), + SettingsSwitchListTile( + valueNotifier: isOriginal, + title: "setting_image_viewer_original_title".tr(), + subtitle: "setting_image_viewer_original_subtitle".tr(), + ), + ]; + + return SettingsSubPageScaffold(settings: viewerSettings); + } +} diff --git a/mobile/lib/modules/settings/ui/image_viewer_quality_setting/image_viewer_quality_setting.dart b/mobile/lib/modules/settings/ui/image_viewer_quality_setting/image_viewer_quality_setting.dart deleted file mode 100644 index bd77043a8..000000000 --- a/mobile/lib/modules/settings/ui/image_viewer_quality_setting/image_viewer_quality_setting.dart +++ /dev/null @@ -1,62 +0,0 @@ -import 'package:easy_localization/easy_localization.dart'; -import 'package:flutter/material.dart'; -import 'package:flutter_hooks/flutter_hooks.dart'; -import 'package:hooks_riverpod/hooks_riverpod.dart'; -import 'package:immich_mobile/extensions/build_context_extensions.dart'; -import 'package:immich_mobile/modules/settings/providers/app_settings.provider.dart'; -import 'package:immich_mobile/modules/settings/services/app_settings.service.dart'; -import 'package:immich_mobile/modules/settings/ui/settings_switch_list_tile.dart'; - -class ImageViewerQualitySetting extends HookConsumerWidget { - const ImageViewerQualitySetting({ - super.key, - }); - - @override - Widget build(BuildContext context, WidgetRef ref) { - final settings = ref.watch(appSettingsServiceProvider); - final isPreview = useState(AppSettingsEnum.loadPreview.defaultValue); - final isOriginal = useState(AppSettingsEnum.loadOriginal.defaultValue); - - useEffect( - () { - isPreview.value = settings.getSetting(AppSettingsEnum.loadPreview); - isOriginal.value = settings.getSetting(AppSettingsEnum.loadOriginal); - return null; - }, - ); - - return ExpansionTile( - textColor: context.primaryColor, - title: Text( - 'theme_setting_image_viewer_quality_title', - style: context.textTheme.titleMedium, - ).tr(), - subtitle: const Text( - 'theme_setting_image_viewer_quality_subtitle', - ).tr(), - children: [ - ListTile( - title: Text( - 'setting_image_viewer_help', - style: context.textTheme.bodyMedium, - ).tr(), - ), - SettingsSwitchListTile( - appSettingService: settings, - valueNotifier: isPreview, - settingsEnum: AppSettingsEnum.loadPreview, - title: "setting_image_viewer_preview_title".tr(), - subtitle: "setting_image_viewer_preview_subtitle".tr(), - ), - SettingsSwitchListTile( - appSettingService: settings, - valueNotifier: isOriginal, - settingsEnum: AppSettingsEnum.loadOriginal, - title: "setting_image_viewer_original_title".tr(), - subtitle: "setting_image_viewer_original_subtitle".tr(), - ), - ], - ); - } -} diff --git a/mobile/lib/modules/settings/ui/local_storage_settings.dart b/mobile/lib/modules/settings/ui/local_storage_settings.dart new file mode 100644 index 000000000..1547ce35e --- /dev/null +++ b/mobile/lib/modules/settings/ui/local_storage_settings.dart @@ -0,0 +1,54 @@ +import 'package:easy_localization/easy_localization.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_hooks/flutter_hooks.dart' show useEffect, useState; +import 'package:immich_mobile/extensions/build_context_extensions.dart'; +import 'package:immich_mobile/modules/backup/models/duplicated_asset.model.dart'; +import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:immich_mobile/shared/providers/db.provider.dart'; + +class LocalStorageSettings extends HookConsumerWidget { + const LocalStorageSettings({super.key}); + @override + Widget build(BuildContext context, WidgetRef ref) { + final isarDb = ref.watch(dbProvider); + final cacheItemCount = useState(0); + + useEffect( + () { + cacheItemCount.value = isarDb.duplicatedAssets.countSync(); + return null; + }, + [], + ); + + void clearCache() async { + await isarDb.writeTxn(() => isarDb.duplicatedAssets.clear()); + cacheItemCount.value = await isarDb.duplicatedAssets.count(); + } + + return ListTile( + contentPadding: const EdgeInsets.symmetric(horizontal: 20), + dense: true, + title: Text( + "cache_settings_duplicated_assets_title", + style: context.textTheme.bodyLarge?.copyWith( + fontWeight: FontWeight.w500, + ), + ).tr(args: ["${cacheItemCount.value}"]), + subtitle: const Text( + "cache_settings_duplicated_assets_subtitle", + ).tr(), + trailing: TextButton( + onPressed: cacheItemCount.value > 0 ? clearCache : null, + child: Text( + "cache_settings_duplicated_assets_clear_button", + style: TextStyle( + fontSize: 12, + color: cacheItemCount.value > 0 ? Colors.red : Colors.grey, + fontWeight: FontWeight.bold, + ), + ).tr(), + ), + ); + } +} diff --git a/mobile/lib/modules/settings/ui/local_storage_settings/local_storage_settings.dart b/mobile/lib/modules/settings/ui/local_storage_settings/local_storage_settings.dart deleted file mode 100644 index a64da0481..000000000 --- a/mobile/lib/modules/settings/ui/local_storage_settings/local_storage_settings.dart +++ /dev/null @@ -1,61 +0,0 @@ -import 'package:easy_localization/easy_localization.dart'; -import 'package:flutter/material.dart'; -import 'package:flutter_hooks/flutter_hooks.dart' show useEffect, useState; -import 'package:immich_mobile/extensions/build_context_extensions.dart'; -import 'package:immich_mobile/modules/backup/models/duplicated_asset.model.dart'; -import 'package:hooks_riverpod/hooks_riverpod.dart'; -import 'package:immich_mobile/shared/providers/db.provider.dart'; - -class LocalStorageSettings extends HookConsumerWidget { - const LocalStorageSettings({super.key}); - @override - Widget build(BuildContext context, WidgetRef ref) { - final isarDb = ref.watch(dbProvider); - final cacheItemCount = useState(0); - useEffect( - () { - cacheItemCount.value = isarDb.duplicatedAssets.countSync(); - return null; - }, - [], - ); - - void clearCache() { - isarDb.writeTxnSync(() => isarDb.duplicatedAssets.clearSync()); - cacheItemCount.value = isarDb.duplicatedAssets.countSync(); - } - - return ExpansionTile( - textColor: context.primaryColor, - title: Text( - "cache_settings_tile_title", - style: context.textTheme.titleMedium, - ).tr(), - subtitle: const Text( - "cache_settings_tile_subtitle", - ).tr(), - children: [ - ListTile( - title: Text( - "cache_settings_duplicated_assets_title", - style: context.textTheme.titleSmall, - ).tr(args: ["${cacheItemCount.value}"]), - subtitle: const Text( - "cache_settings_duplicated_assets_subtitle", - ).tr(), - trailing: TextButton( - onPressed: cacheItemCount.value > 0 ? clearCache : null, - child: Text( - "cache_settings_duplicated_assets_clear_button", - style: TextStyle( - fontSize: 12, - color: cacheItemCount.value > 0 ? Colors.red : Colors.grey, - fontWeight: FontWeight.bold, - ), - ).tr(), - ), - ), - ], - ); - } -} diff --git a/mobile/lib/modules/settings/ui/notification_setting.dart b/mobile/lib/modules/settings/ui/notification_setting.dart new file mode 100644 index 000000000..0d7f0f5b4 --- /dev/null +++ b/mobile/lib/modules/settings/ui/notification_setting.dart @@ -0,0 +1,118 @@ +import 'package:easy_localization/easy_localization.dart'; +import 'package:flutter/material.dart'; +import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:immich_mobile/extensions/build_context_extensions.dart'; +import 'package:immich_mobile/modules/settings/providers/notification_permission.provider.dart'; +import 'package:immich_mobile/modules/settings/services/app_settings.service.dart'; +import 'package:immich_mobile/modules/settings/ui/settings_button_list_tile.dart'; +import 'package:immich_mobile/modules/settings/ui/settings_slider_list_tile.dart'; +import 'package:immich_mobile/modules/settings/ui/settings_sub_page_scaffold.dart'; +import 'package:immich_mobile/modules/settings/ui/settings_switch_list_tile.dart'; +import 'package:immich_mobile/modules/settings/utils/app_settings_update_hook.dart'; +import 'package:permission_handler/permission_handler.dart'; + +class NotificationSetting extends HookConsumerWidget { + const NotificationSetting({ + super.key, + }); + + @override + Widget build(BuildContext context, WidgetRef ref) { + final permissionService = ref.watch(notificationPermissionProvider); + + final sliderValue = + useAppSettingsState(AppSettingsEnum.uploadErrorNotificationGracePeriod); + final totalProgressValue = + useAppSettingsState(AppSettingsEnum.backgroundBackupTotalProgress); + final singleProgressValue = + useAppSettingsState(AppSettingsEnum.backgroundBackupSingleProgress); + + final hasPermission = permissionService == PermissionStatus.granted; + + openAppNotificationSettings(BuildContext ctx) { + ctx.pop(); + openAppSettings(); + } + + // When permissions are permanently denied, you need to go to settings to + // allow them + showPermissionsDialog() { + showDialog( + context: context, + builder: (ctx) => AlertDialog( + content: const Text('notification_permission_dialog_content').tr(), + actions: [ + TextButton( + child: const Text('notification_permission_dialog_cancel').tr(), + onPressed: () => ctx.pop(), + ), + TextButton( + onPressed: () => openAppNotificationSettings(ctx), + child: const Text('notification_permission_dialog_settings').tr(), + ), + ], + ), + ); + } + + final String formattedValue = + _formatSliderValue(sliderValue.value.toDouble()); + + final notificationSettings = [ + if (!hasPermission) + SettingsButtonListTile( + icon: Icons.notifications_outlined, + title: 'notification_permission_list_tile_title'.tr(), + subtileText: 'notification_permission_list_tile_content'.tr(), + buttonText: 'notification_permission_list_tile_enable_button'.tr(), + onButtonTap: () => ref + .watch(notificationPermissionProvider.notifier) + .requestNotificationPermission() + .then((permission) { + if (permission == PermissionStatus.permanentlyDenied) { + showPermissionsDialog(); + } + }), + ), + SettingsSwitchListTile( + enabled: hasPermission, + valueNotifier: totalProgressValue, + title: 'setting_notifications_total_progress_title'.tr(), + subtitle: 'setting_notifications_total_progress_subtitle'.tr(), + ), + SettingsSwitchListTile( + enabled: hasPermission, + valueNotifier: singleProgressValue, + title: 'setting_notifications_single_progress_title'.tr(), + subtitle: 'setting_notifications_single_progress_subtitle'.tr(), + ), + SettingsSliderListTile( + enabled: hasPermission, + valueNotifier: sliderValue, + text: 'setting_notifications_notify_failures_grace_period' + .tr(args: [formattedValue]), + maxValue: 5.0, + noDivisons: 5, + label: formattedValue, + ), + ]; + + return SettingsSubPageScaffold(settings: notificationSettings); + } +} + +String _formatSliderValue(double v) { + if (v == 0.0) { + return 'setting_notifications_notify_immediately'.tr(); + } else if (v == 1.0) { + return 'setting_notifications_notify_minutes'.tr(args: const ['30']); + } else if (v == 2.0) { + return 'setting_notifications_notify_hours'.tr(args: const ['2']); + } else if (v == 3.0) { + return 'setting_notifications_notify_hours'.tr(args: const ['8']); + } else if (v == 4.0) { + return 'setting_notifications_notify_hours'.tr(args: const ['24']); + } else { + return 'setting_notifications_notify_never'.tr(); + } +} diff --git a/mobile/lib/modules/settings/ui/notification_setting/notification_setting.dart b/mobile/lib/modules/settings/ui/notification_setting/notification_setting.dart deleted file mode 100644 index e696c9f1a..000000000 --- a/mobile/lib/modules/settings/ui/notification_setting/notification_setting.dart +++ /dev/null @@ -1,168 +0,0 @@ -import 'package:easy_localization/easy_localization.dart'; -import 'package:flutter/material.dart'; -import 'package:flutter_hooks/flutter_hooks.dart'; -import 'package:hooks_riverpod/hooks_riverpod.dart'; -import 'package:immich_mobile/extensions/build_context_extensions.dart'; -import 'package:immich_mobile/modules/settings/providers/app_settings.provider.dart'; -import 'package:immich_mobile/modules/settings/providers/notification_permission.provider.dart'; -import 'package:immich_mobile/modules/settings/services/app_settings.service.dart'; -import 'package:immich_mobile/modules/settings/ui/settings_switch_list_tile.dart'; -import 'package:permission_handler/permission_handler.dart'; - -class NotificationSetting extends HookConsumerWidget { - const NotificationSetting({ - super.key, - }); - - @override - Widget build(BuildContext context, WidgetRef ref) { - final appSettingService = ref.watch(appSettingsServiceProvider); - final permissionService = ref.watch(notificationPermissionProvider); - - final sliderValue = useState(0.0); - final totalProgressValue = - useState(AppSettingsEnum.backgroundBackupTotalProgress.defaultValue); - final singleProgressValue = - useState(AppSettingsEnum.backgroundBackupSingleProgress.defaultValue); - final hasPermission = permissionService == PermissionStatus.granted; - - useEffect( - () { - sliderValue.value = appSettingService - .getSetting(AppSettingsEnum.uploadErrorNotificationGracePeriod) - .toDouble(); - totalProgressValue.value = appSettingService - .getSetting(AppSettingsEnum.backgroundBackupTotalProgress); - singleProgressValue.value = appSettingService - .getSetting(AppSettingsEnum.backgroundBackupSingleProgress); - return null; - }, - [], - ); - - // When permissions are permanently denied, you need to go to settings to - // allow them - showPermissionsDialog() { - showDialog( - context: context, - builder: (context) => AlertDialog( - content: const Text('notification_permission_dialog_content').tr(), - actions: [ - TextButton( - child: const Text('notification_permission_dialog_cancel').tr(), - onPressed: () => context.pop(), - ), - TextButton( - child: const Text('notification_permission_dialog_settings').tr(), - onPressed: () { - context.pop(); - openAppSettings(); - }, - ), - ], - ), - ); - } - - final String formattedValue = _formatSliderValue(sliderValue.value); - return ExpansionTile( - textColor: context.primaryColor, - title: Text( - 'setting_notifications_title', - style: context.textTheme.titleMedium, - ).tr(), - subtitle: const Text( - 'setting_notifications_subtitle', - ).tr(), - children: [ - if (!hasPermission) - ListTile( - leading: const Icon(Icons.notifications_outlined), - title: Text( - 'notification_permission_list_tile_title', - style: context.textTheme.labelLarge - ?.copyWith(fontWeight: FontWeight.bold), - ).tr(), - subtitle: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - 'notification_permission_list_tile_content', - style: context.textTheme.labelMedium, - ).tr(), - const SizedBox(height: 8), - ElevatedButton( - onPressed: () => ref - .watch(notificationPermissionProvider.notifier) - .requestNotificationPermission() - .then((permission) { - if (permission == PermissionStatus.permanentlyDenied) { - showPermissionsDialog(); - } - }), - child: const Text( - 'notification_permission_list_tile_enable_button', - ).tr(), - ), - ], - ), - isThreeLine: true, - ), - SettingsSwitchListTile( - enabled: hasPermission, - appSettingService: appSettingService, - valueNotifier: totalProgressValue, - settingsEnum: AppSettingsEnum.backgroundBackupTotalProgress, - title: 'setting_notifications_total_progress_title'.tr(), - subtitle: 'setting_notifications_total_progress_subtitle'.tr(), - ), - SettingsSwitchListTile( - enabled: hasPermission, - appSettingService: appSettingService, - valueNotifier: singleProgressValue, - settingsEnum: AppSettingsEnum.backgroundBackupSingleProgress, - title: 'setting_notifications_single_progress_title'.tr(), - subtitle: 'setting_notifications_single_progress_subtitle'.tr(), - ), - ListTile( - enabled: hasPermission, - isThreeLine: false, - dense: true, - title: const Text( - 'setting_notifications_notify_failures_grace_period', - style: TextStyle(fontWeight: FontWeight.bold), - ).tr(args: [formattedValue]), - subtitle: Slider( - value: sliderValue.value, - onChanged: - !hasPermission ? null : (double v) => sliderValue.value = v, - onChangeEnd: (double v) => appSettingService.setSetting( - AppSettingsEnum.uploadErrorNotificationGracePeriod, - v.toInt(), - ), - max: 5.0, - divisions: 5, - label: formattedValue, - activeColor: context.primaryColor, - ), - ), - ], - ); - } -} - -String _formatSliderValue(double v) { - if (v == 0.0) { - return 'setting_notifications_notify_immediately'.tr(); - } else if (v == 1.0) { - return 'setting_notifications_notify_minutes'.tr(args: const ['30']); - } else if (v == 2.0) { - return 'setting_notifications_notify_hours'.tr(args: const ['2']); - } else if (v == 3.0) { - return 'setting_notifications_notify_hours'.tr(args: const ['8']); - } else if (v == 4.0) { - return 'setting_notifications_notify_hours'.tr(args: const ['24']); - } else { - return 'setting_notifications_notify_never'.tr(); - } -} diff --git a/mobile/lib/modules/settings/ui/preference_settings/preference_setting.dart b/mobile/lib/modules/settings/ui/preference_settings/preference_setting.dart new file mode 100644 index 000000000..f75891437 --- /dev/null +++ b/mobile/lib/modules/settings/ui/preference_settings/preference_setting.dart @@ -0,0 +1,18 @@ +import 'package:flutter/material.dart'; +import 'package:immich_mobile/modules/settings/ui/preference_settings/theme_setting.dart'; +import 'package:immich_mobile/modules/settings/ui/settings_sub_page_scaffold.dart'; + +class PreferenceSetting extends StatelessWidget { + const PreferenceSetting({ + super.key, + }); + + @override + Widget build(BuildContext context) { + const preferenceSettings = [ + ThemeSetting(), + ]; + + return const SettingsSubPageScaffold(settings: preferenceSettings); + } +} diff --git a/mobile/lib/modules/settings/ui/preference_settings/theme_setting.dart b/mobile/lib/modules/settings/ui/preference_settings/theme_setting.dart new file mode 100644 index 000000000..3dd023a45 --- /dev/null +++ b/mobile/lib/modules/settings/ui/preference_settings/theme_setting.dart @@ -0,0 +1,81 @@ +import 'package:easy_localization/easy_localization.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_hooks/flutter_hooks.dart'; +import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:immich_mobile/modules/settings/services/app_settings.service.dart'; +import 'package:immich_mobile/modules/settings/ui/settings_sub_title.dart'; +import 'package:immich_mobile/modules/settings/ui/settings_switch_list_tile.dart'; +import 'package:immich_mobile/modules/settings/utils/app_settings_update_hook.dart'; +import 'package:immich_mobile/utils/immich_app_theme.dart'; + +class ThemeSetting extends HookConsumerWidget { + const ThemeSetting({ + super.key, + }); + + @override + Widget build(BuildContext context, WidgetRef ref) { + final currentThemeString = useAppSettingsState(AppSettingsEnum.themeMode); + final currentTheme = useValueNotifier(ref.read(immichThemeProvider)); + final isDarkTheme = useValueNotifier(currentTheme.value == ThemeMode.dark); + final isSystemTheme = + useValueNotifier(currentTheme.value == ThemeMode.system); + + useValueChanged( + currentThemeString.value, + (_, __) => currentTheme.value = switch (currentThemeString.value) { + "light" => ThemeMode.light, + "dark" => ThemeMode.dark, + _ => ThemeMode.system, + }, + ); + + void onThemeChange(bool isDark) { + if (isDark) { + ref.watch(immichThemeProvider.notifier).state = ThemeMode.dark; + currentThemeString.value = "dark"; + } else { + ref.watch(immichThemeProvider.notifier).state = ThemeMode.light; + currentThemeString.value = "light"; + } + } + + void onSystemThemeChange(bool isSystem) { + if (isSystem) { + currentThemeString.value = "system"; + isSystemTheme.value = true; + ref.watch(immichThemeProvider.notifier).state = ThemeMode.system; + } else { + final currentSystemBrightness = + MediaQuery.platformBrightnessOf(context); + isSystemTheme.value = false; + isDarkTheme.value = currentSystemBrightness == Brightness.dark; + if (currentSystemBrightness == Brightness.light) { + currentThemeString.value = "light"; + ref.watch(immichThemeProvider.notifier).state = ThemeMode.light; + } else if (currentSystemBrightness == Brightness.dark) { + currentThemeString.value = "dark"; + ref.watch(immichThemeProvider.notifier).state = ThemeMode.dark; + } + } + } + + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + SettingsSubTitle(title: "theme_setting_theme_title".tr()), + SettingsSwitchListTile( + valueNotifier: isSystemTheme, + title: 'theme_setting_system_theme_switch'.tr(), + onChanged: onSystemThemeChange, + ), + if (currentTheme.value != ThemeMode.system) + SettingsSwitchListTile( + valueNotifier: isDarkTheme, + title: 'theme_setting_dark_mode_switch'.tr(), + onChanged: onThemeChange, + ), + ], + ); + } +} diff --git a/mobile/lib/modules/settings/ui/settings_button_list_tile.dart b/mobile/lib/modules/settings/ui/settings_button_list_tile.dart new file mode 100644 index 000000000..fca5b878d --- /dev/null +++ b/mobile/lib/modules/settings/ui/settings_button_list_tile.dart @@ -0,0 +1,50 @@ +import 'package:flutter/material.dart'; +import 'package:immich_mobile/extensions/build_context_extensions.dart'; + +class SettingsButtonListTile extends StatelessWidget { + final IconData icon; + final Color? iconColor; + final String title; + final Widget? subtitle; + final String? subtileText; + final String buttonText; + final void Function()? onButtonTap; + + const SettingsButtonListTile({ + required this.icon, + this.iconColor, + required this.title, + this.subtileText, + this.subtitle, + required this.buttonText, + this.onButtonTap, + super.key, + }); + + @override + Widget build(BuildContext context) { + return ListTile( + contentPadding: const EdgeInsets.symmetric(horizontal: 20), + horizontalTitleGap: 20, + isThreeLine: true, + leading: Icon(icon, color: iconColor), + title: Text( + title, + style: context.textTheme.bodyLarge?.copyWith( + fontWeight: FontWeight.w500, + ), + ), + subtitle: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + if (subtileText != null) const SizedBox(height: 4), + if (subtileText != null) + Text(subtileText!, style: context.textTheme.bodyMedium), + if (subtitle != null) subtitle!, + const SizedBox(height: 6), + ElevatedButton(onPressed: onButtonTap, child: Text(buttonText)), + ], + ), + ); + } +} diff --git a/mobile/lib/modules/settings/ui/settings_radio_list_tile.dart b/mobile/lib/modules/settings/ui/settings_radio_list_tile.dart new file mode 100644 index 000000000..1c26682a6 --- /dev/null +++ b/mobile/lib/modules/settings/ui/settings_radio_list_tile.dart @@ -0,0 +1,47 @@ +import 'package:flutter/material.dart'; +import 'package:immich_mobile/extensions/build_context_extensions.dart'; + +class SettingsRadioGroup { + final String title; + final T value; + + SettingsRadioGroup({required this.title, required this.value}); +} + +class SettingsRadioListTile extends StatelessWidget { + final List groups; + final T groupBy; + final void Function(T?) onRadioChanged; + + const SettingsRadioListTile({ + super.key, + required this.groups, + required this.groupBy, + required this.onRadioChanged, + }); + + @override + Widget build(BuildContext context) { + return Column( + children: groups + .map( + (g) => RadioListTile( + contentPadding: const EdgeInsets.symmetric(horizontal: 20), + dense: true, + activeColor: context.primaryColor, + title: Text( + g.title, + style: context.textTheme.bodyLarge?.copyWith( + fontWeight: FontWeight.w500, + ), + ), + value: g.value, + groupValue: groupBy, + onChanged: onRadioChanged, + controlAffinity: ListTileControlAffinity.trailing, + ), + ) + .toList(), + ); + } +} diff --git a/mobile/lib/modules/settings/ui/settings_slider_list_tile.dart b/mobile/lib/modules/settings/ui/settings_slider_list_tile.dart new file mode 100644 index 000000000..386a69086 --- /dev/null +++ b/mobile/lib/modules/settings/ui/settings_slider_list_tile.dart @@ -0,0 +1,49 @@ +import 'package:flutter/material.dart'; +import 'package:immich_mobile/extensions/build_context_extensions.dart'; + +class SettingsSliderListTile extends StatelessWidget { + final ValueNotifier valueNotifier; + final String text; + final double maxValue; + final double minValue; + final int noDivisons; + final String? label; + final bool enabled; + final Function(int)? onChangeEnd; + + const SettingsSliderListTile({ + required this.valueNotifier, + required this.text, + required this.maxValue, + this.minValue = 0.0, + required this.noDivisons, + this.enabled = true, + this.label, + this.onChangeEnd, + super.key, + }); + + @override + Widget build(BuildContext context) { + return ListTile( + contentPadding: const EdgeInsets.symmetric(horizontal: 20), + dense: true, + title: Text( + text, + style: context.textTheme.bodyLarge?.copyWith( + fontWeight: FontWeight.w500, + ), + ), + subtitle: Slider( + value: valueNotifier.value.toDouble(), + onChanged: (double v) => valueNotifier.value = v.toInt(), + onChangeEnd: (double v) => onChangeEnd?.call(v.toInt()), + max: maxValue, + min: minValue, + divisions: noDivisons, + label: label ?? "${valueNotifier.value}", + activeColor: context.primaryColor, + ), + ); + } +} diff --git a/mobile/lib/modules/settings/ui/settings_sub_page_scaffold.dart b/mobile/lib/modules/settings/ui/settings_sub_page_scaffold.dart new file mode 100644 index 000000000..96c4678ed --- /dev/null +++ b/mobile/lib/modules/settings/ui/settings_sub_page_scaffold.dart @@ -0,0 +1,30 @@ +import 'package:flutter/material.dart'; + +class SettingsSubPageScaffold extends StatelessWidget { + final List settings; + final bool showDivider; + + const SettingsSubPageScaffold({ + super.key, + required this.settings, + this.showDivider = false, + }); + + @override + Widget build(BuildContext context) { + return ListView.separated( + padding: const EdgeInsets.symmetric(vertical: 20), + itemCount: settings.length, + itemBuilder: (ctx, index) => settings[index], + separatorBuilder: (context, index) => showDivider + ? const Column( + children: [ + SizedBox(height: 5), + Divider(height: 10, indent: 15, endIndent: 15), + SizedBox(height: 15), + ], + ) + : const SizedBox(height: 10), + ); + } +} diff --git a/mobile/lib/modules/settings/ui/settings_sub_title.dart b/mobile/lib/modules/settings/ui/settings_sub_title.dart new file mode 100644 index 000000000..9a3fb6947 --- /dev/null +++ b/mobile/lib/modules/settings/ui/settings_sub_title.dart @@ -0,0 +1,25 @@ +import 'package:flutter/material.dart'; +import 'package:immich_mobile/extensions/build_context_extensions.dart'; + +class SettingsSubTitle extends StatelessWidget { + final String title; + + const SettingsSubTitle({ + super.key, + required this.title, + }); + + @override + Widget build(BuildContext context) { + return Padding( + padding: const EdgeInsets.only(left: 20), + child: Text( + title, + style: context.textTheme.bodyLarge?.copyWith( + color: context.primaryColor, + fontWeight: FontWeight.w700, + ), + ), + ); + } +} diff --git a/mobile/lib/modules/settings/ui/settings_switch_list_tile.dart b/mobile/lib/modules/settings/ui/settings_switch_list_tile.dart index b5277b9c1..c7328f0b9 100644 --- a/mobile/lib/modules/settings/ui/settings_switch_list_tile.dart +++ b/mobile/lib/modules/settings/ui/settings_switch_list_tile.dart @@ -1,51 +1,61 @@ import 'package:flutter/material.dart'; import 'package:immich_mobile/extensions/build_context_extensions.dart'; -import 'package:immich_mobile/modules/settings/services/app_settings.service.dart'; class SettingsSwitchListTile extends StatelessWidget { - final AppSettingsService appSettingService; final ValueNotifier valueNotifier; - final AppSettingsEnum settingsEnum; final String title; final bool enabled; final String? subtitle; + final IconData? icon; final Function(bool)? onChanged; - SettingsSwitchListTile({ - required this.appSettingService, + const SettingsSwitchListTile({ required this.valueNotifier, - required this.settingsEnum, required this.title, this.subtitle, + this.icon, this.enabled = true, this.onChanged, - }) : super(key: Key(settingsEnum.name)); + super.key, + }); @override Widget build(BuildContext context) { + void onSwitchChanged(bool value) { + if (!enabled) return; + + valueNotifier.value = value; + onChanged?.call(value); + } + return SwitchListTile.adaptive( + contentPadding: const EdgeInsets.symmetric(horizontal: 20), selectedTileColor: enabled ? null : context.themeData.disabledColor, value: valueNotifier.value, - onChanged: (bool value) { - if (enabled) { - valueNotifier.value = value; - appSettingService.setSetting(settingsEnum, value); - } - if (onChanged != null) { - onChanged!(value); - } - }, + onChanged: onSwitchChanged, activeColor: enabled ? context.primaryColor : context.themeData.disabledColor, dense: true, + secondary: icon != null + ? Icon( + icon!, + color: valueNotifier.value ? context.primaryColor : null, + ) + : null, title: Text( title, - style: context.textTheme.titleSmall, + style: context.textTheme.bodyLarge?.copyWith( + fontWeight: FontWeight.w500, + color: enabled ? null : context.themeData.disabledColor, + height: 1.5, + ), ), subtitle: subtitle != null ? Text( subtitle!, - style: context.textTheme.bodyMedium, + style: context.textTheme.bodyMedium?.copyWith( + color: enabled ? null : context.themeData.disabledColor, + ), ) : null, ); diff --git a/mobile/lib/modules/settings/ui/theme_setting/theme_setting.dart b/mobile/lib/modules/settings/ui/theme_setting/theme_setting.dart deleted file mode 100644 index e8a145393..000000000 --- a/mobile/lib/modules/settings/ui/theme_setting/theme_setting.dart +++ /dev/null @@ -1,98 +0,0 @@ -import 'package:easy_localization/easy_localization.dart'; -import 'package:flutter/material.dart'; -import 'package:flutter_hooks/flutter_hooks.dart'; -import 'package:hooks_riverpod/hooks_riverpod.dart'; -import 'package:immich_mobile/extensions/build_context_extensions.dart'; -import 'package:immich_mobile/modules/settings/providers/app_settings.provider.dart'; -import 'package:immich_mobile/modules/settings/services/app_settings.service.dart'; -import 'package:immich_mobile/utils/immich_app_theme.dart'; - -class ThemeSetting extends HookConsumerWidget { - const ThemeSetting({ - super.key, - }); - - @override - Widget build(BuildContext context, WidgetRef ref) { - final currentTheme = useState(ThemeMode.system); - - useEffect( - () { - currentTheme.value = ref.read(immichThemeProvider); - return null; - }, - [], - ); - - return ExpansionTile( - textColor: context.primaryColor, - title: Text( - 'theme_setting_theme_title', - style: context.textTheme.titleMedium, - ).tr(), - subtitle: const Text( - 'theme_setting_theme_subtitle', - ).tr(), - children: [ - SwitchListTile.adaptive( - activeColor: context.primaryColor, - title: Text( - 'theme_setting_system_theme_switch', - style: context.textTheme.labelLarge - ?.copyWith(fontWeight: FontWeight.bold), - ).tr(), - value: currentTheme.value == ThemeMode.system, - onChanged: (bool isSystem) { - var currentSystemBrightness = - MediaQuery.of(context).platformBrightness; - - if (isSystem) { - currentTheme.value = ThemeMode.system; - ref.watch(immichThemeProvider.notifier).state = ThemeMode.system; - ref - .watch(appSettingsServiceProvider) - .setSetting(AppSettingsEnum.themeMode, "system"); - } else { - if (currentSystemBrightness == Brightness.light) { - currentTheme.value = ThemeMode.light; - ref.watch(immichThemeProvider.notifier).state = ThemeMode.light; - ref - .watch(appSettingsServiceProvider) - .setSetting(AppSettingsEnum.themeMode, "light"); - } else if (currentSystemBrightness == Brightness.dark) { - currentTheme.value = ThemeMode.dark; - ref.watch(immichThemeProvider.notifier).state = ThemeMode.dark; - ref - .watch(appSettingsServiceProvider) - .setSetting(AppSettingsEnum.themeMode, "dark"); - } - } - }, - ), - if (currentTheme.value != ThemeMode.system) - SwitchListTile.adaptive( - activeColor: context.primaryColor, - title: Text( - 'theme_setting_dark_mode_switch', - style: context.textTheme.labelLarge - ?.copyWith(fontWeight: FontWeight.bold), - ).tr(), - value: ref.watch(immichThemeProvider) == ThemeMode.dark, - onChanged: (bool isDark) { - if (isDark) { - ref.watch(immichThemeProvider.notifier).state = ThemeMode.dark; - ref - .watch(appSettingsServiceProvider) - .setSetting(AppSettingsEnum.themeMode, "dark"); - } else { - ref.watch(immichThemeProvider.notifier).state = ThemeMode.light; - ref - .watch(appSettingsServiceProvider) - .setSetting(AppSettingsEnum.themeMode, "light"); - } - }, - ), - ], - ); - } -} diff --git a/mobile/lib/modules/settings/utils/app_settings_update_hook.dart b/mobile/lib/modules/settings/utils/app_settings_update_hook.dart new file mode 100644 index 000000000..85ffeda23 --- /dev/null +++ b/mobile/lib/modules/settings/utils/app_settings_update_hook.dart @@ -0,0 +1,18 @@ +import 'package:flutter/cupertino.dart'; +import 'package:flutter_hooks/flutter_hooks.dart' hide Store; +import 'package:immich_mobile/modules/settings/services/app_settings.service.dart'; +import 'package:immich_mobile/shared/models/store.dart'; + +ValueNotifier useAppSettingsState( + AppSettingsEnum key, +) { + final notifier = useState(Store.get(key.storeKey, key.defaultValue)); + + // Listen to changes to the notifier and update app settings + useValueChanged( + notifier.value, + (_, __) => Store.put(key.storeKey, notifier.value), + ); + + return notifier; +} diff --git a/mobile/lib/modules/settings/views/settings_page.dart b/mobile/lib/modules/settings/views/settings_page.dart index 3272dd552..eeb4b379f 100644 --- a/mobile/lib/modules/settings/views/settings_page.dart +++ b/mobile/lib/modules/settings/views/settings_page.dart @@ -1,51 +1,118 @@ import 'package:auto_route/auto_route.dart'; import 'package:easy_localization/easy_localization.dart'; import 'package:flutter/material.dart'; -import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:immich_mobile/extensions/build_context_extensions.dart'; -import 'package:immich_mobile/modules/settings/ui/advanced_settings/advanced_settings.dart'; +import 'package:immich_mobile/modules/settings/ui/advanced_settings.dart'; import 'package:immich_mobile/modules/settings/ui/asset_list_settings/asset_list_settings.dart'; -import 'package:immich_mobile/modules/settings/ui/local_storage_settings/local_storage_settings.dart'; -import 'package:immich_mobile/modules/settings/ui/image_viewer_quality_setting/image_viewer_quality_setting.dart'; -import 'package:immich_mobile/modules/settings/ui/notification_setting/notification_setting.dart'; -import 'package:immich_mobile/modules/settings/ui/theme_setting/theme_setting.dart'; +import 'package:immich_mobile/modules/settings/ui/backup_settings/backup_settings.dart'; +import 'package:immich_mobile/modules/settings/ui/image_viewer_quality_setting.dart'; +import 'package:immich_mobile/modules/settings/ui/notification_setting.dart'; +import 'package:immich_mobile/modules/settings/ui/preference_settings/preference_setting.dart'; +import 'package:immich_mobile/routing/router.dart'; + +enum SettingSection { + notifications( + 'setting_notifications_title', + Icons.notifications_none_rounded, + ), + preferences('preferences_settings_title', Icons.interests_outlined), + backup('backup_controller_page_backup', Icons.cloud_upload_outlined), + timeline('asset_list_settings_title', Icons.auto_awesome_mosaic_outlined), + viewer('asset_viewer_settings_title', Icons.image_outlined), + advanced('advanced_settings_tile_title', Icons.build_outlined); + + final String title; + final IconData icon; + + Widget get widget => switch (this) { + SettingSection.notifications => const NotificationSetting(), + SettingSection.preferences => const PreferenceSetting(), + SettingSection.backup => const BackupSettings(), + SettingSection.timeline => const AssetListSettings(), + SettingSection.viewer => const ImageViewerQualitySetting(), + SettingSection.advanced => const AdvancedSettings(), + }; + + const SettingSection(this.title, this.icon); +} @RoutePage() -class SettingsPage extends HookConsumerWidget { +class SettingsPage extends StatelessWidget { const SettingsPage({super.key}); @override - Widget build(BuildContext context, WidgetRef ref) { + Widget build(BuildContext context) { return Scaffold( appBar: AppBar( - leading: IconButton( - iconSize: 20, - splashRadius: 24, - onPressed: () => context.pop(), - icon: const Icon(Icons.arrow_back_ios_new_rounded), - ), - automaticallyImplyLeading: false, centerTitle: false, - title: const Text( - 'setting_pages_app_bar_settings', - ).tr(), - ), - body: ListView( - children: [ - ...ListTile.divideTiles( - context: context, - tiles: [ - const ImageViewerQualitySetting(), - const ThemeSetting(), - const AssetListSettings(), - const NotificationSetting(), - // const ExperimentalSettings(), - const LocalStorageSettings(), - const AdvancedSettings(), - ], - ), - ], + bottom: const PreferredSize( + preferredSize: Size.fromHeight(1), + child: Divider(height: 1), + ), + title: const Text('setting_pages_app_bar_settings').tr(), ), + body: context.isMobile ? _MobileLayout() : _TabletLayout(), + ); + } +} + +class _MobileLayout extends StatelessWidget { + @override + Widget build(BuildContext context) { + return ListView( + children: SettingSection.values + .map( + (s) => ListTile( + title: Text( + s.title, + style: const TextStyle( + fontWeight: FontWeight.bold, + ), + ).tr(), + leading: Icon(s.icon), + onTap: () => context.pushRoute(SettingsSubRoute(section: s)), + ), + ) + .toList(), + ); + } +} + +class _TabletLayout extends HookWidget { + @override + Widget build(BuildContext context) { + final selectedSection = + useState(SettingSection.values.first); + + return Row( + mainAxisAlignment: MainAxisAlignment.start, + children: [ + Expanded( + flex: 2, + child: CustomScrollView( + slivers: SettingSection.values + .map( + (s) => SliverToBoxAdapter( + child: ListTile( + title: Text(s.title).tr(), + leading: Icon(s.icon), + selected: s.index == selectedSection.value.index, + selectedColor: context.primaryColor, + selectedTileColor: context.primaryColor.withAlpha(50), + onTap: () => selectedSection.value = s, + ), + ), + ) + .toList(), + ), + ), + const VerticalDivider(width: 1), + Expanded( + flex: 4, + child: selectedSection.value.widget, + ), + ], ); } } diff --git a/mobile/lib/modules/settings/views/settings_sub_page.dart b/mobile/lib/modules/settings/views/settings_sub_page.dart new file mode 100644 index 000000000..582f45a11 --- /dev/null +++ b/mobile/lib/modules/settings/views/settings_sub_page.dart @@ -0,0 +1,22 @@ +import 'package:auto_route/auto_route.dart'; +import 'package:easy_localization/easy_localization.dart'; +import 'package:flutter/material.dart'; +import 'package:immich_mobile/modules/settings/views/settings_page.dart'; + +@RoutePage() +class SettingsSubPage extends StatelessWidget { + const SettingsSubPage(this.section, {super.key}); + + final SettingSection section; + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + centerTitle: false, + title: Text(section.title).tr(), + ), + body: section.widget, + ); + } +} diff --git a/mobile/lib/modules/trash/views/trash_page.dart b/mobile/lib/modules/trash/views/trash_page.dart index d99cacc0b..1ec982560 100644 --- a/mobile/lib/modules/trash/views/trash_page.dart +++ b/mobile/lib/modules/trash/views/trash_page.dart @@ -93,6 +93,7 @@ class TrashPage extends HookConsumerWidget { await showDialog( context: context, builder: (context) => DeleteDialog( + alert: "delete_dialog_alert_remote", onDelete: () => onPermanentlyDelete(), ), ); diff --git a/mobile/lib/routing/router.dart b/mobile/lib/routing/router.dart index 6da526b9b..f5c1a95d9 100644 --- a/mobile/lib/routing/router.dart +++ b/mobile/lib/routing/router.dart @@ -31,6 +31,7 @@ import 'package:immich_mobile/modules/login/views/change_password_page.dart'; import 'package:immich_mobile/modules/login/views/login_page.dart'; import 'package:immich_mobile/modules/onboarding/providers/gallery_permission.provider.dart'; import 'package:immich_mobile/modules/onboarding/views/permission_onboarding_page.dart'; +import 'package:immich_mobile/modules/settings/views/settings_sub_page.dart'; import 'package:immich_mobile/modules/shared_link/models/shared_link.dart'; import 'package:immich_mobile/modules/shared_link/views/shared_link_edit_page.dart'; import 'package:immich_mobile/modules/shared_link/views/shared_link_page.dart'; @@ -179,6 +180,7 @@ class AppRouter extends _$AppRouter { transitionsBuilder: TransitionsBuilders.slideBottom, ), AutoRoute(page: SettingsRoute.page, guards: [_duplicateGuard]), + AutoRoute(page: SettingsSubRoute.page, guards: [_duplicateGuard]), AutoRoute(page: AppLogRoute.page, guards: [_duplicateGuard]), AutoRoute(page: AppLogDetailRoute.page, guards: [_duplicateGuard]), AutoRoute(page: ArchiveRoute.page, guards: [_authGuard, _duplicateGuard]), diff --git a/mobile/lib/routing/router.gr.dart b/mobile/lib/routing/router.gr.dart index 64bd492a7..cc86b701a 100644 --- a/mobile/lib/routing/router.gr.dart +++ b/mobile/lib/routing/router.gr.dart @@ -299,6 +299,16 @@ abstract class _$AppRouter extends RootStackRouter { child: const SettingsPage(), ); }, + SettingsSubRoute.name: (routeData) { + final args = routeData.argsAs(); + return AutoRoutePage( + routeData: routeData, + child: SettingsSubPage( + args.section, + key: args.key, + ), + ); + }, SharedLinkEditRoute.name: (routeData) { final args = routeData.argsAs( orElse: () => const SharedLinkEditRouteArgs()); @@ -1260,6 +1270,44 @@ class SettingsRoute extends PageRouteInfo { static const PageInfo page = PageInfo(name); } +/// generated route for +/// [SettingsSubPage] +class SettingsSubRoute extends PageRouteInfo { + SettingsSubRoute({ + required SettingSection section, + Key? key, + List? children, + }) : super( + SettingsSubRoute.name, + args: SettingsSubRouteArgs( + section: section, + key: key, + ), + initialChildren: children, + ); + + static const String name = 'SettingsSubRoute'; + + static const PageInfo page = + PageInfo(name); +} + +class SettingsSubRouteArgs { + const SettingsSubRouteArgs({ + required this.section, + this.key, + }); + + final SettingSection section; + + final Key? key; + + @override + String toString() { + return 'SettingsSubRouteArgs{section: $section, key: $key}'; + } +} + /// generated route for /// [SharedLinkEditPage] class SharedLinkEditRoute extends PageRouteInfo { diff --git a/mobile/lib/shared/ui/app_bar_dialog/app_bar_profile_info.dart b/mobile/lib/shared/ui/app_bar_dialog/app_bar_profile_info.dart index 9e7cceae2..f449fcef6 100644 --- a/mobile/lib/shared/ui/app_bar_dialog/app_bar_profile_info.dart +++ b/mobile/lib/shared/ui/app_bar_dialog/app_bar_profile_info.dart @@ -25,7 +25,7 @@ class AppBarProfileInfoBox extends HookConsumerWidget { if (user == null) { return const CircleAvatar( radius: 20, - backgroundImage: AssetImage('assets/immich-logo-no-outline.png'), + backgroundImage: AssetImage('assets/immich-logo.png'), backgroundColor: Colors.transparent, ); } diff --git a/mobile/lib/shared/ui/immich_app_bar.dart b/mobile/lib/shared/ui/immich_app_bar.dart index 0c70e5235..84f070863 100644 --- a/mobile/lib/shared/ui/immich_app_bar.dart +++ b/mobile/lib/shared/ui/immich_app_bar.dart @@ -1,4 +1,5 @@ import 'package:auto_route/auto_route.dart'; +import 'package:easy_localization/easy_localization.dart'; import 'package:flutter/material.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:immich_mobile/extensions/build_context_extensions.dart'; @@ -80,6 +81,7 @@ class ImmichAppBar extends ConsumerWidget implements PreferredSizeWidget { strokeWidth: 2, strokeCap: StrokeCap.round, valueColor: AlwaysStoppedAnimation(iconColor), + semanticsLabel: 'backup_controller_page_backup'.tr(), ), ); } else if (backupState.backupProgress != @@ -89,6 +91,7 @@ class ImmichAppBar extends ConsumerWidget implements PreferredSizeWidget { Icons.check_outlined, size: 9, color: iconColor, + semanticLabel: 'backup_controller_page_backup'.tr(), ); } } @@ -98,6 +101,7 @@ class ImmichAppBar extends ConsumerWidget implements PreferredSizeWidget { Icons.cloud_off_rounded, size: 9, color: iconColor, + semanticLabel: 'backup_controller_page_backup'.tr(), ); } } @@ -150,21 +154,11 @@ class ImmichAppBar extends ConsumerWidget implements PreferredSizeWidget { children: [ Container( padding: const EdgeInsets.only(top: 3), - width: 28, - height: 28, + height: 30, child: Image.asset( - 'assets/immich-logo.png', - ), - ), - Container( - margin: const EdgeInsets.only(left: 10), - child: const Text( - 'IMMICH', - style: TextStyle( - fontFamily: 'SnowburstOne', - fontWeight: FontWeight.bold, - fontSize: 24, - ), + context.isDarkTheme + ? 'assets/immich-logo-inline-dark.png' + : 'assets/immich-logo-inline-light.png', ), ), ], diff --git a/mobile/lib/shared/ui/immich_logo.dart b/mobile/lib/shared/ui/immich_logo.dart index c7f318891..af83887fb 100644 --- a/mobile/lib/shared/ui/immich_logo.dart +++ b/mobile/lib/shared/ui/immich_logo.dart @@ -15,7 +15,7 @@ class ImmichLogo extends StatelessWidget { return Hero( tag: heroTag, child: Image( - image: const AssetImage('assets/immich-logo-no-outline.png'), + image: const AssetImage('assets/immich-logo.png'), width: size, filterQuality: FilterQuality.high, ), diff --git a/mobile/lib/shared/ui/immich_title_text.dart b/mobile/lib/shared/ui/immich_title_text.dart index 3ef0501dd..2a4edb423 100644 --- a/mobile/lib/shared/ui/immich_title_text.dart +++ b/mobile/lib/shared/ui/immich_title_text.dart @@ -13,14 +13,14 @@ class ImmichTitleText extends StatelessWidget { @override Widget build(BuildContext context) { - return Text( - 'IMMICH', - style: TextStyle( - fontFamily: 'SnowburstOne', - fontWeight: FontWeight.bold, - fontSize: fontSize, - color: color ?? context.primaryColor, + return Image( + image: AssetImage( + context.isDarkTheme + ? 'assets/immich-text-dark.png' + : 'assets/immich-text-light.png', ), + width: fontSize * 4, + filterQuality: FilterQuality.high, ); } } diff --git a/mobile/lib/shared/ui/immich_toast.dart b/mobile/lib/shared/ui/immich_toast.dart index 25a0e65fa..e15623c86 100644 --- a/mobile/lib/shared/ui/immich_toast.dart +++ b/mobile/lib/shared/ui/immich_toast.dart @@ -9,7 +9,7 @@ class ImmichToast { required BuildContext context, required String msg, ToastType toastType = ToastType.info, - ToastGravity gravity = ToastGravity.TOP, + ToastGravity gravity = ToastGravity.BOTTOM, int durationInSecond = 3, }) { final fToast = FToast(); diff --git a/mobile/lib/shared/views/splash_screen.dart b/mobile/lib/shared/views/splash_screen.dart index 3c0d65bde..47b550f9d 100644 --- a/mobile/lib/shared/views/splash_screen.dart +++ b/mobile/lib/shared/views/splash_screen.dart @@ -96,7 +96,7 @@ class SplashScreenPage extends HookConsumerWidget { return const Scaffold( body: Center( child: Image( - image: AssetImage('assets/immich-logo-no-outline.png'), + image: AssetImage('assets/immich-logo.png'), width: 80, filterQuality: FilterQuality.high, ), diff --git a/mobile/openapi/analysis_options.yaml b/mobile/openapi/analysis_options.yaml deleted file mode 100644 index e69de29bb..000000000 diff --git a/mobile/pubspec.yaml b/mobile/pubspec.yaml index 85f240ae9..ed8a4fad6 100644 --- a/mobile/pubspec.yaml +++ b/mobile/pubspec.yaml @@ -1,12 +1,12 @@ name: immich_mobile description: Immich - selfhosted backup media file on mobile phone -publish_to: "none" +publish_to: 'none' version: 1.98.2+128 isar_version: &isar_version 3.1.0+1 environment: - sdk: ">=3.0.0 <4.0.0" + sdk: '>=3.0.0 <4.0.0' dependencies: flutter: @@ -127,10 +127,12 @@ flutter: - asset: fonts/overpass/OverpassMono.ttf flutter_launcher_icons: - image_path_android: "assets/immich-logo-no-outline.png" - image_path_ios: "assets/immich-logo-no-outline.png" - android: true # can specify file name here e.g. "ic_launcher" - ios: true # can specify file name here e.g. "My-Launcher-Icon + image_path_android: 'assets/immich-logo.png' + adaptive_icon_background: '#ffffff' + adaptive_icon_foreground: 'assets/immich-logo-android-adaptive-icon.png' + image_path_ios: 'assets/immich-logo-w-bg.png' + android: 'ic_launcher' # can specify file name here e.g. "ic_launcher" + ios: false # can specify file name here e.g. "My-Launcher-Icon remove_alpha_ios: true analyzer: diff --git a/open-api/bin/generate-open-api.sh b/open-api/bin/generate-open-api.sh index ba62bfd9e..c972a4c80 100755 --- a/open-api/bin/generate-open-api.sh +++ b/open-api/bin/generate-open-api.sh @@ -14,6 +14,9 @@ function dart { # Post generate patches patch --no-backup-if-mismatch -u ../mobile/openapi/lib/api_client.dart <./patch/api_client.dart.patch patch --no-backup-if-mismatch -u ../mobile/openapi/lib/api.dart <./patch/api.dart.patch + # Don't include analysis_options.yaml for the generated openapi files + # so that language servers can properly exclude the mobile/openapi directory + rm ../mobile/openapi/analysis_options.yaml } function typescript { diff --git a/open-api/typescript-sdk/.npmignore b/open-api/typescript-sdk/.npmignore new file mode 100644 index 000000000..1898c3e21 --- /dev/null +++ b/open-api/typescript-sdk/.npmignore @@ -0,0 +1,3 @@ +package-lock.json +tsconfig.json +src/ diff --git a/open-api/typescript-sdk/README.md b/open-api/typescript-sdk/README.md new file mode 100644 index 000000000..53a10eefc --- /dev/null +++ b/open-api/typescript-sdk/README.md @@ -0,0 +1,28 @@ +# @immich/sdk + +A TypeScript SDK for interfacing with the [Immich](https://immich.app/) API. + +## Install + +```bash +npm i --save @immich/sdk +``` + +## Usage + +For a more detailed example, check out the [`@immich/cli`](https://github.com/immich-app/immich/tree/main/cli). + +```typescript +import { defaults, getAllAlbums, getAllAssets, getMyUserInfo } from "@immich/sdk"; + +const API_KEY = ""; // process.env.IMMICH_API_KEY + +defaults.baseUrl = "https://demo.immich.app/api"; +defaults.headers = { "x-api-key": API_KEY }; + +const user = await getMyUserInfo(); +const assets = await getAllAssets({ take: 1000 }); +const albums = await getAllAlbums({}); + +console.log({ user, assets, albums }); +``` diff --git a/open-api/typescript-sdk/package-lock.json b/open-api/typescript-sdk/package-lock.json index 0c2230835..0f1926996 100644 --- a/open-api/typescript-sdk/package-lock.json +++ b/open-api/typescript-sdk/package-lock.json @@ -8,31 +8,32 @@ "name": "@immich/sdk", "version": "1.98.2", "license": "GNU Affero General Public License version 3", + "dependencies": { + "@oazapfts/runtime": "^1.0.2" + }, "devDependencies": { - "@oazapfts/runtime": "^1.0.0", "@types/node": "^20.11.0", "typescript": "^5.3.3" } }, "node_modules/@oazapfts/runtime": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@oazapfts/runtime/-/runtime-1.0.1.tgz", - "integrity": "sha512-CMl7f1gXYpjIyEtDhg4YfXwr2MXfbadbvqwKbMsaHkVtSglmuz5A8jSyefTqaJlmh0MOA2ZNS9jnbfIdtcoDiw==", - "dev": true + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@oazapfts/runtime/-/runtime-1.0.2.tgz", + "integrity": "sha512-V33FjR6V+AkGRWYQW3XPm5BLn2loGl2ujSeja1TzdjjEn2zjGgl3ve0dcFf/jEwPZEOqQZl6YwIgIB/clXVqWw==" }, "node_modules/@types/node": { - "version": "20.11.24", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.11.24.tgz", - "integrity": "sha512-Kza43ewS3xoLgCEpQrsT+xRo/EJej1y0kVYGiLFE1NEODXGzTfwiC6tXTLMQskn1X4/Rjlh0MQUvx9W+L9long==", + "version": "20.11.25", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.11.25.tgz", + "integrity": "sha512-TBHyJxk2b7HceLVGFcpAUjsa5zIdsPWlR6XHfyGzd0SFu+/NFgQgMAl96MSDZgQDvJAvV6BKsFOrt6zIL09JDw==", "dev": true, "dependencies": { "undici-types": "~5.26.4" } }, "node_modules/typescript": { - "version": "5.3.3", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.3.3.tgz", - "integrity": "sha512-pXWcraxM0uxAS+tN0AG/BF2TyqmHO014Z070UsJ+pFvYuRSq8KH8DmWpnbXe0pEPDHXZV3FcAbJkijJ5oNEnWw==", + "version": "5.4.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.4.2.tgz", + "integrity": "sha512-+2/g0Fds1ERlP6JsakQQDXjZdZMM+rqpamFZJEKh4kwTIn3iDkgKtby0CeNd5ATNZ4Ry1ax15TMx0W2V+miizQ==", "dev": true, "bin": { "tsc": "bin/tsc", diff --git a/open-api/typescript-sdk/package.json b/open-api/typescript-sdk/package.json index ec5e78fac..4b04ee7c2 100644 --- a/open-api/typescript-sdk/package.json +++ b/open-api/typescript-sdk/package.json @@ -1,7 +1,7 @@ { "name": "@immich/sdk", "version": "1.98.2", - "description": "", + "description": "Auto-generated TypeScript SDK for the Immich API", "type": "module", "main": "./build/index.js", "types": "./build/index.d.ts", @@ -15,9 +15,16 @@ "build": "tsc" }, "license": "GNU Affero General Public License version 3", + "dependencies": { + "@oazapfts/runtime": "^1.0.2" + }, "devDependencies": { - "@oazapfts/runtime": "^1.0.0", "@types/node": "^20.11.0", "typescript": "^5.3.3" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/immich-app/immich.git", + "directory": "open-api/typescript-sdk" } } diff --git a/open-api/typescript-sdk/src/index.ts b/open-api/typescript-sdk/src/index.ts index 5759e66ad..d81c7282a 100644 --- a/open-api/typescript-sdk/src/index.ts +++ b/open-api/typescript-sdk/src/index.ts @@ -1,2 +1,2 @@ -export * from './fetch-client'; -export * from './fetch-errors'; +export * from './fetch-client.js'; +export * from './fetch-errors.js'; diff --git a/open-api/typescript-sdk/tsconfig.json b/open-api/typescript-sdk/tsconfig.json index 251202774..30d58d517 100644 --- a/open-api/typescript-sdk/tsconfig.json +++ b/open-api/typescript-sdk/tsconfig.json @@ -5,8 +5,8 @@ "skipLibCheck": true, "declaration": true, "outDir": "build", - "module": "esnext", - "moduleResolution": "Bundler", + "module": "Node16", + "moduleResolution": "Node16", "lib": ["esnext", "dom"] }, "include": ["src/**/*.ts"] diff --git a/server/Dockerfile b/server/Dockerfile index e6af34fd6..2c66c0af3 100644 --- a/server/Dockerfile +++ b/server/Dockerfile @@ -1,5 +1,5 @@ # dev build -FROM ghcr.io/immich-app/base-server-dev:20240305@sha256:99ca204d84284dac24dbec59ffeaea07c02f4bd9b06b09e1aa9aacc4f3ece92e as dev +FROM ghcr.io/immich-app/base-server-dev:20240312@sha256:3cb168dd87a2b412b25c512ec638a1e7f362e1d3eb8dd19a38d92d4a7c47999c as dev RUN apt-get install --no-install-recommends -yqq tini WORKDIR /usr/src/app @@ -40,7 +40,7 @@ RUN npm run build # prod build -FROM ghcr.io/immich-app/base-server-prod:20240305@sha256:d0bcac4e77f1371d6c4b8ecc415c390cc348d09e48504d4455f38f2968e41c1c +FROM ghcr.io/immich-app/base-server-prod:20240312@sha256:8359fb1acc56580f2b4835e273293fdaa99d273b210892e1485fc6f1e47cf2bb WORKDIR /usr/src/app ENV NODE_ENV=production \ diff --git a/server/e2e/docker-compose.server-e2e.yml b/server/e2e/docker-compose.server-e2e.yml index 09db7ecf3..61b38e1ee 100644 --- a/server/e2e/docker-compose.server-e2e.yml +++ b/server/e2e/docker-compose.server-e2e.yml @@ -18,6 +18,7 @@ services: - DB_USERNAME=postgres - DB_PASSWORD=postgres - DB_DATABASE_NAME=e2e_test + - IMMICH_METRICS=true depends_on: - database diff --git a/server/package-lock.json b/server/package-lock.json index 2468c0c97..deab0b791 100644 --- a/server/package-lock.json +++ b/server/package-lock.json @@ -21,6 +21,9 @@ "@nestjs/swagger": "^7.1.8", "@nestjs/typeorm": "^10.0.0", "@nestjs/websockets": "^10.2.2", + "@opentelemetry/auto-instrumentations-node": "^0.42.0", + "@opentelemetry/exporter-prometheus": "^0.49.0", + "@opentelemetry/sdk-node": "^0.49.0", "@socket.io/postgres-adapter": "^0.3.1", "@types/picomatch": "^2.3.3", "archiver": "^7.0.0", @@ -41,9 +44,11 @@ "i18n-iso-countries": "^7.6.0", "ioredis": "^5.3.2", "joi": "^17.10.0", + "js-yaml": "^4.1.0", "lodash": "^4.17.21", "luxon": "^3.4.2", "nest-commander": "^3.11.1", + "nestjs-otel": "^5.1.5", "node-addon-api": "^7.0.0", "openid-client": "^5.4.3", "pg": "^8.11.3", @@ -71,6 +76,7 @@ "@types/imagemin": "^8.0.1", "@types/jest": "29.5.12", "@types/jest-when": "^3.5.2", + "@types/js-yaml": "^4.0.9", "@types/lodash": "^4.14.197", "@types/mock-fs": "^4.13.1", "@types/multer": "^1.4.7", @@ -1089,11 +1095,148 @@ "@nestjs/core": "^10.x" } }, + "node_modules/@grpc/grpc-js": { + "version": "1.10.2", + "resolved": "https://registry.npmjs.org/@grpc/grpc-js/-/grpc-js-1.10.2.tgz", + "integrity": "sha512-lSbgu8iayAod8O0YcoXK3+bMFGThY2svtN35Zlm9VepsB3jfyIcoupKknEht7Kh9Q8ITjsp0J4KpYo9l4+FhNg==", + "dependencies": { + "@grpc/proto-loader": "^0.7.10", + "@js-sdsl/ordered-map": "^4.4.2" + }, + "engines": { + "node": ">=12.10.0" + } + }, + "node_modules/@grpc/proto-loader": { + "version": "0.7.10", + "resolved": "https://registry.npmjs.org/@grpc/proto-loader/-/proto-loader-0.7.10.tgz", + "integrity": "sha512-CAqDfoaQ8ykFd9zqBDn4k6iWT9loLAlc2ETmDFS9JCD70gDcnA4L3AFEo2iV7KyAtAAHFW9ftq1Fz+Vsgq80RQ==", + "dependencies": { + "lodash.camelcase": "^4.3.0", + "long": "^5.0.0", + "protobufjs": "^7.2.4", + "yargs": "^17.7.2" + }, + "bin": { + "proto-loader-gen-types": "build/bin/proto-loader-gen-types.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/@grpc/proto-loader/node_modules/cliui": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", + "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.1", + "wrap-ansi": "^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@grpc/proto-loader/node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/@grpc/proto-loader/node_modules/yargs": { + "version": "17.7.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", + "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", + "dependencies": { + "cliui": "^8.0.1", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.3", + "y18n": "^5.0.5", + "yargs-parser": "^21.1.1" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@hapi/b64": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/@hapi/b64/-/b64-5.0.0.tgz", + "integrity": "sha512-ngu0tSEmrezoiIaNGG6rRvKOUkUuDdf4XTPnONHGYfSGRmDqPZX5oJL6HAdKTo1UQHECbdB4OzhWrfgVppjHUw==", + "dependencies": { + "@hapi/hoek": "9.x.x" + } + }, + "node_modules/@hapi/boom": { + "version": "9.1.4", + "resolved": "https://registry.npmjs.org/@hapi/boom/-/boom-9.1.4.tgz", + "integrity": "sha512-Ls1oH8jaN1vNsqcaHVYJrKmgMcKsC1wcp8bujvXrHaAqD2iDYq3HoOwsxwo09Cuda5R5nC0o0IxlrlTuvPuzSw==", + "dependencies": { + "@hapi/hoek": "9.x.x" + } + }, + "node_modules/@hapi/bourne": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@hapi/bourne/-/bourne-2.1.0.tgz", + "integrity": "sha512-i1BpaNDVLJdRBEKeJWkVO6tYX6DMFBuwMhSuWqLsY4ufeTKGVuV5rBsUhxPayXqnnWHgXUAmWK16H/ykO5Wj4Q==" + }, + "node_modules/@hapi/cryptiles": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/@hapi/cryptiles/-/cryptiles-5.1.0.tgz", + "integrity": "sha512-fo9+d1Ba5/FIoMySfMqPBR/7Pa29J2RsiPrl7bkwo5W5o+AN1dAYQRi4SPrPwwVxVGKjgLOEWrsvt1BonJSfLA==", + "dependencies": { + "@hapi/boom": "9.x.x" + }, + "engines": { + "node": ">=12.0.0" + } + }, "node_modules/@hapi/hoek": { "version": "9.3.0", "resolved": "https://registry.npmjs.org/@hapi/hoek/-/hoek-9.3.0.tgz", "integrity": "sha512-/c6rf4UJlmHlC9b5BaNvzAcFv7HZ2QHaV0D4/HNlBdvFnvQq8RI4kYdhyPCl7Xj+oWvTWQ8ujhqS53LIgAe6KQ==" }, + "node_modules/@hapi/iron": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/@hapi/iron/-/iron-6.0.0.tgz", + "integrity": "sha512-zvGvWDufiTGpTJPG1Y/McN8UqWBu0k/xs/7l++HVU535NLHXsHhy54cfEMdW7EjwKfbBfM9Xy25FmTiobb7Hvw==", + "dependencies": { + "@hapi/b64": "5.x.x", + "@hapi/boom": "9.x.x", + "@hapi/bourne": "2.x.x", + "@hapi/cryptiles": "5.x.x", + "@hapi/hoek": "9.x.x" + } + }, + "node_modules/@hapi/podium": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/@hapi/podium/-/podium-4.1.3.tgz", + "integrity": "sha512-ljsKGQzLkFqnQxE7qeanvgGj4dejnciErYd30dbrYzUOF/FyS/DOF97qcrT3bhoVwCYmxa6PEMhxfCPlnUcD2g==", + "dependencies": { + "@hapi/hoek": "9.x.x", + "@hapi/teamwork": "5.x.x", + "@hapi/validate": "1.x.x" + } + }, + "node_modules/@hapi/teamwork": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/@hapi/teamwork/-/teamwork-5.1.1.tgz", + "integrity": "sha512-1oPx9AE5TIv+V6Ih54RP9lTZBso3rP8j4Xhb6iSVwPXtAM+sDopl5TFMv5Paw73UnpZJ9gjcrTE1BXrWt9eQrg==", + "engines": { + "node": ">=12.0.0" + } + }, "node_modules/@hapi/topo": { "version": "5.1.0", "resolved": "https://registry.npmjs.org/@hapi/topo/-/topo-5.1.0.tgz", @@ -1102,6 +1245,15 @@ "@hapi/hoek": "^9.0.0" } }, + "node_modules/@hapi/validate": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@hapi/validate/-/validate-1.1.3.tgz", + "integrity": "sha512-/XMR0N0wjw0Twzq2pQOzPBZlDzkekGcoCtzO314BpIEsbXdYGthQUbxgkGDf4nhk1+IPDAsXqWjMohRQYO06UA==", + "dependencies": { + "@hapi/hoek": "^9.0.0", + "@hapi/topo": "^5.0.0" + } + }, "node_modules/@humanwhocodes/config-array": { "version": "0.11.14", "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.14.tgz", @@ -2135,6 +2287,15 @@ "@jridgewell/sourcemap-codec": "^1.4.14" } }, + "node_modules/@js-sdsl/ordered-map": { + "version": "4.4.2", + "resolved": "https://registry.npmjs.org/@js-sdsl/ordered-map/-/ordered-map-4.4.2.tgz", + "integrity": "sha512-iUKgm52T8HOE/makSxjqoWhe95ZJA1/G1sYsGev2JDKUSS14KAgg1LHb+Ba+IPow0xflbnSkOsZcO08C7w1gYw==", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/js-sdsl" + } + }, "node_modules/@ljharb/through": { "version": "2.3.12", "resolved": "https://registry.npmjs.org/@ljharb/through/-/through-2.3.12.tgz", @@ -2375,6 +2536,19 @@ "url": "https://github.com/sponsors/isaacs" } }, + "node_modules/@nestjs/cli/node_modules/typescript": { + "version": "5.3.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.3.3.tgz", + "integrity": "sha512-pXWcraxM0uxAS+tN0AG/BF2TyqmHO014Z070UsJ+pFvYuRSq8KH8DmWpnbXe0pEPDHXZV3FcAbJkijJ5oNEnWw==", + "dev": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, "node_modules/@nestjs/common": { "version": "10.3.3", "resolved": "https://registry.npmjs.org/@nestjs/common/-/common-10.3.3.tgz", @@ -2703,6 +2877,1144 @@ "npm": ">=5.0.0" } }, + "node_modules/@opentelemetry/api": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/api/-/api-1.7.0.tgz", + "integrity": "sha512-AdY5wvN0P2vXBi3b29hxZgSFvdhdxPB9+f0B6s//P9Q8nibRWeA3cHm8UmLpio9ABigkVHJ5NMPk+Mz8VCCyrw==", + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/@opentelemetry/api-logs": { + "version": "0.49.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/api-logs/-/api-logs-0.49.1.tgz", + "integrity": "sha512-kaNl/T7WzyMUQHQlVq7q0oV4Kev6+0xFwqzofryC66jgGMacd0QH5TwfpbUwSTby+SdAdprAe5UKMvBw4tKS5Q==", + "dependencies": { + "@opentelemetry/api": "^1.0.0" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/@opentelemetry/auto-instrumentations-node": { + "version": "0.42.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/auto-instrumentations-node/-/auto-instrumentations-node-0.42.0.tgz", + "integrity": "sha512-fxcB7My5QTVfX6kBH4r5OFduGSxdpROgyIu7CqClp1psFHfVaBMQd4lbK2u+39K5kbjzJT2OaUP8yQuAvKJqBg==", + "dependencies": { + "@opentelemetry/instrumentation": "^0.49.1", + "@opentelemetry/instrumentation-amqplib": "^0.35.0", + "@opentelemetry/instrumentation-aws-lambda": "^0.39.0", + "@opentelemetry/instrumentation-aws-sdk": "^0.39.0", + "@opentelemetry/instrumentation-bunyan": "^0.36.0", + "@opentelemetry/instrumentation-cassandra-driver": "^0.36.0", + "@opentelemetry/instrumentation-connect": "^0.34.0", + "@opentelemetry/instrumentation-cucumber": "^0.4.0", + "@opentelemetry/instrumentation-dataloader": "^0.7.0", + "@opentelemetry/instrumentation-dns": "^0.34.0", + "@opentelemetry/instrumentation-express": "^0.36.0", + "@opentelemetry/instrumentation-fastify": "^0.34.0", + "@opentelemetry/instrumentation-fs": "^0.10.0", + "@opentelemetry/instrumentation-generic-pool": "^0.34.0", + "@opentelemetry/instrumentation-graphql": "^0.38.0", + "@opentelemetry/instrumentation-grpc": "^0.49.1", + "@opentelemetry/instrumentation-hapi": "^0.35.0", + "@opentelemetry/instrumentation-http": "^0.49.1", + "@opentelemetry/instrumentation-ioredis": "^0.38.0", + "@opentelemetry/instrumentation-knex": "^0.34.0", + "@opentelemetry/instrumentation-koa": "^0.38.0", + "@opentelemetry/instrumentation-lru-memoizer": "^0.35.0", + "@opentelemetry/instrumentation-memcached": "^0.34.0", + "@opentelemetry/instrumentation-mongodb": "^0.40.0", + "@opentelemetry/instrumentation-mongoose": "^0.36.0", + "@opentelemetry/instrumentation-mysql": "^0.36.0", + "@opentelemetry/instrumentation-mysql2": "^0.36.0", + "@opentelemetry/instrumentation-nestjs-core": "^0.35.0", + "@opentelemetry/instrumentation-net": "^0.34.0", + "@opentelemetry/instrumentation-pg": "^0.39.0", + "@opentelemetry/instrumentation-pino": "^0.36.0", + "@opentelemetry/instrumentation-redis": "^0.37.0", + "@opentelemetry/instrumentation-redis-4": "^0.37.0", + "@opentelemetry/instrumentation-restify": "^0.36.0", + "@opentelemetry/instrumentation-router": "^0.35.0", + "@opentelemetry/instrumentation-socket.io": "^0.37.0", + "@opentelemetry/instrumentation-tedious": "^0.8.0", + "@opentelemetry/instrumentation-winston": "^0.35.0", + "@opentelemetry/resource-detector-alibaba-cloud": "^0.28.7", + "@opentelemetry/resource-detector-aws": "^1.4.0", + "@opentelemetry/resource-detector-container": "^0.3.7", + "@opentelemetry/resource-detector-gcp": "^0.29.7", + "@opentelemetry/resources": "^1.12.0", + "@opentelemetry/sdk-node": "^0.49.1" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.4.1" + } + }, + "node_modules/@opentelemetry/context-async-hooks": { + "version": "1.22.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/context-async-hooks/-/context-async-hooks-1.22.0.tgz", + "integrity": "sha512-Nfdxyg8YtWqVWkyrCukkundAjPhUXi93JtVQmqDT1mZRVKqA7e2r7eJCrI+F651XUBMp0hsOJSGiFk3QSpaIJw==", + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.0.0 <1.9.0" + } + }, + "node_modules/@opentelemetry/core": { + "version": "1.22.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/core/-/core-1.22.0.tgz", + "integrity": "sha512-0VoAlT6x+Xzik1v9goJ3pZ2ppi6+xd3aUfg4brfrLkDBHRIVjMP0eBHrKrhB+NKcDyMAg8fAbGL3Npg/F6AwWA==", + "dependencies": { + "@opentelemetry/semantic-conventions": "1.22.0" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.0.0 <1.9.0" + } + }, + "node_modules/@opentelemetry/exporter-prometheus": { + "version": "0.49.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/exporter-prometheus/-/exporter-prometheus-0.49.1.tgz", + "integrity": "sha512-FgzGl6OH22f+Wb1dh/TnoQSnZE2SCADhHx06nMqxivSqRJ9t3AhUdMsEOFt2IMjZClE705pcsLHk10BCJ79vsA==", + "dependencies": { + "@opentelemetry/core": "1.22.0", + "@opentelemetry/resources": "1.22.0", + "@opentelemetry/sdk-metrics": "1.22.0" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/exporter-trace-otlp-grpc": { + "version": "0.49.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/exporter-trace-otlp-grpc/-/exporter-trace-otlp-grpc-0.49.1.tgz", + "integrity": "sha512-Zbd7f3zF7fI2587MVhBizaW21cO/SordyrZGtMtvhoxU6n4Qb02Gx71X4+PzXH620e0+JX+Pcr9bYb1HTeVyJA==", + "dependencies": { + "@grpc/grpc-js": "^1.7.1", + "@opentelemetry/core": "1.22.0", + "@opentelemetry/otlp-grpc-exporter-base": "0.49.1", + "@opentelemetry/otlp-transformer": "0.49.1", + "@opentelemetry/resources": "1.22.0", + "@opentelemetry/sdk-trace-base": "1.22.0" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.0.0" + } + }, + "node_modules/@opentelemetry/exporter-trace-otlp-http": { + "version": "0.49.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/exporter-trace-otlp-http/-/exporter-trace-otlp-http-0.49.1.tgz", + "integrity": "sha512-KOLtZfZvIrpGZLVvblKsiVQT7gQUZNKcUUH24Zz6Xbi7LJb9Vt6xtUZFYdR5IIjvt47PIqBKDWUQlU0o1wAsRw==", + "dependencies": { + "@opentelemetry/core": "1.22.0", + "@opentelemetry/otlp-exporter-base": "0.49.1", + "@opentelemetry/otlp-transformer": "0.49.1", + "@opentelemetry/resources": "1.22.0", + "@opentelemetry/sdk-trace-base": "1.22.0" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.0.0" + } + }, + "node_modules/@opentelemetry/exporter-trace-otlp-proto": { + "version": "0.49.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/exporter-trace-otlp-proto/-/exporter-trace-otlp-proto-0.49.1.tgz", + "integrity": "sha512-n8ON/c9pdMyYAfSFWKkgsPwjYoxnki+6Olzo+klKfW7KqLWoyEkryNkbcMIYnGGNXwdkMIrjoaP0VxXB26Oxcg==", + "dependencies": { + "@opentelemetry/core": "1.22.0", + "@opentelemetry/otlp-exporter-base": "0.49.1", + "@opentelemetry/otlp-proto-exporter-base": "0.49.1", + "@opentelemetry/otlp-transformer": "0.49.1", + "@opentelemetry/resources": "1.22.0", + "@opentelemetry/sdk-trace-base": "1.22.0" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.0.0" + } + }, + "node_modules/@opentelemetry/exporter-zipkin": { + "version": "1.22.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/exporter-zipkin/-/exporter-zipkin-1.22.0.tgz", + "integrity": "sha512-XcFs6rGvcTz0qW5uY7JZDYD0yNEXdekXAb6sFtnZgY/cHY6BQ09HMzOjv9SX+iaXplRDcHr1Gta7VQKM1XXM6g==", + "dependencies": { + "@opentelemetry/core": "1.22.0", + "@opentelemetry/resources": "1.22.0", + "@opentelemetry/sdk-trace-base": "1.22.0", + "@opentelemetry/semantic-conventions": "1.22.0" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.0.0" + } + }, + "node_modules/@opentelemetry/host-metrics": { + "version": "0.32.2", + "resolved": "https://registry.npmjs.org/@opentelemetry/host-metrics/-/host-metrics-0.32.2.tgz", + "integrity": "sha512-zrnls0CWMAYEUHQbdplY0M6v3L/cgEoiwpjAnHAaG7M3ICs7K4/Hms1UlVMDydEvNDkQilx63scpDcE1/M5V4A==", + "dependencies": { + "@opentelemetry/sdk-metrics": "^1.8.0", + "systeminformation": "^5.0.0" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/instrumentation": { + "version": "0.49.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation/-/instrumentation-0.49.1.tgz", + "integrity": "sha512-0DLtWtaIppuNNRRllSD4bjU8ZIiLp1cDXvJEbp752/Zf+y3gaLNaoGRGIlX4UHhcsrmtL+P2qxi3Hodi8VuKiQ==", + "dependencies": { + "@opentelemetry/api-logs": "0.49.1", + "@types/shimmer": "^1.0.2", + "import-in-the-middle": "1.7.1", + "require-in-the-middle": "^7.1.1", + "semver": "^7.5.2", + "shimmer": "^1.2.1" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/instrumentation-amqplib": { + "version": "0.35.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-amqplib/-/instrumentation-amqplib-0.35.0.tgz", + "integrity": "sha512-rb3hIWA7f0HXpXpfElnGC6CukRxy58/OJ6XYlTzpZJtNJPao7BuobZjkQEscaRYhUzgi7X7R1aKkIUOTV5JFrg==", + "dependencies": { + "@opentelemetry/core": "^1.8.0", + "@opentelemetry/instrumentation": "^0.49.1", + "@opentelemetry/semantic-conventions": "^1.0.0" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/instrumentation-aws-lambda": { + "version": "0.39.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-aws-lambda/-/instrumentation-aws-lambda-0.39.0.tgz", + "integrity": "sha512-D+oG/hIBDdwCNq7Y6BEuddjcwDVD0C8NhBE7A85mRZ9RLG0bKoWrhIdVvbpqEoa0U5AWe9Y98RX4itNg7WTy4w==", + "dependencies": { + "@opentelemetry/instrumentation": "^0.49.1", + "@opentelemetry/propagator-aws-xray": "^1.3.1", + "@opentelemetry/resources": "^1.8.0", + "@opentelemetry/semantic-conventions": "^1.0.0", + "@types/aws-lambda": "8.10.122" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/instrumentation-aws-sdk": { + "version": "0.39.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-aws-sdk/-/instrumentation-aws-sdk-0.39.1.tgz", + "integrity": "sha512-QnvIMVpzRYqQHSXydGUksbhBjPbMyHSUBwi6ocN7gEXoI711+tIY3R1cfRutl0u3M67A/fAvPI3IgACfJaFORg==", + "dependencies": { + "@opentelemetry/core": "^1.8.0", + "@opentelemetry/instrumentation": "^0.49.1", + "@opentelemetry/propagation-utils": "^0.30.7", + "@opentelemetry/semantic-conventions": "^1.0.0" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/instrumentation-bunyan": { + "version": "0.36.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-bunyan/-/instrumentation-bunyan-0.36.0.tgz", + "integrity": "sha512-sHD5BSiqSrgWow7VmugEFzV8vGdsz5m+w1v9tK6YwRzuAD7vbo57chluq+UBzIqStoCH+0yOzRzSALH7hrfffg==", + "dependencies": { + "@opentelemetry/api-logs": "^0.49.1", + "@opentelemetry/instrumentation": "^0.49.1", + "@types/bunyan": "1.8.9" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/instrumentation-cassandra-driver": { + "version": "0.36.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-cassandra-driver/-/instrumentation-cassandra-driver-0.36.0.tgz", + "integrity": "sha512-gMfxzryOIP/mvSLXBJp/QxSr2NvS+cC1dkIXn+aSOzYoU1U3apeF3nAyuikmY9dRCQDV7wHPslqbi+pCmd4pAQ==", + "dependencies": { + "@opentelemetry/instrumentation": "^0.49.1", + "@opentelemetry/semantic-conventions": "^1.0.0" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/instrumentation-connect": { + "version": "0.34.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-connect/-/instrumentation-connect-0.34.0.tgz", + "integrity": "sha512-PJO99nfyUp3JSoBMhwZsOQDm/XKfkb/QQ8YTsNX4ZJ28phoRcNLqe36mqIMp80DKmKAX4xkxCAyrSYtW8QqZxA==", + "dependencies": { + "@opentelemetry/core": "^1.8.0", + "@opentelemetry/instrumentation": "^0.49.1", + "@opentelemetry/semantic-conventions": "^1.0.0", + "@types/connect": "3.4.36" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/instrumentation-cucumber": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-cucumber/-/instrumentation-cucumber-0.4.0.tgz", + "integrity": "sha512-n53QvozzgMS9imEclow2nBYJ/jtZlZqiKIqDUi2/g0nDi08F555JhDS03d/Z+4NJxbu7bDLAg12giCV9KZN/Jw==", + "dependencies": { + "@opentelemetry/instrumentation": "^0.49.1", + "@opentelemetry/semantic-conventions": "^1.0.0" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.0.0" + } + }, + "node_modules/@opentelemetry/instrumentation-dataloader": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-dataloader/-/instrumentation-dataloader-0.7.0.tgz", + "integrity": "sha512-sIaevxATJV5YaZzBTTcTaDEnI+/1vxYs+lVk1honnvrEAaP0FA9C/cFrQEN0kP2BDHkHRE/t6y5lGUqusi/h3A==", + "dependencies": { + "@opentelemetry/instrumentation": "^0.49.1" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/instrumentation-dns": { + "version": "0.34.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-dns/-/instrumentation-dns-0.34.0.tgz", + "integrity": "sha512-3tmXdvrzHQ7S3v82Cm36PTYLtgg2+hVm00K1xB3uzP08GEo9w/F8DW4me9z6rDroVGiLIg621RZ6dzjBcmmFCg==", + "dependencies": { + "@opentelemetry/instrumentation": "^0.49.1", + "@opentelemetry/semantic-conventions": "^1.0.0", + "semver": "^7.5.4" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/instrumentation-express": { + "version": "0.36.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-express/-/instrumentation-express-0.36.1.tgz", + "integrity": "sha512-ltIE4kIMa+83QjW/p7oe7XCESF29w3FQ9/T1VgShdX7fzm56K2a0xfEX1vF8lnHRGERYxIWX9D086C6gJOjVGA==", + "dependencies": { + "@opentelemetry/core": "^1.8.0", + "@opentelemetry/instrumentation": "^0.49.1", + "@opentelemetry/semantic-conventions": "^1.0.0" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/instrumentation-fastify": { + "version": "0.34.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-fastify/-/instrumentation-fastify-0.34.0.tgz", + "integrity": "sha512-2Qu66XBkfJ8tr6H+RHBTyw/EX73N9U7pvNa49aonDnT9/mK58k7AKOscpRnKXOvHqc2YIdEPRcBIWxhksPFZVA==", + "dependencies": { + "@opentelemetry/core": "^1.8.0", + "@opentelemetry/instrumentation": "^0.49.1", + "@opentelemetry/semantic-conventions": "^1.0.0" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/instrumentation-fs": { + "version": "0.10.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-fs/-/instrumentation-fs-0.10.0.tgz", + "integrity": "sha512-XtMoNINVsIQTQHjtxe7A0Lng96wxA5DSD5CYVVvpquG6HJRdZ4xNe9DTU03YtoEFqlN9qTfvGb/6ILzhKhiG8g==", + "dependencies": { + "@opentelemetry/core": "^1.8.0", + "@opentelemetry/instrumentation": "^0.49.1", + "@opentelemetry/semantic-conventions": "^1.0.0" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/instrumentation-generic-pool": { + "version": "0.34.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-generic-pool/-/instrumentation-generic-pool-0.34.0.tgz", + "integrity": "sha512-jdI7tfVVwZJuTu4j2kAvJtx4wlEQKIXSZnZG4RdqRHc56KqQQDuVTBLvUgmDXvnSVclH9ayf4oaAV08R9fICtw==", + "dependencies": { + "@opentelemetry/instrumentation": "^0.49.1", + "@opentelemetry/semantic-conventions": "^1.0.0" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/instrumentation-graphql": { + "version": "0.38.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-graphql/-/instrumentation-graphql-0.38.1.tgz", + "integrity": "sha512-mSt4ztn3EVlLtZJ+tDEqq5GUEYdY8cbTT9SeVJFmXSfdSQkPZn0ovo/dRe6dUcplM60gg4w+llw8SZuQN0iZfQ==", + "dependencies": { + "@opentelemetry/instrumentation": "^0.49.1" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/instrumentation-grpc": { + "version": "0.49.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-grpc/-/instrumentation-grpc-0.49.1.tgz", + "integrity": "sha512-f8mQjFi5/PiP4SK3VDU1/3sUUgs6exMtBgcnNycgCKgN40htiPT+MuDRwdRnRMNI/4vNQ7p1/5r4Q5oN0GuRBw==", + "dependencies": { + "@opentelemetry/instrumentation": "0.49.1", + "@opentelemetry/semantic-conventions": "1.22.0" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/instrumentation-hapi": { + "version": "0.35.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-hapi/-/instrumentation-hapi-0.35.0.tgz", + "integrity": "sha512-j7q99aTLHfjNKW94qJnEaDatgz+q2psTKs7lxZO4QHRnoDltDk39a44/+AkI1qBJNw5xyLjrApqkglfbWJ2abg==", + "dependencies": { + "@opentelemetry/core": "^1.8.0", + "@opentelemetry/instrumentation": "^0.49.1", + "@opentelemetry/semantic-conventions": "^1.0.0", + "@types/hapi__hapi": "20.0.13" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/instrumentation-http": { + "version": "0.49.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-http/-/instrumentation-http-0.49.1.tgz", + "integrity": "sha512-Yib5zrW2s0V8wTeUK/B3ZtpyP4ldgXj9L3Ws/axXrW1dW0/mEFKifK50MxMQK9g5NNJQS9dWH7rvcEGZdWdQDA==", + "dependencies": { + "@opentelemetry/core": "1.22.0", + "@opentelemetry/instrumentation": "0.49.1", + "@opentelemetry/semantic-conventions": "1.22.0", + "semver": "^7.5.2" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/instrumentation-ioredis": { + "version": "0.38.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-ioredis/-/instrumentation-ioredis-0.38.0.tgz", + "integrity": "sha512-c9nQFhRjFAtpInTks7z5v9CiOCiR8U9GbIhIv0TLEJ/r0wqdKNLfLZzCrr9XQ9WasxeOmziLlPFhpRBAd9Q4oA==", + "dependencies": { + "@opentelemetry/instrumentation": "^0.49.1", + "@opentelemetry/redis-common": "^0.36.1", + "@opentelemetry/semantic-conventions": "^1.0.0", + "@types/ioredis4": "npm:@types/ioredis@^4.28.10" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/instrumentation-knex": { + "version": "0.34.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-knex/-/instrumentation-knex-0.34.0.tgz", + "integrity": "sha512-6kZOEvNJOylTQunU5zSSi4iTuCkwIL9nwFnZg7719p61u3d6Qj3X4xi9su46VE3M0dH7vEoxUW+nb/0ilm+aZg==", + "dependencies": { + "@opentelemetry/instrumentation": "^0.49.1", + "@opentelemetry/semantic-conventions": "^1.0.0" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/instrumentation-koa": { + "version": "0.38.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-koa/-/instrumentation-koa-0.38.0.tgz", + "integrity": "sha512-lQujF4I3wdcrOF14miCV2pC72H+OJKb2LrrmTvTDAhELQDN/95v0doWgT9aHybUGkaAeB3QG4d09sved548TlA==", + "dependencies": { + "@opentelemetry/core": "^1.8.0", + "@opentelemetry/instrumentation": "^0.49.1", + "@opentelemetry/semantic-conventions": "^1.0.0", + "@types/koa": "2.14.0", + "@types/koa__router": "12.0.3" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/instrumentation-lru-memoizer": { + "version": "0.35.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-lru-memoizer/-/instrumentation-lru-memoizer-0.35.0.tgz", + "integrity": "sha512-wCXe+iCF7JweMgY3blLM2Y1G0GSwLEeSA61z/y1UwzvBLEEXt7vL6qOl2mkNcUL9ZbLDS+EABatBH+vFO6DV5Q==", + "dependencies": { + "@opentelemetry/instrumentation": "^0.49.1" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/instrumentation-memcached": { + "version": "0.34.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-memcached/-/instrumentation-memcached-0.34.0.tgz", + "integrity": "sha512-RleFfaag3Evg4pTzHwDBwo1KiFgnCtiT4V6MQRRHadytNGdpcL+Ynz32ydDdiOXeadt7xpRI7HSvBy0quGTXSw==", + "dependencies": { + "@opentelemetry/instrumentation": "^0.49.1", + "@opentelemetry/semantic-conventions": "^1.0.0", + "@types/memcached": "^2.2.6" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/instrumentation-mongodb": { + "version": "0.40.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-mongodb/-/instrumentation-mongodb-0.40.0.tgz", + "integrity": "sha512-ldlJUW/1UlnGtIWBt7fIUl+7+TGOKxIU+0Js5ukpXfQc07ENYFeck5TdbFjvYtF8GppPErnsZJiFiRdYm6Pv/Q==", + "dependencies": { + "@opentelemetry/instrumentation": "^0.49.1", + "@opentelemetry/sdk-metrics": "^1.9.1", + "@opentelemetry/semantic-conventions": "^1.0.0" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/instrumentation-mongoose": { + "version": "0.36.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-mongoose/-/instrumentation-mongoose-0.36.0.tgz", + "integrity": "sha512-UelQ8dLQRLTdck3tPJdZ17b+Hk9usLf1cY2ou5THAaZpulUdpg62Q9Hx2RHRU71Rp2/YMDk25og7GJhuWScfEA==", + "dependencies": { + "@opentelemetry/core": "^1.8.0", + "@opentelemetry/instrumentation": "^0.49.1", + "@opentelemetry/semantic-conventions": "^1.0.0" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/instrumentation-mysql": { + "version": "0.36.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-mysql/-/instrumentation-mysql-0.36.0.tgz", + "integrity": "sha512-2mt/032SLkiuddzMrq3YwM0bHksXRep69EzGRnBfF+bCbwYvKLpqmSFqJZ9T3yY/mBWj+tvdvc1+klXGrh2QnQ==", + "dependencies": { + "@opentelemetry/instrumentation": "^0.49.1", + "@opentelemetry/semantic-conventions": "^1.0.0", + "@types/mysql": "2.15.22" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/instrumentation-mysql2": { + "version": "0.36.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-mysql2/-/instrumentation-mysql2-0.36.0.tgz", + "integrity": "sha512-F63lKcl/R+if2j5Vz66c2/SLXQEtLlFkWTmYb8NQSgmcCaEKjML4RRRjZISIT4IBwdpanJ2qmNuXVM6MYqhBXw==", + "dependencies": { + "@opentelemetry/instrumentation": "^0.49.1", + "@opentelemetry/semantic-conventions": "^1.0.0", + "@opentelemetry/sql-common": "^0.40.0" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/instrumentation-nestjs-core": { + "version": "0.35.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-nestjs-core/-/instrumentation-nestjs-core-0.35.0.tgz", + "integrity": "sha512-INKA7CIOteTSRVxP7SQaFby11AYU3uezI93xDaDRGY4TloXNVoyw5n6UmcVJU4yDn6xY2r7zZ2SVHvblUc21/g==", + "dependencies": { + "@opentelemetry/instrumentation": "^0.49.1", + "@opentelemetry/semantic-conventions": "^1.0.0" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/instrumentation-net": { + "version": "0.34.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-net/-/instrumentation-net-0.34.0.tgz", + "integrity": "sha512-gjybNOQQqbXmD1qVHNO2qBJI4V6p3QQ7xKg3pnC/x7wRdxn+siLQj7QIVxW85C3mymngoJJdRs6BwI3qPUfsPQ==", + "dependencies": { + "@opentelemetry/instrumentation": "^0.49.1", + "@opentelemetry/semantic-conventions": "^1.0.0" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/instrumentation-pg": { + "version": "0.39.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-pg/-/instrumentation-pg-0.39.1.tgz", + "integrity": "sha512-pX5ujDOyGpPcrZlzaD3LJzmyaSMMMKAP+ffTHJp9vasvZJr+LifCk53TMPVUafcXKV/xX/IIkvADO+67M1Z25g==", + "dependencies": { + "@opentelemetry/instrumentation": "^0.49.1", + "@opentelemetry/semantic-conventions": "^1.0.0", + "@opentelemetry/sql-common": "^0.40.0", + "@types/pg": "8.6.1", + "@types/pg-pool": "2.0.4" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/instrumentation-pg/node_modules/@types/pg": { + "version": "8.6.1", + "resolved": "https://registry.npmjs.org/@types/pg/-/pg-8.6.1.tgz", + "integrity": "sha512-1Kc4oAGzAl7uqUStZCDvaLFqZrW9qWSjXOmBfdgyBP5La7Us6Mg4GBvRlSoaZMhQF/zSj1C8CtKMBkoiT8eL8w==", + "dependencies": { + "@types/node": "*", + "pg-protocol": "*", + "pg-types": "^2.2.0" + } + }, + "node_modules/@opentelemetry/instrumentation-pino": { + "version": "0.36.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-pino/-/instrumentation-pino-0.36.0.tgz", + "integrity": "sha512-oEz+BJEYRBMAUu7MVJFJhhlsBuwLaUGjbJciKZRIeGX+fUtgcbQGV+a2Ris9jR3yFzWZrYg0aNBSCbGqvPCtMQ==", + "dependencies": { + "@opentelemetry/instrumentation": "^0.49.1" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/instrumentation-redis": { + "version": "0.37.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-redis/-/instrumentation-redis-0.37.0.tgz", + "integrity": "sha512-9G0T74kheu37k+UvyBnAcieB5iowxska3z2rhUcSTL8Cl0y/CvMn7sZ7txkUbXt0rdX6qeEUdMLmbsY2fPUM7Q==", + "dependencies": { + "@opentelemetry/instrumentation": "^0.49.1", + "@opentelemetry/redis-common": "^0.36.1", + "@opentelemetry/semantic-conventions": "^1.0.0" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/instrumentation-redis-4": { + "version": "0.37.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-redis-4/-/instrumentation-redis-4-0.37.0.tgz", + "integrity": "sha512-WNO+HALvPPvjbh7UEEIuay0Z0d2mIfSCkBZbPRwZttDGX6LYGc2WnRgJh3TnYqjp7/y9IryWIbajAFIebj1OBA==", + "dependencies": { + "@opentelemetry/instrumentation": "^0.49.1", + "@opentelemetry/redis-common": "^0.36.1", + "@opentelemetry/semantic-conventions": "^1.0.0" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/instrumentation-restify": { + "version": "0.36.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-restify/-/instrumentation-restify-0.36.0.tgz", + "integrity": "sha512-QbOh8HpnnRn4xxFXX77Gdww6M78yx7dRiIKR6+H3j5LH5u6sYckTXw3TGPSsXsaM4DQHy0fOw15sAcJoWkC+aQ==", + "dependencies": { + "@opentelemetry/core": "^1.8.0", + "@opentelemetry/instrumentation": "^0.49.1", + "@opentelemetry/semantic-conventions": "^1.0.0" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/instrumentation-router": { + "version": "0.35.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-router/-/instrumentation-router-0.35.0.tgz", + "integrity": "sha512-MdxGJuNTIy/2qDI8yow6cRBQ87m6O//VuHIlawe8v0x1NsTOSwS72xm+BzTuY9D0iMqiJUiTlE3dBs8DA91MTw==", + "dependencies": { + "@opentelemetry/instrumentation": "^0.49.1", + "@opentelemetry/semantic-conventions": "^1.0.0" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/instrumentation-socket.io": { + "version": "0.37.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-socket.io/-/instrumentation-socket.io-0.37.0.tgz", + "integrity": "sha512-aIztxmx/yis/goEndnoITrZvDDr1GdCtlsWo9ex7MhUIjqq5nJbTuyigf3GmU86XFFhSThxfQuJ9DpJyPxfBfA==", + "dependencies": { + "@opentelemetry/instrumentation": "^0.49.1", + "@opentelemetry/semantic-conventions": "^1.0.0" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/instrumentation-tedious": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-tedious/-/instrumentation-tedious-0.8.0.tgz", + "integrity": "sha512-BBRW8+Qm2PLNkVMynr3Q7L4xCAOCOs0J9BJIJ8ZGoatW42b2H4qhMhq35jfPDvEL5u5azxHDapmUVYrDJDjAfA==", + "dependencies": { + "@opentelemetry/instrumentation": "^0.49.1", + "@opentelemetry/semantic-conventions": "^1.0.0", + "@types/tedious": "^4.0.10" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/instrumentation-winston": { + "version": "0.35.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-winston/-/instrumentation-winston-0.35.0.tgz", + "integrity": "sha512-ymcuA3S2flnLmH1GS0105H91iDLap8cizOCaLMCp7Xz7r4L+wFf1zfix9M+iSkxcPFshHRt8LFA/ELXw51nk0g==", + "dependencies": { + "@opentelemetry/instrumentation": "^0.49.1" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/otlp-exporter-base": { + "version": "0.49.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/otlp-exporter-base/-/otlp-exporter-base-0.49.1.tgz", + "integrity": "sha512-z6sHliPqDgJU45kQatAettY9/eVF58qVPaTuejw9YWfSRqid9pXPYeegDCSdyS47KAUgAtm+nC28K3pfF27HWg==", + "dependencies": { + "@opentelemetry/core": "1.22.0" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.0.0" + } + }, + "node_modules/@opentelemetry/otlp-grpc-exporter-base": { + "version": "0.49.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/otlp-grpc-exporter-base/-/otlp-grpc-exporter-base-0.49.1.tgz", + "integrity": "sha512-DNDNUWmOqtKTFJAyOyHHKotVox0NQ/09ETX8fUOeEtyNVHoGekAVtBbvIA3AtK+JflP7LC0PTjlLfruPM3Wy6w==", + "dependencies": { + "@grpc/grpc-js": "^1.7.1", + "@opentelemetry/core": "1.22.0", + "@opentelemetry/otlp-exporter-base": "0.49.1", + "protobufjs": "^7.2.3" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.0.0" + } + }, + "node_modules/@opentelemetry/otlp-proto-exporter-base": { + "version": "0.49.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/otlp-proto-exporter-base/-/otlp-proto-exporter-base-0.49.1.tgz", + "integrity": "sha512-x1qB4EUC7KikUl2iNuxCkV8yRzrSXSyj4itfpIO674H7dhI7Zv37SFaOJTDN+8Z/F50gF2ISFH9CWQ4KCtGm2A==", + "dependencies": { + "@opentelemetry/core": "1.22.0", + "@opentelemetry/otlp-exporter-base": "0.49.1", + "protobufjs": "^7.2.3" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.0.0" + } + }, + "node_modules/@opentelemetry/otlp-transformer": { + "version": "0.49.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/otlp-transformer/-/otlp-transformer-0.49.1.tgz", + "integrity": "sha512-Z+koA4wp9L9e3jkFacyXTGphSWTbOKjwwXMpb0CxNb0kjTHGUxhYRN8GnkLFsFo5NbZPjP07hwAqeEG/uCratQ==", + "dependencies": { + "@opentelemetry/api-logs": "0.49.1", + "@opentelemetry/core": "1.22.0", + "@opentelemetry/resources": "1.22.0", + "@opentelemetry/sdk-logs": "0.49.1", + "@opentelemetry/sdk-metrics": "1.22.0", + "@opentelemetry/sdk-trace-base": "1.22.0" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.3.0 <1.9.0" + } + }, + "node_modules/@opentelemetry/propagation-utils": { + "version": "0.30.7", + "resolved": "https://registry.npmjs.org/@opentelemetry/propagation-utils/-/propagation-utils-0.30.7.tgz", + "integrity": "sha512-QkxOkuCQdq8YgJstEMF4ntSyr0ivCrcQc49uvO2pyccrniu2DwA+JD071aM4BXfNVSCeOuhIyW/3QPiZYl4zdA==", + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.0.0" + } + }, + "node_modules/@opentelemetry/propagator-aws-xray": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/propagator-aws-xray/-/propagator-aws-xray-1.3.1.tgz", + "integrity": "sha512-6fDMzFlt5r6VWv7MUd0eOpglXPFqykW8CnOuUxJ1VZyLy6mV1bzBlzpsqEmhx1bjvZYvH93vhGkQZqrm95mlrQ==", + "dependencies": { + "@opentelemetry/core": "^1.0.0" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.0.0" + } + }, + "node_modules/@opentelemetry/propagator-b3": { + "version": "1.22.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/propagator-b3/-/propagator-b3-1.22.0.tgz", + "integrity": "sha512-qBItJm9ygg/jCB5rmivyGz1qmKZPsL/sX715JqPMFgq++Idm0x+N9sLQvWFHFt2+ZINnCSojw7FVBgFW6izcXA==", + "dependencies": { + "@opentelemetry/core": "1.22.0" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.0.0 <1.9.0" + } + }, + "node_modules/@opentelemetry/propagator-jaeger": { + "version": "1.22.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/propagator-jaeger/-/propagator-jaeger-1.22.0.tgz", + "integrity": "sha512-pMLgst3QIwrUfepraH5WG7xfpJ8J3CrPKrtINK0t7kBkuu96rn+HDYQ8kt3+0FXvrZI8YJE77MCQwnJWXIrgpA==", + "dependencies": { + "@opentelemetry/core": "1.22.0" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.0.0 <1.9.0" + } + }, + "node_modules/@opentelemetry/redis-common": { + "version": "0.36.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/redis-common/-/redis-common-0.36.1.tgz", + "integrity": "sha512-YjfNEr7DK1Ymc5H0bzhmqVvMcCs+PUEUerzrpTFdHfZxj3HpnnjZTIFKx/gxiL/sajQ8dxycjlreoYTVYKBXlw==", + "engines": { + "node": ">=14" + } + }, + "node_modules/@opentelemetry/resource-detector-alibaba-cloud": { + "version": "0.28.7", + "resolved": "https://registry.npmjs.org/@opentelemetry/resource-detector-alibaba-cloud/-/resource-detector-alibaba-cloud-0.28.7.tgz", + "integrity": "sha512-7o/waBJ08JrKED4blHGyBPIN1HMM1KEvhbO1HmdA+tsUqsGwZdTjsdMKFW7hc1TvAu4AQEnuvMy/Q5OByVr95A==", + "dependencies": { + "@opentelemetry/resources": "^1.0.0", + "@opentelemetry/semantic-conventions": "^1.0.0" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.0.0" + } + }, + "node_modules/@opentelemetry/resource-detector-aws": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/resource-detector-aws/-/resource-detector-aws-1.4.0.tgz", + "integrity": "sha512-Cn8eQ/heLqrNrPuHGG7xUkk//VQt4hzVIPurmLlCI0wrDV6HR+yykBvRkJBuSdLzbjeQ/qNbGel9OvTmA6PBQA==", + "dependencies": { + "@opentelemetry/core": "^1.0.0", + "@opentelemetry/resources": "^1.0.0", + "@opentelemetry/semantic-conventions": "^1.0.0" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.0.0" + } + }, + "node_modules/@opentelemetry/resource-detector-container": { + "version": "0.3.7", + "resolved": "https://registry.npmjs.org/@opentelemetry/resource-detector-container/-/resource-detector-container-0.3.7.tgz", + "integrity": "sha512-AYqwffGVuGLuzzVOQMLNHTztwyvsep9noxN9HTQ/grwmJSWZ6851kNx+W735K7v6GZEDmXeLpBn+J3TeqKQUJA==", + "dependencies": { + "@opentelemetry/resources": "^1.0.0", + "@opentelemetry/semantic-conventions": "^1.0.0" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.0.0" + } + }, + "node_modules/@opentelemetry/resource-detector-gcp": { + "version": "0.29.7", + "resolved": "https://registry.npmjs.org/@opentelemetry/resource-detector-gcp/-/resource-detector-gcp-0.29.7.tgz", + "integrity": "sha512-uUHKfoOgBCZCEPCU6FWnRrbYuz1miaeIfos0Xe38YuR06vQvddhqZ0tewYunJpfECfKEcjSjY0eDe2QIRLMkXw==", + "dependencies": { + "@opentelemetry/core": "^1.0.0", + "@opentelemetry/resources": "^1.0.0", + "@opentelemetry/semantic-conventions": "^1.0.0", + "gcp-metadata": "^6.0.0" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.0.0" + } + }, + "node_modules/@opentelemetry/resources": { + "version": "1.22.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/resources/-/resources-1.22.0.tgz", + "integrity": "sha512-+vNeIFPH2hfcNL0AJk/ykJXoUCtR1YaDUZM+p3wZNU4Hq98gzq+7b43xbkXjadD9VhWIUQqEwXyY64q6msPj6A==", + "dependencies": { + "@opentelemetry/core": "1.22.0", + "@opentelemetry/semantic-conventions": "1.22.0" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.0.0 <1.9.0" + } + }, + "node_modules/@opentelemetry/sdk-logs": { + "version": "0.49.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-logs/-/sdk-logs-0.49.1.tgz", + "integrity": "sha512-gCzYWsJE0h+3cuh3/cK+9UwlVFyHvj3PReIOCDOmdeXOp90ZjKRoDOJBc3mvk1LL6wyl1RWIivR8Rg9OToyesw==", + "dependencies": { + "@opentelemetry/core": "1.22.0", + "@opentelemetry/resources": "1.22.0" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.4.0 <1.9.0", + "@opentelemetry/api-logs": ">=0.39.1" + } + }, + "node_modules/@opentelemetry/sdk-metrics": { + "version": "1.22.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-metrics/-/sdk-metrics-1.22.0.tgz", + "integrity": "sha512-k6iIx6H3TZ+BVMr2z8M16ri2OxWaljg5h8ihGJxi/KQWcjign6FEaEzuigXt5bK9wVEhqAcWLCfarSftaNWkkg==", + "dependencies": { + "@opentelemetry/core": "1.22.0", + "@opentelemetry/resources": "1.22.0", + "lodash.merge": "^4.6.2" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.3.0 <1.9.0" + } + }, + "node_modules/@opentelemetry/sdk-node": { + "version": "0.49.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-node/-/sdk-node-0.49.1.tgz", + "integrity": "sha512-feBIT85ndiSHXsQ2gfGpXC/sNeX4GCHLksC4A9s/bfpUbbgbCSl0RvzZlmEpCHarNrkZMwFRi4H0xFfgvJEjrg==", + "dependencies": { + "@opentelemetry/api-logs": "0.49.1", + "@opentelemetry/core": "1.22.0", + "@opentelemetry/exporter-trace-otlp-grpc": "0.49.1", + "@opentelemetry/exporter-trace-otlp-http": "0.49.1", + "@opentelemetry/exporter-trace-otlp-proto": "0.49.1", + "@opentelemetry/exporter-zipkin": "1.22.0", + "@opentelemetry/instrumentation": "0.49.1", + "@opentelemetry/resources": "1.22.0", + "@opentelemetry/sdk-logs": "0.49.1", + "@opentelemetry/sdk-metrics": "1.22.0", + "@opentelemetry/sdk-trace-base": "1.22.0", + "@opentelemetry/sdk-trace-node": "1.22.0", + "@opentelemetry/semantic-conventions": "1.22.0" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.3.0 <1.9.0" + } + }, + "node_modules/@opentelemetry/sdk-trace-base": { + "version": "1.22.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-trace-base/-/sdk-trace-base-1.22.0.tgz", + "integrity": "sha512-pfTuSIpCKONC6vkTpv6VmACxD+P1woZf4q0K46nSUvXFvOFqjBYKFaAMkKD3M1mlKUUh0Oajwj35qNjMl80m1Q==", + "dependencies": { + "@opentelemetry/core": "1.22.0", + "@opentelemetry/resources": "1.22.0", + "@opentelemetry/semantic-conventions": "1.22.0" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.0.0 <1.9.0" + } + }, + "node_modules/@opentelemetry/sdk-trace-node": { + "version": "1.22.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-trace-node/-/sdk-trace-node-1.22.0.tgz", + "integrity": "sha512-gTGquNz7ue8uMeiWPwp3CU321OstQ84r7PCDtOaCicjbJxzvO8RZMlEC4geOipTeiF88kss5n6w+//A0MhP1lQ==", + "dependencies": { + "@opentelemetry/context-async-hooks": "1.22.0", + "@opentelemetry/core": "1.22.0", + "@opentelemetry/propagator-b3": "1.22.0", + "@opentelemetry/propagator-jaeger": "1.22.0", + "@opentelemetry/sdk-trace-base": "1.22.0", + "semver": "^7.5.2" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.0.0 <1.9.0" + } + }, + "node_modules/@opentelemetry/semantic-conventions": { + "version": "1.22.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/semantic-conventions/-/semantic-conventions-1.22.0.tgz", + "integrity": "sha512-CAOgFOKLybd02uj/GhCdEeeBjOS0yeoDeo/CA7ASBSmenpZHAKGB3iDm/rv3BQLcabb/OprDEsSQ1y0P8A7Siw==", + "engines": { + "node": ">=14" + } + }, + "node_modules/@opentelemetry/sql-common": { + "version": "0.40.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/sql-common/-/sql-common-0.40.0.tgz", + "integrity": "sha512-vSqRJYUPJVjMFQpYkQS3ruexCPSZJ8esne3LazLwtCPaPRvzZ7WG3tX44RouAn7w4wMp8orKguBqtt+ng2UTnw==", + "dependencies": { + "@opentelemetry/core": "^1.1.0" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.1.0" + } + }, "node_modules/@photostructure/tz-lookup": { "version": "9.0.1", "resolved": "https://registry.npmjs.org/@photostructure/tz-lookup/-/tz-lookup-9.0.1.tgz", @@ -2734,6 +4046,60 @@ "resolved": "https://registry.npmjs.org/@polka/url/-/url-1.0.0-next.25.tgz", "integrity": "sha512-j7P6Rgr3mmtdkeDGTe0E/aYyWEWVtc5yFXtHCRHs28/jptDEWfaVOc5T7cblqy1XKPPfCxJc/8DwQ5YgLOZOVQ==" }, + "node_modules/@protobufjs/aspromise": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@protobufjs/aspromise/-/aspromise-1.1.2.tgz", + "integrity": "sha512-j+gKExEuLmKwvz3OgROXtrJ2UG2x8Ch2YZUxahh+s1F2HZ+wAceUNLkvy6zKCPVRkU++ZWQrdxsUeQXmcg4uoQ==" + }, + "node_modules/@protobufjs/base64": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@protobufjs/base64/-/base64-1.1.2.tgz", + "integrity": "sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg==" + }, + "node_modules/@protobufjs/codegen": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@protobufjs/codegen/-/codegen-2.0.4.tgz", + "integrity": "sha512-YyFaikqM5sH0ziFZCN3xDC7zeGaB/d0IUb9CATugHWbd1FRFwWwt4ld4OYMPWu5a3Xe01mGAULCdqhMlPl29Jg==" + }, + "node_modules/@protobufjs/eventemitter": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/eventemitter/-/eventemitter-1.1.0.tgz", + "integrity": "sha512-j9ednRT81vYJ9OfVuXG6ERSTdEL1xVsNgqpkxMsbIabzSo3goCjDIveeGv5d03om39ML71RdmrGNjG5SReBP/Q==" + }, + "node_modules/@protobufjs/fetch": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/fetch/-/fetch-1.1.0.tgz", + "integrity": "sha512-lljVXpqXebpsijW71PZaCYeIcE5on1w5DlQy5WH6GLbFryLUrBD4932W/E2BSpfRJWseIL4v/KPgBFxDOIdKpQ==", + "dependencies": { + "@protobufjs/aspromise": "^1.1.1", + "@protobufjs/inquire": "^1.1.0" + } + }, + "node_modules/@protobufjs/float": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@protobufjs/float/-/float-1.0.2.tgz", + "integrity": "sha512-Ddb+kVXlXst9d+R9PfTIxh1EdNkgoRe5tOX6t01f1lYWOvJnSPDBlG241QLzcyPdoNTsblLUdujGSE4RzrTZGQ==" + }, + "node_modules/@protobufjs/inquire": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/inquire/-/inquire-1.1.0.tgz", + "integrity": "sha512-kdSefcPdruJiFMVSbn801t4vFK7KB/5gd2fYvrxhuJYg8ILrmn9SKSX2tZdV6V+ksulWqS7aXjBcRXl3wHoD9Q==" + }, + "node_modules/@protobufjs/path": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@protobufjs/path/-/path-1.1.2.tgz", + "integrity": "sha512-6JOcJ5Tm08dOHAbdR3GrvP+yUUfkjG5ePsHYczMFLq3ZmMkAD98cDgcT2iA1lJ9NVwFd4tH/iSSoe44YWkltEA==" + }, + "node_modules/@protobufjs/pool": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/pool/-/pool-1.1.0.tgz", + "integrity": "sha512-0kELaGSIDBKvcgS4zkjz1PeddatrjYcmMWOlAuAPwAeccUrPHdUqo/J6LiymHHEiJT5NrF1UVwxY14f+fy4WQw==" + }, + "node_modules/@protobufjs/utf8": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/utf8/-/utf8-1.1.0.tgz", + "integrity": "sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw==" + }, "node_modules/@sideway/address": { "version": "4.1.5", "resolved": "https://registry.npmjs.org/@sideway/address/-/address-4.1.5.tgz", @@ -2867,6 +4233,14 @@ "url": "https://opencollective.com/turf" } }, + "node_modules/@types/accepts": { + "version": "1.3.7", + "resolved": "https://registry.npmjs.org/@types/accepts/-/accepts-1.3.7.tgz", + "integrity": "sha512-Pay9fq2lM2wXPWbteBsRAGiWH2hig4ZE2asK+mm7kUzlxRTfL961rj89I6zV/E3PcIkDqyuBEcMxFT7rccugeQ==", + "dependencies": { + "@types/node": "*" + } + }, "node_modules/@types/archiver": { "version": "6.0.2", "resolved": "https://registry.npmjs.org/@types/archiver/-/archiver-6.0.2.tgz", @@ -2882,6 +4256,11 @@ "integrity": "sha512-HlZ6Dcr205BmNhwkdXqrg2vkFMN2PluI7Lgr8In3B3wE5PiQHhjRqtW/lGdVU9gw+sM0JcIDx2AN+cW8oSWIcw==", "dev": true }, + "node_modules/@types/aws-lambda": { + "version": "8.10.122", + "resolved": "https://registry.npmjs.org/@types/aws-lambda/-/aws-lambda-8.10.122.tgz", + "integrity": "sha512-vBkIh9AY22kVOCEKo5CJlyCgmSWvasC+SWUxL/x/vOwRobMpI/HG1xp/Ae3AqmSiZeLUbOhW0FCD3ZjqqUxmXw==" + }, "node_modules/@types/babel__core": { "version": "7.20.2", "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.2.tgz", @@ -2936,21 +4315,32 @@ "version": "1.19.3", "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.3.tgz", "integrity": "sha512-oyl4jvAfTGX9Bt6Or4H9ni1Z447/tQuxnZsytsCaExKlmJiU8sFgnIBRzJUpKwB5eWn9HuBYlUlVA74q/yN0eQ==", - "dev": true, "dependencies": { "@types/connect": "*", "@types/node": "*" } }, + "node_modules/@types/bunyan": { + "version": "1.8.9", + "resolved": "https://registry.npmjs.org/@types/bunyan/-/bunyan-1.8.9.tgz", + "integrity": "sha512-ZqS9JGpBxVOvsawzmVt30sP++gSQMTejCkIAQ3VdadOcRE8izTyW66hufvwLeH+YEGP6Js2AW7Gz+RMyvrEbmw==", + "dependencies": { + "@types/node": "*" + } + }, "node_modules/@types/connect": { "version": "3.4.36", "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.36.tgz", "integrity": "sha512-P63Zd/JUGq+PdrM1lv0Wv5SBYeA2+CORvbrXbngriYY0jzLUWfQMQQxOhjONEz/wlHOAxOdY7CY65rgQdTjq2w==", - "dev": true, "dependencies": { "@types/node": "*" } }, + "node_modules/@types/content-disposition": { + "version": "0.5.8", + "resolved": "https://registry.npmjs.org/@types/content-disposition/-/content-disposition-0.5.8.tgz", + "integrity": "sha512-QVSSvno3dE0MgO76pJhmv4Qyi/j0Yk9pBp0Y7TJ2Tlj+KCgJWY6qX7nnxCOLkZ3VYRSIk1WTxCvwUSdx6CCLdg==" + }, "node_modules/@types/cookie": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/@types/cookie/-/cookie-0.4.1.tgz", @@ -2971,6 +4361,17 @@ "integrity": "sha512-he+DHOWReW0nghN24E1WUqM0efK4kI9oTqDm6XmK8ZPe2djZ90BSNdGnIyCLzCPw7/pogPlGbzI2wHGGmi4O/Q==", "dev": true }, + "node_modules/@types/cookies": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/@types/cookies/-/cookies-0.9.0.tgz", + "integrity": "sha512-40Zk8qR147RABiQ7NQnBzWzDcjKzNrntB5BAmeGCb2p/MIyOE+4BVvc17wumsUqUw00bJYqoXFHYygQnEFh4/Q==", + "dependencies": { + "@types/connect": "*", + "@types/express": "*", + "@types/keygrip": "*", + "@types/node": "*" + } + }, "node_modules/@types/cors": { "version": "2.8.14", "resolved": "https://registry.npmjs.org/@types/cors/-/cors-2.8.14.tgz", @@ -3029,7 +4430,6 @@ "version": "4.17.21", "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.21.tgz", "integrity": "sha512-ejlPM315qwLpaQlQDTjPdsUFSc6ZsP4AN6AlWnogPjQ7CVi7PYF3YVz+CY3jE2pwYf7E/7HlDAN0rV2GxTG0HQ==", - "dev": true, "dependencies": { "@types/body-parser": "*", "@types/express-serve-static-core": "^4.17.33", @@ -3041,7 +4441,6 @@ "version": "4.17.37", "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.37.tgz", "integrity": "sha512-ZohaCYTgGFcOP7u6aJOhY9uIZQgZ2vxC2yWoArY+FeDXlqeH66ZVBjgvg+RLVAS/DWNq4Ap9ZXu1+SUQiiWYMg==", - "dev": true, "dependencies": { "@types/node": "*", "@types/qs": "*", @@ -3067,11 +4466,51 @@ "@types/node": "*" } }, + "node_modules/@types/hapi__catbox": { + "version": "10.2.6", + "resolved": "https://registry.npmjs.org/@types/hapi__catbox/-/hapi__catbox-10.2.6.tgz", + "integrity": "sha512-qdMHk4fBlwRfnBBDJaoaxb+fU9Ewi2xqkXD3mNjSPl2v/G/8IJbDpVRBuIcF7oXrcE8YebU5M8cCeKh1NXEn0w==" + }, + "node_modules/@types/hapi__hapi": { + "version": "20.0.13", + "resolved": "https://registry.npmjs.org/@types/hapi__hapi/-/hapi__hapi-20.0.13.tgz", + "integrity": "sha512-LP4IPfhIO5ZPVOrJo7H8c8Slc0WYTFAUNQX1U0LBPKyXioXhH5H2TawIgxKujIyOhbwoBbpvOsBf6o5+ToJIrQ==", + "dependencies": { + "@hapi/boom": "^9.0.0", + "@hapi/iron": "^6.0.0", + "@hapi/podium": "^4.1.3", + "@types/hapi__catbox": "*", + "@types/hapi__mimos": "*", + "@types/hapi__shot": "*", + "@types/node": "*", + "joi": "^17.3.0" + } + }, + "node_modules/@types/hapi__mimos": { + "version": "4.1.4", + "resolved": "https://registry.npmjs.org/@types/hapi__mimos/-/hapi__mimos-4.1.4.tgz", + "integrity": "sha512-i9hvJpFYTT/qzB5xKWvDYaSXrIiNqi4ephi+5Lo6+DoQdwqPXQgmVVOZR+s3MBiHoFqsCZCX9TmVWG3HczmTEQ==", + "dependencies": { + "@types/mime-db": "*" + } + }, + "node_modules/@types/hapi__shot": { + "version": "4.1.6", + "resolved": "https://registry.npmjs.org/@types/hapi__shot/-/hapi__shot-4.1.6.tgz", + "integrity": "sha512-h33NBjx2WyOs/9JgcFeFhkxnioYWQAZxOHdmqDuoJ1Qjxpcs+JGvSjEEoDeWfcrF+1n47kKgqph5IpfmPOnzbg==", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/http-assert": { + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/@types/http-assert/-/http-assert-1.5.5.tgz", + "integrity": "sha512-4+tE/lwdAahgZT1g30Jkdm9PzFRde0xwxBNUyRsCitRvCQB90iuA2uJYdUnhnANRcqGXaWOGY4FEoxeElNAK2g==" + }, "node_modules/@types/http-errors": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/@types/http-errors/-/http-errors-2.0.2.tgz", - "integrity": "sha512-lPG6KlZs88gef6aD85z3HNkztpj7w2R7HmR3gygjfXCQmsLloWNARFkMuzKiiY8FGdh1XDpgBdrSf4aKDiA7Kg==", - "dev": true + "integrity": "sha512-lPG6KlZs88gef6aD85z3HNkztpj7w2R7HmR3gygjfXCQmsLloWNARFkMuzKiiY8FGdh1XDpgBdrSf4aKDiA7Kg==" }, "node_modules/@types/imagemin": { "version": "8.0.5", @@ -3092,6 +4531,15 @@ "rxjs": "^7.2.0" } }, + "node_modules/@types/ioredis4": { + "name": "@types/ioredis", + "version": "4.28.10", + "resolved": "https://registry.npmjs.org/@types/ioredis/-/ioredis-4.28.10.tgz", + "integrity": "sha512-69LyhUgrXdgcNDv7ogs1qXZomnfOEnSmrmMFqKgt1XMJxmoOSG/u3wYy13yACIfKuMJ8IhKgHafDO3sx19zVQQ==", + "dependencies": { + "@types/node": "*" + } + }, "node_modules/@types/istanbul-lib-coverage": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.4.tgz", @@ -3135,12 +4583,54 @@ "@types/jest": "*" } }, + "node_modules/@types/js-yaml": { + "version": "4.0.9", + "resolved": "https://registry.npmjs.org/@types/js-yaml/-/js-yaml-4.0.9.tgz", + "integrity": "sha512-k4MGaQl5TGo/iipqb2UDG2UwjXziSWkh0uysQelTlJpX1qGlpUZYm8PnO4DxG1qBomtJUdYJ6qR6xdIah10JLg==", + "dev": true + }, "node_modules/@types/json-schema": { "version": "7.0.13", "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.13.tgz", "integrity": "sha512-RbSSoHliUbnXj3ny0CNFOoxrIDV6SUGyStHsvDqosw6CkdPV8TtWGlfecuK4ToyMEAql6pzNxgCFKanovUzlgQ==", "dev": true }, + "node_modules/@types/keygrip": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/@types/keygrip/-/keygrip-1.0.6.tgz", + "integrity": "sha512-lZuNAY9xeJt7Bx4t4dx0rYCDqGPW8RXhQZK1td7d4H6E9zYbLoOtjBvfwdTKpsyxQI/2jv+armjX/RW+ZNpXOQ==" + }, + "node_modules/@types/koa": { + "version": "2.14.0", + "resolved": "https://registry.npmjs.org/@types/koa/-/koa-2.14.0.tgz", + "integrity": "sha512-DTDUyznHGNHAl+wd1n0z1jxNajduyTh8R53xoewuerdBzGo6Ogj6F2299BFtrexJw4NtgjsI5SMPCmV9gZwGXA==", + "dependencies": { + "@types/accepts": "*", + "@types/content-disposition": "*", + "@types/cookies": "*", + "@types/http-assert": "*", + "@types/http-errors": "*", + "@types/keygrip": "*", + "@types/koa-compose": "*", + "@types/node": "*" + } + }, + "node_modules/@types/koa__router": { + "version": "12.0.3", + "resolved": "https://registry.npmjs.org/@types/koa__router/-/koa__router-12.0.3.tgz", + "integrity": "sha512-5YUJVv6NwM1z7m6FuYpKfNLTZ932Z6EF6xy2BbtpJSyn13DKNQEkXVffFVSnJHxvwwWh2SAeumpjAYUELqgjyw==", + "dependencies": { + "@types/koa": "*" + } + }, + "node_modules/@types/koa-compose": { + "version": "3.2.8", + "resolved": "https://registry.npmjs.org/@types/koa-compose/-/koa-compose-3.2.8.tgz", + "integrity": "sha512-4Olc63RY+MKvxMwVknCUDhRQX1pFQoBZ/lXcRLP69PQkEpze/0cr8LNqJQe5NFb/b19DWi2a5bTi2VAlQzhJuA==", + "dependencies": { + "@types/koa": "*" + } + }, "node_modules/@types/lodash": { "version": "4.14.202", "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.202.tgz", @@ -3152,6 +4642,14 @@ "resolved": "https://registry.npmjs.org/@types/luxon/-/luxon-3.3.7.tgz", "integrity": "sha512-gKc9P2d4g5uYwmy4s/MO/yOVPmvHyvzka1YH6i5dM03UrFofHSmgc0D0ymbDRStFWHusk6cwwF6nhLm/ckBbbQ==" }, + "node_modules/@types/memcached": { + "version": "2.2.10", + "resolved": "https://registry.npmjs.org/@types/memcached/-/memcached-2.2.10.tgz", + "integrity": "sha512-AM9smvZN55Gzs2wRrqeMHVP7KE8KWgCJO/XL5yCly2xF6EKa4YlbpK+cLSAH4NG/Ah64HrlegmGqW8kYws7Vxg==", + "dependencies": { + "@types/node": "*" + } + }, "node_modules/@types/methods": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/@types/methods/-/methods-1.1.4.tgz", @@ -3161,8 +4659,12 @@ "node_modules/@types/mime": { "version": "1.3.3", "resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.3.tgz", - "integrity": "sha512-Ys+/St+2VF4+xuY6+kDIXGxbNRO0mesVg0bbxEfB97Od1Vjpjx9KD1qxs64Gcb3CWPirk9Xe+PT4YiiHQ9T+eg==", - "dev": true + "integrity": "sha512-Ys+/St+2VF4+xuY6+kDIXGxbNRO0mesVg0bbxEfB97Od1Vjpjx9KD1qxs64Gcb3CWPirk9Xe+PT4YiiHQ9T+eg==" + }, + "node_modules/@types/mime-db": { + "version": "1.43.5", + "resolved": "https://registry.npmjs.org/@types/mime-db/-/mime-db-1.43.5.tgz", + "integrity": "sha512-/bfTiIUTNPUBnwnYvUxXAre5MhD88jgagLEQiQtIASjU+bwxd8kS/ASDA4a8ufd8m0Lheu6eeMJHEUpLHoJ28A==" }, "node_modules/@types/mock-fs": { "version": "4.13.4", @@ -3182,10 +4684,18 @@ "@types/express": "*" } }, + "node_modules/@types/mysql": { + "version": "2.15.22", + "resolved": "https://registry.npmjs.org/@types/mysql/-/mysql-2.15.22.tgz", + "integrity": "sha512-wK1pzsJVVAjYCSZWQoWHziQZbNggXFDUEIGf54g4ZM/ERuP86uGdWeKZWMYlqTPMZfHJJvLPyogXGvCOg87yLQ==", + "dependencies": { + "@types/node": "*" + } + }, "node_modules/@types/node": { - "version": "20.11.24", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.11.24.tgz", - "integrity": "sha512-Kza43ewS3xoLgCEpQrsT+xRo/EJej1y0kVYGiLFE1NEODXGzTfwiC6tXTLMQskn1X4/Rjlh0MQUvx9W+L9long==", + "version": "20.11.25", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.11.25.tgz", + "integrity": "sha512-TBHyJxk2b7HceLVGFcpAUjsa5zIdsPWlR6XHfyGzd0SFu+/NFgQgMAl96MSDZgQDvJAvV6BKsFOrt6zIL09JDw==", "dependencies": { "undici-types": "~5.26.4" } @@ -3206,6 +4716,14 @@ "pg-types": "^4.0.1" } }, + "node_modules/@types/pg-pool": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@types/pg-pool/-/pg-pool-2.0.4.tgz", + "integrity": "sha512-qZAvkv1K3QbmHHFYSNRYPkRjOWRLBYrL4B9c+wG0GSVGBw0NtJwPcgx/DSddeDJvRGMHCEQ4VMEVfuJ/0gZ3XQ==", + "dependencies": { + "@types/pg": "*" + } + }, "node_modules/@types/pg/node_modules/pg-types": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/pg-types/-/pg-types-4.0.1.tgz", @@ -3266,14 +4784,12 @@ "node_modules/@types/qs": { "version": "6.9.8", "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.8.tgz", - "integrity": "sha512-u95svzDlTysU5xecFNTgfFG5RUWu1A9P0VzgpcIiGZA9iraHOdSzcxMxQ55DyeRaGCSxQi7LxXDI4rzq/MYfdg==", - "dev": true + "integrity": "sha512-u95svzDlTysU5xecFNTgfFG5RUWu1A9P0VzgpcIiGZA9iraHOdSzcxMxQ55DyeRaGCSxQi7LxXDI4rzq/MYfdg==" }, "node_modules/@types/range-parser": { "version": "1.2.5", "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.5.tgz", - "integrity": "sha512-xrO9OoVPqFuYyR/loIHjnbvvyRZREYKLjxV4+dY6v3FQR3stQ9ZxIGkaclF7YhI9hfjpuTbu14hZEy94qKLtOA==", - "dev": true + "integrity": "sha512-xrO9OoVPqFuYyR/loIHjnbvvyRZREYKLjxV4+dY6v3FQR3stQ9ZxIGkaclF7YhI9hfjpuTbu14hZEy94qKLtOA==" }, "node_modules/@types/readdir-glob": { "version": "1.1.2", @@ -3294,7 +4810,6 @@ "version": "0.17.2", "resolved": "https://registry.npmjs.org/@types/send/-/send-0.17.2.tgz", "integrity": "sha512-aAG6yRf6r0wQ29bkS+x97BIs64ZLxeE/ARwyS6wrldMm3C1MdKwCcnnEwMC1slI8wuxJOpiUH9MioC0A0i+GJw==", - "dev": true, "dependencies": { "@types/mime": "^1", "@types/node": "*" @@ -3304,7 +4819,6 @@ "version": "1.15.3", "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.15.3.tgz", "integrity": "sha512-yVRvFsEMrv7s0lGhzrggJjNOSmZCdgCjw9xWrPr/kNNLp6FaDfMC1KaYl3TSJ0c58bECwNBMoQrZJ8hA8E1eFg==", - "dev": true, "dependencies": { "@types/http-errors": "*", "@types/mime": "*", @@ -3320,6 +4834,11 @@ "@types/node": "*" } }, + "node_modules/@types/shimmer": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/@types/shimmer/-/shimmer-1.0.5.tgz", + "integrity": "sha512-9Hp0ObzwwO57DpLFF0InUjUm/II8GmKAvzbefxQTihCb7KI6yc9yzf0nLc4mVdby5N4DRCgQM2wCup9KTieeww==" + }, "node_modules/@types/ssh2": { "version": "0.5.52", "resolved": "https://registry.npmjs.org/@types/ssh2/-/ssh2-0.5.52.tgz", @@ -3366,6 +4885,14 @@ "@types/superagent": "^8.1.0" } }, + "node_modules/@types/tedious": { + "version": "4.0.14", + "resolved": "https://registry.npmjs.org/@types/tedious/-/tedious-4.0.14.tgz", + "integrity": "sha512-KHPsfX/FoVbUGbyYvk1q9MMQHLPeRZhRJZdO45Q4YjvFkv4hMNghCWTvy7rdKessBsmtz4euWCWAB6/tVpI1Iw==", + "dependencies": { + "@types/node": "*" + } + }, "node_modules/@types/through": { "version": "0.0.31", "resolved": "https://registry.npmjs.org/@types/through/-/through-0.0.31.tgz", @@ -3402,16 +4929,16 @@ "dev": true }, "node_modules/@typescript-eslint/eslint-plugin": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.1.0.tgz", - "integrity": "sha512-j6vT/kCulhG5wBmGtstKeiVr1rdXE4nk+DT1k6trYkwlrvW9eOF5ZbgKnd/YR6PcM4uTEXa0h6Fcvf6X7Dxl0w==", + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.1.1.tgz", + "integrity": "sha512-zioDz623d0RHNhvx0eesUmGfIjzrk18nSBC8xewepKXbBvN/7c1qImV7Hg8TI1URTxKax7/zxfxj3Uph8Chcuw==", "dev": true, "dependencies": { "@eslint-community/regexpp": "^4.5.1", - "@typescript-eslint/scope-manager": "7.1.0", - "@typescript-eslint/type-utils": "7.1.0", - "@typescript-eslint/utils": "7.1.0", - "@typescript-eslint/visitor-keys": "7.1.0", + "@typescript-eslint/scope-manager": "7.1.1", + "@typescript-eslint/type-utils": "7.1.1", + "@typescript-eslint/utils": "7.1.1", + "@typescript-eslint/visitor-keys": "7.1.1", "debug": "^4.3.4", "graphemer": "^1.4.0", "ignore": "^5.2.4", @@ -3437,15 +4964,15 @@ } }, "node_modules/@typescript-eslint/parser": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-7.1.0.tgz", - "integrity": "sha512-V1EknKUubZ1gWFjiOZhDSNToOjs63/9O0puCgGS8aDOgpZY326fzFu15QAUjwaXzRZjf/qdsdBrckYdv9YxB8w==", + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-7.1.1.tgz", + "integrity": "sha512-ZWUFyL0z04R1nAEgr9e79YtV5LbafdOtN7yapNbn1ansMyaegl2D4bL7vHoJ4HPSc4CaLwuCVas8CVuneKzplQ==", "dev": true, "dependencies": { - "@typescript-eslint/scope-manager": "7.1.0", - "@typescript-eslint/types": "7.1.0", - "@typescript-eslint/typescript-estree": "7.1.0", - "@typescript-eslint/visitor-keys": "7.1.0", + "@typescript-eslint/scope-manager": "7.1.1", + "@typescript-eslint/types": "7.1.1", + "@typescript-eslint/typescript-estree": "7.1.1", + "@typescript-eslint/visitor-keys": "7.1.1", "debug": "^4.3.4" }, "engines": { @@ -3465,13 +4992,13 @@ } }, "node_modules/@typescript-eslint/scope-manager": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.1.0.tgz", - "integrity": "sha512-6TmN4OJiohHfoOdGZ3huuLhpiUgOGTpgXNUPJgeZOZR3DnIpdSgtt83RS35OYNNXxM4TScVlpVKC9jyQSETR1A==", + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.1.1.tgz", + "integrity": "sha512-cirZpA8bJMRb4WZ+rO6+mnOJrGFDd38WoXCEI57+CYBqta8Yc8aJym2i7vyqLL1vVYljgw0X27axkUXz32T8TA==", "dev": true, "dependencies": { - "@typescript-eslint/types": "7.1.0", - "@typescript-eslint/visitor-keys": "7.1.0" + "@typescript-eslint/types": "7.1.1", + "@typescript-eslint/visitor-keys": "7.1.1" }, "engines": { "node": "^16.0.0 || >=18.0.0" @@ -3482,13 +5009,13 @@ } }, "node_modules/@typescript-eslint/type-utils": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-7.1.0.tgz", - "integrity": "sha512-UZIhv8G+5b5skkcuhgvxYWHjk7FW7/JP5lPASMEUoliAPwIH/rxoUSQPia2cuOj9AmDZmwUl1usKm85t5VUMew==", + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-7.1.1.tgz", + "integrity": "sha512-5r4RKze6XHEEhlZnJtR3GYeCh1IueUHdbrukV2KSlLXaTjuSfeVF8mZUVPLovidCuZfbVjfhi4c0DNSa/Rdg5g==", "dev": true, "dependencies": { - "@typescript-eslint/typescript-estree": "7.1.0", - "@typescript-eslint/utils": "7.1.0", + "@typescript-eslint/typescript-estree": "7.1.1", + "@typescript-eslint/utils": "7.1.1", "debug": "^4.3.4", "ts-api-utils": "^1.0.1" }, @@ -3509,9 +5036,9 @@ } }, "node_modules/@typescript-eslint/types": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.1.0.tgz", - "integrity": "sha512-qTWjWieJ1tRJkxgZYXx6WUYtWlBc48YRxgY2JN1aGeVpkhmnopq+SUC8UEVGNXIvWH7XyuTjwALfG6bFEgCkQA==", + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.1.1.tgz", + "integrity": "sha512-KhewzrlRMrgeKm1U9bh2z5aoL4s7K3tK5DwHDn8MHv0yQfWFz/0ZR6trrIHHa5CsF83j/GgHqzdbzCXJ3crx0Q==", "dev": true, "engines": { "node": "^16.0.0 || >=18.0.0" @@ -3522,13 +5049,13 @@ } }, "node_modules/@typescript-eslint/typescript-estree": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.1.0.tgz", - "integrity": "sha512-k7MyrbD6E463CBbSpcOnwa8oXRdHzH1WiVzOipK3L5KSML92ZKgUBrTlehdi7PEIMT8k0bQixHUGXggPAlKnOQ==", + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.1.1.tgz", + "integrity": "sha512-9ZOncVSfr+sMXVxxca2OJOPagRwT0u/UHikM2Rd6L/aB+kL/QAuTnsv6MeXtjzCJYb8PzrXarypSGIPx3Jemxw==", "dev": true, "dependencies": { - "@typescript-eslint/types": "7.1.0", - "@typescript-eslint/visitor-keys": "7.1.0", + "@typescript-eslint/types": "7.1.1", + "@typescript-eslint/visitor-keys": "7.1.1", "debug": "^4.3.4", "globby": "^11.1.0", "is-glob": "^4.0.3", @@ -3574,17 +5101,17 @@ } }, "node_modules/@typescript-eslint/utils": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.1.0.tgz", - "integrity": "sha512-WUFba6PZC5OCGEmbweGpnNJytJiLG7ZvDBJJoUcX4qZYf1mGZ97mO2Mps6O2efxJcJdRNpqweCistDbZMwIVHw==", + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.1.1.tgz", + "integrity": "sha512-thOXM89xA03xAE0lW7alstvnyoBUbBX38YtY+zAUcpRPcq9EIhXPuJ0YTv948MbzmKh6e1AUszn5cBFK49Umqg==", "dev": true, "dependencies": { "@eslint-community/eslint-utils": "^4.4.0", "@types/json-schema": "^7.0.12", "@types/semver": "^7.5.0", - "@typescript-eslint/scope-manager": "7.1.0", - "@typescript-eslint/types": "7.1.0", - "@typescript-eslint/typescript-estree": "7.1.0", + "@typescript-eslint/scope-manager": "7.1.1", + "@typescript-eslint/types": "7.1.1", + "@typescript-eslint/typescript-estree": "7.1.1", "semver": "^7.5.4" }, "engines": { @@ -3599,12 +5126,12 @@ } }, "node_modules/@typescript-eslint/visitor-keys": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.1.0.tgz", - "integrity": "sha512-FhUqNWluiGNzlvnDZiXad4mZRhtghdoKW6e98GoEOYSu5cND+E39rG5KwJMUzeENwm1ztYBRqof8wMLP+wNPIA==", + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.1.1.tgz", + "integrity": "sha512-yTdHDQxY7cSoCcAtiBzVzxleJhkGB9NncSIyMYe2+OGON1ZsP9zOPws/Pqgopa65jvknOjlk/w7ulPlZ78PiLQ==", "dev": true, "dependencies": { - "@typescript-eslint/types": "7.1.0", + "@typescript-eslint/types": "7.1.1", "eslint-visitor-keys": "^3.4.1" }, "engines": { @@ -3811,7 +5338,6 @@ "version": "8.10.0", "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.10.0.tgz", "integrity": "sha512-F0SAmZ8iUtS//m8DmCTA0jlh6TDKkHQyK6xc6V4KDTyZKA9dnvX9/3sRTVQrWm79glUAZbnmmNcdYwUIHWVybw==", - "devOptional": true, "bin": { "acorn": "bin/acorn" }, @@ -3823,7 +5349,6 @@ "version": "1.9.0", "resolved": "https://registry.npmjs.org/acorn-import-assertions/-/acorn-import-assertions-1.9.0.tgz", "integrity": "sha512-cmMwop9x+8KFhxvKrKfPYmN6/pKTYYHBqLa0DfvVZcKMJWNyWLnaqND7dx/qn66R7ewM1UX5XMaDVP5wlVTaVA==", - "dev": true, "peerDependencies": { "acorn": "^8" } @@ -4375,6 +5900,14 @@ "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-5.1.0.tgz", "integrity": "sha512-eh0GgfEkpnoWDq+VY8OyvYhFEzBk6jIYbRKdIlyTiAXIVJ8PyBaKb0rp7oDtoddbdoHWhq8wwr+XZ81F1rpNdA==" }, + "node_modules/bignumber.js": { + "version": "9.1.2", + "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.1.2.tgz", + "integrity": "sha512-2/mKyZH9K85bzOEfhXDBFZTGd1CTs+5IHpeFQo9luiBG7hghdC851Pj2WAhb6E3R6b9tZj/XKhbg4fum+Kepug==", + "engines": { + "node": "*" + } + }, "node_modules/binary-extensions": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", @@ -4791,8 +6324,7 @@ "node_modules/cjs-module-lexer": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-1.2.3.tgz", - "integrity": "sha512-0TNiGstbQmCFwt4akjjBg5pLRTSyj/PkWQ1ZoO2zntmg9yLqSRxwEa4iCfQLGjqhiqBfOJa7W/E8wfGrTDmlZQ==", - "dev": true + "integrity": "sha512-0TNiGstbQmCFwt4akjjBg5pLRTSyj/PkWQ1ZoO2zntmg9yLqSRxwEa4iCfQLGjqhiqBfOJa7W/E8wfGrTDmlZQ==" }, "node_modules/class-transformer": { "version": "0.5.1", @@ -6309,6 +7841,11 @@ "node": ">= 0.8" } }, + "node_modules/extend": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==" + }, "node_modules/external-editor": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-3.1.0.tgz", @@ -6756,6 +8293,55 @@ "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==" }, + "node_modules/gaxios": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/gaxios/-/gaxios-6.2.0.tgz", + "integrity": "sha512-H6+bHeoEAU5D6XNc6mPKeN5dLZqEDs9Gpk6I+SZBEzK5So58JVrHPmevNi35fRl1J9Y5TaeLW0kYx3pCJ1U2mQ==", + "dependencies": { + "extend": "^3.0.2", + "https-proxy-agent": "^7.0.1", + "is-stream": "^2.0.0", + "node-fetch": "^2.6.9" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/gaxios/node_modules/agent-base": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.0.tgz", + "integrity": "sha512-o/zjMZRhJxny7OyEF+Op8X+efiELC7k7yOjMzgfzVqOzXqkBkWI79YoTdOtsuWd5BWhAGAuOY/Xa6xpiaWXiNg==", + "dependencies": { + "debug": "^4.3.4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/gaxios/node_modules/https-proxy-agent": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.4.tgz", + "integrity": "sha512-wlwpilI7YdjSkWaQ/7omYBMTliDcmCN8OLihO6I9B86g06lMyAoqgoDpV0XqoaPOKj+0DIdAvnsWfyAAhmimcg==", + "dependencies": { + "agent-base": "^7.0.2", + "debug": "4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/gcp-metadata": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/gcp-metadata/-/gcp-metadata-6.1.0.tgz", + "integrity": "sha512-Jh/AIwwgaxan+7ZUUmRLCjtchyDiqh4KjBJ5tW3plBZb5iL/BPcso8A5DlzeD9qlw0duCamnNdpFjxwaT0KyKg==", + "dependencies": { + "gaxios": "^6.0.0", + "json-bigint": "^1.0.0" + }, + "engines": { + "node": ">=14" + } + }, "node_modules/gensync": { "version": "1.0.0-beta.2", "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", @@ -7017,7 +8603,6 @@ "version": "1.0.3", "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", - "dev": true, "dependencies": { "function-bind": "^1.1.1" }, @@ -7165,9 +8750,9 @@ } }, "node_modules/i18n-iso-countries": { - "version": "7.10.0", - "resolved": "https://registry.npmjs.org/i18n-iso-countries/-/i18n-iso-countries-7.10.0.tgz", - "integrity": "sha512-Y4wkIS2MzYk7cvaV665qcHpBUK4FaMcAhSfsggu9SPV9VpWvmH8NklofWvPPFWG1ZXmxqZ0Ubgr+ZtqddxG4ag==", + "version": "7.10.1", + "resolved": "https://registry.npmjs.org/i18n-iso-countries/-/i18n-iso-countries-7.10.1.tgz", + "integrity": "sha512-9DXmAMkfGcGNE+E/2fE85UUjjkPeT0LHMA8d+kcxXiO+s50W28lxiICel8f8qWZmCNic1cuhN1+nw7ZazMQJFA==", "dependencies": { "diacritics": "1.3.0" }, @@ -7229,6 +8814,17 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/import-in-the-middle": { + "version": "1.7.1", + "resolved": "https://registry.npmjs.org/import-in-the-middle/-/import-in-the-middle-1.7.1.tgz", + "integrity": "sha512-1LrZPDtW+atAxH42S6288qyDFNQ2YCty+2mxEPRtfazH6Z5QwkaBSTS2ods7hnVJioF6rkRfNoA6A/MstpFXLg==", + "dependencies": { + "acorn": "^8.8.2", + "acorn-import-assertions": "^1.9.0", + "cjs-module-lexer": "^1.2.2", + "module-details-from-path": "^1.0.3" + } + }, "node_modules/import-local": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.1.0.tgz", @@ -7380,7 +8976,6 @@ "version": "2.13.0", "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.13.0.tgz", "integrity": "sha512-Z7dk6Qo8pOCp3l4tsX2C5ZVas4V+UxwQodwZhLopL91TX8UyyHEXafPcyoeeWuLrwzHcr3igO78wNLwHJHsMCQ==", - "dev": true, "dependencies": { "has": "^1.0.3" }, @@ -7453,7 +9048,6 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", - "dev": true, "engines": { "node": ">=8" }, @@ -8329,6 +9923,14 @@ "node": ">=4" } }, + "node_modules/json-bigint": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-bigint/-/json-bigint-1.0.0.tgz", + "integrity": "sha512-SiPv/8VpZuWbvLSMtTDU8hEfrZWg/mH/nV/b4o0CYbSxu1UIQPLdwKOCIyLQX+VIPO5vrLX3i8qtqFyhdPSUSQ==", + "dependencies": { + "bignumber.js": "^9.0.0" + } + }, "node_modules/json-buffer": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", @@ -8499,6 +10101,11 @@ "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" }, + "node_modules/lodash.camelcase": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz", + "integrity": "sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA==" + }, "node_modules/lodash.defaults": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/lodash.defaults/-/lodash.defaults-4.2.0.tgz", @@ -8536,8 +10143,7 @@ "node_modules/lodash.merge": { "version": "4.6.2", "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", - "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", - "dev": true + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==" }, "node_modules/lodash.union": { "version": "4.6.0", @@ -8560,6 +10166,11 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/long": { + "version": "5.2.3", + "resolved": "https://registry.npmjs.org/long/-/long-5.2.3.tgz", + "integrity": "sha512-lcHwpNoggQTObv5apGNCTdJrO69eHOZMi4BNC+rTLER8iHAqGrUVeLh/irVIM7zTw2bOXA8T6uNPeujwOLg/2Q==" + }, "node_modules/lru-cache": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", @@ -8824,6 +10435,11 @@ "node": ">=12.0.0" } }, + "node_modules/module-details-from-path": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/module-details-from-path/-/module-details-from-path-1.0.3.tgz", + "integrity": "sha512-ySViT69/76t8VhE1xXHK6Ch4NcDd26gx0MzKXLO+F7NOtnqH68d9zF94nT8ZWSxXh8ELOERsnJO/sWt1xZYw5A==" + }, "node_modules/moo": { "version": "0.5.2", "resolved": "https://registry.npmjs.org/moo/-/moo-0.5.2.tgz", @@ -9035,6 +10651,20 @@ "node": ">=16" } }, + "node_modules/nestjs-otel": { + "version": "5.1.5", + "resolved": "https://registry.npmjs.org/nestjs-otel/-/nestjs-otel-5.1.5.tgz", + "integrity": "sha512-4u87aSy/GpbwuYvb5OAm0Zk3CP/q9QATI2bb9DQNpLYC5uYsqNkLHL3AdLBMVueNIMqp8rZui67XW0WTM8rr6g==", + "dependencies": { + "@opentelemetry/api": "^1.4.1", + "@opentelemetry/host-metrics": "^0.32.2", + "response-time": "^2.3.2" + }, + "peerDependencies": { + "@nestjs/common": "^9.0.0 || ^10.0.0", + "@nestjs/core": "^9.0.0 || ^10.0.0" + } + }, "node_modules/node-abort-controller": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/node-abort-controller/-/node-abort-controller-3.1.1.tgz", @@ -9213,6 +10843,14 @@ "node": ">= 0.8" } }, + "node_modules/on-headers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.0.2.tgz", + "integrity": "sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA==", + "engines": { + "node": ">= 0.8" + } + }, "node_modules/once": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", @@ -9236,9 +10874,9 @@ } }, "node_modules/openid-client": { - "version": "5.6.4", - "resolved": "https://registry.npmjs.org/openid-client/-/openid-client-5.6.4.tgz", - "integrity": "sha512-T1h3B10BRPKfcObdBklX639tVz+xh34O7GjofqrqiAQdm7eHsQ00ih18x6wuJ/E6FxdtS2u3FmUGPDeEcMwzNA==", + "version": "5.6.5", + "resolved": "https://registry.npmjs.org/openid-client/-/openid-client-5.6.5.tgz", + "integrity": "sha512-5P4qO9nGJzB5PI0LFlhj4Dzg3m4odt0qsJTfyEtZyOlkgpILwEioOhVVJOrS1iVH494S4Ee5OCjjg6Bf5WOj3w==", "dependencies": { "jose": "^4.15.5", "lru-cache": "^6.0.0", @@ -9446,8 +11084,7 @@ "node_modules/path-parse": { "version": "1.0.7", "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", - "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", - "dev": true + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==" }, "node_modules/path-scurry": { "version": "1.10.1", @@ -9888,6 +11525,29 @@ "node": ">=10" } }, + "node_modules/protobufjs": { + "version": "7.2.6", + "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-7.2.6.tgz", + "integrity": "sha512-dgJaEDDL6x8ASUZ1YqWciTRrdOuYNzoOf27oHNfdyvKqHr5i0FV7FSLU+aIeFjyFgVxrpTOtQUi0BLLBymZaBw==", + "hasInstallScript": true, + "dependencies": { + "@protobufjs/aspromise": "^1.1.2", + "@protobufjs/base64": "^1.1.2", + "@protobufjs/codegen": "^2.0.4", + "@protobufjs/eventemitter": "^1.1.0", + "@protobufjs/fetch": "^1.1.0", + "@protobufjs/float": "^1.0.2", + "@protobufjs/inquire": "^1.1.0", + "@protobufjs/path": "^1.1.2", + "@protobufjs/pool": "^1.1.0", + "@protobufjs/utf8": "^1.1.0", + "@types/node": ">=13.7.0", + "long": "^5.0.0" + }, + "engines": { + "node": ">=12.0.0" + } + }, "node_modules/protocol-buffers-schema": { "version": "3.6.0", "resolved": "https://registry.npmjs.org/protocol-buffers-schema/-/protocol-buffers-schema-3.6.0.tgz", @@ -10295,11 +11955,23 @@ "node": ">=0.10.0" } }, + "node_modules/require-in-the-middle": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/require-in-the-middle/-/require-in-the-middle-7.2.0.tgz", + "integrity": "sha512-3TLx5TGyAY6AOqLBoXmHkNql0HIf2RGbuMgCDT2WO/uGVAPJs6h7Kl+bN6TIZGd9bWhWPwnDnTHGtW8Iu77sdw==", + "dependencies": { + "debug": "^4.1.1", + "module-details-from-path": "^1.0.3", + "resolve": "^1.22.1" + }, + "engines": { + "node": ">=8.6.0" + } + }, "node_modules/resolve": { "version": "1.22.6", "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.6.tgz", "integrity": "sha512-njhxM7mV12JfufShqGy3Rz8j11RPdLy4xi15UurGJeoHLfJpVXKdh3ueuOqbYUcDZnffr6X739JBo5LzyahEsw==", - "dev": true, "dependencies": { "is-core-module": "^2.13.0", "path-parse": "^1.0.7", @@ -10358,6 +12030,26 @@ "node": ">=10" } }, + "node_modules/response-time": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/response-time/-/response-time-2.3.2.tgz", + "integrity": "sha512-MUIDaDQf+CVqflfTdQ5yam+aYCkXj1PY8fjlPDQ6ppxJlmgZb864pHtA750mayywNg8tx4rS7qH9JXd/OF+3gw==", + "dependencies": { + "depd": "~1.1.0", + "on-headers": "~1.0.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/response-time/node_modules/depd": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", + "integrity": "sha512-7emPTl6Dpo6JRXOXjLRxck+FlLRX5847cLKEn00PLAgc3g2hTZZgr+e4c2v6QpSmLeFP3n5yUo7ft6avBK/5jQ==", + "engines": { + "node": ">= 0.6" + } + }, "node_modules/restore-cursor": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz", @@ -10788,6 +12480,11 @@ "url": "https://github.com/sponsors/isaacs" } }, + "node_modules/shimmer": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/shimmer/-/shimmer-1.2.1.tgz", + "integrity": "sha512-sQTKC1Re/rM6XyFM6fIAGHRPVGvyXfgzIDvzoq608vM+jeyVD0Tu1E6Np0Kc2zAIFWIj963V2800iF/9LPieQw==" + }, "node_modules/side-channel": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", @@ -11247,7 +12944,6 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", - "dev": true, "engines": { "node": ">= 0.4" }, @@ -11285,6 +12981,31 @@ "url": "https://opencollective.com/unts" } }, + "node_modules/systeminformation": { + "version": "5.22.0", + "resolved": "https://registry.npmjs.org/systeminformation/-/systeminformation-5.22.0.tgz", + "integrity": "sha512-oAP80ymt8ssrAzjX8k3frbL7ys6AotqC35oikG6/SG15wBw+tG9nCk4oPaXIhEaAOAZ8XngxUv3ORq2IuR3r4Q==", + "os": [ + "darwin", + "linux", + "win32", + "freebsd", + "openbsd", + "netbsd", + "sunos", + "android" + ], + "bin": { + "systeminformation": "lib/cli.js" + }, + "engines": { + "node": ">=8.0.0" + }, + "funding": { + "type": "Buy me a coffee", + "url": "https://www.buymeacoffee.com/systeminfo" + } + }, "node_modules/tapable": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz", @@ -12205,9 +13926,9 @@ } }, "node_modules/typescript": { - "version": "5.3.3", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.3.3.tgz", - "integrity": "sha512-pXWcraxM0uxAS+tN0AG/BF2TyqmHO014Z070UsJ+pFvYuRSq8KH8DmWpnbXe0pEPDHXZV3FcAbJkijJ5oNEnWw==", + "version": "5.4.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.4.2.tgz", + "integrity": "sha512-+2/g0Fds1ERlP6JsakQQDXjZdZMM+rqpamFZJEKh4kwTIn3iDkgKtby0CeNd5ATNZ4Ry1ax15TMx0W2V+miizQ==", "devOptional": true, "bin": { "tsc": "bin/tsc", @@ -13524,11 +15245,123 @@ "lodash": "^4.17.21" } }, + "@grpc/grpc-js": { + "version": "1.10.2", + "resolved": "https://registry.npmjs.org/@grpc/grpc-js/-/grpc-js-1.10.2.tgz", + "integrity": "sha512-lSbgu8iayAod8O0YcoXK3+bMFGThY2svtN35Zlm9VepsB3jfyIcoupKknEht7Kh9Q8ITjsp0J4KpYo9l4+FhNg==", + "requires": { + "@grpc/proto-loader": "^0.7.10", + "@js-sdsl/ordered-map": "^4.4.2" + } + }, + "@grpc/proto-loader": { + "version": "0.7.10", + "resolved": "https://registry.npmjs.org/@grpc/proto-loader/-/proto-loader-0.7.10.tgz", + "integrity": "sha512-CAqDfoaQ8ykFd9zqBDn4k6iWT9loLAlc2ETmDFS9JCD70gDcnA4L3AFEo2iV7KyAtAAHFW9ftq1Fz+Vsgq80RQ==", + "requires": { + "lodash.camelcase": "^4.3.0", + "long": "^5.0.0", + "protobufjs": "^7.2.4", + "yargs": "^17.7.2" + }, + "dependencies": { + "cliui": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", + "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", + "requires": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.1", + "wrap-ansi": "^7.0.0" + } + }, + "wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "requires": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + } + }, + "yargs": { + "version": "17.7.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", + "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", + "requires": { + "cliui": "^8.0.1", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.3", + "y18n": "^5.0.5", + "yargs-parser": "^21.1.1" + } + } + } + }, + "@hapi/b64": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/@hapi/b64/-/b64-5.0.0.tgz", + "integrity": "sha512-ngu0tSEmrezoiIaNGG6rRvKOUkUuDdf4XTPnONHGYfSGRmDqPZX5oJL6HAdKTo1UQHECbdB4OzhWrfgVppjHUw==", + "requires": { + "@hapi/hoek": "9.x.x" + } + }, + "@hapi/boom": { + "version": "9.1.4", + "resolved": "https://registry.npmjs.org/@hapi/boom/-/boom-9.1.4.tgz", + "integrity": "sha512-Ls1oH8jaN1vNsqcaHVYJrKmgMcKsC1wcp8bujvXrHaAqD2iDYq3HoOwsxwo09Cuda5R5nC0o0IxlrlTuvPuzSw==", + "requires": { + "@hapi/hoek": "9.x.x" + } + }, + "@hapi/bourne": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@hapi/bourne/-/bourne-2.1.0.tgz", + "integrity": "sha512-i1BpaNDVLJdRBEKeJWkVO6tYX6DMFBuwMhSuWqLsY4ufeTKGVuV5rBsUhxPayXqnnWHgXUAmWK16H/ykO5Wj4Q==" + }, + "@hapi/cryptiles": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/@hapi/cryptiles/-/cryptiles-5.1.0.tgz", + "integrity": "sha512-fo9+d1Ba5/FIoMySfMqPBR/7Pa29J2RsiPrl7bkwo5W5o+AN1dAYQRi4SPrPwwVxVGKjgLOEWrsvt1BonJSfLA==", + "requires": { + "@hapi/boom": "9.x.x" + } + }, "@hapi/hoek": { "version": "9.3.0", "resolved": "https://registry.npmjs.org/@hapi/hoek/-/hoek-9.3.0.tgz", "integrity": "sha512-/c6rf4UJlmHlC9b5BaNvzAcFv7HZ2QHaV0D4/HNlBdvFnvQq8RI4kYdhyPCl7Xj+oWvTWQ8ujhqS53LIgAe6KQ==" }, + "@hapi/iron": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/@hapi/iron/-/iron-6.0.0.tgz", + "integrity": "sha512-zvGvWDufiTGpTJPG1Y/McN8UqWBu0k/xs/7l++HVU535NLHXsHhy54cfEMdW7EjwKfbBfM9Xy25FmTiobb7Hvw==", + "requires": { + "@hapi/b64": "5.x.x", + "@hapi/boom": "9.x.x", + "@hapi/bourne": "2.x.x", + "@hapi/cryptiles": "5.x.x", + "@hapi/hoek": "9.x.x" + } + }, + "@hapi/podium": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/@hapi/podium/-/podium-4.1.3.tgz", + "integrity": "sha512-ljsKGQzLkFqnQxE7qeanvgGj4dejnciErYd30dbrYzUOF/FyS/DOF97qcrT3bhoVwCYmxa6PEMhxfCPlnUcD2g==", + "requires": { + "@hapi/hoek": "9.x.x", + "@hapi/teamwork": "5.x.x", + "@hapi/validate": "1.x.x" + } + }, + "@hapi/teamwork": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/@hapi/teamwork/-/teamwork-5.1.1.tgz", + "integrity": "sha512-1oPx9AE5TIv+V6Ih54RP9lTZBso3rP8j4Xhb6iSVwPXtAM+sDopl5TFMv5Paw73UnpZJ9gjcrTE1BXrWt9eQrg==" + }, "@hapi/topo": { "version": "5.1.0", "resolved": "https://registry.npmjs.org/@hapi/topo/-/topo-5.1.0.tgz", @@ -13537,6 +15370,15 @@ "@hapi/hoek": "^9.0.0" } }, + "@hapi/validate": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@hapi/validate/-/validate-1.1.3.tgz", + "integrity": "sha512-/XMR0N0wjw0Twzq2pQOzPBZlDzkekGcoCtzO314BpIEsbXdYGthQUbxgkGDf4nhk1+IPDAsXqWjMohRQYO06UA==", + "requires": { + "@hapi/hoek": "^9.0.0", + "@hapi/topo": "^5.0.0" + } + }, "@humanwhocodes/config-array": { "version": "0.11.14", "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.14.tgz", @@ -14137,6 +15979,11 @@ "@jridgewell/sourcemap-codec": "^1.4.14" } }, + "@js-sdsl/ordered-map": { + "version": "4.4.2", + "resolved": "https://registry.npmjs.org/@js-sdsl/ordered-map/-/ordered-map-4.4.2.tgz", + "integrity": "sha512-iUKgm52T8HOE/makSxjqoWhe95ZJA1/G1sYsGev2JDKUSS14KAgg1LHb+Ba+IPow0xflbnSkOsZcO08C7w1gYw==" + }, "@ljharb/through": { "version": "2.3.12", "resolved": "https://registry.npmjs.org/@ljharb/through/-/through-2.3.12.tgz", @@ -14299,6 +16146,12 @@ } } } + }, + "typescript": { + "version": "5.3.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.3.3.tgz", + "integrity": "sha512-pXWcraxM0uxAS+tN0AG/BF2TyqmHO014Z070UsJ+pFvYuRSq8KH8DmWpnbXe0pEPDHXZV3FcAbJkijJ5oNEnWw==", + "dev": true } } }, @@ -14473,6 +16326,739 @@ "node-fetch": "^2.6.1" } }, + "@opentelemetry/api": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/api/-/api-1.7.0.tgz", + "integrity": "sha512-AdY5wvN0P2vXBi3b29hxZgSFvdhdxPB9+f0B6s//P9Q8nibRWeA3cHm8UmLpio9ABigkVHJ5NMPk+Mz8VCCyrw==" + }, + "@opentelemetry/api-logs": { + "version": "0.49.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/api-logs/-/api-logs-0.49.1.tgz", + "integrity": "sha512-kaNl/T7WzyMUQHQlVq7q0oV4Kev6+0xFwqzofryC66jgGMacd0QH5TwfpbUwSTby+SdAdprAe5UKMvBw4tKS5Q==", + "requires": { + "@opentelemetry/api": "^1.0.0" + } + }, + "@opentelemetry/auto-instrumentations-node": { + "version": "0.42.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/auto-instrumentations-node/-/auto-instrumentations-node-0.42.0.tgz", + "integrity": "sha512-fxcB7My5QTVfX6kBH4r5OFduGSxdpROgyIu7CqClp1psFHfVaBMQd4lbK2u+39K5kbjzJT2OaUP8yQuAvKJqBg==", + "requires": { + "@opentelemetry/instrumentation": "^0.49.1", + "@opentelemetry/instrumentation-amqplib": "^0.35.0", + "@opentelemetry/instrumentation-aws-lambda": "^0.39.0", + "@opentelemetry/instrumentation-aws-sdk": "^0.39.0", + "@opentelemetry/instrumentation-bunyan": "^0.36.0", + "@opentelemetry/instrumentation-cassandra-driver": "^0.36.0", + "@opentelemetry/instrumentation-connect": "^0.34.0", + "@opentelemetry/instrumentation-cucumber": "^0.4.0", + "@opentelemetry/instrumentation-dataloader": "^0.7.0", + "@opentelemetry/instrumentation-dns": "^0.34.0", + "@opentelemetry/instrumentation-express": "^0.36.0", + "@opentelemetry/instrumentation-fastify": "^0.34.0", + "@opentelemetry/instrumentation-fs": "^0.10.0", + "@opentelemetry/instrumentation-generic-pool": "^0.34.0", + "@opentelemetry/instrumentation-graphql": "^0.38.0", + "@opentelemetry/instrumentation-grpc": "^0.49.1", + "@opentelemetry/instrumentation-hapi": "^0.35.0", + "@opentelemetry/instrumentation-http": "^0.49.1", + "@opentelemetry/instrumentation-ioredis": "^0.38.0", + "@opentelemetry/instrumentation-knex": "^0.34.0", + "@opentelemetry/instrumentation-koa": "^0.38.0", + "@opentelemetry/instrumentation-lru-memoizer": "^0.35.0", + "@opentelemetry/instrumentation-memcached": "^0.34.0", + "@opentelemetry/instrumentation-mongodb": "^0.40.0", + "@opentelemetry/instrumentation-mongoose": "^0.36.0", + "@opentelemetry/instrumentation-mysql": "^0.36.0", + "@opentelemetry/instrumentation-mysql2": "^0.36.0", + "@opentelemetry/instrumentation-nestjs-core": "^0.35.0", + "@opentelemetry/instrumentation-net": "^0.34.0", + "@opentelemetry/instrumentation-pg": "^0.39.0", + "@opentelemetry/instrumentation-pino": "^0.36.0", + "@opentelemetry/instrumentation-redis": "^0.37.0", + "@opentelemetry/instrumentation-redis-4": "^0.37.0", + "@opentelemetry/instrumentation-restify": "^0.36.0", + "@opentelemetry/instrumentation-router": "^0.35.0", + "@opentelemetry/instrumentation-socket.io": "^0.37.0", + "@opentelemetry/instrumentation-tedious": "^0.8.0", + "@opentelemetry/instrumentation-winston": "^0.35.0", + "@opentelemetry/resource-detector-alibaba-cloud": "^0.28.7", + "@opentelemetry/resource-detector-aws": "^1.4.0", + "@opentelemetry/resource-detector-container": "^0.3.7", + "@opentelemetry/resource-detector-gcp": "^0.29.7", + "@opentelemetry/resources": "^1.12.0", + "@opentelemetry/sdk-node": "^0.49.1" + } + }, + "@opentelemetry/context-async-hooks": { + "version": "1.22.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/context-async-hooks/-/context-async-hooks-1.22.0.tgz", + "integrity": "sha512-Nfdxyg8YtWqVWkyrCukkundAjPhUXi93JtVQmqDT1mZRVKqA7e2r7eJCrI+F651XUBMp0hsOJSGiFk3QSpaIJw==", + "requires": {} + }, + "@opentelemetry/core": { + "version": "1.22.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/core/-/core-1.22.0.tgz", + "integrity": "sha512-0VoAlT6x+Xzik1v9goJ3pZ2ppi6+xd3aUfg4brfrLkDBHRIVjMP0eBHrKrhB+NKcDyMAg8fAbGL3Npg/F6AwWA==", + "requires": { + "@opentelemetry/semantic-conventions": "1.22.0" + } + }, + "@opentelemetry/exporter-prometheus": { + "version": "0.49.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/exporter-prometheus/-/exporter-prometheus-0.49.1.tgz", + "integrity": "sha512-FgzGl6OH22f+Wb1dh/TnoQSnZE2SCADhHx06nMqxivSqRJ9t3AhUdMsEOFt2IMjZClE705pcsLHk10BCJ79vsA==", + "requires": { + "@opentelemetry/core": "1.22.0", + "@opentelemetry/resources": "1.22.0", + "@opentelemetry/sdk-metrics": "1.22.0" + } + }, + "@opentelemetry/exporter-trace-otlp-grpc": { + "version": "0.49.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/exporter-trace-otlp-grpc/-/exporter-trace-otlp-grpc-0.49.1.tgz", + "integrity": "sha512-Zbd7f3zF7fI2587MVhBizaW21cO/SordyrZGtMtvhoxU6n4Qb02Gx71X4+PzXH620e0+JX+Pcr9bYb1HTeVyJA==", + "requires": { + "@grpc/grpc-js": "^1.7.1", + "@opentelemetry/core": "1.22.0", + "@opentelemetry/otlp-grpc-exporter-base": "0.49.1", + "@opentelemetry/otlp-transformer": "0.49.1", + "@opentelemetry/resources": "1.22.0", + "@opentelemetry/sdk-trace-base": "1.22.0" + } + }, + "@opentelemetry/exporter-trace-otlp-http": { + "version": "0.49.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/exporter-trace-otlp-http/-/exporter-trace-otlp-http-0.49.1.tgz", + "integrity": "sha512-KOLtZfZvIrpGZLVvblKsiVQT7gQUZNKcUUH24Zz6Xbi7LJb9Vt6xtUZFYdR5IIjvt47PIqBKDWUQlU0o1wAsRw==", + "requires": { + "@opentelemetry/core": "1.22.0", + "@opentelemetry/otlp-exporter-base": "0.49.1", + "@opentelemetry/otlp-transformer": "0.49.1", + "@opentelemetry/resources": "1.22.0", + "@opentelemetry/sdk-trace-base": "1.22.0" + } + }, + "@opentelemetry/exporter-trace-otlp-proto": { + "version": "0.49.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/exporter-trace-otlp-proto/-/exporter-trace-otlp-proto-0.49.1.tgz", + "integrity": "sha512-n8ON/c9pdMyYAfSFWKkgsPwjYoxnki+6Olzo+klKfW7KqLWoyEkryNkbcMIYnGGNXwdkMIrjoaP0VxXB26Oxcg==", + "requires": { + "@opentelemetry/core": "1.22.0", + "@opentelemetry/otlp-exporter-base": "0.49.1", + "@opentelemetry/otlp-proto-exporter-base": "0.49.1", + "@opentelemetry/otlp-transformer": "0.49.1", + "@opentelemetry/resources": "1.22.0", + "@opentelemetry/sdk-trace-base": "1.22.0" + } + }, + "@opentelemetry/exporter-zipkin": { + "version": "1.22.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/exporter-zipkin/-/exporter-zipkin-1.22.0.tgz", + "integrity": "sha512-XcFs6rGvcTz0qW5uY7JZDYD0yNEXdekXAb6sFtnZgY/cHY6BQ09HMzOjv9SX+iaXplRDcHr1Gta7VQKM1XXM6g==", + "requires": { + "@opentelemetry/core": "1.22.0", + "@opentelemetry/resources": "1.22.0", + "@opentelemetry/sdk-trace-base": "1.22.0", + "@opentelemetry/semantic-conventions": "1.22.0" + } + }, + "@opentelemetry/host-metrics": { + "version": "0.32.2", + "resolved": "https://registry.npmjs.org/@opentelemetry/host-metrics/-/host-metrics-0.32.2.tgz", + "integrity": "sha512-zrnls0CWMAYEUHQbdplY0M6v3L/cgEoiwpjAnHAaG7M3ICs7K4/Hms1UlVMDydEvNDkQilx63scpDcE1/M5V4A==", + "requires": { + "@opentelemetry/sdk-metrics": "^1.8.0", + "systeminformation": "^5.0.0" + } + }, + "@opentelemetry/instrumentation": { + "version": "0.49.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation/-/instrumentation-0.49.1.tgz", + "integrity": "sha512-0DLtWtaIppuNNRRllSD4bjU8ZIiLp1cDXvJEbp752/Zf+y3gaLNaoGRGIlX4UHhcsrmtL+P2qxi3Hodi8VuKiQ==", + "requires": { + "@opentelemetry/api-logs": "0.49.1", + "@types/shimmer": "^1.0.2", + "import-in-the-middle": "1.7.1", + "require-in-the-middle": "^7.1.1", + "semver": "^7.5.2", + "shimmer": "^1.2.1" + } + }, + "@opentelemetry/instrumentation-amqplib": { + "version": "0.35.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-amqplib/-/instrumentation-amqplib-0.35.0.tgz", + "integrity": "sha512-rb3hIWA7f0HXpXpfElnGC6CukRxy58/OJ6XYlTzpZJtNJPao7BuobZjkQEscaRYhUzgi7X7R1aKkIUOTV5JFrg==", + "requires": { + "@opentelemetry/core": "^1.8.0", + "@opentelemetry/instrumentation": "^0.49.1", + "@opentelemetry/semantic-conventions": "^1.0.0" + } + }, + "@opentelemetry/instrumentation-aws-lambda": { + "version": "0.39.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-aws-lambda/-/instrumentation-aws-lambda-0.39.0.tgz", + "integrity": "sha512-D+oG/hIBDdwCNq7Y6BEuddjcwDVD0C8NhBE7A85mRZ9RLG0bKoWrhIdVvbpqEoa0U5AWe9Y98RX4itNg7WTy4w==", + "requires": { + "@opentelemetry/instrumentation": "^0.49.1", + "@opentelemetry/propagator-aws-xray": "^1.3.1", + "@opentelemetry/resources": "^1.8.0", + "@opentelemetry/semantic-conventions": "^1.0.0", + "@types/aws-lambda": "8.10.122" + } + }, + "@opentelemetry/instrumentation-aws-sdk": { + "version": "0.39.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-aws-sdk/-/instrumentation-aws-sdk-0.39.1.tgz", + "integrity": "sha512-QnvIMVpzRYqQHSXydGUksbhBjPbMyHSUBwi6ocN7gEXoI711+tIY3R1cfRutl0u3M67A/fAvPI3IgACfJaFORg==", + "requires": { + "@opentelemetry/core": "^1.8.0", + "@opentelemetry/instrumentation": "^0.49.1", + "@opentelemetry/propagation-utils": "^0.30.7", + "@opentelemetry/semantic-conventions": "^1.0.0" + } + }, + "@opentelemetry/instrumentation-bunyan": { + "version": "0.36.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-bunyan/-/instrumentation-bunyan-0.36.0.tgz", + "integrity": "sha512-sHD5BSiqSrgWow7VmugEFzV8vGdsz5m+w1v9tK6YwRzuAD7vbo57chluq+UBzIqStoCH+0yOzRzSALH7hrfffg==", + "requires": { + "@opentelemetry/api-logs": "^0.49.1", + "@opentelemetry/instrumentation": "^0.49.1", + "@types/bunyan": "1.8.9" + } + }, + "@opentelemetry/instrumentation-cassandra-driver": { + "version": "0.36.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-cassandra-driver/-/instrumentation-cassandra-driver-0.36.0.tgz", + "integrity": "sha512-gMfxzryOIP/mvSLXBJp/QxSr2NvS+cC1dkIXn+aSOzYoU1U3apeF3nAyuikmY9dRCQDV7wHPslqbi+pCmd4pAQ==", + "requires": { + "@opentelemetry/instrumentation": "^0.49.1", + "@opentelemetry/semantic-conventions": "^1.0.0" + } + }, + "@opentelemetry/instrumentation-connect": { + "version": "0.34.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-connect/-/instrumentation-connect-0.34.0.tgz", + "integrity": "sha512-PJO99nfyUp3JSoBMhwZsOQDm/XKfkb/QQ8YTsNX4ZJ28phoRcNLqe36mqIMp80DKmKAX4xkxCAyrSYtW8QqZxA==", + "requires": { + "@opentelemetry/core": "^1.8.0", + "@opentelemetry/instrumentation": "^0.49.1", + "@opentelemetry/semantic-conventions": "^1.0.0", + "@types/connect": "3.4.36" + } + }, + "@opentelemetry/instrumentation-cucumber": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-cucumber/-/instrumentation-cucumber-0.4.0.tgz", + "integrity": "sha512-n53QvozzgMS9imEclow2nBYJ/jtZlZqiKIqDUi2/g0nDi08F555JhDS03d/Z+4NJxbu7bDLAg12giCV9KZN/Jw==", + "requires": { + "@opentelemetry/instrumentation": "^0.49.1", + "@opentelemetry/semantic-conventions": "^1.0.0" + } + }, + "@opentelemetry/instrumentation-dataloader": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-dataloader/-/instrumentation-dataloader-0.7.0.tgz", + "integrity": "sha512-sIaevxATJV5YaZzBTTcTaDEnI+/1vxYs+lVk1honnvrEAaP0FA9C/cFrQEN0kP2BDHkHRE/t6y5lGUqusi/h3A==", + "requires": { + "@opentelemetry/instrumentation": "^0.49.1" + } + }, + "@opentelemetry/instrumentation-dns": { + "version": "0.34.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-dns/-/instrumentation-dns-0.34.0.tgz", + "integrity": "sha512-3tmXdvrzHQ7S3v82Cm36PTYLtgg2+hVm00K1xB3uzP08GEo9w/F8DW4me9z6rDroVGiLIg621RZ6dzjBcmmFCg==", + "requires": { + "@opentelemetry/instrumentation": "^0.49.1", + "@opentelemetry/semantic-conventions": "^1.0.0", + "semver": "^7.5.4" + } + }, + "@opentelemetry/instrumentation-express": { + "version": "0.36.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-express/-/instrumentation-express-0.36.1.tgz", + "integrity": "sha512-ltIE4kIMa+83QjW/p7oe7XCESF29w3FQ9/T1VgShdX7fzm56K2a0xfEX1vF8lnHRGERYxIWX9D086C6gJOjVGA==", + "requires": { + "@opentelemetry/core": "^1.8.0", + "@opentelemetry/instrumentation": "^0.49.1", + "@opentelemetry/semantic-conventions": "^1.0.0" + } + }, + "@opentelemetry/instrumentation-fastify": { + "version": "0.34.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-fastify/-/instrumentation-fastify-0.34.0.tgz", + "integrity": "sha512-2Qu66XBkfJ8tr6H+RHBTyw/EX73N9U7pvNa49aonDnT9/mK58k7AKOscpRnKXOvHqc2YIdEPRcBIWxhksPFZVA==", + "requires": { + "@opentelemetry/core": "^1.8.0", + "@opentelemetry/instrumentation": "^0.49.1", + "@opentelemetry/semantic-conventions": "^1.0.0" + } + }, + "@opentelemetry/instrumentation-fs": { + "version": "0.10.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-fs/-/instrumentation-fs-0.10.0.tgz", + "integrity": "sha512-XtMoNINVsIQTQHjtxe7A0Lng96wxA5DSD5CYVVvpquG6HJRdZ4xNe9DTU03YtoEFqlN9qTfvGb/6ILzhKhiG8g==", + "requires": { + "@opentelemetry/core": "^1.8.0", + "@opentelemetry/instrumentation": "^0.49.1", + "@opentelemetry/semantic-conventions": "^1.0.0" + } + }, + "@opentelemetry/instrumentation-generic-pool": { + "version": "0.34.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-generic-pool/-/instrumentation-generic-pool-0.34.0.tgz", + "integrity": "sha512-jdI7tfVVwZJuTu4j2kAvJtx4wlEQKIXSZnZG4RdqRHc56KqQQDuVTBLvUgmDXvnSVclH9ayf4oaAV08R9fICtw==", + "requires": { + "@opentelemetry/instrumentation": "^0.49.1", + "@opentelemetry/semantic-conventions": "^1.0.0" + } + }, + "@opentelemetry/instrumentation-graphql": { + "version": "0.38.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-graphql/-/instrumentation-graphql-0.38.1.tgz", + "integrity": "sha512-mSt4ztn3EVlLtZJ+tDEqq5GUEYdY8cbTT9SeVJFmXSfdSQkPZn0ovo/dRe6dUcplM60gg4w+llw8SZuQN0iZfQ==", + "requires": { + "@opentelemetry/instrumentation": "^0.49.1" + } + }, + "@opentelemetry/instrumentation-grpc": { + "version": "0.49.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-grpc/-/instrumentation-grpc-0.49.1.tgz", + "integrity": "sha512-f8mQjFi5/PiP4SK3VDU1/3sUUgs6exMtBgcnNycgCKgN40htiPT+MuDRwdRnRMNI/4vNQ7p1/5r4Q5oN0GuRBw==", + "requires": { + "@opentelemetry/instrumentation": "0.49.1", + "@opentelemetry/semantic-conventions": "1.22.0" + } + }, + "@opentelemetry/instrumentation-hapi": { + "version": "0.35.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-hapi/-/instrumentation-hapi-0.35.0.tgz", + "integrity": "sha512-j7q99aTLHfjNKW94qJnEaDatgz+q2psTKs7lxZO4QHRnoDltDk39a44/+AkI1qBJNw5xyLjrApqkglfbWJ2abg==", + "requires": { + "@opentelemetry/core": "^1.8.0", + "@opentelemetry/instrumentation": "^0.49.1", + "@opentelemetry/semantic-conventions": "^1.0.0", + "@types/hapi__hapi": "20.0.13" + } + }, + "@opentelemetry/instrumentation-http": { + "version": "0.49.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-http/-/instrumentation-http-0.49.1.tgz", + "integrity": "sha512-Yib5zrW2s0V8wTeUK/B3ZtpyP4ldgXj9L3Ws/axXrW1dW0/mEFKifK50MxMQK9g5NNJQS9dWH7rvcEGZdWdQDA==", + "requires": { + "@opentelemetry/core": "1.22.0", + "@opentelemetry/instrumentation": "0.49.1", + "@opentelemetry/semantic-conventions": "1.22.0", + "semver": "^7.5.2" + } + }, + "@opentelemetry/instrumentation-ioredis": { + "version": "0.38.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-ioredis/-/instrumentation-ioredis-0.38.0.tgz", + "integrity": "sha512-c9nQFhRjFAtpInTks7z5v9CiOCiR8U9GbIhIv0TLEJ/r0wqdKNLfLZzCrr9XQ9WasxeOmziLlPFhpRBAd9Q4oA==", + "requires": { + "@opentelemetry/instrumentation": "^0.49.1", + "@opentelemetry/redis-common": "^0.36.1", + "@opentelemetry/semantic-conventions": "^1.0.0", + "@types/ioredis4": "npm:@types/ioredis@^4.28.10" + } + }, + "@opentelemetry/instrumentation-knex": { + "version": "0.34.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-knex/-/instrumentation-knex-0.34.0.tgz", + "integrity": "sha512-6kZOEvNJOylTQunU5zSSi4iTuCkwIL9nwFnZg7719p61u3d6Qj3X4xi9su46VE3M0dH7vEoxUW+nb/0ilm+aZg==", + "requires": { + "@opentelemetry/instrumentation": "^0.49.1", + "@opentelemetry/semantic-conventions": "^1.0.0" + } + }, + "@opentelemetry/instrumentation-koa": { + "version": "0.38.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-koa/-/instrumentation-koa-0.38.0.tgz", + "integrity": "sha512-lQujF4I3wdcrOF14miCV2pC72H+OJKb2LrrmTvTDAhELQDN/95v0doWgT9aHybUGkaAeB3QG4d09sved548TlA==", + "requires": { + "@opentelemetry/core": "^1.8.0", + "@opentelemetry/instrumentation": "^0.49.1", + "@opentelemetry/semantic-conventions": "^1.0.0", + "@types/koa": "2.14.0", + "@types/koa__router": "12.0.3" + } + }, + "@opentelemetry/instrumentation-lru-memoizer": { + "version": "0.35.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-lru-memoizer/-/instrumentation-lru-memoizer-0.35.0.tgz", + "integrity": "sha512-wCXe+iCF7JweMgY3blLM2Y1G0GSwLEeSA61z/y1UwzvBLEEXt7vL6qOl2mkNcUL9ZbLDS+EABatBH+vFO6DV5Q==", + "requires": { + "@opentelemetry/instrumentation": "^0.49.1" + } + }, + "@opentelemetry/instrumentation-memcached": { + "version": "0.34.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-memcached/-/instrumentation-memcached-0.34.0.tgz", + "integrity": "sha512-RleFfaag3Evg4pTzHwDBwo1KiFgnCtiT4V6MQRRHadytNGdpcL+Ynz32ydDdiOXeadt7xpRI7HSvBy0quGTXSw==", + "requires": { + "@opentelemetry/instrumentation": "^0.49.1", + "@opentelemetry/semantic-conventions": "^1.0.0", + "@types/memcached": "^2.2.6" + } + }, + "@opentelemetry/instrumentation-mongodb": { + "version": "0.40.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-mongodb/-/instrumentation-mongodb-0.40.0.tgz", + "integrity": "sha512-ldlJUW/1UlnGtIWBt7fIUl+7+TGOKxIU+0Js5ukpXfQc07ENYFeck5TdbFjvYtF8GppPErnsZJiFiRdYm6Pv/Q==", + "requires": { + "@opentelemetry/instrumentation": "^0.49.1", + "@opentelemetry/sdk-metrics": "^1.9.1", + "@opentelemetry/semantic-conventions": "^1.0.0" + } + }, + "@opentelemetry/instrumentation-mongoose": { + "version": "0.36.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-mongoose/-/instrumentation-mongoose-0.36.0.tgz", + "integrity": "sha512-UelQ8dLQRLTdck3tPJdZ17b+Hk9usLf1cY2ou5THAaZpulUdpg62Q9Hx2RHRU71Rp2/YMDk25og7GJhuWScfEA==", + "requires": { + "@opentelemetry/core": "^1.8.0", + "@opentelemetry/instrumentation": "^0.49.1", + "@opentelemetry/semantic-conventions": "^1.0.0" + } + }, + "@opentelemetry/instrumentation-mysql": { + "version": "0.36.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-mysql/-/instrumentation-mysql-0.36.0.tgz", + "integrity": "sha512-2mt/032SLkiuddzMrq3YwM0bHksXRep69EzGRnBfF+bCbwYvKLpqmSFqJZ9T3yY/mBWj+tvdvc1+klXGrh2QnQ==", + "requires": { + "@opentelemetry/instrumentation": "^0.49.1", + "@opentelemetry/semantic-conventions": "^1.0.0", + "@types/mysql": "2.15.22" + } + }, + "@opentelemetry/instrumentation-mysql2": { + "version": "0.36.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-mysql2/-/instrumentation-mysql2-0.36.0.tgz", + "integrity": "sha512-F63lKcl/R+if2j5Vz66c2/SLXQEtLlFkWTmYb8NQSgmcCaEKjML4RRRjZISIT4IBwdpanJ2qmNuXVM6MYqhBXw==", + "requires": { + "@opentelemetry/instrumentation": "^0.49.1", + "@opentelemetry/semantic-conventions": "^1.0.0", + "@opentelemetry/sql-common": "^0.40.0" + } + }, + "@opentelemetry/instrumentation-nestjs-core": { + "version": "0.35.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-nestjs-core/-/instrumentation-nestjs-core-0.35.0.tgz", + "integrity": "sha512-INKA7CIOteTSRVxP7SQaFby11AYU3uezI93xDaDRGY4TloXNVoyw5n6UmcVJU4yDn6xY2r7zZ2SVHvblUc21/g==", + "requires": { + "@opentelemetry/instrumentation": "^0.49.1", + "@opentelemetry/semantic-conventions": "^1.0.0" + } + }, + "@opentelemetry/instrumentation-net": { + "version": "0.34.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-net/-/instrumentation-net-0.34.0.tgz", + "integrity": "sha512-gjybNOQQqbXmD1qVHNO2qBJI4V6p3QQ7xKg3pnC/x7wRdxn+siLQj7QIVxW85C3mymngoJJdRs6BwI3qPUfsPQ==", + "requires": { + "@opentelemetry/instrumentation": "^0.49.1", + "@opentelemetry/semantic-conventions": "^1.0.0" + } + }, + "@opentelemetry/instrumentation-pg": { + "version": "0.39.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-pg/-/instrumentation-pg-0.39.1.tgz", + "integrity": "sha512-pX5ujDOyGpPcrZlzaD3LJzmyaSMMMKAP+ffTHJp9vasvZJr+LifCk53TMPVUafcXKV/xX/IIkvADO+67M1Z25g==", + "requires": { + "@opentelemetry/instrumentation": "^0.49.1", + "@opentelemetry/semantic-conventions": "^1.0.0", + "@opentelemetry/sql-common": "^0.40.0", + "@types/pg": "8.6.1", + "@types/pg-pool": "2.0.4" + }, + "dependencies": { + "@types/pg": { + "version": "8.6.1", + "resolved": "https://registry.npmjs.org/@types/pg/-/pg-8.6.1.tgz", + "integrity": "sha512-1Kc4oAGzAl7uqUStZCDvaLFqZrW9qWSjXOmBfdgyBP5La7Us6Mg4GBvRlSoaZMhQF/zSj1C8CtKMBkoiT8eL8w==", + "requires": { + "@types/node": "*", + "pg-protocol": "*", + "pg-types": "^2.2.0" + } + } + } + }, + "@opentelemetry/instrumentation-pino": { + "version": "0.36.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-pino/-/instrumentation-pino-0.36.0.tgz", + "integrity": "sha512-oEz+BJEYRBMAUu7MVJFJhhlsBuwLaUGjbJciKZRIeGX+fUtgcbQGV+a2Ris9jR3yFzWZrYg0aNBSCbGqvPCtMQ==", + "requires": { + "@opentelemetry/instrumentation": "^0.49.1" + } + }, + "@opentelemetry/instrumentation-redis": { + "version": "0.37.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-redis/-/instrumentation-redis-0.37.0.tgz", + "integrity": "sha512-9G0T74kheu37k+UvyBnAcieB5iowxska3z2rhUcSTL8Cl0y/CvMn7sZ7txkUbXt0rdX6qeEUdMLmbsY2fPUM7Q==", + "requires": { + "@opentelemetry/instrumentation": "^0.49.1", + "@opentelemetry/redis-common": "^0.36.1", + "@opentelemetry/semantic-conventions": "^1.0.0" + } + }, + "@opentelemetry/instrumentation-redis-4": { + "version": "0.37.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-redis-4/-/instrumentation-redis-4-0.37.0.tgz", + "integrity": "sha512-WNO+HALvPPvjbh7UEEIuay0Z0d2mIfSCkBZbPRwZttDGX6LYGc2WnRgJh3TnYqjp7/y9IryWIbajAFIebj1OBA==", + "requires": { + "@opentelemetry/instrumentation": "^0.49.1", + "@opentelemetry/redis-common": "^0.36.1", + "@opentelemetry/semantic-conventions": "^1.0.0" + } + }, + "@opentelemetry/instrumentation-restify": { + "version": "0.36.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-restify/-/instrumentation-restify-0.36.0.tgz", + "integrity": "sha512-QbOh8HpnnRn4xxFXX77Gdww6M78yx7dRiIKR6+H3j5LH5u6sYckTXw3TGPSsXsaM4DQHy0fOw15sAcJoWkC+aQ==", + "requires": { + "@opentelemetry/core": "^1.8.0", + "@opentelemetry/instrumentation": "^0.49.1", + "@opentelemetry/semantic-conventions": "^1.0.0" + } + }, + "@opentelemetry/instrumentation-router": { + "version": "0.35.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-router/-/instrumentation-router-0.35.0.tgz", + "integrity": "sha512-MdxGJuNTIy/2qDI8yow6cRBQ87m6O//VuHIlawe8v0x1NsTOSwS72xm+BzTuY9D0iMqiJUiTlE3dBs8DA91MTw==", + "requires": { + "@opentelemetry/instrumentation": "^0.49.1", + "@opentelemetry/semantic-conventions": "^1.0.0" + } + }, + "@opentelemetry/instrumentation-socket.io": { + "version": "0.37.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-socket.io/-/instrumentation-socket.io-0.37.0.tgz", + "integrity": "sha512-aIztxmx/yis/goEndnoITrZvDDr1GdCtlsWo9ex7MhUIjqq5nJbTuyigf3GmU86XFFhSThxfQuJ9DpJyPxfBfA==", + "requires": { + "@opentelemetry/instrumentation": "^0.49.1", + "@opentelemetry/semantic-conventions": "^1.0.0" + } + }, + "@opentelemetry/instrumentation-tedious": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-tedious/-/instrumentation-tedious-0.8.0.tgz", + "integrity": "sha512-BBRW8+Qm2PLNkVMynr3Q7L4xCAOCOs0J9BJIJ8ZGoatW42b2H4qhMhq35jfPDvEL5u5azxHDapmUVYrDJDjAfA==", + "requires": { + "@opentelemetry/instrumentation": "^0.49.1", + "@opentelemetry/semantic-conventions": "^1.0.0", + "@types/tedious": "^4.0.10" + } + }, + "@opentelemetry/instrumentation-winston": { + "version": "0.35.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-winston/-/instrumentation-winston-0.35.0.tgz", + "integrity": "sha512-ymcuA3S2flnLmH1GS0105H91iDLap8cizOCaLMCp7Xz7r4L+wFf1zfix9M+iSkxcPFshHRt8LFA/ELXw51nk0g==", + "requires": { + "@opentelemetry/instrumentation": "^0.49.1" + } + }, + "@opentelemetry/otlp-exporter-base": { + "version": "0.49.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/otlp-exporter-base/-/otlp-exporter-base-0.49.1.tgz", + "integrity": "sha512-z6sHliPqDgJU45kQatAettY9/eVF58qVPaTuejw9YWfSRqid9pXPYeegDCSdyS47KAUgAtm+nC28K3pfF27HWg==", + "requires": { + "@opentelemetry/core": "1.22.0" + } + }, + "@opentelemetry/otlp-grpc-exporter-base": { + "version": "0.49.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/otlp-grpc-exporter-base/-/otlp-grpc-exporter-base-0.49.1.tgz", + "integrity": "sha512-DNDNUWmOqtKTFJAyOyHHKotVox0NQ/09ETX8fUOeEtyNVHoGekAVtBbvIA3AtK+JflP7LC0PTjlLfruPM3Wy6w==", + "requires": { + "@grpc/grpc-js": "^1.7.1", + "@opentelemetry/core": "1.22.0", + "@opentelemetry/otlp-exporter-base": "0.49.1", + "protobufjs": "^7.2.3" + } + }, + "@opentelemetry/otlp-proto-exporter-base": { + "version": "0.49.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/otlp-proto-exporter-base/-/otlp-proto-exporter-base-0.49.1.tgz", + "integrity": "sha512-x1qB4EUC7KikUl2iNuxCkV8yRzrSXSyj4itfpIO674H7dhI7Zv37SFaOJTDN+8Z/F50gF2ISFH9CWQ4KCtGm2A==", + "requires": { + "@opentelemetry/core": "1.22.0", + "@opentelemetry/otlp-exporter-base": "0.49.1", + "protobufjs": "^7.2.3" + } + }, + "@opentelemetry/otlp-transformer": { + "version": "0.49.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/otlp-transformer/-/otlp-transformer-0.49.1.tgz", + "integrity": "sha512-Z+koA4wp9L9e3jkFacyXTGphSWTbOKjwwXMpb0CxNb0kjTHGUxhYRN8GnkLFsFo5NbZPjP07hwAqeEG/uCratQ==", + "requires": { + "@opentelemetry/api-logs": "0.49.1", + "@opentelemetry/core": "1.22.0", + "@opentelemetry/resources": "1.22.0", + "@opentelemetry/sdk-logs": "0.49.1", + "@opentelemetry/sdk-metrics": "1.22.0", + "@opentelemetry/sdk-trace-base": "1.22.0" + } + }, + "@opentelemetry/propagation-utils": { + "version": "0.30.7", + "resolved": "https://registry.npmjs.org/@opentelemetry/propagation-utils/-/propagation-utils-0.30.7.tgz", + "integrity": "sha512-QkxOkuCQdq8YgJstEMF4ntSyr0ivCrcQc49uvO2pyccrniu2DwA+JD071aM4BXfNVSCeOuhIyW/3QPiZYl4zdA==", + "requires": {} + }, + "@opentelemetry/propagator-aws-xray": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/propagator-aws-xray/-/propagator-aws-xray-1.3.1.tgz", + "integrity": "sha512-6fDMzFlt5r6VWv7MUd0eOpglXPFqykW8CnOuUxJ1VZyLy6mV1bzBlzpsqEmhx1bjvZYvH93vhGkQZqrm95mlrQ==", + "requires": { + "@opentelemetry/core": "^1.0.0" + } + }, + "@opentelemetry/propagator-b3": { + "version": "1.22.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/propagator-b3/-/propagator-b3-1.22.0.tgz", + "integrity": "sha512-qBItJm9ygg/jCB5rmivyGz1qmKZPsL/sX715JqPMFgq++Idm0x+N9sLQvWFHFt2+ZINnCSojw7FVBgFW6izcXA==", + "requires": { + "@opentelemetry/core": "1.22.0" + } + }, + "@opentelemetry/propagator-jaeger": { + "version": "1.22.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/propagator-jaeger/-/propagator-jaeger-1.22.0.tgz", + "integrity": "sha512-pMLgst3QIwrUfepraH5WG7xfpJ8J3CrPKrtINK0t7kBkuu96rn+HDYQ8kt3+0FXvrZI8YJE77MCQwnJWXIrgpA==", + "requires": { + "@opentelemetry/core": "1.22.0" + } + }, + "@opentelemetry/redis-common": { + "version": "0.36.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/redis-common/-/redis-common-0.36.1.tgz", + "integrity": "sha512-YjfNEr7DK1Ymc5H0bzhmqVvMcCs+PUEUerzrpTFdHfZxj3HpnnjZTIFKx/gxiL/sajQ8dxycjlreoYTVYKBXlw==" + }, + "@opentelemetry/resource-detector-alibaba-cloud": { + "version": "0.28.7", + "resolved": "https://registry.npmjs.org/@opentelemetry/resource-detector-alibaba-cloud/-/resource-detector-alibaba-cloud-0.28.7.tgz", + "integrity": "sha512-7o/waBJ08JrKED4blHGyBPIN1HMM1KEvhbO1HmdA+tsUqsGwZdTjsdMKFW7hc1TvAu4AQEnuvMy/Q5OByVr95A==", + "requires": { + "@opentelemetry/resources": "^1.0.0", + "@opentelemetry/semantic-conventions": "^1.0.0" + } + }, + "@opentelemetry/resource-detector-aws": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/resource-detector-aws/-/resource-detector-aws-1.4.0.tgz", + "integrity": "sha512-Cn8eQ/heLqrNrPuHGG7xUkk//VQt4hzVIPurmLlCI0wrDV6HR+yykBvRkJBuSdLzbjeQ/qNbGel9OvTmA6PBQA==", + "requires": { + "@opentelemetry/core": "^1.0.0", + "@opentelemetry/resources": "^1.0.0", + "@opentelemetry/semantic-conventions": "^1.0.0" + } + }, + "@opentelemetry/resource-detector-container": { + "version": "0.3.7", + "resolved": "https://registry.npmjs.org/@opentelemetry/resource-detector-container/-/resource-detector-container-0.3.7.tgz", + "integrity": "sha512-AYqwffGVuGLuzzVOQMLNHTztwyvsep9noxN9HTQ/grwmJSWZ6851kNx+W735K7v6GZEDmXeLpBn+J3TeqKQUJA==", + "requires": { + "@opentelemetry/resources": "^1.0.0", + "@opentelemetry/semantic-conventions": "^1.0.0" + } + }, + "@opentelemetry/resource-detector-gcp": { + "version": "0.29.7", + "resolved": "https://registry.npmjs.org/@opentelemetry/resource-detector-gcp/-/resource-detector-gcp-0.29.7.tgz", + "integrity": "sha512-uUHKfoOgBCZCEPCU6FWnRrbYuz1miaeIfos0Xe38YuR06vQvddhqZ0tewYunJpfECfKEcjSjY0eDe2QIRLMkXw==", + "requires": { + "@opentelemetry/core": "^1.0.0", + "@opentelemetry/resources": "^1.0.0", + "@opentelemetry/semantic-conventions": "^1.0.0", + "gcp-metadata": "^6.0.0" + } + }, + "@opentelemetry/resources": { + "version": "1.22.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/resources/-/resources-1.22.0.tgz", + "integrity": "sha512-+vNeIFPH2hfcNL0AJk/ykJXoUCtR1YaDUZM+p3wZNU4Hq98gzq+7b43xbkXjadD9VhWIUQqEwXyY64q6msPj6A==", + "requires": { + "@opentelemetry/core": "1.22.0", + "@opentelemetry/semantic-conventions": "1.22.0" + } + }, + "@opentelemetry/sdk-logs": { + "version": "0.49.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-logs/-/sdk-logs-0.49.1.tgz", + "integrity": "sha512-gCzYWsJE0h+3cuh3/cK+9UwlVFyHvj3PReIOCDOmdeXOp90ZjKRoDOJBc3mvk1LL6wyl1RWIivR8Rg9OToyesw==", + "requires": { + "@opentelemetry/core": "1.22.0", + "@opentelemetry/resources": "1.22.0" + } + }, + "@opentelemetry/sdk-metrics": { + "version": "1.22.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-metrics/-/sdk-metrics-1.22.0.tgz", + "integrity": "sha512-k6iIx6H3TZ+BVMr2z8M16ri2OxWaljg5h8ihGJxi/KQWcjign6FEaEzuigXt5bK9wVEhqAcWLCfarSftaNWkkg==", + "requires": { + "@opentelemetry/core": "1.22.0", + "@opentelemetry/resources": "1.22.0", + "lodash.merge": "^4.6.2" + } + }, + "@opentelemetry/sdk-node": { + "version": "0.49.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-node/-/sdk-node-0.49.1.tgz", + "integrity": "sha512-feBIT85ndiSHXsQ2gfGpXC/sNeX4GCHLksC4A9s/bfpUbbgbCSl0RvzZlmEpCHarNrkZMwFRi4H0xFfgvJEjrg==", + "requires": { + "@opentelemetry/api-logs": "0.49.1", + "@opentelemetry/core": "1.22.0", + "@opentelemetry/exporter-trace-otlp-grpc": "0.49.1", + "@opentelemetry/exporter-trace-otlp-http": "0.49.1", + "@opentelemetry/exporter-trace-otlp-proto": "0.49.1", + "@opentelemetry/exporter-zipkin": "1.22.0", + "@opentelemetry/instrumentation": "0.49.1", + "@opentelemetry/resources": "1.22.0", + "@opentelemetry/sdk-logs": "0.49.1", + "@opentelemetry/sdk-metrics": "1.22.0", + "@opentelemetry/sdk-trace-base": "1.22.0", + "@opentelemetry/sdk-trace-node": "1.22.0", + "@opentelemetry/semantic-conventions": "1.22.0" + } + }, + "@opentelemetry/sdk-trace-base": { + "version": "1.22.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-trace-base/-/sdk-trace-base-1.22.0.tgz", + "integrity": "sha512-pfTuSIpCKONC6vkTpv6VmACxD+P1woZf4q0K46nSUvXFvOFqjBYKFaAMkKD3M1mlKUUh0Oajwj35qNjMl80m1Q==", + "requires": { + "@opentelemetry/core": "1.22.0", + "@opentelemetry/resources": "1.22.0", + "@opentelemetry/semantic-conventions": "1.22.0" + } + }, + "@opentelemetry/sdk-trace-node": { + "version": "1.22.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-trace-node/-/sdk-trace-node-1.22.0.tgz", + "integrity": "sha512-gTGquNz7ue8uMeiWPwp3CU321OstQ84r7PCDtOaCicjbJxzvO8RZMlEC4geOipTeiF88kss5n6w+//A0MhP1lQ==", + "requires": { + "@opentelemetry/context-async-hooks": "1.22.0", + "@opentelemetry/core": "1.22.0", + "@opentelemetry/propagator-b3": "1.22.0", + "@opentelemetry/propagator-jaeger": "1.22.0", + "@opentelemetry/sdk-trace-base": "1.22.0", + "semver": "^7.5.2" + } + }, + "@opentelemetry/semantic-conventions": { + "version": "1.22.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/semantic-conventions/-/semantic-conventions-1.22.0.tgz", + "integrity": "sha512-CAOgFOKLybd02uj/GhCdEeeBjOS0yeoDeo/CA7ASBSmenpZHAKGB3iDm/rv3BQLcabb/OprDEsSQ1y0P8A7Siw==" + }, + "@opentelemetry/sql-common": { + "version": "0.40.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/sql-common/-/sql-common-0.40.0.tgz", + "integrity": "sha512-vSqRJYUPJVjMFQpYkQS3ruexCPSZJ8esne3LazLwtCPaPRvzZ7WG3tX44RouAn7w4wMp8orKguBqtt+ng2UTnw==", + "requires": { + "@opentelemetry/core": "^1.1.0" + } + }, "@photostructure/tz-lookup": { "version": "9.0.1", "resolved": "https://registry.npmjs.org/@photostructure/tz-lookup/-/tz-lookup-9.0.1.tgz", @@ -14495,6 +17081,60 @@ "resolved": "https://registry.npmjs.org/@polka/url/-/url-1.0.0-next.25.tgz", "integrity": "sha512-j7P6Rgr3mmtdkeDGTe0E/aYyWEWVtc5yFXtHCRHs28/jptDEWfaVOc5T7cblqy1XKPPfCxJc/8DwQ5YgLOZOVQ==" }, + "@protobufjs/aspromise": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@protobufjs/aspromise/-/aspromise-1.1.2.tgz", + "integrity": "sha512-j+gKExEuLmKwvz3OgROXtrJ2UG2x8Ch2YZUxahh+s1F2HZ+wAceUNLkvy6zKCPVRkU++ZWQrdxsUeQXmcg4uoQ==" + }, + "@protobufjs/base64": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@protobufjs/base64/-/base64-1.1.2.tgz", + "integrity": "sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg==" + }, + "@protobufjs/codegen": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@protobufjs/codegen/-/codegen-2.0.4.tgz", + "integrity": "sha512-YyFaikqM5sH0ziFZCN3xDC7zeGaB/d0IUb9CATugHWbd1FRFwWwt4ld4OYMPWu5a3Xe01mGAULCdqhMlPl29Jg==" + }, + "@protobufjs/eventemitter": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/eventemitter/-/eventemitter-1.1.0.tgz", + "integrity": "sha512-j9ednRT81vYJ9OfVuXG6ERSTdEL1xVsNgqpkxMsbIabzSo3goCjDIveeGv5d03om39ML71RdmrGNjG5SReBP/Q==" + }, + "@protobufjs/fetch": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/fetch/-/fetch-1.1.0.tgz", + "integrity": "sha512-lljVXpqXebpsijW71PZaCYeIcE5on1w5DlQy5WH6GLbFryLUrBD4932W/E2BSpfRJWseIL4v/KPgBFxDOIdKpQ==", + "requires": { + "@protobufjs/aspromise": "^1.1.1", + "@protobufjs/inquire": "^1.1.0" + } + }, + "@protobufjs/float": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@protobufjs/float/-/float-1.0.2.tgz", + "integrity": "sha512-Ddb+kVXlXst9d+R9PfTIxh1EdNkgoRe5tOX6t01f1lYWOvJnSPDBlG241QLzcyPdoNTsblLUdujGSE4RzrTZGQ==" + }, + "@protobufjs/inquire": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/inquire/-/inquire-1.1.0.tgz", + "integrity": "sha512-kdSefcPdruJiFMVSbn801t4vFK7KB/5gd2fYvrxhuJYg8ILrmn9SKSX2tZdV6V+ksulWqS7aXjBcRXl3wHoD9Q==" + }, + "@protobufjs/path": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@protobufjs/path/-/path-1.1.2.tgz", + "integrity": "sha512-6JOcJ5Tm08dOHAbdR3GrvP+yUUfkjG5ePsHYczMFLq3ZmMkAD98cDgcT2iA1lJ9NVwFd4tH/iSSoe44YWkltEA==" + }, + "@protobufjs/pool": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/pool/-/pool-1.1.0.tgz", + "integrity": "sha512-0kELaGSIDBKvcgS4zkjz1PeddatrjYcmMWOlAuAPwAeccUrPHdUqo/J6LiymHHEiJT5NrF1UVwxY14f+fy4WQw==" + }, + "@protobufjs/utf8": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/utf8/-/utf8-1.1.0.tgz", + "integrity": "sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw==" + }, "@sideway/address": { "version": "4.1.5", "resolved": "https://registry.npmjs.org/@sideway/address/-/address-4.1.5.tgz", @@ -14613,6 +17253,14 @@ "@turf/helpers": "^6.5.0" } }, + "@types/accepts": { + "version": "1.3.7", + "resolved": "https://registry.npmjs.org/@types/accepts/-/accepts-1.3.7.tgz", + "integrity": "sha512-Pay9fq2lM2wXPWbteBsRAGiWH2hig4ZE2asK+mm7kUzlxRTfL961rj89I6zV/E3PcIkDqyuBEcMxFT7rccugeQ==", + "requires": { + "@types/node": "*" + } + }, "@types/archiver": { "version": "6.0.2", "resolved": "https://registry.npmjs.org/@types/archiver/-/archiver-6.0.2.tgz", @@ -14628,6 +17276,11 @@ "integrity": "sha512-HlZ6Dcr205BmNhwkdXqrg2vkFMN2PluI7Lgr8In3B3wE5PiQHhjRqtW/lGdVU9gw+sM0JcIDx2AN+cW8oSWIcw==", "dev": true }, + "@types/aws-lambda": { + "version": "8.10.122", + "resolved": "https://registry.npmjs.org/@types/aws-lambda/-/aws-lambda-8.10.122.tgz", + "integrity": "sha512-vBkIh9AY22kVOCEKo5CJlyCgmSWvasC+SWUxL/x/vOwRobMpI/HG1xp/Ae3AqmSiZeLUbOhW0FCD3ZjqqUxmXw==" + }, "@types/babel__core": { "version": "7.20.2", "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.2.tgz", @@ -14682,21 +17335,32 @@ "version": "1.19.3", "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.3.tgz", "integrity": "sha512-oyl4jvAfTGX9Bt6Or4H9ni1Z447/tQuxnZsytsCaExKlmJiU8sFgnIBRzJUpKwB5eWn9HuBYlUlVA74q/yN0eQ==", - "dev": true, "requires": { "@types/connect": "*", "@types/node": "*" } }, + "@types/bunyan": { + "version": "1.8.9", + "resolved": "https://registry.npmjs.org/@types/bunyan/-/bunyan-1.8.9.tgz", + "integrity": "sha512-ZqS9JGpBxVOvsawzmVt30sP++gSQMTejCkIAQ3VdadOcRE8izTyW66hufvwLeH+YEGP6Js2AW7Gz+RMyvrEbmw==", + "requires": { + "@types/node": "*" + } + }, "@types/connect": { "version": "3.4.36", "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.36.tgz", "integrity": "sha512-P63Zd/JUGq+PdrM1lv0Wv5SBYeA2+CORvbrXbngriYY0jzLUWfQMQQxOhjONEz/wlHOAxOdY7CY65rgQdTjq2w==", - "dev": true, "requires": { "@types/node": "*" } }, + "@types/content-disposition": { + "version": "0.5.8", + "resolved": "https://registry.npmjs.org/@types/content-disposition/-/content-disposition-0.5.8.tgz", + "integrity": "sha512-QVSSvno3dE0MgO76pJhmv4Qyi/j0Yk9pBp0Y7TJ2Tlj+KCgJWY6qX7nnxCOLkZ3VYRSIk1WTxCvwUSdx6CCLdg==" + }, "@types/cookie": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/@types/cookie/-/cookie-0.4.1.tgz", @@ -14717,6 +17381,17 @@ "integrity": "sha512-he+DHOWReW0nghN24E1WUqM0efK4kI9oTqDm6XmK8ZPe2djZ90BSNdGnIyCLzCPw7/pogPlGbzI2wHGGmi4O/Q==", "dev": true }, + "@types/cookies": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/@types/cookies/-/cookies-0.9.0.tgz", + "integrity": "sha512-40Zk8qR147RABiQ7NQnBzWzDcjKzNrntB5BAmeGCb2p/MIyOE+4BVvc17wumsUqUw00bJYqoXFHYygQnEFh4/Q==", + "requires": { + "@types/connect": "*", + "@types/express": "*", + "@types/keygrip": "*", + "@types/node": "*" + } + }, "@types/cors": { "version": "2.8.14", "resolved": "https://registry.npmjs.org/@types/cors/-/cors-2.8.14.tgz", @@ -14775,7 +17450,6 @@ "version": "4.17.21", "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.21.tgz", "integrity": "sha512-ejlPM315qwLpaQlQDTjPdsUFSc6ZsP4AN6AlWnogPjQ7CVi7PYF3YVz+CY3jE2pwYf7E/7HlDAN0rV2GxTG0HQ==", - "dev": true, "requires": { "@types/body-parser": "*", "@types/express-serve-static-core": "^4.17.33", @@ -14787,7 +17461,6 @@ "version": "4.17.37", "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.37.tgz", "integrity": "sha512-ZohaCYTgGFcOP7u6aJOhY9uIZQgZ2vxC2yWoArY+FeDXlqeH66ZVBjgvg+RLVAS/DWNq4Ap9ZXu1+SUQiiWYMg==", - "dev": true, "requires": { "@types/node": "*", "@types/qs": "*", @@ -14813,11 +17486,51 @@ "@types/node": "*" } }, + "@types/hapi__catbox": { + "version": "10.2.6", + "resolved": "https://registry.npmjs.org/@types/hapi__catbox/-/hapi__catbox-10.2.6.tgz", + "integrity": "sha512-qdMHk4fBlwRfnBBDJaoaxb+fU9Ewi2xqkXD3mNjSPl2v/G/8IJbDpVRBuIcF7oXrcE8YebU5M8cCeKh1NXEn0w==" + }, + "@types/hapi__hapi": { + "version": "20.0.13", + "resolved": "https://registry.npmjs.org/@types/hapi__hapi/-/hapi__hapi-20.0.13.tgz", + "integrity": "sha512-LP4IPfhIO5ZPVOrJo7H8c8Slc0WYTFAUNQX1U0LBPKyXioXhH5H2TawIgxKujIyOhbwoBbpvOsBf6o5+ToJIrQ==", + "requires": { + "@hapi/boom": "^9.0.0", + "@hapi/iron": "^6.0.0", + "@hapi/podium": "^4.1.3", + "@types/hapi__catbox": "*", + "@types/hapi__mimos": "*", + "@types/hapi__shot": "*", + "@types/node": "*", + "joi": "^17.3.0" + } + }, + "@types/hapi__mimos": { + "version": "4.1.4", + "resolved": "https://registry.npmjs.org/@types/hapi__mimos/-/hapi__mimos-4.1.4.tgz", + "integrity": "sha512-i9hvJpFYTT/qzB5xKWvDYaSXrIiNqi4ephi+5Lo6+DoQdwqPXQgmVVOZR+s3MBiHoFqsCZCX9TmVWG3HczmTEQ==", + "requires": { + "@types/mime-db": "*" + } + }, + "@types/hapi__shot": { + "version": "4.1.6", + "resolved": "https://registry.npmjs.org/@types/hapi__shot/-/hapi__shot-4.1.6.tgz", + "integrity": "sha512-h33NBjx2WyOs/9JgcFeFhkxnioYWQAZxOHdmqDuoJ1Qjxpcs+JGvSjEEoDeWfcrF+1n47kKgqph5IpfmPOnzbg==", + "requires": { + "@types/node": "*" + } + }, + "@types/http-assert": { + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/@types/http-assert/-/http-assert-1.5.5.tgz", + "integrity": "sha512-4+tE/lwdAahgZT1g30Jkdm9PzFRde0xwxBNUyRsCitRvCQB90iuA2uJYdUnhnANRcqGXaWOGY4FEoxeElNAK2g==" + }, "@types/http-errors": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/@types/http-errors/-/http-errors-2.0.2.tgz", - "integrity": "sha512-lPG6KlZs88gef6aD85z3HNkztpj7w2R7HmR3gygjfXCQmsLloWNARFkMuzKiiY8FGdh1XDpgBdrSf4aKDiA7Kg==", - "dev": true + "integrity": "sha512-lPG6KlZs88gef6aD85z3HNkztpj7w2R7HmR3gygjfXCQmsLloWNARFkMuzKiiY8FGdh1XDpgBdrSf4aKDiA7Kg==" }, "@types/imagemin": { "version": "8.0.5", @@ -14838,6 +17551,14 @@ "rxjs": "^7.2.0" } }, + "@types/ioredis4": { + "version": "npm:@types/ioredis@4.28.10", + "resolved": "https://registry.npmjs.org/@types/ioredis/-/ioredis-4.28.10.tgz", + "integrity": "sha512-69LyhUgrXdgcNDv7ogs1qXZomnfOEnSmrmMFqKgt1XMJxmoOSG/u3wYy13yACIfKuMJ8IhKgHafDO3sx19zVQQ==", + "requires": { + "@types/node": "*" + } + }, "@types/istanbul-lib-coverage": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.4.tgz", @@ -14881,12 +17602,54 @@ "@types/jest": "*" } }, + "@types/js-yaml": { + "version": "4.0.9", + "resolved": "https://registry.npmjs.org/@types/js-yaml/-/js-yaml-4.0.9.tgz", + "integrity": "sha512-k4MGaQl5TGo/iipqb2UDG2UwjXziSWkh0uysQelTlJpX1qGlpUZYm8PnO4DxG1qBomtJUdYJ6qR6xdIah10JLg==", + "dev": true + }, "@types/json-schema": { "version": "7.0.13", "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.13.tgz", "integrity": "sha512-RbSSoHliUbnXj3ny0CNFOoxrIDV6SUGyStHsvDqosw6CkdPV8TtWGlfecuK4ToyMEAql6pzNxgCFKanovUzlgQ==", "dev": true }, + "@types/keygrip": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/@types/keygrip/-/keygrip-1.0.6.tgz", + "integrity": "sha512-lZuNAY9xeJt7Bx4t4dx0rYCDqGPW8RXhQZK1td7d4H6E9zYbLoOtjBvfwdTKpsyxQI/2jv+armjX/RW+ZNpXOQ==" + }, + "@types/koa": { + "version": "2.14.0", + "resolved": "https://registry.npmjs.org/@types/koa/-/koa-2.14.0.tgz", + "integrity": "sha512-DTDUyznHGNHAl+wd1n0z1jxNajduyTh8R53xoewuerdBzGo6Ogj6F2299BFtrexJw4NtgjsI5SMPCmV9gZwGXA==", + "requires": { + "@types/accepts": "*", + "@types/content-disposition": "*", + "@types/cookies": "*", + "@types/http-assert": "*", + "@types/http-errors": "*", + "@types/keygrip": "*", + "@types/koa-compose": "*", + "@types/node": "*" + } + }, + "@types/koa__router": { + "version": "12.0.3", + "resolved": "https://registry.npmjs.org/@types/koa__router/-/koa__router-12.0.3.tgz", + "integrity": "sha512-5YUJVv6NwM1z7m6FuYpKfNLTZ932Z6EF6xy2BbtpJSyn13DKNQEkXVffFVSnJHxvwwWh2SAeumpjAYUELqgjyw==", + "requires": { + "@types/koa": "*" + } + }, + "@types/koa-compose": { + "version": "3.2.8", + "resolved": "https://registry.npmjs.org/@types/koa-compose/-/koa-compose-3.2.8.tgz", + "integrity": "sha512-4Olc63RY+MKvxMwVknCUDhRQX1pFQoBZ/lXcRLP69PQkEpze/0cr8LNqJQe5NFb/b19DWi2a5bTi2VAlQzhJuA==", + "requires": { + "@types/koa": "*" + } + }, "@types/lodash": { "version": "4.14.202", "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.202.tgz", @@ -14898,6 +17661,14 @@ "resolved": "https://registry.npmjs.org/@types/luxon/-/luxon-3.3.7.tgz", "integrity": "sha512-gKc9P2d4g5uYwmy4s/MO/yOVPmvHyvzka1YH6i5dM03UrFofHSmgc0D0ymbDRStFWHusk6cwwF6nhLm/ckBbbQ==" }, + "@types/memcached": { + "version": "2.2.10", + "resolved": "https://registry.npmjs.org/@types/memcached/-/memcached-2.2.10.tgz", + "integrity": "sha512-AM9smvZN55Gzs2wRrqeMHVP7KE8KWgCJO/XL5yCly2xF6EKa4YlbpK+cLSAH4NG/Ah64HrlegmGqW8kYws7Vxg==", + "requires": { + "@types/node": "*" + } + }, "@types/methods": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/@types/methods/-/methods-1.1.4.tgz", @@ -14907,8 +17678,12 @@ "@types/mime": { "version": "1.3.3", "resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.3.tgz", - "integrity": "sha512-Ys+/St+2VF4+xuY6+kDIXGxbNRO0mesVg0bbxEfB97Od1Vjpjx9KD1qxs64Gcb3CWPirk9Xe+PT4YiiHQ9T+eg==", - "dev": true + "integrity": "sha512-Ys+/St+2VF4+xuY6+kDIXGxbNRO0mesVg0bbxEfB97Od1Vjpjx9KD1qxs64Gcb3CWPirk9Xe+PT4YiiHQ9T+eg==" + }, + "@types/mime-db": { + "version": "1.43.5", + "resolved": "https://registry.npmjs.org/@types/mime-db/-/mime-db-1.43.5.tgz", + "integrity": "sha512-/bfTiIUTNPUBnwnYvUxXAre5MhD88jgagLEQiQtIASjU+bwxd8kS/ASDA4a8ufd8m0Lheu6eeMJHEUpLHoJ28A==" }, "@types/mock-fs": { "version": "4.13.4", @@ -14928,10 +17703,18 @@ "@types/express": "*" } }, + "@types/mysql": { + "version": "2.15.22", + "resolved": "https://registry.npmjs.org/@types/mysql/-/mysql-2.15.22.tgz", + "integrity": "sha512-wK1pzsJVVAjYCSZWQoWHziQZbNggXFDUEIGf54g4ZM/ERuP86uGdWeKZWMYlqTPMZfHJJvLPyogXGvCOg87yLQ==", + "requires": { + "@types/node": "*" + } + }, "@types/node": { - "version": "20.11.24", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.11.24.tgz", - "integrity": "sha512-Kza43ewS3xoLgCEpQrsT+xRo/EJej1y0kVYGiLFE1NEODXGzTfwiC6tXTLMQskn1X4/Rjlh0MQUvx9W+L9long==", + "version": "20.11.25", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.11.25.tgz", + "integrity": "sha512-TBHyJxk2b7HceLVGFcpAUjsa5zIdsPWlR6XHfyGzd0SFu+/NFgQgMAl96MSDZgQDvJAvV6BKsFOrt6zIL09JDw==", "requires": { "undici-types": "~5.26.4" } @@ -14991,6 +17774,14 @@ } } }, + "@types/pg-pool": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@types/pg-pool/-/pg-pool-2.0.4.tgz", + "integrity": "sha512-qZAvkv1K3QbmHHFYSNRYPkRjOWRLBYrL4B9c+wG0GSVGBw0NtJwPcgx/DSddeDJvRGMHCEQ4VMEVfuJ/0gZ3XQ==", + "requires": { + "@types/pg": "*" + } + }, "@types/picomatch": { "version": "2.3.3", "resolved": "https://registry.npmjs.org/@types/picomatch/-/picomatch-2.3.3.tgz", @@ -14999,14 +17790,12 @@ "@types/qs": { "version": "6.9.8", "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.8.tgz", - "integrity": "sha512-u95svzDlTysU5xecFNTgfFG5RUWu1A9P0VzgpcIiGZA9iraHOdSzcxMxQ55DyeRaGCSxQi7LxXDI4rzq/MYfdg==", - "dev": true + "integrity": "sha512-u95svzDlTysU5xecFNTgfFG5RUWu1A9P0VzgpcIiGZA9iraHOdSzcxMxQ55DyeRaGCSxQi7LxXDI4rzq/MYfdg==" }, "@types/range-parser": { "version": "1.2.5", "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.5.tgz", - "integrity": "sha512-xrO9OoVPqFuYyR/loIHjnbvvyRZREYKLjxV4+dY6v3FQR3stQ9ZxIGkaclF7YhI9hfjpuTbu14hZEy94qKLtOA==", - "dev": true + "integrity": "sha512-xrO9OoVPqFuYyR/loIHjnbvvyRZREYKLjxV4+dY6v3FQR3stQ9ZxIGkaclF7YhI9hfjpuTbu14hZEy94qKLtOA==" }, "@types/readdir-glob": { "version": "1.1.2", @@ -15027,7 +17816,6 @@ "version": "0.17.2", "resolved": "https://registry.npmjs.org/@types/send/-/send-0.17.2.tgz", "integrity": "sha512-aAG6yRf6r0wQ29bkS+x97BIs64ZLxeE/ARwyS6wrldMm3C1MdKwCcnnEwMC1slI8wuxJOpiUH9MioC0A0i+GJw==", - "dev": true, "requires": { "@types/mime": "^1", "@types/node": "*" @@ -15037,7 +17825,6 @@ "version": "1.15.3", "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.15.3.tgz", "integrity": "sha512-yVRvFsEMrv7s0lGhzrggJjNOSmZCdgCjw9xWrPr/kNNLp6FaDfMC1KaYl3TSJ0c58bECwNBMoQrZJ8hA8E1eFg==", - "dev": true, "requires": { "@types/http-errors": "*", "@types/mime": "*", @@ -15053,6 +17840,11 @@ "@types/node": "*" } }, + "@types/shimmer": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/@types/shimmer/-/shimmer-1.0.5.tgz", + "integrity": "sha512-9Hp0ObzwwO57DpLFF0InUjUm/II8GmKAvzbefxQTihCb7KI6yc9yzf0nLc4mVdby5N4DRCgQM2wCup9KTieeww==" + }, "@types/ssh2": { "version": "0.5.52", "resolved": "https://registry.npmjs.org/@types/ssh2/-/ssh2-0.5.52.tgz", @@ -15099,6 +17891,14 @@ "@types/superagent": "^8.1.0" } }, + "@types/tedious": { + "version": "4.0.14", + "resolved": "https://registry.npmjs.org/@types/tedious/-/tedious-4.0.14.tgz", + "integrity": "sha512-KHPsfX/FoVbUGbyYvk1q9MMQHLPeRZhRJZdO45Q4YjvFkv4hMNghCWTvy7rdKessBsmtz4euWCWAB6/tVpI1Iw==", + "requires": { + "@types/node": "*" + } + }, "@types/through": { "version": "0.0.31", "resolved": "https://registry.npmjs.org/@types/through/-/through-0.0.31.tgz", @@ -15135,16 +17935,16 @@ "dev": true }, "@typescript-eslint/eslint-plugin": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.1.0.tgz", - "integrity": "sha512-j6vT/kCulhG5wBmGtstKeiVr1rdXE4nk+DT1k6trYkwlrvW9eOF5ZbgKnd/YR6PcM4uTEXa0h6Fcvf6X7Dxl0w==", + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.1.1.tgz", + "integrity": "sha512-zioDz623d0RHNhvx0eesUmGfIjzrk18nSBC8xewepKXbBvN/7c1qImV7Hg8TI1URTxKax7/zxfxj3Uph8Chcuw==", "dev": true, "requires": { "@eslint-community/regexpp": "^4.5.1", - "@typescript-eslint/scope-manager": "7.1.0", - "@typescript-eslint/type-utils": "7.1.0", - "@typescript-eslint/utils": "7.1.0", - "@typescript-eslint/visitor-keys": "7.1.0", + "@typescript-eslint/scope-manager": "7.1.1", + "@typescript-eslint/type-utils": "7.1.1", + "@typescript-eslint/utils": "7.1.1", + "@typescript-eslint/visitor-keys": "7.1.1", "debug": "^4.3.4", "graphemer": "^1.4.0", "ignore": "^5.2.4", @@ -15154,54 +17954,54 @@ } }, "@typescript-eslint/parser": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-7.1.0.tgz", - "integrity": "sha512-V1EknKUubZ1gWFjiOZhDSNToOjs63/9O0puCgGS8aDOgpZY326fzFu15QAUjwaXzRZjf/qdsdBrckYdv9YxB8w==", + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-7.1.1.tgz", + "integrity": "sha512-ZWUFyL0z04R1nAEgr9e79YtV5LbafdOtN7yapNbn1ansMyaegl2D4bL7vHoJ4HPSc4CaLwuCVas8CVuneKzplQ==", "dev": true, "requires": { - "@typescript-eslint/scope-manager": "7.1.0", - "@typescript-eslint/types": "7.1.0", - "@typescript-eslint/typescript-estree": "7.1.0", - "@typescript-eslint/visitor-keys": "7.1.0", + "@typescript-eslint/scope-manager": "7.1.1", + "@typescript-eslint/types": "7.1.1", + "@typescript-eslint/typescript-estree": "7.1.1", + "@typescript-eslint/visitor-keys": "7.1.1", "debug": "^4.3.4" } }, "@typescript-eslint/scope-manager": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.1.0.tgz", - "integrity": "sha512-6TmN4OJiohHfoOdGZ3huuLhpiUgOGTpgXNUPJgeZOZR3DnIpdSgtt83RS35OYNNXxM4TScVlpVKC9jyQSETR1A==", + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.1.1.tgz", + "integrity": "sha512-cirZpA8bJMRb4WZ+rO6+mnOJrGFDd38WoXCEI57+CYBqta8Yc8aJym2i7vyqLL1vVYljgw0X27axkUXz32T8TA==", "dev": true, "requires": { - "@typescript-eslint/types": "7.1.0", - "@typescript-eslint/visitor-keys": "7.1.0" + "@typescript-eslint/types": "7.1.1", + "@typescript-eslint/visitor-keys": "7.1.1" } }, "@typescript-eslint/type-utils": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-7.1.0.tgz", - "integrity": "sha512-UZIhv8G+5b5skkcuhgvxYWHjk7FW7/JP5lPASMEUoliAPwIH/rxoUSQPia2cuOj9AmDZmwUl1usKm85t5VUMew==", + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-7.1.1.tgz", + "integrity": "sha512-5r4RKze6XHEEhlZnJtR3GYeCh1IueUHdbrukV2KSlLXaTjuSfeVF8mZUVPLovidCuZfbVjfhi4c0DNSa/Rdg5g==", "dev": true, "requires": { - "@typescript-eslint/typescript-estree": "7.1.0", - "@typescript-eslint/utils": "7.1.0", + "@typescript-eslint/typescript-estree": "7.1.1", + "@typescript-eslint/utils": "7.1.1", "debug": "^4.3.4", "ts-api-utils": "^1.0.1" } }, "@typescript-eslint/types": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.1.0.tgz", - "integrity": "sha512-qTWjWieJ1tRJkxgZYXx6WUYtWlBc48YRxgY2JN1aGeVpkhmnopq+SUC8UEVGNXIvWH7XyuTjwALfG6bFEgCkQA==", + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.1.1.tgz", + "integrity": "sha512-KhewzrlRMrgeKm1U9bh2z5aoL4s7K3tK5DwHDn8MHv0yQfWFz/0ZR6trrIHHa5CsF83j/GgHqzdbzCXJ3crx0Q==", "dev": true }, "@typescript-eslint/typescript-estree": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.1.0.tgz", - "integrity": "sha512-k7MyrbD6E463CBbSpcOnwa8oXRdHzH1WiVzOipK3L5KSML92ZKgUBrTlehdi7PEIMT8k0bQixHUGXggPAlKnOQ==", + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.1.1.tgz", + "integrity": "sha512-9ZOncVSfr+sMXVxxca2OJOPagRwT0u/UHikM2Rd6L/aB+kL/QAuTnsv6MeXtjzCJYb8PzrXarypSGIPx3Jemxw==", "dev": true, "requires": { - "@typescript-eslint/types": "7.1.0", - "@typescript-eslint/visitor-keys": "7.1.0", + "@typescript-eslint/types": "7.1.1", + "@typescript-eslint/visitor-keys": "7.1.1", "debug": "^4.3.4", "globby": "^11.1.0", "is-glob": "^4.0.3", @@ -15231,27 +18031,27 @@ } }, "@typescript-eslint/utils": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.1.0.tgz", - "integrity": "sha512-WUFba6PZC5OCGEmbweGpnNJytJiLG7ZvDBJJoUcX4qZYf1mGZ97mO2Mps6O2efxJcJdRNpqweCistDbZMwIVHw==", + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.1.1.tgz", + "integrity": "sha512-thOXM89xA03xAE0lW7alstvnyoBUbBX38YtY+zAUcpRPcq9EIhXPuJ0YTv948MbzmKh6e1AUszn5cBFK49Umqg==", "dev": true, "requires": { "@eslint-community/eslint-utils": "^4.4.0", "@types/json-schema": "^7.0.12", "@types/semver": "^7.5.0", - "@typescript-eslint/scope-manager": "7.1.0", - "@typescript-eslint/types": "7.1.0", - "@typescript-eslint/typescript-estree": "7.1.0", + "@typescript-eslint/scope-manager": "7.1.1", + "@typescript-eslint/types": "7.1.1", + "@typescript-eslint/typescript-estree": "7.1.1", "semver": "^7.5.4" } }, "@typescript-eslint/visitor-keys": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.1.0.tgz", - "integrity": "sha512-FhUqNWluiGNzlvnDZiXad4mZRhtghdoKW6e98GoEOYSu5cND+E39rG5KwJMUzeENwm1ztYBRqof8wMLP+wNPIA==", + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.1.1.tgz", + "integrity": "sha512-yTdHDQxY7cSoCcAtiBzVzxleJhkGB9NncSIyMYe2+OGON1ZsP9zOPws/Pqgopa65jvknOjlk/w7ulPlZ78PiLQ==", "dev": true, "requires": { - "@typescript-eslint/types": "7.1.0", + "@typescript-eslint/types": "7.1.1", "eslint-visitor-keys": "^3.4.1" } }, @@ -15444,14 +18244,12 @@ "acorn": { "version": "8.10.0", "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.10.0.tgz", - "integrity": "sha512-F0SAmZ8iUtS//m8DmCTA0jlh6TDKkHQyK6xc6V4KDTyZKA9dnvX9/3sRTVQrWm79glUAZbnmmNcdYwUIHWVybw==", - "devOptional": true + "integrity": "sha512-F0SAmZ8iUtS//m8DmCTA0jlh6TDKkHQyK6xc6V4KDTyZKA9dnvX9/3sRTVQrWm79glUAZbnmmNcdYwUIHWVybw==" }, "acorn-import-assertions": { "version": "1.9.0", "resolved": "https://registry.npmjs.org/acorn-import-assertions/-/acorn-import-assertions-1.9.0.tgz", "integrity": "sha512-cmMwop9x+8KFhxvKrKfPYmN6/pKTYYHBqLa0DfvVZcKMJWNyWLnaqND7dx/qn66R7ewM1UX5XMaDVP5wlVTaVA==", - "dev": true, "requires": {} }, "acorn-jsx": { @@ -15872,6 +18670,11 @@ "tweetnacl": "^0.14.3" } }, + "bignumber.js": { + "version": "9.1.2", + "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.1.2.tgz", + "integrity": "sha512-2/mKyZH9K85bzOEfhXDBFZTGd1CTs+5IHpeFQo9luiBG7hghdC851Pj2WAhb6E3R6b9tZj/XKhbg4fum+Kepug==" + }, "binary-extensions": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", @@ -16154,8 +18957,7 @@ "cjs-module-lexer": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-1.2.3.tgz", - "integrity": "sha512-0TNiGstbQmCFwt4akjjBg5pLRTSyj/PkWQ1ZoO2zntmg9yLqSRxwEa4iCfQLGjqhiqBfOJa7W/E8wfGrTDmlZQ==", - "dev": true + "integrity": "sha512-0TNiGstbQmCFwt4akjjBg5pLRTSyj/PkWQ1ZoO2zntmg9yLqSRxwEa4iCfQLGjqhiqBfOJa7W/E8wfGrTDmlZQ==" }, "class-transformer": { "version": "0.5.1", @@ -17277,6 +20079,11 @@ } } }, + "extend": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==" + }, "external-editor": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-3.1.0.tgz", @@ -17637,6 +20444,45 @@ } } }, + "gaxios": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/gaxios/-/gaxios-6.2.0.tgz", + "integrity": "sha512-H6+bHeoEAU5D6XNc6mPKeN5dLZqEDs9Gpk6I+SZBEzK5So58JVrHPmevNi35fRl1J9Y5TaeLW0kYx3pCJ1U2mQ==", + "requires": { + "extend": "^3.0.2", + "https-proxy-agent": "^7.0.1", + "is-stream": "^2.0.0", + "node-fetch": "^2.6.9" + }, + "dependencies": { + "agent-base": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.0.tgz", + "integrity": "sha512-o/zjMZRhJxny7OyEF+Op8X+efiELC7k7yOjMzgfzVqOzXqkBkWI79YoTdOtsuWd5BWhAGAuOY/Xa6xpiaWXiNg==", + "requires": { + "debug": "^4.3.4" + } + }, + "https-proxy-agent": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.4.tgz", + "integrity": "sha512-wlwpilI7YdjSkWaQ/7omYBMTliDcmCN8OLihO6I9B86g06lMyAoqgoDpV0XqoaPOKj+0DIdAvnsWfyAAhmimcg==", + "requires": { + "agent-base": "^7.0.2", + "debug": "4" + } + } + } + }, + "gcp-metadata": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/gcp-metadata/-/gcp-metadata-6.1.0.tgz", + "integrity": "sha512-Jh/AIwwgaxan+7ZUUmRLCjtchyDiqh4KjBJ5tW3plBZb5iL/BPcso8A5DlzeD9qlw0duCamnNdpFjxwaT0KyKg==", + "requires": { + "gaxios": "^6.0.0", + "json-bigint": "^1.0.0" + } + }, "gensync": { "version": "1.0.0-beta.2", "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", @@ -17814,7 +20660,6 @@ "version": "1.0.3", "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", - "dev": true, "requires": { "function-bind": "^1.1.1" } @@ -17917,9 +20762,9 @@ "dev": true }, "i18n-iso-countries": { - "version": "7.10.0", - "resolved": "https://registry.npmjs.org/i18n-iso-countries/-/i18n-iso-countries-7.10.0.tgz", - "integrity": "sha512-Y4wkIS2MzYk7cvaV665qcHpBUK4FaMcAhSfsggu9SPV9VpWvmH8NklofWvPPFWG1ZXmxqZ0Ubgr+ZtqddxG4ag==", + "version": "7.10.1", + "resolved": "https://registry.npmjs.org/i18n-iso-countries/-/i18n-iso-countries-7.10.1.tgz", + "integrity": "sha512-9DXmAMkfGcGNE+E/2fE85UUjjkPeT0LHMA8d+kcxXiO+s50W28lxiICel8f8qWZmCNic1cuhN1+nw7ZazMQJFA==", "requires": { "diacritics": "1.3.0" } @@ -17952,6 +20797,17 @@ "resolve-from": "^4.0.0" } }, + "import-in-the-middle": { + "version": "1.7.1", + "resolved": "https://registry.npmjs.org/import-in-the-middle/-/import-in-the-middle-1.7.1.tgz", + "integrity": "sha512-1LrZPDtW+atAxH42S6288qyDFNQ2YCty+2mxEPRtfazH6Z5QwkaBSTS2ods7hnVJioF6rkRfNoA6A/MstpFXLg==", + "requires": { + "acorn": "^8.8.2", + "acorn-import-assertions": "^1.9.0", + "cjs-module-lexer": "^1.2.2", + "module-details-from-path": "^1.0.3" + } + }, "import-local": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.1.0.tgz", @@ -18063,7 +20919,6 @@ "version": "2.13.0", "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.13.0.tgz", "integrity": "sha512-Z7dk6Qo8pOCp3l4tsX2C5ZVas4V+UxwQodwZhLopL91TX8UyyHEXafPcyoeeWuLrwzHcr3igO78wNLwHJHsMCQ==", - "dev": true, "requires": { "has": "^1.0.3" } @@ -18111,8 +20966,7 @@ "is-stream": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", - "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", - "dev": true + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==" }, "is-unicode-supported": { "version": "0.1.0", @@ -18779,6 +21633,14 @@ "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", "dev": true }, + "json-bigint": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-bigint/-/json-bigint-1.0.0.tgz", + "integrity": "sha512-SiPv/8VpZuWbvLSMtTDU8hEfrZWg/mH/nV/b4o0CYbSxu1UIQPLdwKOCIyLQX+VIPO5vrLX3i8qtqFyhdPSUSQ==", + "requires": { + "bignumber.js": "^9.0.0" + } + }, "json-buffer": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", @@ -18922,6 +21784,11 @@ "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" }, + "lodash.camelcase": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz", + "integrity": "sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA==" + }, "lodash.defaults": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/lodash.defaults/-/lodash.defaults-4.2.0.tgz", @@ -18959,8 +21826,7 @@ "lodash.merge": { "version": "4.6.2", "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", - "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", - "dev": true + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==" }, "lodash.union": { "version": "4.6.0", @@ -18977,6 +21843,11 @@ "is-unicode-supported": "^0.1.0" } }, + "long": { + "version": "5.2.3", + "resolved": "https://registry.npmjs.org/long/-/long-5.2.3.tgz", + "integrity": "sha512-lcHwpNoggQTObv5apGNCTdJrO69eHOZMi4BNC+rTLER8iHAqGrUVeLh/irVIM7zTw2bOXA8T6uNPeujwOLg/2Q==" + }, "lru-cache": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", @@ -19172,6 +22043,11 @@ "integrity": "sha512-2dF2R6YMSZbpip1V1WHKGLNjr/k48uQClqMVb5H3MOvwc9qhYis3/IWbj02qIg/Y8MDXKFF4c5v0rxx2o6xTZw==", "dev": true }, + "module-details-from-path": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/module-details-from-path/-/module-details-from-path-1.0.3.tgz", + "integrity": "sha512-ySViT69/76t8VhE1xXHK6Ch4NcDd26gx0MzKXLO+F7NOtnqH68d9zF94nT8ZWSxXh8ELOERsnJO/sWt1xZYw5A==" + }, "moo": { "version": "0.5.2", "resolved": "https://registry.npmjs.org/moo/-/moo-0.5.2.tgz", @@ -19350,6 +22226,16 @@ } } }, + "nestjs-otel": { + "version": "5.1.5", + "resolved": "https://registry.npmjs.org/nestjs-otel/-/nestjs-otel-5.1.5.tgz", + "integrity": "sha512-4u87aSy/GpbwuYvb5OAm0Zk3CP/q9QATI2bb9DQNpLYC5uYsqNkLHL3AdLBMVueNIMqp8rZui67XW0WTM8rr6g==", + "requires": { + "@opentelemetry/api": "^1.4.1", + "@opentelemetry/host-metrics": "^0.32.2", + "response-time": "^2.3.2" + } + }, "node-abort-controller": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/node-abort-controller/-/node-abort-controller-3.1.1.tgz", @@ -19481,6 +22367,11 @@ "ee-first": "1.1.1" } }, + "on-headers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.0.2.tgz", + "integrity": "sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA==" + }, "once": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", @@ -19498,9 +22389,9 @@ } }, "openid-client": { - "version": "5.6.4", - "resolved": "https://registry.npmjs.org/openid-client/-/openid-client-5.6.4.tgz", - "integrity": "sha512-T1h3B10BRPKfcObdBklX639tVz+xh34O7GjofqrqiAQdm7eHsQ00ih18x6wuJ/E6FxdtS2u3FmUGPDeEcMwzNA==", + "version": "5.6.5", + "resolved": "https://registry.npmjs.org/openid-client/-/openid-client-5.6.5.tgz", + "integrity": "sha512-5P4qO9nGJzB5PI0LFlhj4Dzg3m4odt0qsJTfyEtZyOlkgpILwEioOhVVJOrS1iVH494S4Ee5OCjjg6Bf5WOj3w==", "requires": { "jose": "^4.15.5", "lru-cache": "^6.0.0", @@ -19655,8 +22546,7 @@ "path-parse": { "version": "1.0.7", "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", - "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", - "dev": true + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==" }, "path-scurry": { "version": "1.10.1", @@ -19970,6 +22860,25 @@ } } }, + "protobufjs": { + "version": "7.2.6", + "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-7.2.6.tgz", + "integrity": "sha512-dgJaEDDL6x8ASUZ1YqWciTRrdOuYNzoOf27oHNfdyvKqHr5i0FV7FSLU+aIeFjyFgVxrpTOtQUi0BLLBymZaBw==", + "requires": { + "@protobufjs/aspromise": "^1.1.2", + "@protobufjs/base64": "^1.1.2", + "@protobufjs/codegen": "^2.0.4", + "@protobufjs/eventemitter": "^1.1.0", + "@protobufjs/fetch": "^1.1.0", + "@protobufjs/float": "^1.0.2", + "@protobufjs/inquire": "^1.1.0", + "@protobufjs/path": "^1.1.2", + "@protobufjs/pool": "^1.1.0", + "@protobufjs/utf8": "^1.1.0", + "@types/node": ">=13.7.0", + "long": "^5.0.0" + } + }, "protocol-buffers-schema": { "version": "3.6.0", "resolved": "https://registry.npmjs.org/protocol-buffers-schema/-/protocol-buffers-schema-3.6.0.tgz", @@ -20270,11 +23179,20 @@ "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", "dev": true }, + "require-in-the-middle": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/require-in-the-middle/-/require-in-the-middle-7.2.0.tgz", + "integrity": "sha512-3TLx5TGyAY6AOqLBoXmHkNql0HIf2RGbuMgCDT2WO/uGVAPJs6h7Kl+bN6TIZGd9bWhWPwnDnTHGtW8Iu77sdw==", + "requires": { + "debug": "^4.1.1", + "module-details-from-path": "^1.0.3", + "resolve": "^1.22.1" + } + }, "resolve": { "version": "1.22.6", "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.6.tgz", "integrity": "sha512-njhxM7mV12JfufShqGy3Rz8j11RPdLy4xi15UurGJeoHLfJpVXKdh3ueuOqbYUcDZnffr6X739JBo5LzyahEsw==", - "dev": true, "requires": { "is-core-module": "^2.13.0", "path-parse": "^1.0.7", @@ -20317,6 +23235,22 @@ "integrity": "sha512-X2UW6Nw3n/aMgDVy+0rSqgHlv39WZAlZrXCdnbyEiKm17DSqHX4MmQMaST3FbeWR5FTuRcUwYAziZajji0Y7mg==", "dev": true }, + "response-time": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/response-time/-/response-time-2.3.2.tgz", + "integrity": "sha512-MUIDaDQf+CVqflfTdQ5yam+aYCkXj1PY8fjlPDQ6ppxJlmgZb864pHtA750mayywNg8tx4rS7qH9JXd/OF+3gw==", + "requires": { + "depd": "~1.1.0", + "on-headers": "~1.0.1" + }, + "dependencies": { + "depd": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", + "integrity": "sha512-7emPTl6Dpo6JRXOXjLRxck+FlLRX5847cLKEn00PLAgc3g2hTZZgr+e4c2v6QpSmLeFP3n5yUo7ft6avBK/5jQ==" + } + } + }, "restore-cursor": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz", @@ -20642,6 +23576,11 @@ } } }, + "shimmer": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/shimmer/-/shimmer-1.2.1.tgz", + "integrity": "sha512-sQTKC1Re/rM6XyFM6fIAGHRPVGvyXfgzIDvzoq608vM+jeyVD0Tu1E6Np0Kc2zAIFWIj963V2800iF/9LPieQw==" + }, "side-channel": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", @@ -21010,8 +23949,7 @@ "supports-preserve-symlinks-flag": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", - "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", - "dev": true + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==" }, "swagger-ui-dist": { "version": "5.11.2", @@ -21034,6 +23972,11 @@ "tslib": "^2.6.2" } }, + "systeminformation": { + "version": "5.22.0", + "resolved": "https://registry.npmjs.org/systeminformation/-/systeminformation-5.22.0.tgz", + "integrity": "sha512-oAP80ymt8ssrAzjX8k3frbL7ys6AotqC35oikG6/SG15wBw+tG9nCk4oPaXIhEaAOAZ8XngxUv3ORq2IuR3r4Q==" + }, "tapable": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz", @@ -21655,9 +24598,9 @@ } }, "typescript": { - "version": "5.3.3", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.3.3.tgz", - "integrity": "sha512-pXWcraxM0uxAS+tN0AG/BF2TyqmHO014Z070UsJ+pFvYuRSq8KH8DmWpnbXe0pEPDHXZV3FcAbJkijJ5oNEnWw==", + "version": "5.4.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.4.2.tgz", + "integrity": "sha512-+2/g0Fds1ERlP6JsakQQDXjZdZMM+rqpamFZJEKh4kwTIn3iDkgKtby0CeNd5ATNZ4Ry1ax15TMx0W2V+miizQ==", "devOptional": true }, "ua-parser-js": { diff --git a/server/package.json b/server/package.json index 70d647989..0acd97837 100644 --- a/server/package.json +++ b/server/package.json @@ -45,6 +45,9 @@ "@nestjs/swagger": "^7.1.8", "@nestjs/typeorm": "^10.0.0", "@nestjs/websockets": "^10.2.2", + "@opentelemetry/auto-instrumentations-node": "^0.42.0", + "@opentelemetry/exporter-prometheus": "^0.49.0", + "@opentelemetry/sdk-node": "^0.49.0", "@socket.io/postgres-adapter": "^0.3.1", "@types/picomatch": "^2.3.3", "archiver": "^7.0.0", @@ -65,9 +68,11 @@ "i18n-iso-countries": "^7.6.0", "ioredis": "^5.3.2", "joi": "^17.10.0", + "js-yaml": "^4.1.0", "lodash": "^4.17.21", "luxon": "^3.4.2", "nest-commander": "^3.11.1", + "nestjs-otel": "^5.1.5", "node-addon-api": "^7.0.0", "openid-client": "^5.4.3", "pg": "^8.11.3", @@ -95,6 +100,7 @@ "@types/imagemin": "^8.0.1", "@types/jest": "29.5.12", "@types/jest-when": "^3.5.2", + "@types/js-yaml": "^4.0.9", "@types/lodash": "^4.14.197", "@types/mock-fs": "^4.13.1", "@types/multer": "^1.4.7", diff --git a/server/src/domain/domain.config.ts b/server/src/domain/domain.config.ts index b77fd7412..b0471080d 100644 --- a/server/src/domain/domain.config.ts +++ b/server/src/domain/domain.config.ts @@ -14,16 +14,23 @@ export const immichAppConfig: ConfigModuleOptions = { isGlobal: true, validationSchema: Joi.object({ NODE_ENV: Joi.string().optional().valid('development', 'production', 'staging').default('development'), + LOG_LEVEL: Joi.string() + .optional() + .valid(...Object.values(LogLevel)), + DB_USERNAME: WHEN_DB_URL_SET, DB_PASSWORD: WHEN_DB_URL_SET, DB_DATABASE_NAME: WHEN_DB_URL_SET, DB_URL: Joi.string().optional(), DB_VECTOR_EXTENSION: Joi.string().optional().valid('pgvector', 'pgvecto.rs').default('pgvecto.rs'), - LOG_LEVEL: Joi.string() - .optional() - .valid(...Object.values(LogLevel)), + MACHINE_LEARNING_PORT: Joi.number().optional(), MICROSERVICES_PORT: Joi.number().optional(), - SERVER_PORT: Joi.number().optional(), + IMMICH_METRICS_PORT: Joi.number().optional(), + + IMMICH_METRICS: Joi.boolean().optional().default(false), + IMMICH_HOST_METRICS: Joi.boolean().optional().default(false), + IMMICH_API_METRICS: Joi.boolean().optional().default(false), + IMMICH_IO_METRICS: Joi.boolean().optional().default(false), }), }; diff --git a/server/src/domain/metadata/metadata.service.spec.ts b/server/src/domain/metadata/metadata.service.spec.ts index 3da9ba371..36315cf72 100644 --- a/server/src/domain/metadata/metadata.service.spec.ts +++ b/server/src/domain/metadata/metadata.service.spec.ts @@ -646,7 +646,7 @@ describe(MetadataService.name, () => { expect(assetMock.save).not.toHaveBeenCalled(); }); - it('should set sidecar path if exists', async () => { + it('should set sidecar path if exists (sidecar named photo.ext.xmp)', async () => { assetMock.getByIds.mockResolvedValue([assetStub.sidecar]); storageMock.checkFileExists.mockResolvedValue(true); @@ -658,6 +658,41 @@ describe(MetadataService.name, () => { }); }); + it('should set sidecar path if exists (sidecar named photo.xmp)', async () => { + assetMock.getByIds.mockResolvedValue([assetStub.sidecarWithoutExt]); + storageMock.checkFileExists.mockResolvedValueOnce(false); + storageMock.checkFileExists.mockResolvedValueOnce(true); + + await expect(sut.handleSidecarSync({ id: assetStub.sidecarWithoutExt.id })).resolves.toBe(true); + expect(storageMock.checkFileExists).toHaveBeenNthCalledWith( + 2, + assetStub.sidecarWithoutExt.sidecarPath, + constants.R_OK, + ); + expect(assetMock.save).toHaveBeenCalledWith({ + id: assetStub.sidecarWithoutExt.id, + sidecarPath: assetStub.sidecarWithoutExt.sidecarPath, + }); + }); + + it('should set sidecar path if exists (two sidecars named photo.ext.xmp and photo.xmp, should pick photo.ext.xmp)', async () => { + assetMock.getByIds.mockResolvedValue([assetStub.sidecar]); + storageMock.checkFileExists.mockResolvedValueOnce(true); + storageMock.checkFileExists.mockResolvedValueOnce(true); + + await expect(sut.handleSidecarSync({ id: assetStub.sidecar.id })).resolves.toBe(true); + expect(storageMock.checkFileExists).toHaveBeenNthCalledWith(1, assetStub.sidecar.sidecarPath, constants.R_OK); + expect(storageMock.checkFileExists).toHaveBeenNthCalledWith( + 2, + assetStub.sidecarWithoutExt.sidecarPath, + constants.R_OK, + ); + expect(assetMock.save).toHaveBeenCalledWith({ + id: assetStub.sidecar.id, + sidecarPath: assetStub.sidecar.sidecarPath, + }); + }); + it('should unset sidecar path if file does not exist anymore', async () => { assetMock.getByIds.mockResolvedValue([assetStub.sidecar]); storageMock.checkFileExists.mockResolvedValue(false); diff --git a/server/src/domain/metadata/metadata.service.ts b/server/src/domain/metadata/metadata.service.ts index 7d2248511..39919f78f 100644 --- a/server/src/domain/metadata/metadata.service.ts +++ b/server/src/domain/metadata/metadata.service.ts @@ -6,6 +6,7 @@ import { firstDateTime } from 'exiftool-vendored/dist/FirstDateTime'; import _ from 'lodash'; import { Duration } from 'luxon'; import { constants } from 'node:fs/promises'; +import path from 'node:path'; import { Subscription } from 'rxjs'; import { handlePromiseError, usePagination } from '../domain.util'; import { IBaseJob, IEntityJob, ISidecarWriteJob, JOBS_ASSET_PAGINATION_SIZE, JobName, QueueName } from '../job'; @@ -566,9 +567,25 @@ export class MetadataService { return false; } - const sidecarPath = `${asset.originalPath}.xmp`; - const exists = await this.storageRepository.checkFileExists(sidecarPath, constants.R_OK); - if (exists) { + // XMP sidecars can come in two filename formats. For a photo named photo.ext, the filenames are photo.ext.xmp and photo.xmp + const assetPath = path.parse(asset.originalPath); + const assetPathWithoutExt = path.join(assetPath.dir, assetPath.name); + const sidecarPathWithoutExt = `${assetPathWithoutExt}.xmp`; + const sidecarPathWithExt = `${asset.originalPath}.xmp`; + + const [sidecarPathWithExtExists, sidecarPathWithoutExtExists] = await Promise.all([ + this.storageRepository.checkFileExists(sidecarPathWithExt, constants.R_OK), + this.storageRepository.checkFileExists(sidecarPathWithoutExt, constants.R_OK), + ]); + + let sidecarPath = null; + if (sidecarPathWithExtExists) { + sidecarPath = sidecarPathWithExt; + } else if (sidecarPathWithoutExtExists) { + sidecarPath = sidecarPathWithoutExt; + } + + if (sidecarPath) { await this.assetRepository.save({ id: asset.id, sidecarPath }); return true; } @@ -577,7 +594,9 @@ export class MetadataService { return false; } - this.logger.debug(`Sidecar File '${sidecarPath}' was not found, removing sidecarPath for asset ${asset.id}`); + this.logger.debug( + `Sidecar file was not found. Checked paths '${sidecarPathWithExt}' and '${sidecarPathWithoutExt}'. Removing sidecarPath for asset ${asset.id}`, + ); await this.assetRepository.save({ id: asset.id, sidecarPath: null }); return true; diff --git a/server/src/domain/system-config/system-config.core.ts b/server/src/domain/system-config/system-config.core.ts index 644d5c3cb..4a45de93e 100644 --- a/server/src/domain/system-config/system-config.core.ts +++ b/server/src/domain/system-config/system-config.core.ts @@ -17,6 +17,7 @@ import { BadRequestException, ForbiddenException, Injectable } from '@nestjs/com import { CronExpression } from '@nestjs/schedule'; import { plainToInstance } from 'class-transformer'; import { validate } from 'class-validator'; +import { load as loadYaml } from 'js-yaml'; import * as _ from 'lodash'; import { Subject } from 'rxjs'; import { QueueName } from '../job/job.constants'; @@ -341,19 +342,19 @@ export class SystemConfigCore { if (force || !this.configCache) { try { const file = await this.repository.readFile(filepath); - const json = JSON.parse(file.toString()); + const config = loadYaml(file.toString()) as any; const overrides: SystemConfigEntity[] = []; for (const key of Object.values(SystemConfigKey)) { - const value = _.get(json, key); - this.unsetDeep(json, key); + const value = _.get(config, key); + this.unsetDeep(config, key); if (value !== undefined) { overrides.push({ key, value }); } } - if (!_.isEmpty(json)) { - this.logger.warn(`Unknown keys found: ${JSON.stringify(json, null, 2)}`); + if (!_.isEmpty(config)) { + this.logger.warn(`Unknown keys found: ${JSON.stringify(config, null, 2)}`); } this.configCache = overrides; diff --git a/server/src/domain/system-config/system-config.service.spec.ts b/server/src/domain/system-config/system-config.service.spec.ts index 91c095cb7..8fa203ae2 100644 --- a/server/src/domain/system-config/system-config.service.spec.ts +++ b/server/src/domain/system-config/system-config.service.spec.ts @@ -209,7 +209,7 @@ describe(SystemConfigService.name, () => { await expect(sut.getConfig()).resolves.toEqual(updatedConfig); }); - it('should load the config from a file', async () => { + it('should load the config from a json file', async () => { process.env.IMMICH_CONFIG_FILE = 'immich-config.json'; const partialConfig = { ffmpeg: { crf: 30 }, @@ -224,6 +224,25 @@ describe(SystemConfigService.name, () => { expect(configMock.readFile).toHaveBeenCalledWith('immich-config.json'); }); + it('should load the config from a yaml file', async () => { + process.env.IMMICH_CONFIG_FILE = 'immich-config.yaml'; + const partialConfig = ` + ffmpeg: + crf: 30 + oauth: + autoLaunch: true + trash: + days: 10 + user: + deleteDelay: 15 + `; + configMock.readFile.mockResolvedValue(partialConfig); + + await expect(sut.getConfig()).resolves.toEqual(updatedConfig); + + expect(configMock.readFile).toHaveBeenCalledWith('immich-config.yaml'); + }); + it('should accept an empty configuration file', async () => { process.env.IMMICH_CONFIG_FILE = 'immich-config.json'; configMock.readFile.mockResolvedValue(JSON.stringify({})); @@ -242,6 +261,17 @@ describe(SystemConfigService.name, () => { expect(config.machineLearning.url).toEqual('immich_machine_learning'); }); + it('should warn for unknown options in yaml', async () => { + process.env.IMMICH_CONFIG_FILE = 'immich-config.yaml'; + const partialConfig = ` + unknownOption: true + `; + configMock.readFile.mockResolvedValue(partialConfig); + + await sut.getConfig(); + expect(warnLog).toHaveBeenCalled(); + }); + const tests = [ { should: 'validate numbers', config: { ffmpeg: { crf: 'not-a-number' } } }, { should: 'validate booleans', config: { oauth: { enabled: 'invalid' } } }, diff --git a/server/src/immich-admin/app.module.ts b/server/src/immich-admin/app.module.ts index 293e43c09..b350aec83 100644 --- a/server/src/immich-admin/app.module.ts +++ b/server/src/immich-admin/app.module.ts @@ -2,6 +2,7 @@ import { DomainModule } from '@app/domain'; import { InfraModule } from '@app/infra'; import { Module } from '@nestjs/common'; import { ListUsersCommand } from './commands/list-users.command'; +import { DisableOAuthLogin, EnableOAuthLogin } from './commands/oauth-login'; import { DisablePasswordLoginCommand, EnablePasswordLoginCommand } from './commands/password-login'; import { PromptPasswordQuestions, ResetAdminPasswordCommand } from './commands/reset-admin-password.command'; @@ -12,6 +13,8 @@ import { PromptPasswordQuestions, ResetAdminPasswordCommand } from './commands/r PromptPasswordQuestions, EnablePasswordLoginCommand, DisablePasswordLoginCommand, + EnableOAuthLogin, + DisableOAuthLogin, ListUsersCommand, ], }) diff --git a/server/src/immich-admin/commands/oauth-login.ts b/server/src/immich-admin/commands/oauth-login.ts new file mode 100644 index 000000000..23747bf03 --- /dev/null +++ b/server/src/immich-admin/commands/oauth-login.ts @@ -0,0 +1,36 @@ +import { SystemConfigService } from '@app/domain'; +import { Command, CommandRunner } from 'nest-commander'; + +@Command({ + name: 'enable-oauth-login', + description: 'Enable OAuth login', +}) +export class EnableOAuthLogin extends CommandRunner { + constructor(private configService: SystemConfigService) { + super(); + } + + async run(): Promise { + const config = await this.configService.getConfig(); + config.oauth.enabled = true; + await this.configService.updateConfig(config); + console.log('OAuth login has been enabled.'); + } +} + +@Command({ + name: 'disable-oauth-login', + description: 'Disable OAuth login', +}) +export class DisableOAuthLogin extends CommandRunner { + constructor(private configService: SystemConfigService) { + super(); + } + + async run(): Promise { + const config = await this.configService.getConfig(); + config.oauth.enabled = false; + await this.configService.updateConfig(config); + console.log('OAuth login has been disabled.'); + } +} diff --git a/server/src/immich/main.ts b/server/src/immich/main.ts index d2fe44f1f..60e323e6a 100644 --- a/server/src/immich/main.ts +++ b/server/src/immich/main.ts @@ -1,5 +1,6 @@ import { WEB_ROOT, envName, isDev, serverVersion } from '@app/domain'; -import { WebSocketAdapter } from '@app/infra'; +import { WebSocketAdapter, excludePaths } from '@app/infra'; +import { otelSDK } from '@app/infra/instrumentation'; import { ImmichLogger } from '@app/infra/logger'; import { NestFactory } from '@nestjs/core'; import { NestExpressApplication } from '@nestjs/platform-express'; @@ -15,6 +16,7 @@ const logger = new ImmichLogger('ImmichServer'); const port = Number(process.env.SERVER_PORT) || 3001; export async function bootstrap() { + otelSDK.start(); const app = await NestFactory.create(AppModule, { bufferLogs: true }); app.useLogger(app.get(ImmichLogger)); @@ -28,7 +30,6 @@ export async function bootstrap() { app.useWebSocketAdapter(new WebSocketAdapter(app)); useSwagger(app, isDev); - const excludePaths = ['/.well-known/immich', '/custom.css']; app.setGlobalPrefix('api', { exclude: excludePaths }); if (existsSync(WEB_ROOT)) { // copied from https://github.com/sveltejs/kit/blob/679b5989fe62e3964b9a73b712d7b41831aa1f07/packages/adapter-node/src/handler.js#L46 diff --git a/server/src/infra/infra.config.ts b/server/src/infra/infra.config.ts index f72f33334..9ea570953 100644 --- a/server/src/infra/infra.config.ts +++ b/server/src/infra/infra.config.ts @@ -34,3 +34,5 @@ export const bullConfig: QueueOptions = { }; export const bullQueues: RegisterQueueOptions[] = Object.values(QueueName).map((name) => ({ name })); + +export const excludePaths = ['/.well-known/immich', '/custom.css', '/favicon.ico']; diff --git a/server/src/infra/infra.module.ts b/server/src/infra/infra.module.ts index b36fdf6f0..cdd5ab442 100644 --- a/server/src/infra/infra.module.ts +++ b/server/src/infra/infra.module.ts @@ -33,9 +33,11 @@ import { Global, Module, Provider } from '@nestjs/common'; import { ConfigModule } from '@nestjs/config'; import { ScheduleModule, SchedulerRegistry } from '@nestjs/schedule'; import { TypeOrmModule } from '@nestjs/typeorm'; +import { OpenTelemetryModule } from 'nestjs-otel'; import { databaseConfig } from './database.config'; import { databaseEntities } from './entities'; import { bullConfig, bullQueues } from './infra.config'; +import { otelConfig } from './instrumentation'; import { AccessRepository, ActivityRepository, @@ -106,6 +108,7 @@ const providers: Provider[] = [ ScheduleModule, BullModule.forRoot(bullConfig), BullModule.registerQueue(...bullQueues), + OpenTelemetryModule.forRoot(otelConfig), ], providers: [...providers], exports: [...providers, BullModule], diff --git a/server/src/infra/infra.utils.ts b/server/src/infra/infra.utils.ts index 636d78ab7..247244108 100644 --- a/server/src/infra/infra.utils.ts +++ b/server/src/infra/infra.utils.ts @@ -121,6 +121,27 @@ export function ChunkedSet(options?: { paramIndex?: number }): MethodDecorator { return Chunked({ ...options, mergeFn: setUnion }); } +// https://stackoverflow.com/a/74898678 +export function DecorateAll( + decorator: ( + target: any, + propertyKey: string, + descriptor: TypedPropertyDescriptor, + ) => TypedPropertyDescriptor | void, +) { + return (target: any) => { + const descriptors = Object.getOwnPropertyDescriptors(target.prototype); + for (const [propName, descriptor] of Object.entries(descriptors)) { + const isMethod = typeof descriptor.value == 'function' && propName !== 'constructor'; + if (!isMethod) { + continue; + } + decorator({ ...target, constructor: { ...target.constructor, name: target.name } as any }, propName, descriptor); + Object.defineProperty(target.prototype, propName, descriptor); + } + }; +} + export function searchAssetBuilder( builder: SelectQueryBuilder, options: AssetSearchBuilderOptions, diff --git a/server/src/infra/instrumentation.ts b/server/src/infra/instrumentation.ts new file mode 100644 index 000000000..130eaea3d --- /dev/null +++ b/server/src/infra/instrumentation.ts @@ -0,0 +1,106 @@ +import { serverVersion } from '@app/domain/domain.constant'; +import { Histogram, MetricOptions, ValueType, metrics } from '@opentelemetry/api'; +import { AsyncLocalStorageContextManager } from '@opentelemetry/context-async-hooks'; +import { PrometheusExporter } from '@opentelemetry/exporter-prometheus'; +import { HttpInstrumentation } from '@opentelemetry/instrumentation-http'; +import { IORedisInstrumentation } from '@opentelemetry/instrumentation-ioredis'; +import { NestInstrumentation } from '@opentelemetry/instrumentation-nestjs-core'; +import { PgInstrumentation } from '@opentelemetry/instrumentation-pg'; +import { Resource } from '@opentelemetry/resources'; +import { ExplicitBucketHistogramAggregation, View } from '@opentelemetry/sdk-metrics'; +import { NodeSDK } from '@opentelemetry/sdk-node'; +import { SemanticResourceAttributes } from '@opentelemetry/semantic-conventions'; +import { snakeCase, startCase } from 'lodash'; +import { OpenTelemetryModuleOptions } from 'nestjs-otel/lib/interfaces'; +import { copyMetadataFromFunctionToFunction } from 'nestjs-otel/lib/opentelemetry.utils'; +import { performance } from 'node:perf_hooks'; +import { excludePaths } from './infra.config'; +import { DecorateAll } from './infra.utils'; + +let metricsEnabled = process.env.IMMICH_METRICS === 'true'; +const hostMetrics = + process.env.IMMICH_HOST_METRICS == null ? metricsEnabled : process.env.IMMICH_HOST_METRICS === 'true'; +const apiMetrics = process.env.IMMICH_API_METRICS == null ? metricsEnabled : process.env.IMMICH_API_METRICS === 'true'; +const repoMetrics = process.env.IMMICH_IO_METRICS == null ? metricsEnabled : process.env.IMMICH_IO_METRICS === 'true'; + +metricsEnabled ||= hostMetrics || apiMetrics || repoMetrics; +if (!metricsEnabled && process.env.OTEL_SDK_DISABLED === undefined) { + process.env.OTEL_SDK_DISABLED = 'true'; +} + +const aggregation = new ExplicitBucketHistogramAggregation( + [0.1, 0.25, 0.5, 0.75, 1, 2.5, 5, 7.5, 10, 25, 50, 75, 100, 250, 500, 750, 1000, 2500, 5000, 7500, 10_000], + true, +); + +const metricsPort = Number.parseInt(process.env.IMMICH_METRICS_PORT ?? '8081'); + +export const otelSDK = new NodeSDK({ + resource: new Resource({ + [SemanticResourceAttributes.SERVICE_NAME]: `immich`, + [SemanticResourceAttributes.SERVICE_VERSION]: serverVersion.toString(), + }), + metricReader: new PrometheusExporter({ port: metricsPort }), + contextManager: new AsyncLocalStorageContextManager(), + instrumentations: [ + new HttpInstrumentation(), + new IORedisInstrumentation(), + new NestInstrumentation(), + new PgInstrumentation(), + ], + views: [new View({ aggregation, instrumentName: '*', instrumentUnit: 'ms' })], +}); + +export const otelConfig: OpenTelemetryModuleOptions = { + metrics: { + hostMetrics, + apiMetrics: { + enable: apiMetrics, + ignoreRoutes: excludePaths, + }, + }, +}; + +function ExecutionTimeHistogram({ description, unit = 'ms', valueType = ValueType.DOUBLE }: MetricOptions = {}) { + return (target: any, propertyKey: string | symbol, descriptor: PropertyDescriptor) => { + if (!repoMetrics || process.env.OTEL_SDK_DISABLED) { + return; + } + + const method = descriptor.value; + const className = target.constructor.name as string; + const propertyName = String(propertyKey); + const metricName = `${snakeCase(className).replaceAll(/_(?=(repository)|(controller)|(provider)|(service)|(module))/g, '.')}.${snakeCase(propertyName)}.duration`; + + const metricDescription = + description ?? + `The elapsed time in ${unit} for the ${startCase(className)} to ${startCase(propertyName).toLowerCase()}`; + + let histogram: Histogram | undefined; + + descriptor.value = function (...args: any[]) { + const start = performance.now(); + const result = method.apply(this, args); + + void Promise.resolve(result) + .then(() => { + const end = performance.now(); + if (!histogram) { + histogram = metrics + .getMeter('immich') + .createHistogram(metricName, { description: metricDescription, unit, valueType }); + } + histogram.record(end - start, {}); + }) + .catch(() => { + // noop + }); + + return result; + }; + + copyMetadataFromFunctionToFunction(method, descriptor.value); + }; +} + +export const Instrumentation = () => DecorateAll(ExecutionTimeHistogram()); diff --git a/server/src/infra/repositories/access.repository.ts b/server/src/infra/repositories/access.repository.ts index fea1985ce..25691846d 100644 --- a/server/src/infra/repositories/access.repository.ts +++ b/server/src/infra/repositories/access.repository.ts @@ -14,6 +14,7 @@ import { } from '../entities'; import { DummyValue, GenerateSql } from '../infra.util'; import { ChunkedSet } from '../infra.utils'; +import { Instrumentation } from '../instrumentation'; type IActivityAccess = IAccessRepository['activity']; type IAlbumAccess = IAccessRepository['album']; @@ -24,6 +25,7 @@ type ITimelineAccess = IAccessRepository['timeline']; type IPersonAccess = IAccessRepository['person']; type IPartnerAccess = IAccessRepository['partner']; +@Instrumentation() class ActivityAccess implements IActivityAccess { constructor( private activityRepository: Repository, diff --git a/server/src/infra/repositories/activity.repository.ts b/server/src/infra/repositories/activity.repository.ts index 319c9c647..c546056db 100644 --- a/server/src/infra/repositories/activity.repository.ts +++ b/server/src/infra/repositories/activity.repository.ts @@ -4,6 +4,7 @@ import { InjectRepository } from '@nestjs/typeorm'; import { IsNull, Repository } from 'typeorm'; import { ActivityEntity } from '../entities/activity.entity'; import { DummyValue, GenerateSql } from '../infra.util'; +import { Instrumentation } from '../instrumentation'; export interface ActivitySearch { albumId?: string; @@ -12,6 +13,7 @@ export interface ActivitySearch { isLiked?: boolean; } +@Instrumentation() @Injectable() export class ActivityRepository implements IActivityRepository { constructor(@InjectRepository(ActivityEntity) private repository: Repository) {} diff --git a/server/src/infra/repositories/album.repository.ts b/server/src/infra/repositories/album.repository.ts index 2d3fd795d..60ef6126c 100644 --- a/server/src/infra/repositories/album.repository.ts +++ b/server/src/infra/repositories/album.repository.ts @@ -8,7 +8,9 @@ import { dataSource } from '../database.config'; import { AlbumEntity, AssetEntity } from '../entities'; import { DATABASE_PARAMETER_CHUNK_SIZE, DummyValue, GenerateSql } from '../infra.util'; import { Chunked, ChunkedArray } from '../infra.utils'; +import { Instrumentation } from '../instrumentation'; +@Instrumentation() @Injectable() export class AlbumRepository implements IAlbumRepository { constructor( diff --git a/server/src/infra/repositories/api-key.repository.ts b/server/src/infra/repositories/api-key.repository.ts index b7ebc303d..3cafc22eb 100644 --- a/server/src/infra/repositories/api-key.repository.ts +++ b/server/src/infra/repositories/api-key.repository.ts @@ -4,7 +4,9 @@ import { InjectRepository } from '@nestjs/typeorm'; import { Repository } from 'typeorm'; import { APIKeyEntity } from '../entities'; import { DummyValue, GenerateSql } from '../infra.util'; +import { Instrumentation } from '../instrumentation'; +@Instrumentation() @Injectable() export class ApiKeyRepository implements IKeyRepository { constructor(@InjectRepository(APIKeyEntity) private repository: Repository) {} diff --git a/server/src/infra/repositories/asset-stack.repository.ts b/server/src/infra/repositories/asset-stack.repository.ts index 4b23b9c1a..d769030bb 100644 --- a/server/src/infra/repositories/asset-stack.repository.ts +++ b/server/src/infra/repositories/asset-stack.repository.ts @@ -3,7 +3,9 @@ import { Injectable } from '@nestjs/common'; import { InjectRepository } from '@nestjs/typeorm'; import { Repository } from 'typeorm'; import { AssetStackEntity } from '../entities'; +import { Instrumentation } from '../instrumentation'; +@Instrumentation() @Injectable() export class AssetStackRepository implements IAssetStackRepository { constructor(@InjectRepository(AssetStackEntity) private repository: Repository) {} diff --git a/server/src/infra/repositories/asset.repository.ts b/server/src/infra/repositories/asset.repository.ts index ff60be9fe..c91ef5e0b 100644 --- a/server/src/infra/repositories/asset.repository.ts +++ b/server/src/infra/repositories/asset.repository.ts @@ -39,6 +39,7 @@ import { import { AssetEntity, AssetJobStatusEntity, AssetType, ExifEntity, SmartInfoEntity } from '../entities'; import { DummyValue, GenerateSql } from '../infra.util'; import { Chunked, ChunkedArray, OptionalBetween, paginate, paginatedBuilder, searchAssetBuilder } from '../infra.utils'; +import { Instrumentation } from '../instrumentation'; const truncateMap: Record = { [TimeBucketSize.DAY]: 'day', @@ -50,6 +51,7 @@ const dateTrunc = (options: TimeBucketOptions) => truncateMap[options.size] }', (asset."localDateTime" at time zone 'UTC')) at time zone 'UTC')::timestamptz`; +@Instrumentation() @Injectable() export class AssetRepository implements IAssetRepository { constructor( diff --git a/server/src/infra/repositories/audit.repository.ts b/server/src/infra/repositories/audit.repository.ts index b19d38577..bc00cbe9a 100644 --- a/server/src/infra/repositories/audit.repository.ts +++ b/server/src/infra/repositories/audit.repository.ts @@ -2,7 +2,9 @@ import { AuditSearch, IAuditRepository } from '@app/domain'; import { InjectRepository } from '@nestjs/typeorm'; import { LessThan, MoreThan, Repository } from 'typeorm'; import { AuditEntity } from '../entities'; +import { Instrumentation } from '../instrumentation'; +@Instrumentation() export class AuditRepository implements IAuditRepository { constructor(@InjectRepository(AuditEntity) private repository: Repository) {} diff --git a/server/src/infra/repositories/communication.repository.ts b/server/src/infra/repositories/communication.repository.ts index ec9eb005b..b7ac6ac99 100644 --- a/server/src/infra/repositories/communication.repository.ts +++ b/server/src/infra/repositories/communication.repository.ts @@ -15,7 +15,9 @@ import { WebSocketServer, } from '@nestjs/websockets'; import { Server, Socket } from 'socket.io'; +import { Instrumentation } from '../instrumentation'; +@Instrumentation() @WebSocketGateway({ cors: true, path: '/api/socket.io', diff --git a/server/src/infra/repositories/crypto.repository.ts b/server/src/infra/repositories/crypto.repository.ts index f445ed850..f98fa9d87 100644 --- a/server/src/infra/repositories/crypto.repository.ts +++ b/server/src/infra/repositories/crypto.repository.ts @@ -3,14 +3,26 @@ import { Injectable } from '@nestjs/common'; import { compareSync, hash } from 'bcrypt'; import { createHash, randomBytes, randomUUID } from 'node:crypto'; import { createReadStream } from 'node:fs'; +import { Instrumentation } from '../instrumentation'; +@Instrumentation() @Injectable() export class CryptoRepository implements ICryptoRepository { - randomUUID = randomUUID; - randomBytes = randomBytes; + randomUUID() { + return randomUUID(); + } - hashBcrypt = hash; - compareBcrypt = compareSync; + randomBytes(size: number) { + return randomBytes(size); + } + + hashBcrypt(data: string | Buffer, saltOrRounds: string | number) { + return hash(data, saltOrRounds); + } + + compareBcrypt(data: string | Buffer, encrypted: string) { + return compareSync(data, encrypted); + } hashSha256(value: string) { return createHash('sha256').update(value).digest('base64'); diff --git a/server/src/infra/repositories/database.repository.ts b/server/src/infra/repositories/database.repository.ts index b24602b89..8154e9122 100644 --- a/server/src/infra/repositories/database.repository.ts +++ b/server/src/infra/repositories/database.repository.ts @@ -15,8 +15,10 @@ import { InjectDataSource } from '@nestjs/typeorm'; import AsyncLock from 'async-lock'; import { DataSource, EntityManager, QueryRunner } from 'typeorm'; import { isValidInteger } from '../infra.utils'; +import { Instrumentation } from '../instrumentation'; import { ImmichLogger } from '../logger'; +@Instrumentation() @Injectable() export class DatabaseRepository implements IDatabaseRepository { private logger = new ImmichLogger(DatabaseRepository.name); diff --git a/server/src/infra/repositories/filesystem.provider.ts b/server/src/infra/repositories/filesystem.provider.ts index 32880ae18..386ee5d71 100644 --- a/server/src/infra/repositories/filesystem.provider.ts +++ b/server/src/infra/repositories/filesystem.provider.ts @@ -13,23 +13,37 @@ import archiver from 'archiver'; import chokidar, { WatchOptions } from 'chokidar'; import { glob } from 'fast-glob'; import { constants, createReadStream, existsSync, mkdirSync } from 'node:fs'; -import fs, { copyFile, readdir, rename, stat, utimes, writeFile } from 'node:fs/promises'; +import fs from 'node:fs/promises'; import path from 'node:path'; +import { Instrumentation } from '../instrumentation'; +@Instrumentation() export class FilesystemProvider implements IStorageRepository { private logger = new ImmichLogger(FilesystemProvider.name); - readdir = readdir; + readdir(folder: string): Promise { + return fs.readdir(folder); + } - copyFile = copyFile; + copyFile(source: string, target: string) { + return fs.copyFile(source, target); + } - stat = stat; + stat(filepath: string) { + return fs.stat(filepath); + } - writeFile = writeFile; + writeFile(filepath: string, buffer: Buffer) { + return fs.writeFile(filepath, buffer); + } - rename = rename; + rename(source: string, target: string) { + return fs.rename(source, target); + } - utimes = utimes; + utimes(filepath: string, atime: Date, mtime: Date) { + return fs.utimes(filepath, atime, mtime); + } createZipStream(): ImmichZipStream { const archive = archiver('zip', { store: true }); diff --git a/server/src/infra/repositories/job.repository.ts b/server/src/infra/repositories/job.repository.ts index 8160ff844..227967a07 100644 --- a/server/src/infra/repositories/job.repository.ts +++ b/server/src/infra/repositories/job.repository.ts @@ -17,7 +17,9 @@ import { Job, JobsOptions, Processor, Queue, Worker, WorkerOptions } from 'bullm import { CronJob, CronTime } from 'cron'; import { setTimeout } from 'node:timers/promises'; import { bullConfig } from '../infra.config'; +import { Instrumentation } from '../instrumentation'; +@Instrumentation() @Injectable() export class JobRepository implements IJobRepository { private workers: Partial> = {}; diff --git a/server/src/infra/repositories/library.repository.ts b/server/src/infra/repositories/library.repository.ts index 89db3d175..5ae3de96f 100644 --- a/server/src/infra/repositories/library.repository.ts +++ b/server/src/infra/repositories/library.repository.ts @@ -5,7 +5,9 @@ import { IsNull, Not } from 'typeorm'; import { Repository } from 'typeorm/repository/Repository.js'; import { LibraryEntity, LibraryType } from '../entities'; import { DummyValue, GenerateSql } from '../infra.util'; +import { Instrumentation } from '../instrumentation'; +@Instrumentation() @Injectable() export class LibraryRepository implements ILibraryRepository { constructor(@InjectRepository(LibraryEntity) private repository: Repository) {} diff --git a/server/src/infra/repositories/machine-learning.repository.ts b/server/src/infra/repositories/machine-learning.repository.ts index 4542c6577..767ca812b 100644 --- a/server/src/infra/repositories/machine-learning.repository.ts +++ b/server/src/infra/repositories/machine-learning.repository.ts @@ -11,9 +11,11 @@ import { } from '@app/domain'; import { Injectable } from '@nestjs/common'; import { readFile } from 'node:fs/promises'; +import { Instrumentation } from '../instrumentation'; const errorPrefix = 'Machine learning request'; +@Instrumentation() @Injectable() export class MachineLearningRepository implements IMachineLearningRepository { private async predict(url: string, input: TextModelInput | VisionModelInput, config: ModelConfig): Promise { @@ -50,7 +52,7 @@ export class MachineLearningRepository implements IMachineLearningRepository { } as CLIPConfig); } - async getFormData(input: TextModelInput | VisionModelInput, config: ModelConfig): Promise { + private async getFormData(input: TextModelInput | VisionModelInput, config: ModelConfig): Promise { const formData = new FormData(); const { enabled, modelName, modelType, ...options } = config; if (!enabled) { diff --git a/server/src/infra/repositories/media.repository.ts b/server/src/infra/repositories/media.repository.ts index d5e4cd36f..39cec03af 100644 --- a/server/src/infra/repositories/media.repository.ts +++ b/server/src/infra/repositories/media.repository.ts @@ -13,11 +13,13 @@ import fs from 'node:fs/promises'; import { Writable } from 'node:stream'; import { promisify } from 'node:util'; import sharp from 'sharp'; +import { Instrumentation } from '../instrumentation'; const probe = promisify(ffmpeg.ffprobe); sharp.concurrency(0); sharp.cache({ files: 0 }); +@Instrumentation() export class MediaRepository implements IMediaRepository { private logger = new ImmichLogger(MediaRepository.name); @@ -115,19 +117,6 @@ export class MediaRepository implements IMediaRepository { }); } - configureFfmpegCall(input: string, output: string | Writable, options: TranscodeOptions) { - return ffmpeg(input, { niceness: 10 }) - .inputOptions(options.inputOptions) - .outputOptions(options.outputOptions) - .output(output) - .on('error', (error, stdout, stderr) => this.logger.error(stderr || error)); - } - - chainPath(existing: string, path: string) { - const separator = existing.endsWith(':') ? '' : ':'; - return `${existing}${separator}${path}`; - } - async generateThumbhash(imagePath: string): Promise { const maxSize = 100; @@ -140,4 +129,17 @@ export class MediaRepository implements IMediaRepository { const thumbhash = await import('thumbhash'); return Buffer.from(thumbhash.rgbaToThumbHash(info.width, info.height, data)); } + + private configureFfmpegCall(input: string, output: string | Writable, options: TranscodeOptions) { + return ffmpeg(input, { niceness: 10 }) + .inputOptions(options.inputOptions) + .outputOptions(options.outputOptions) + .output(output) + .on('error', (error, stdout, stderr) => this.logger.error(stderr || error)); + } + + private chainPath(existing: string, path: string) { + const separator = existing.endsWith(':') ? '' : ':'; + return `${existing}${separator}${path}`; + } } diff --git a/server/src/infra/repositories/metadata.repository.ts b/server/src/infra/repositories/metadata.repository.ts index 4abfe0eac..bf9bb8a46 100644 --- a/server/src/infra/repositories/metadata.repository.ts +++ b/server/src/infra/repositories/metadata.repository.ts @@ -23,7 +23,9 @@ import * as readLine from 'node:readline'; import { DataSource, QueryRunner, Repository } from 'typeorm'; import { QueryDeepPartialEntity } from 'typeorm/query-builder/QueryPartialEntity.js'; import { DummyValue, GenerateSql } from '../infra.util'; +import { Instrumentation } from '../instrumentation'; +@Instrumentation() export class MetadataRepository implements IMetadataRepository { constructor( @InjectRepository(ExifEntity) private exifRepository: Repository, diff --git a/server/src/infra/repositories/move.repository.ts b/server/src/infra/repositories/move.repository.ts index f7995b54e..205c67ad6 100644 --- a/server/src/infra/repositories/move.repository.ts +++ b/server/src/infra/repositories/move.repository.ts @@ -4,7 +4,9 @@ import { InjectRepository } from '@nestjs/typeorm'; import { Repository } from 'typeorm'; import { MoveEntity, PathType } from '../entities'; import { DummyValue, GenerateSql } from '../infra.util'; +import { Instrumentation } from '../instrumentation'; +@Instrumentation() @Injectable() export class MoveRepository implements IMoveRepository { constructor(@InjectRepository(MoveEntity) private repository: Repository) {} diff --git a/server/src/infra/repositories/partner.repository.ts b/server/src/infra/repositories/partner.repository.ts index b5b876558..eb07902dc 100644 --- a/server/src/infra/repositories/partner.repository.ts +++ b/server/src/infra/repositories/partner.repository.ts @@ -3,7 +3,9 @@ import { Injectable } from '@nestjs/common'; import { InjectRepository } from '@nestjs/typeorm'; import { DeepPartial, Repository } from 'typeorm'; import { PartnerEntity } from '../entities'; +import { Instrumentation } from '../instrumentation'; +@Instrumentation() @Injectable() export class PartnerRepository implements IPartnerRepository { constructor(@InjectRepository(PartnerEntity) private readonly repository: Repository) {} diff --git a/server/src/infra/repositories/person.repository.ts b/server/src/infra/repositories/person.repository.ts index 14c847ef6..562a56fb6 100644 --- a/server/src/infra/repositories/person.repository.ts +++ b/server/src/infra/repositories/person.repository.ts @@ -15,7 +15,9 @@ import { FindManyOptions, FindOptionsRelations, FindOptionsSelect, In, Repositor import { AssetEntity, AssetFaceEntity, PersonEntity } from '../entities'; import { DummyValue, GenerateSql } from '../infra.util'; import { ChunkedArray, asVector, paginate } from '../infra.utils'; +import { Instrumentation } from '../instrumentation'; +@Instrumentation() export class PersonRepository implements IPersonRepository { constructor( @InjectRepository(AssetEntity) private assetRepository: Repository, diff --git a/server/src/infra/repositories/search.repository.ts b/server/src/infra/repositories/search.repository.ts index 823193138..f5d1cbda3 100644 --- a/server/src/infra/repositories/search.repository.ts +++ b/server/src/infra/repositories/search.repository.ts @@ -26,7 +26,9 @@ import { Repository, SelectQueryBuilder } from 'typeorm'; import { vectorExt } from '../database.config'; import { DummyValue, GenerateSql } from '../infra.util'; import { asVector, isValidInteger, paginatedBuilder, searchAssetBuilder } from '../infra.utils'; +import { Instrumentation } from '../instrumentation'; +@Instrumentation() @Injectable() export class SearchRepository implements ISearchRepository { private logger = new ImmichLogger(SearchRepository.name); diff --git a/server/src/infra/repositories/server-info.repository.ts b/server/src/infra/repositories/server-info.repository.ts index 8c917cb63..bd56a58dd 100644 --- a/server/src/infra/repositories/server-info.repository.ts +++ b/server/src/infra/repositories/server-info.repository.ts @@ -1,6 +1,8 @@ import { GitHubRelease, IServerInfoRepository } from '@app/domain'; import { Injectable } from '@nestjs/common'; +import { Instrumentation } from '../instrumentation'; +@Instrumentation() @Injectable() export class ServerInfoRepository implements IServerInfoRepository { async getGitHubRelease(): Promise { diff --git a/server/src/infra/repositories/shared-link.repository.ts b/server/src/infra/repositories/shared-link.repository.ts index ae8826f79..5e796a772 100644 --- a/server/src/infra/repositories/shared-link.repository.ts +++ b/server/src/infra/repositories/shared-link.repository.ts @@ -4,7 +4,9 @@ import { InjectRepository } from '@nestjs/typeorm'; import { Repository } from 'typeorm'; import { SharedLinkEntity } from '../entities'; import { DummyValue, GenerateSql } from '../infra.util'; +import { Instrumentation } from '../instrumentation'; +@Instrumentation() @Injectable() export class SharedLinkRepository implements ISharedLinkRepository { constructor(@InjectRepository(SharedLinkEntity) private repository: Repository) {} diff --git a/server/src/infra/repositories/system-config.repository.ts b/server/src/infra/repositories/system-config.repository.ts index 1e9242e47..598333d9f 100644 --- a/server/src/infra/repositories/system-config.repository.ts +++ b/server/src/infra/repositories/system-config.repository.ts @@ -5,12 +5,15 @@ import { In, Repository } from 'typeorm'; import { SystemConfigEntity } from '../entities'; import { DummyValue, GenerateSql } from '../infra.util'; import { Chunked } from '../infra.utils'; +import { Instrumentation } from '../instrumentation'; +@Instrumentation() export class SystemConfigRepository implements ISystemConfigRepository { constructor( @InjectRepository(SystemConfigEntity) private repository: Repository, ) {} + async fetchStyle(url: string) { try { const response = await fetch(url); diff --git a/server/src/infra/repositories/system-metadata.repository.ts b/server/src/infra/repositories/system-metadata.repository.ts index d43002b0b..5b99cd1dd 100644 --- a/server/src/infra/repositories/system-metadata.repository.ts +++ b/server/src/infra/repositories/system-metadata.repository.ts @@ -2,12 +2,15 @@ import { ISystemMetadataRepository } from '@app/domain/repositories/system-metad import { InjectRepository } from '@nestjs/typeorm'; import { Repository } from 'typeorm'; import { SystemMetadata, SystemMetadataEntity } from '../entities'; +import { Instrumentation } from '../instrumentation'; +@Instrumentation() export class SystemMetadataRepository implements ISystemMetadataRepository { constructor( @InjectRepository(SystemMetadataEntity) private repository: Repository, ) {} + async get(key: T): Promise { const metadata = await this.repository.findOne({ where: { key } }); if (!metadata) { diff --git a/server/src/infra/repositories/tag.repository.ts b/server/src/infra/repositories/tag.repository.ts index 8713f0650..3ac5afd0e 100644 --- a/server/src/infra/repositories/tag.repository.ts +++ b/server/src/infra/repositories/tag.repository.ts @@ -3,7 +3,9 @@ import { AssetEntity, TagEntity } from '@app/infra/entities'; import { Injectable } from '@nestjs/common'; import { InjectRepository } from '@nestjs/typeorm'; import { Repository } from 'typeorm'; +import { Instrumentation } from '../instrumentation'; +@Instrumentation() @Injectable() export class TagRepository implements ITagRepository { constructor( diff --git a/server/src/infra/repositories/user-token.repository.ts b/server/src/infra/repositories/user-token.repository.ts index b5656d922..60eccb2e5 100644 --- a/server/src/infra/repositories/user-token.repository.ts +++ b/server/src/infra/repositories/user-token.repository.ts @@ -4,7 +4,9 @@ import { InjectRepository } from '@nestjs/typeorm'; import { Repository } from 'typeorm'; import { UserTokenEntity } from '../entities'; import { DummyValue, GenerateSql } from '../infra.util'; +import { Instrumentation } from '../instrumentation'; +@Instrumentation() @Injectable() export class UserTokenRepository implements IUserTokenRepository { constructor(@InjectRepository(UserTokenEntity) private repository: Repository) {} diff --git a/server/src/infra/repositories/user.repository.ts b/server/src/infra/repositories/user.repository.ts index d9f12bb31..865a9c8cb 100644 --- a/server/src/infra/repositories/user.repository.ts +++ b/server/src/infra/repositories/user.repository.ts @@ -4,7 +4,9 @@ import { InjectRepository } from '@nestjs/typeorm'; import { IsNull, Not, Repository } from 'typeorm'; import { AssetEntity, UserEntity } from '../entities'; import { DummyValue, GenerateSql } from '../infra.util'; +import { Instrumentation } from '../instrumentation'; +@Instrumentation() @Injectable() export class UserRepository implements IUserRepository { constructor( diff --git a/server/src/microservices/app.service.ts b/server/src/microservices/app.service.ts index 14a6eb691..9fabd5855 100644 --- a/server/src/microservices/app.service.ts +++ b/server/src/microservices/app.service.ts @@ -15,6 +15,7 @@ import { SystemConfigService, UserService, } from '@app/domain'; +import { otelSDK } from '@app/infra/instrumentation'; import { Injectable } from '@nestjs/common'; @Injectable() @@ -87,5 +88,6 @@ export class AppService { async teardown() { await this.libraryService.teardown(); await this.metadataService.teardown(); + await otelSDK.shutdown(); } } diff --git a/server/src/microservices/main.ts b/server/src/microservices/main.ts index 0a85cb37a..f7dc64f57 100644 --- a/server/src/microservices/main.ts +++ b/server/src/microservices/main.ts @@ -1,5 +1,6 @@ import { envName, serverVersion } from '@app/domain'; import { WebSocketAdapter } from '@app/infra'; +import { otelSDK } from '@app/infra/instrumentation'; import { ImmichLogger } from '@app/infra/logger'; import { NestFactory } from '@nestjs/core'; import { MicroservicesModule } from './microservices.module'; @@ -8,8 +9,8 @@ const logger = new ImmichLogger('ImmichMicroservice'); const port = Number(process.env.MICROSERVICES_PORT) || 3002; export async function bootstrap() { + otelSDK.start(); const app = await NestFactory.create(MicroservicesModule, { bufferLogs: true }); - app.useLogger(app.get(ImmichLogger)); app.useWebSocketAdapter(new WebSocketAdapter(app)); diff --git a/server/test/fixtures/asset.stub.ts b/server/test/fixtures/asset.stub.ts index ea1617d6a..d72a295d4 100644 --- a/server/test/fixtures/asset.stub.ts +++ b/server/test/fixtures/asset.stub.ts @@ -524,6 +524,42 @@ export const assetStub = { sidecarPath: '/original/path.ext.xmp', deletedAt: null, }), + sidecarWithoutExt: Object.freeze({ + id: 'asset-id', + deviceAssetId: 'device-asset-id', + fileModifiedAt: new Date('2023-02-23T05:06:29.716Z'), + fileCreatedAt: new Date('2023-02-23T05:06:29.716Z'), + owner: userStub.user1, + ownerId: 'user-id', + deviceId: 'device-id', + originalPath: '/original/path.ext', + resizePath: '/uploads/user-id/thumbs/path.ext', + thumbhash: null, + checksum: Buffer.from('file hash', 'utf8'), + type: AssetType.IMAGE, + webpPath: null, + encodedVideoPath: null, + createdAt: new Date('2023-02-23T05:06:29.716Z'), + updatedAt: new Date('2023-02-23T05:06:29.716Z'), + localDateTime: new Date('2023-02-23T05:06:29.716Z'), + isFavorite: true, + isArchived: false, + isReadOnly: false, + isExternal: false, + isOffline: false, + libraryId: 'library-id', + library: libraryStub.uploadLibrary1, + duration: null, + isVisible: true, + livePhotoVideo: null, + livePhotoVideoId: null, + tags: [], + sharedLinks: [], + originalFileName: 'asset-id.ext', + faces: [], + sidecarPath: '/original/path.xmp', + deletedAt: null, + }), readOnly: Object.freeze({ id: 'read-only-asset', diff --git a/web/package-lock.json b/web/package-lock.json index 5d8212d3e..899ec9156 100644 --- a/web/package-lock.json +++ b/web/package-lock.json @@ -65,8 +65,10 @@ "name": "@immich/sdk", "version": "1.98.2", "license": "GNU Affero General Public License version 3", + "dependencies": { + "@oazapfts/runtime": "^1.0.2" + }, "devDependencies": { - "@oazapfts/runtime": "^1.0.0", "@types/node": "^20.11.0", "typescript": "^5.3.3" } @@ -1581,9 +1583,9 @@ } }, "node_modules/@photo-sphere-viewer/core": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/@photo-sphere-viewer/core/-/core-5.7.1.tgz", - "integrity": "sha512-2wwErCpRiCee8mv9k5YAr4itMrAh2DL9dHriaOysS84xRJcmEZBMZXfhTuTFEdBvEq0o8Iv/gKheQvCrbLyv5w==", + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/@photo-sphere-viewer/core/-/core-5.7.2.tgz", + "integrity": "sha512-5RznXVRwuO+Izceae2SbwYM/H8GHtwxKlT26P4UcRFZYsYKllMAggAz9hhU729Vu+r1+il5PHvomIsmPHVTTaw==", "dependencies": { "three": "^0.161.0" } @@ -2262,16 +2264,16 @@ } }, "node_modules/@typescript-eslint/eslint-plugin": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.1.0.tgz", - "integrity": "sha512-j6vT/kCulhG5wBmGtstKeiVr1rdXE4nk+DT1k6trYkwlrvW9eOF5ZbgKnd/YR6PcM4uTEXa0h6Fcvf6X7Dxl0w==", + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.1.1.tgz", + "integrity": "sha512-zioDz623d0RHNhvx0eesUmGfIjzrk18nSBC8xewepKXbBvN/7c1qImV7Hg8TI1URTxKax7/zxfxj3Uph8Chcuw==", "dev": true, "dependencies": { "@eslint-community/regexpp": "^4.5.1", - "@typescript-eslint/scope-manager": "7.1.0", - "@typescript-eslint/type-utils": "7.1.0", - "@typescript-eslint/utils": "7.1.0", - "@typescript-eslint/visitor-keys": "7.1.0", + "@typescript-eslint/scope-manager": "7.1.1", + "@typescript-eslint/type-utils": "7.1.1", + "@typescript-eslint/utils": "7.1.1", + "@typescript-eslint/visitor-keys": "7.1.1", "debug": "^4.3.4", "graphemer": "^1.4.0", "ignore": "^5.2.4", @@ -2330,15 +2332,15 @@ "dev": true }, "node_modules/@typescript-eslint/parser": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-7.1.0.tgz", - "integrity": "sha512-V1EknKUubZ1gWFjiOZhDSNToOjs63/9O0puCgGS8aDOgpZY326fzFu15QAUjwaXzRZjf/qdsdBrckYdv9YxB8w==", + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-7.1.1.tgz", + "integrity": "sha512-ZWUFyL0z04R1nAEgr9e79YtV5LbafdOtN7yapNbn1ansMyaegl2D4bL7vHoJ4HPSc4CaLwuCVas8CVuneKzplQ==", "dev": true, "dependencies": { - "@typescript-eslint/scope-manager": "7.1.0", - "@typescript-eslint/types": "7.1.0", - "@typescript-eslint/typescript-estree": "7.1.0", - "@typescript-eslint/visitor-keys": "7.1.0", + "@typescript-eslint/scope-manager": "7.1.1", + "@typescript-eslint/types": "7.1.1", + "@typescript-eslint/typescript-estree": "7.1.1", + "@typescript-eslint/visitor-keys": "7.1.1", "debug": "^4.3.4" }, "engines": { @@ -2358,13 +2360,13 @@ } }, "node_modules/@typescript-eslint/scope-manager": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.1.0.tgz", - "integrity": "sha512-6TmN4OJiohHfoOdGZ3huuLhpiUgOGTpgXNUPJgeZOZR3DnIpdSgtt83RS35OYNNXxM4TScVlpVKC9jyQSETR1A==", + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.1.1.tgz", + "integrity": "sha512-cirZpA8bJMRb4WZ+rO6+mnOJrGFDd38WoXCEI57+CYBqta8Yc8aJym2i7vyqLL1vVYljgw0X27axkUXz32T8TA==", "dev": true, "dependencies": { - "@typescript-eslint/types": "7.1.0", - "@typescript-eslint/visitor-keys": "7.1.0" + "@typescript-eslint/types": "7.1.1", + "@typescript-eslint/visitor-keys": "7.1.1" }, "engines": { "node": "^16.0.0 || >=18.0.0" @@ -2375,13 +2377,13 @@ } }, "node_modules/@typescript-eslint/type-utils": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-7.1.0.tgz", - "integrity": "sha512-UZIhv8G+5b5skkcuhgvxYWHjk7FW7/JP5lPASMEUoliAPwIH/rxoUSQPia2cuOj9AmDZmwUl1usKm85t5VUMew==", + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-7.1.1.tgz", + "integrity": "sha512-5r4RKze6XHEEhlZnJtR3GYeCh1IueUHdbrukV2KSlLXaTjuSfeVF8mZUVPLovidCuZfbVjfhi4c0DNSa/Rdg5g==", "dev": true, "dependencies": { - "@typescript-eslint/typescript-estree": "7.1.0", - "@typescript-eslint/utils": "7.1.0", + "@typescript-eslint/typescript-estree": "7.1.1", + "@typescript-eslint/utils": "7.1.1", "debug": "^4.3.4", "ts-api-utils": "^1.0.1" }, @@ -2402,9 +2404,9 @@ } }, "node_modules/@typescript-eslint/types": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.1.0.tgz", - "integrity": "sha512-qTWjWieJ1tRJkxgZYXx6WUYtWlBc48YRxgY2JN1aGeVpkhmnopq+SUC8UEVGNXIvWH7XyuTjwALfG6bFEgCkQA==", + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.1.1.tgz", + "integrity": "sha512-KhewzrlRMrgeKm1U9bh2z5aoL4s7K3tK5DwHDn8MHv0yQfWFz/0ZR6trrIHHa5CsF83j/GgHqzdbzCXJ3crx0Q==", "dev": true, "engines": { "node": "^16.0.0 || >=18.0.0" @@ -2415,13 +2417,13 @@ } }, "node_modules/@typescript-eslint/typescript-estree": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.1.0.tgz", - "integrity": "sha512-k7MyrbD6E463CBbSpcOnwa8oXRdHzH1WiVzOipK3L5KSML92ZKgUBrTlehdi7PEIMT8k0bQixHUGXggPAlKnOQ==", + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.1.1.tgz", + "integrity": "sha512-9ZOncVSfr+sMXVxxca2OJOPagRwT0u/UHikM2Rd6L/aB+kL/QAuTnsv6MeXtjzCJYb8PzrXarypSGIPx3Jemxw==", "dev": true, "dependencies": { - "@typescript-eslint/types": "7.1.0", - "@typescript-eslint/visitor-keys": "7.1.0", + "@typescript-eslint/types": "7.1.1", + "@typescript-eslint/visitor-keys": "7.1.1", "debug": "^4.3.4", "globby": "^11.1.0", "is-glob": "^4.0.3", @@ -2500,17 +2502,17 @@ "dev": true }, "node_modules/@typescript-eslint/utils": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.1.0.tgz", - "integrity": "sha512-WUFba6PZC5OCGEmbweGpnNJytJiLG7ZvDBJJoUcX4qZYf1mGZ97mO2Mps6O2efxJcJdRNpqweCistDbZMwIVHw==", + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.1.1.tgz", + "integrity": "sha512-thOXM89xA03xAE0lW7alstvnyoBUbBX38YtY+zAUcpRPcq9EIhXPuJ0YTv948MbzmKh6e1AUszn5cBFK49Umqg==", "dev": true, "dependencies": { "@eslint-community/eslint-utils": "^4.4.0", "@types/json-schema": "^7.0.12", "@types/semver": "^7.5.0", - "@typescript-eslint/scope-manager": "7.1.0", - "@typescript-eslint/types": "7.1.0", - "@typescript-eslint/typescript-estree": "7.1.0", + "@typescript-eslint/scope-manager": "7.1.1", + "@typescript-eslint/types": "7.1.1", + "@typescript-eslint/typescript-estree": "7.1.1", "semver": "^7.5.4" }, "engines": { @@ -2558,12 +2560,12 @@ "dev": true }, "node_modules/@typescript-eslint/visitor-keys": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.1.0.tgz", - "integrity": "sha512-FhUqNWluiGNzlvnDZiXad4mZRhtghdoKW6e98GoEOYSu5cND+E39rG5KwJMUzeENwm1ztYBRqof8wMLP+wNPIA==", + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.1.1.tgz", + "integrity": "sha512-yTdHDQxY7cSoCcAtiBzVzxleJhkGB9NncSIyMYe2+OGON1ZsP9zOPws/Pqgopa65jvknOjlk/w7ulPlZ78PiLQ==", "dev": true, "dependencies": { - "@typescript-eslint/types": "7.1.0", + "@typescript-eslint/types": "7.1.1", "eslint-visitor-keys": "^3.4.1" }, "engines": { @@ -3001,9 +3003,9 @@ "peer": true }, "node_modules/autoprefixer": { - "version": "10.4.17", - "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.17.tgz", - "integrity": "sha512-/cpVNRLSfhOtcGflT13P2794gVSgmPgTR+erw5ifnMLZb0UnSlkK4tquLmkd3BhA+nLo5tX8Cu0upUsGKvKbmg==", + "version": "10.4.18", + "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.18.tgz", + "integrity": "sha512-1DKbDfsr6KUElM6wg+0zRNkB/Q7WcKYAaK+pzXn+Xqmszm/5Xa9coeNdtP88Vi+dPzZnMjhge8GIV49ZQkDa+g==", "dev": true, "funding": [ { @@ -3020,8 +3022,8 @@ } ], "dependencies": { - "browserslist": "^4.22.2", - "caniuse-lite": "^1.0.30001578", + "browserslist": "^4.23.0", + "caniuse-lite": "^1.0.30001591", "fraction.js": "^4.3.7", "normalize-range": "^0.1.2", "picocolors": "^1.0.0", @@ -3114,9 +3116,9 @@ } }, "node_modules/browserslist": { - "version": "4.22.2", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.22.2.tgz", - "integrity": "sha512-0UgcrvQmBDvZHFGdYUehrCNIazki7/lUP3kkoi/r3YB2amZbFM9J43ZRkJTXBUZK4gmx56+Sqk9+Vs9mwZx9+A==", + "version": "4.23.0", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.23.0.tgz", + "integrity": "sha512-QW8HiM1shhT2GuzkvklfjcKDiWFXHOeFCIA/huJPwHsslwcydgk7X+z2zXpEijP98UCY7HbubZt5J2Zgvf0CaQ==", "dev": true, "funding": [ { @@ -3133,8 +3135,8 @@ } ], "dependencies": { - "caniuse-lite": "^1.0.30001565", - "electron-to-chromium": "^1.4.601", + "caniuse-lite": "^1.0.30001587", + "electron-to-chromium": "^1.4.668", "node-releases": "^2.0.14", "update-browserslist-db": "^1.0.13" }, @@ -3253,9 +3255,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001579", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001579.tgz", - "integrity": "sha512-u5AUVkixruKHJjw/pj9wISlcMpgFWzSrczLZbrqBSxukQixmg0SJ5sZTpvaFvxU0HoQKd4yoyAogyrAz9pzJnA==", + "version": "1.0.30001597", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001597.tgz", + "integrity": "sha512-7LjJvmQU6Sj7bL0j5b5WY/3n7utXUJvAe1lxhsHDbLmwX9mdL86Yjtr+5SRCyf8qME4M7pU2hswj0FpyBVCv9w==", "dev": true, "funding": [ { @@ -3860,9 +3862,9 @@ "integrity": "sha512-/pjZsA1b4RPHbeWZQn66SWS8nZZWLQQ23oE3Eam7aroEFGEvwKAsJfZ9ytiEMycfzXWpca4FA9QIOehf7PocBQ==" }, "node_modules/electron-to-chromium": { - "version": "1.4.614", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.614.tgz", - "integrity": "sha512-X4ze/9Sc3QWs6h92yerwqv7aB/uU8vCjZcrMjA8N9R1pjMFRe44dLsck5FzLilOYvcXuDn93B+bpGYyufc70gQ==", + "version": "1.4.701", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.701.tgz", + "integrity": "sha512-K3WPQ36bUOtXg/1+69bFlFOvdSm0/0bGqmsfPDLRXLanoKXdA+pIWuf/VbA9b+2CwBFuONgl4NEz4OEm+OJOKA==", "dev": true }, "node_modules/emoji-regex": { @@ -8108,9 +8110,9 @@ } }, "node_modules/svelte-maplibre": { - "version": "0.8.1", - "resolved": "https://registry.npmjs.org/svelte-maplibre/-/svelte-maplibre-0.8.1.tgz", - "integrity": "sha512-CTm/s0+mJzBHSoO5zPKBo3ORmUyiWS3Ex4xvVdNgVg+sDesHasEAJ0N1/NUrd56S33zgRdFZGzRnRguCnKFAzw==", + "version": "0.8.2", + "resolved": "https://registry.npmjs.org/svelte-maplibre/-/svelte-maplibre-0.8.2.tgz", + "integrity": "sha512-l4FW7VE/1/uUUyk639gtvYyK0QbNw3roRq9ouxPDS+DAW8gwpxlnDwYTtjEO+Yq7TK6xOjimJtKOG3KES8e7Uw==", "dependencies": { "d3-geo": "^3.1.0", "just-compare": "^2.3.0", @@ -8518,9 +8520,9 @@ } }, "node_modules/typescript": { - "version": "5.3.3", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.3.3.tgz", - "integrity": "sha512-pXWcraxM0uxAS+tN0AG/BF2TyqmHO014Z070UsJ+pFvYuRSq8KH8DmWpnbXe0pEPDHXZV3FcAbJkijJ5oNEnWw==", + "version": "5.4.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.4.2.tgz", + "integrity": "sha512-+2/g0Fds1ERlP6JsakQQDXjZdZMM+rqpamFZJEKh4kwTIn3iDkgKtby0CeNd5ATNZ4Ry1ax15TMx0W2V+miizQ==", "dev": true, "bin": { "tsc": "bin/tsc", @@ -8668,9 +8670,9 @@ } }, "node_modules/vite": { - "version": "5.1.4", - "resolved": "https://registry.npmjs.org/vite/-/vite-5.1.4.tgz", - "integrity": "sha512-n+MPqzq+d9nMVTKyewqw6kSt+R3CkvF9QAKY8obiQn8g1fwTscKxyfaYnC632HtBXAQGc1Yjomphwn1dtwGAHg==", + "version": "5.1.5", + "resolved": "https://registry.npmjs.org/vite/-/vite-5.1.5.tgz", + "integrity": "sha512-BdN1xh0Of/oQafhU+FvopafUp6WaYenLU/NFoL5WyJL++GxkNfieKzBhM24H3HVsPQrlAqB7iJYTHabzaRed5Q==", "dev": true, "dependencies": { "esbuild": "^0.19.3", diff --git a/web/src/app.css b/web/src/app.css index 54cd03b89..c361d890c 100644 --- a/web/src/app.css +++ b/web/src/app.css @@ -23,6 +23,7 @@ --immich-dark-warning: 245 124 0; } } + @font-face { font-family: 'Overpass'; src: url('$lib/assets/fonts/overpass/Overpass.ttf') format('truetype-variations'); @@ -48,6 +49,14 @@ --navbar-height: calc(theme(spacing.18) + 4px); } +:root.dark { + color-scheme: dark; +} + +:root:not(.dark) { + color-scheme: light; +} + html { height: 100%; width: 100%; diff --git a/web/src/lib/assets/immich-logo-inline-dark.svg b/web/src/lib/assets/immich-logo-inline-dark.svg new file mode 100644 index 000000000..024337c2e --- /dev/null +++ b/web/src/lib/assets/immich-logo-inline-dark.svg @@ -0,0 +1,63 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/web/src/lib/assets/immich-logo-inline-light.svg b/web/src/lib/assets/immich-logo-inline-light.svg new file mode 100644 index 000000000..216466f58 --- /dev/null +++ b/web/src/lib/assets/immich-logo-inline-light.svg @@ -0,0 +1,62 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/web/src/lib/assets/immich-logo-no-outline.png b/web/src/lib/assets/immich-logo-no-outline.png deleted file mode 100644 index d4e7085f1..000000000 Binary files a/web/src/lib/assets/immich-logo-no-outline.png and /dev/null differ diff --git a/web/src/lib/assets/immich-logo-stacked-dark.svg b/web/src/lib/assets/immich-logo-stacked-dark.svg new file mode 100644 index 000000000..7f8381869 --- /dev/null +++ b/web/src/lib/assets/immich-logo-stacked-dark.svg @@ -0,0 +1,66 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/web/src/lib/assets/immich-logo-stacked-light.svg b/web/src/lib/assets/immich-logo-stacked-light.svg new file mode 100644 index 000000000..8c4505d97 --- /dev/null +++ b/web/src/lib/assets/immich-logo-stacked-light.svg @@ -0,0 +1,66 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/web/src/lib/assets/immich-logo.svg b/web/src/lib/assets/immich-logo.svg index e7edba069..376fa6f3e 100644 --- a/web/src/lib/assets/immich-logo.svg +++ b/web/src/lib/assets/immich-logo.svg @@ -1,98 +1,29 @@ - - + + - - - - - - - - - - - - - - - - + + + + + + + diff --git a/web/src/lib/components/album-page/album-viewer.svelte b/web/src/lib/components/album-page/album-viewer.svelte index 9897125bc..ab5eb91d5 100644 --- a/web/src/lib/components/album-page/album-viewer.svelte +++ b/web/src/lib/components/album-page/album-viewer.svelte @@ -87,9 +87,8 @@ {:else} - - -

IMMICH

+ + diff --git a/web/src/lib/components/album-page/user-selection-modal.svelte b/web/src/lib/components/album-page/user-selection-modal.svelte index 03f662c84..b7c0b53b6 100644 --- a/web/src/lib/components/album-page/user-selection-modal.svelte +++ b/web/src/lib/components/album-page/user-selection-modal.svelte @@ -58,7 +58,7 @@ dispatch('close')}> - +

Invite to album

diff --git a/web/src/lib/components/asset-viewer/asset-viewer.svelte b/web/src/lib/components/asset-viewer/asset-viewer.svelte index 5f32c000c..b1f70cbeb 100644 --- a/web/src/lib/components/asset-viewer/asset-viewer.svelte +++ b/web/src/lib/components/asset-viewer/asset-viewer.svelte @@ -592,9 +592,9 @@ {#if $slideshowState === SlideshowState.None && showNavigation}
- navigateAsset('previous', e)} - > + navigateAsset('previous', e)} label="View previous asset"> + +
{/if} @@ -708,9 +708,9 @@ {#if $slideshowState === SlideshowState.None && showNavigation}
- navigateAsset('next', e)} - > + navigateAsset('next', e)} label="View next asset"> + +
{/if} diff --git a/web/src/lib/components/asset-viewer/detail-panel.svelte b/web/src/lib/components/asset-viewer/detail-panel.svelte index aa6905a4d..334b406bb 100644 --- a/web/src/lib/components/asset-viewer/detail-panel.svelte +++ b/web/src/lib/components/asset-viewer/detail-panel.svelte @@ -258,62 +258,58 @@ @@ -341,12 +337,10 @@ {@const assetDateTimeOriginal = DateTime.fromISO(asset.exifInfo.dateTimeOriginal, { zone: asset.exifInfo.timeZone ?? undefined, })} -
(isOwner ? (isShowChangeDate = true) : null)} - on:keydown={(event) => (isOwner ? event.key === 'Enter' && (isShowChangeDate = true) : null)} title={isOwner ? 'Edit date' : ''} class:hover:dark:text-immich-dark-primary={isOwner} class:hover:text-immich-primary={isOwner} @@ -384,11 +378,11 @@
{#if isOwner} - + {/if} - + {:else if !asset.exifInfo?.dateTimeOriginal && !asset.isReadOnly && isOwner}
@@ -396,9 +390,9 @@
- + {:else if asset.exifInfo?.dateTimeOriginal && asset.isReadOnly} {@const assetDateTimeOriginal = DateTime.fromISO(asset.exifInfo.dateTimeOriginal, { @@ -517,13 +511,11 @@ {/if} {#if asset.exifInfo?.city && !asset.isReadOnly} -
(isOwner ? (isShowChangeLocation = true) : null)} - on:keydown={(event) => (isOwner ? event.key === 'Enter' && (isShowChangeLocation = true) : null)} - tabindex="0" title={isOwner ? 'Edit location' : ''} - role="button" class:hover:dark:text-immich-dark-primary={isOwner} class:hover:text-immich-primary={isOwner} > @@ -550,14 +542,12 @@
{/if} - + {:else if !asset.exifInfo?.city && !asset.isReadOnly && isOwner} -
(isShowChangeLocation = true)} - on:keydown={(event) => event.key === 'Enter' && (isShowChangeLocation = true)} - tabindex="0" - role="button" title="Add location" >
@@ -570,7 +560,7 @@
-
+ {:else if asset.exifInfo?.city && asset.isReadOnly}
diff --git a/web/src/lib/components/asset-viewer/navigation-area.svelte b/web/src/lib/components/asset-viewer/navigation-area.svelte index 093f55588..efa2761cb 100644 --- a/web/src/lib/components/asset-viewer/navigation-area.svelte +++ b/web/src/lib/components/asset-viewer/navigation-area.svelte @@ -1,9 +1,15 @@ -
-
diff --git a/web/src/lib/components/forms/create-user-form.svelte b/web/src/lib/components/forms/create-user-form.svelte index 00188ec2e..1f612af15 100644 --- a/web/src/lib/components/forms/create-user-form.svelte +++ b/web/src/lib/components/forms/create-user-form.svelte @@ -73,7 +73,7 @@ class="max-h-screen w-[500px] max-w-[95vw] overflow-y-auto immich-scrollbar rounded-3xl border bg-immich-bg p-4 py-8 shadow-sm dark:border-immich-dark-gray dark:bg-immich-dark-gray dark:text-immich-dark-fg" >
- +

Create new user

diff --git a/web/src/lib/components/memory-page/memory-viewer.svelte b/web/src/lib/components/memory-page/memory-viewer.svelte index 7b6bd4aae..0ed583878 100644 --- a/web/src/lib/components/memory-page/memory-viewer.svelte +++ b/web/src/lib/components/memory-page/memory-viewer.svelte @@ -112,7 +112,7 @@

- {#if !galleryInView} + {#if canGoForward}
(paused = !paused)} /> @@ -268,7 +268,7 @@
- +
- +

Welcome, {$user.name}

diff --git a/web/src/lib/components/photos-page/asset-grid.svelte b/web/src/lib/components/photos-page/asset-grid.svelte index 2dd35ca30..b66bfc96f 100644 --- a/web/src/lib/components/photos-page/asset-grid.svelte +++ b/web/src/lib/components/photos-page/asset-grid.svelte @@ -387,7 +387,7 @@
goto(AppRoute.PHOTOS)} backIcon={mdiArrowLeft} showBackButton={false}> - - -

IMMICH

+
+
diff --git a/web/src/lib/components/shared-components/combobox.svelte b/web/src/lib/components/shared-components/combobox.svelte index 80ea3b796..c69460640 100644 --- a/web/src/lib/components/shared-components/combobox.svelte +++ b/web/src/lib/components/shared-components/combobox.svelte @@ -24,6 +24,7 @@ export let placeholder = ''; let isOpen = false; + let inputFocused = false; let searchQuery = selectedOption?.label || ''; $: filteredOptions = options.filter((option) => option.label.toLowerCase().includes(searchQuery.toLowerCase())); @@ -36,11 +37,16 @@ const handleClick = () => { searchQuery = ''; isOpen = true; + inputFocused = true; dispatch('click'); }; let handleOutClick = () => { - isOpen = false; + // In rare cases it's possible for the input to still have focus and + // outclick to fire. + if (!inputFocused) { + isOpen = false; + } }; let handleSelect = (option: ComboBoxOption) => { @@ -79,6 +85,7 @@ value={isOpen ? '' : selectedOption?.label || ''} on:input={(e) => (searchQuery = e.currentTarget.value)} on:focus={handleClick} + on:blur={() => (inputFocused = false)} />
- +
Drop files anywhere to upload
{/if} diff --git a/web/src/lib/components/shared-components/empty-placeholder.svelte b/web/src/lib/components/shared-components/empty-placeholder.svelte index fc234aa4d..781f7821f 100644 --- a/web/src/lib/components/shared-components/empty-placeholder.svelte +++ b/web/src/lib/components/shared-components/empty-placeholder.svelte @@ -1,28 +1,24 @@ -
- -

{text}

-
+ +

{text}

+ diff --git a/web/src/lib/components/shared-components/immich-logo.svelte b/web/src/lib/components/shared-components/immich-logo.svelte index e3881c5b3..a8e832a41 100644 --- a/web/src/lib/components/shared-components/immich-logo.svelte +++ b/web/src/lib/components/shared-components/immich-logo.svelte @@ -1,7 +1,17 @@ -Immich Logo +Immich Logo diff --git a/web/src/lib/components/shared-components/map/map.svelte b/web/src/lib/components/shared-components/map/map.svelte index 17fd92021..74643e502 100644 --- a/web/src/lib/components/shared-components/map/map.svelte +++ b/web/src/lib/components/shared-components/map/map.svelte @@ -158,7 +158,7 @@ applyToClusters asButton let:feature - on:click={(event) => handlePromiseError(handleClusterClick(event.detail.feature.properties.cluster_id, map))} + on:click={(event) => handlePromiseError(handleClusterClick(event.detail.feature.properties?.cluster_id, map))} >
{ - $$slots.popup || handleAssetClick(event.detail.feature.properties.id, map); + $$slots.popup || handleAssetClick(event.detail.feature.properties?.id, map); }} > {#if useLocationPin} diff --git a/web/src/lib/components/shared-components/navigation-bar/navigation-bar.svelte b/web/src/lib/components/shared-components/navigation-bar/navigation-bar.svelte index 5d85fe8c0..43834c648 100644 --- a/web/src/lib/components/shared-components/navigation-bar/navigation-bar.svelte +++ b/web/src/lib/components/shared-components/navigation-bar/navigation-bar.svelte @@ -23,7 +23,7 @@ let shouldShowAccountInfo = false; let shouldShowAccountInfoPanel = false; - + let innerWidth: number; const dispatch = createEventDispatcher<{ uploadClicked: void; }>(); @@ -39,19 +39,18 @@ }; + +
Skip to content
- - -

- IMMICH -

+
+
- + {#await getStats({ isFavorite: true })} @@ -113,15 +105,8 @@
{/await} - - - - + + {#await handleAlbumCount()} @@ -131,10 +116,9 @@
{/await} - - - - + + + {#await getStats({ isArchived: true })} @@ -145,12 +129,10 @@
{/await} - - + - {#if $featureFlags.trash} - - + {#if $featureFlags.trash} + {#await getStats({ isTrashed: true })} @@ -161,9 +143,9 @@
{/await} - - - {/if} + + {/if} +
diff --git a/web/src/lib/components/shared-components/upload-asset-preview.svelte b/web/src/lib/components/shared-components/upload-asset-preview.svelte index 4aa6f18ec..a442fefcd 100644 --- a/web/src/lib/components/shared-components/upload-asset-preview.svelte +++ b/web/src/lib/components/shared-components/upload-asset-preview.svelte @@ -27,7 +27,7 @@
- +

{ - notificationController.show({ - message: - ($errorCounter > 0 - ? `Upload completed with ${$errorCounter} error${$errorCounter > 1 ? 's' : ''}` - : 'Upload success') + ', refresh the page to see new upload assets.', - type: $errorCounter > 0 ? NotificationType.Warning : NotificationType.Info, - }); - + if ($errorCounter > 0) { + notificationController.show({ + message: `Upload completed with ${$errorCounter} error${$errorCounter > 1 ? 's' : ''}, refresh the page to see new upload assets.`, + type: NotificationType.Warning, + }); + } else if ($successCounter > 0) { + notificationController.show({ + message: 'Upload success, refresh the page to see new upload assets.', + type: NotificationType.Info, + }); + } if ($duplicateCounter > 0) { notificationController.show({ message: `Skipped ${$duplicateCounter} duplicate asset${$duplicateCounter > 1 ? 's' : ''}`, type: NotificationType.Warning, }); } - uploadAssetsStore.resetStore(); }} class="absolute bottom-6 right-6 z-[10000]" diff --git a/web/src/lib/components/shared-components/version-announcement-box.svelte b/web/src/lib/components/shared-components/version-announcement-box.svelte index d3e7089b1..7cb9cca57 100644 --- a/web/src/lib/components/shared-components/version-announcement-box.svelte +++ b/web/src/lib/components/shared-components/version-announcement-box.svelte @@ -40,9 +40,7 @@

🎉 NEW VERSION AVAILABLE 🎉

- Hi friend, there is a new release of - IMMICH, - please take your time to visit the + Hi friend, there is a new version of the application please take your time to visit the release notes - import { goto } from '$app/navigation'; import Icon from '$lib/components/elements/icon.svelte'; import { AppRoute } from '$lib/constants'; import { getAssetThumbnailUrl } from '$lib/utils'; @@ -122,15 +121,9 @@ {/if} {#if !link.expiresAt || !isExpired(link.expiresAt)} - -
goto(`${AppRoute.SHARE}/${link.key}`)} - on:keydown={() => goto(`${AppRoute.SHARE}/${link.key}`)} - > + -
+ {/if}
diff --git a/web/src/lib/components/user-settings-page/device-card.svelte b/web/src/lib/components/user-settings-page/device-card.svelte index 5395ae43f..64f17ad9e 100644 --- a/web/src/lib/components/user-settings-page/device-card.svelte +++ b/web/src/lib/components/user-settings-page/device-card.svelte @@ -28,7 +28,6 @@
- {#if !device.current} diff --git a/web/src/lib/components/user-settings-page/partner-selection-modal.svelte b/web/src/lib/components/user-settings-page/partner-selection-modal.svelte index 6d920d310..9b184bc51 100644 --- a/web/src/lib/components/user-settings-page/partner-selection-modal.svelte +++ b/web/src/lib/components/user-settings-page/partner-selection-modal.svelte @@ -36,7 +36,7 @@ dispatch('close')}> - +

Add partner

diff --git a/web/src/lib/utils.ts b/web/src/lib/utils.ts index e4ac01f87..4b1892ae8 100644 --- a/web/src/lib/utils.ts +++ b/web/src/lib/utils.ts @@ -59,7 +59,7 @@ export const uploadRequest = async (options: UploadRequestOptions): Promise<{ }); if (onProgress) { - xhr.addEventListener('progress', (event) => onProgress(event)); + xhr.upload.addEventListener('progress', (event) => onProgress(event)); } xhr.open('POST', url); diff --git a/web/src/lib/utils/file-uploader.ts b/web/src/lib/utils/file-uploader.ts index c53d6e2a8..fbfc1abc6 100644 --- a/web/src/lib/utils/file-uploader.ts +++ b/web/src/lib/utils/file-uploader.ts @@ -99,6 +99,8 @@ async function fileUploader(asset: File, albumId: string | undefined = undefined if (res.duplicate) { uploadAssetsStore.duplicateCounter.update((count) => count + 1); + } else { + uploadAssetsStore.successCounter.update((c) => c + 1); } if (albumId && res.id) { @@ -110,7 +112,6 @@ async function fileUploader(asset: File, albumId: string | undefined = undefined uploadAssetsStore.updateAsset(deviceAssetId, { state: res.duplicate ? UploadState.DUPLICATED : UploadState.DONE, }); - uploadAssetsStore.successCounter.update((c) => c + 1); setTimeout(() => { uploadAssetsStore.removeUploadAsset(deviceAssetId); diff --git a/web/src/routes/(user)/albums/+page.svelte b/web/src/routes/(user)/albums/+page.svelte index d14be267e..c8d591f91 100644 --- a/web/src/routes/(user)/albums/+page.svelte +++ b/web/src/routes/(user)/albums/+page.svelte @@ -375,11 +375,7 @@ {:else} - + {/if} diff --git a/web/src/routes/(user)/archive/+page.svelte b/web/src/routes/(user)/archive/+page.svelte index 227835354..93dc09a50 100644 --- a/web/src/routes/(user)/archive/+page.svelte +++ b/web/src/routes/(user)/archive/+page.svelte @@ -45,10 +45,6 @@ - + diff --git a/web/src/routes/(user)/favorites/+page.svelte b/web/src/routes/(user)/favorites/+page.svelte index 21b563a50..067859b69 100644 --- a/web/src/routes/(user)/favorites/+page.svelte +++ b/web/src/routes/(user)/favorites/+page.svelte @@ -50,10 +50,6 @@ - + diff --git a/web/src/routes/(user)/photos/+page.svelte b/web/src/routes/(user)/photos/+page.svelte index df2328aaa..9e80c71e0 100644 --- a/web/src/routes/(user)/photos/+page.svelte +++ b/web/src/routes/(user)/photos/+page.svelte @@ -88,10 +88,6 @@ {#if $user.memoriesEnabled} {/if} - openFileUploadDialog()} - slot="empty" - /> + openFileUploadDialog()} slot="empty" /> diff --git a/web/src/routes/(user)/share/[key]/+page.svelte b/web/src/routes/(user)/share/[key]/+page.svelte index 78c2a97dd..f64575924 100644 --- a/web/src/routes/(user)/share/[key]/+page.svelte +++ b/web/src/routes/(user)/share/[key]/+page.svelte @@ -37,9 +37,8 @@
- - -

IMMICH

+
+
diff --git a/web/src/routes/(user)/sharing/+page.svelte b/web/src/routes/(user)/sharing/+page.svelte index b50cb5089..2d6e5b532 100644 --- a/web/src/routes/(user)/sharing/+page.svelte +++ b/web/src/routes/(user)/sharing/+page.svelte @@ -92,7 +92,6 @@ {#if data.sharedAlbums.length === 0} {/if} diff --git a/web/src/routes/(user)/trash/+page.svelte b/web/src/routes/(user)/trash/+page.svelte index 6ce6c5423..fd176b7a1 100644 --- a/web/src/routes/(user)/trash/+page.svelte +++ b/web/src/routes/(user)/trash/+page.svelte @@ -91,12 +91,7 @@

Trashed items will be permanently deleted after {$serverConfig.trashDays} days.

- + {/if} diff --git a/web/src/routes/+error.svelte b/web/src/routes/+error.svelte index 2f5d0ab51..1bd02ccfd 100644 --- a/web/src/routes/+error.svelte +++ b/web/src/routes/+error.svelte @@ -20,8 +20,7 @@
diff --git a/web/src/routes/+page.svelte b/web/src/routes/+page.svelte index 17a2b62fc..8c1a5b894 100644 --- a/web/src/routes/+page.svelte +++ b/web/src/routes/+page.svelte @@ -7,11 +7,9 @@
diff --git a/web/src/routes/admin/repair/+page.svelte b/web/src/routes/admin/repair/+page.svelte index 939e151f5..fa0f66ec3 100644 --- a/web/src/routes/admin/repair/+page.svelte +++ b/web/src/routes/admin/repair/+page.svelte @@ -203,12 +203,7 @@
{#if matches.length + extras.length + orphans.length === 0}
- +
{:else}
diff --git a/web/static/apple-icon-180.png b/web/static/apple-icon-180.png index efa1a0c46..4e642631a 100644 Binary files a/web/static/apple-icon-180.png and b/web/static/apple-icon-180.png differ diff --git a/web/static/favicon-144.png b/web/static/favicon-144.png index fd5e5aafa..66c75b0b5 100644 Binary files a/web/static/favicon-144.png and b/web/static/favicon-144.png differ diff --git a/web/static/favicon-16.png b/web/static/favicon-16.png index 4233a3c09..a26e052df 100644 Binary files a/web/static/favicon-16.png and b/web/static/favicon-16.png differ diff --git a/web/static/favicon-32.png b/web/static/favicon-32.png index 20f8d345f..ed86cbc4e 100644 Binary files a/web/static/favicon-32.png and b/web/static/favicon-32.png differ diff --git a/web/static/favicon-48.png b/web/static/favicon-48.png index 3802a0aaa..0e0bedac5 100644 Binary files a/web/static/favicon-48.png and b/web/static/favicon-48.png differ diff --git a/web/static/favicon-96.png b/web/static/favicon-96.png index 8095377f3..7ef070839 100644 Binary files a/web/static/favicon-96.png and b/web/static/favicon-96.png differ diff --git a/web/static/favicon.ico b/web/static/favicon.ico index 7b4600ac7..6082fc3bd 100644 Binary files a/web/static/favicon.ico and b/web/static/favicon.ico differ diff --git a/web/static/favicon.png b/web/static/favicon.png index 11adddaa1..4e642631a 100644 Binary files a/web/static/favicon.png and b/web/static/favicon.png differ diff --git a/web/static/immich-logo.svg b/web/static/immich-logo.svg index 631f2490f..a3522c233 100644 --- a/web/static/immich-logo.svg +++ b/web/static/immich-logo.svg @@ -1,98 +1,8 @@ - - - - - - - - - - - - - - - - - - - - + + + + + + + diff --git a/web/static/manifest-icon-192.maskable.png b/web/static/manifest-icon-192.maskable.png index 8f1fa614e..49fd3ae28 100644 Binary files a/web/static/manifest-icon-192.maskable.png and b/web/static/manifest-icon-192.maskable.png differ diff --git a/web/static/manifest-icon-512.maskable.png b/web/static/manifest-icon-512.maskable.png index bdec822b5..a7220554b 100644 Binary files a/web/static/manifest-icon-512.maskable.png and b/web/static/manifest-icon-512.maskable.png differ