From 545814abc1ecd1fb08a0e755fabc4d698dc30edd Mon Sep 17 00:00:00 2001 From: Jiralite <33201955+Jiralite@users.noreply.github.com> Date: Tue, 23 Jun 2026 03:41:46 +0100 Subject: [PATCH] ci: add tests (#1141) --- .github/workflows/_build-image.yaml | 1 - .github/workflows/build-app-proxy.yaml | 1 - .github/workflows/build-desktop.yaml | 1 - .github/workflows/deploy-service.yaml | 1 - .github/workflows/i18n-source-sync.yaml | 1 - .github/workflows/i18n-weblate-pr.yaml | 1 - .../repair-static-asset-metadata.yaml | 3 - .github/workflows/sync-static-bucket.yaml | 3 - .github/workflows/{ci.yaml => tests.yaml} | 69 +++++---- fluxer_admin/src/api/types/instance_config.rs | 32 +--- fluxer_api/pkgs/cache/package.json | 6 +- fluxer_api/pkgs/cache/vitest.config.ts | 27 ---- .../pkgs/email/src/email_i18n/EmailI18n.ts | 4 - .../pkgs/email/src/email_i18n/locales/ar.ts | 2 +- .../pkgs/email/src/email_i18n/locales/bg.ts | 2 +- .../pkgs/email/src/email_i18n/locales/cs.ts | 2 +- .../pkgs/email/src/email_i18n/locales/da.ts | 2 +- .../pkgs/email/src/email_i18n/locales/de.ts | 2 +- .../pkgs/email/src/email_i18n/locales/el.ts | 2 +- .../email/src/email_i18n/locales/en-GB.ts | 2 +- .../email/src/email_i18n/locales/es-419.ts | 2 +- .../email/src/email_i18n/locales/es-ES.ts | 2 +- .../pkgs/email/src/email_i18n/locales/fi.ts | 2 +- .../pkgs/email/src/email_i18n/locales/fr.ts | 2 +- .../pkgs/email/src/email_i18n/locales/he.ts | 2 +- .../pkgs/email/src/email_i18n/locales/hi.ts | 2 +- .../pkgs/email/src/email_i18n/locales/hr.ts | 2 +- .../pkgs/email/src/email_i18n/locales/hu.ts | 2 +- .../pkgs/email/src/email_i18n/locales/id.ts | 2 +- .../pkgs/email/src/email_i18n/locales/it.ts | 2 +- .../pkgs/email/src/email_i18n/locales/ja.ts | 2 +- .../pkgs/email/src/email_i18n/locales/ko.ts | 2 +- .../pkgs/email/src/email_i18n/locales/lt.ts | 2 +- .../pkgs/email/src/email_i18n/locales/nl.ts | 2 +- .../pkgs/email/src/email_i18n/locales/no.ts | 2 +- .../pkgs/email/src/email_i18n/locales/pl.ts | 2 +- .../email/src/email_i18n/locales/pt-BR.ts | 2 +- .../pkgs/email/src/email_i18n/locales/ro.ts | 2 +- .../pkgs/email/src/email_i18n/locales/ru.ts | 2 +- .../email/src/email_i18n/locales/sv-SE.ts | 2 +- .../pkgs/email/src/email_i18n/locales/th.ts | 2 +- .../pkgs/email/src/email_i18n/locales/tr.ts | 2 +- .../pkgs/email/src/email_i18n/locales/uk.ts | 2 +- .../pkgs/email/src/email_i18n/locales/vi.ts | 2 +- .../email/src/email_i18n/locales/zh-CN.ts | 2 +- .../email/src/email_i18n/locales/zh-TW.ts | 2 +- .../pkgs/rate_limit/src/RateLimitService.ts | 142 ------------------ .../auth/tests/EmailVerificationFlow.test.ts | 7 +- .../MfaEmailVerificationRequired.test.ts | 13 +- .../auth/tests/PhoneVerificationFlow.test.ts | 6 + .../src/api/channel/tests/ChannelTestUtils.ts | 13 -- fluxer_api/src/api/constants/LimitConfig.ts | 13 ++ fluxer_api/src/api/content_i18n/locales/ar.ts | 2 +- fluxer_api/src/api/content_i18n/locales/bg.ts | 2 +- fluxer_api/src/api/content_i18n/locales/cs.ts | 2 +- fluxer_api/src/api/content_i18n/locales/da.ts | 2 +- fluxer_api/src/api/content_i18n/locales/de.ts | 2 +- fluxer_api/src/api/content_i18n/locales/el.ts | 2 +- .../src/api/content_i18n/locales/en-GB.ts | 2 +- .../src/api/content_i18n/locales/es-419.ts | 2 +- .../src/api/content_i18n/locales/es-ES.ts | 2 +- fluxer_api/src/api/content_i18n/locales/fi.ts | 2 +- fluxer_api/src/api/content_i18n/locales/fr.ts | 2 +- fluxer_api/src/api/content_i18n/locales/he.ts | 2 +- fluxer_api/src/api/content_i18n/locales/hi.ts | 2 +- fluxer_api/src/api/content_i18n/locales/hr.ts | 2 +- fluxer_api/src/api/content_i18n/locales/hu.ts | 2 +- fluxer_api/src/api/content_i18n/locales/id.ts | 2 +- fluxer_api/src/api/content_i18n/locales/it.ts | 2 +- fluxer_api/src/api/content_i18n/locales/ja.ts | 2 +- fluxer_api/src/api/content_i18n/locales/ko.ts | 2 +- fluxer_api/src/api/content_i18n/locales/lt.ts | 2 +- fluxer_api/src/api/content_i18n/locales/nl.ts | 2 +- fluxer_api/src/api/content_i18n/locales/no.ts | 2 +- fluxer_api/src/api/content_i18n/locales/pl.ts | 2 +- .../src/api/content_i18n/locales/pt-BR.ts | 2 +- fluxer_api/src/api/content_i18n/locales/ro.ts | 2 +- fluxer_api/src/api/content_i18n/locales/ru.ts | 2 +- .../src/api/content_i18n/locales/sv-SE.ts | 2 +- fluxer_api/src/api/content_i18n/locales/th.ts | 2 +- fluxer_api/src/api/content_i18n/locales/tr.ts | 2 +- fluxer_api/src/api/content_i18n/locales/uk.ts | 2 +- fluxer_api/src/api/content_i18n/locales/vi.ts | 2 +- .../src/api/content_i18n/locales/zh-CN.ts | 2 +- .../src/api/content_i18n/locales/zh-TW.ts | 2 +- .../api/database/CassandraQueryExecution.ts | 4 - .../limits/tests/LimitConfigDefaults.test.ts | 20 ++- .../app/components/HookOrderStability.test.ts | 2 +- fluxer_gateway/rebar.config | 2 +- .../src/cache/clustered_ets_cache.erl | 4 +- fluxer_gateway/src/fluxer_gateway.app.src | 1 + .../src/gateway/gateway_handler_resume.erl | 10 +- .../src/gateway/gateway_hotpatch_loader.erl | 1 - .../src/gateway/gateway_hotpatch_store.erl | 9 +- .../src/gateway/gateway_nats_pool.erl | 3 + .../src/gateway/gateway_rollout_config.erl | 3 +- fluxer_gateway/src/guild/guild_common.erl | 4 +- fluxer_gateway/src/guild/guild_data_index.erl | 4 +- .../src/guild/guild_data_index_channels.erl | 4 +- .../src/guild/guild_data_index_roles.erl | 4 +- .../src/guild/guild_data_normalize.erl | 17 +-- .../src/guild/guild_member_list_oset.erl | 3 +- .../src/guild/guild_member_list_oset_nif.erl | 6 +- .../src/guild/guild_presence_reconcile.erl | 11 +- fluxer_gateway/src/push/push_fcm_payload.erl | 4 +- .../src/push/push_markdown_plaintext.erl | 3 +- .../src/push/push_markdown_plaintext_nif.erl | 8 +- .../src/push/push_notification_format.erl | 8 +- .../session/session_manager_shard_start.erl | 2 - .../src/session/session_ready_collect.erl | 13 -- .../src/telemetry/process_registry.erl | 5 +- fluxer_gateway/test/gateway_handler_tests.erl | 21 ++- packages/errors/src/i18n/locales/ar.ts | 2 +- packages/errors/src/i18n/locales/bg.ts | 2 +- packages/errors/src/i18n/locales/cs.ts | 2 +- packages/errors/src/i18n/locales/da.ts | 2 +- packages/errors/src/i18n/locales/de.ts | 2 +- packages/errors/src/i18n/locales/el.ts | 2 +- packages/errors/src/i18n/locales/en-GB.ts | 2 +- packages/errors/src/i18n/locales/es-419.ts | 2 +- packages/errors/src/i18n/locales/es-ES.ts | 2 +- packages/errors/src/i18n/locales/fi.ts | 2 +- packages/errors/src/i18n/locales/fr.ts | 2 +- packages/errors/src/i18n/locales/he.ts | 2 +- packages/errors/src/i18n/locales/hi.ts | 2 +- packages/errors/src/i18n/locales/hr.ts | 2 +- packages/errors/src/i18n/locales/hu.ts | 2 +- packages/errors/src/i18n/locales/id.ts | 2 +- packages/errors/src/i18n/locales/it.ts | 2 +- packages/errors/src/i18n/locales/ja.ts | 2 +- packages/errors/src/i18n/locales/ko.ts | 2 +- packages/errors/src/i18n/locales/lt.ts | 2 +- packages/errors/src/i18n/locales/nl.ts | 2 +- packages/errors/src/i18n/locales/no.ts | 2 +- packages/errors/src/i18n/locales/pl.ts | 2 +- packages/errors/src/i18n/locales/pt-BR.ts | 2 +- packages/errors/src/i18n/locales/ro.ts | 2 +- packages/errors/src/i18n/locales/ru.ts | 2 +- packages/errors/src/i18n/locales/sv-SE.ts | 2 +- packages/errors/src/i18n/locales/th.ts | 2 +- packages/errors/src/i18n/locales/tr.ts | 2 +- packages/errors/src/i18n/locales/uk.ts | 2 +- packages/errors/src/i18n/locales/vi.ts | 2 +- packages/errors/src/i18n/locales/zh-CN.ts | 2 +- packages/errors/src/i18n/locales/zh-TW.ts | 2 +- .../i18n/scripts/SyncStaticI18nCatalogs.ts | 2 +- .../src/simulation/SimulatorPorts.ts | 2 +- .../src/testing/determinism.test.ts | 38 ----- pnpm-lock.yaml | 6 - tools/ci/src/app_proxy.rs | 12 +- tools/ci/src/ci_workflow.rs | 37 ++++- tools/ci/src/desktop.rs | 4 +- 152 files changed, 287 insertions(+), 532 deletions(-) rename .github/workflows/{ci.yaml => tests.yaml} (90%) delete mode 100644 fluxer_api/pkgs/cache/vitest.config.ts diff --git a/.github/workflows/_build-image.yaml b/.github/workflows/_build-image.yaml index 4f0e3a703..dae72e318 100644 --- a/.github/workflows/_build-image.yaml +++ b/.github/workflows/_build-image.yaml @@ -43,7 +43,6 @@ defaults: shell: bash env: - FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: "true" GHCR_OWNER: ${{ github.repository_owner }} jobs: diff --git a/.github/workflows/build-app-proxy.yaml b/.github/workflows/build-app-proxy.yaml index 8563b9b47..305fbfcdb 100644 --- a/.github/workflows/build-app-proxy.yaml +++ b/.github/workflows/build-app-proxy.yaml @@ -23,7 +23,6 @@ permissions: packages: write env: - FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: "true" GHCR_OWNER: ${{ github.repository_owner }} jobs: diff --git a/.github/workflows/build-desktop.yaml b/.github/workflows/build-desktop.yaml index 7b80510d5..897d4fc1a 100644 --- a/.github/workflows/build-desktop.yaml +++ b/.github/workflows/build-desktop.yaml @@ -37,7 +37,6 @@ concurrency: cancel-in-progress: true env: - FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: "true" CHANNEL: ${{ inputs.channel }} BUILD_CHANNEL: ${{ inputs.channel == 'canary' && 'canary' || 'stable' }} TEST_BUILD: ${{ inputs.test_build && 'true' || 'false' }} diff --git a/.github/workflows/deploy-service.yaml b/.github/workflows/deploy-service.yaml index 13885f0dc..812ca92f9 100644 --- a/.github/workflows/deploy-service.yaml +++ b/.github/workflows/deploy-service.yaml @@ -80,7 +80,6 @@ on: required: false env: - FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: "true" GHCR_OWNER: ${{ github.repository_owner }} GHCR_REGISTRY: ghcr.io/${{ github.repository_owner }} diff --git a/.github/workflows/i18n-source-sync.yaml b/.github/workflows/i18n-source-sync.yaml index f440329d8..8f2282f9b 100644 --- a/.github/workflows/i18n-source-sync.yaml +++ b/.github/workflows/i18n-source-sync.yaml @@ -17,7 +17,6 @@ defaults: shell: bash env: - FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: "true" SOURCE_BRANCH: automation/i18n-source-catalogs GH_TOKEN: ${{ github.token }} diff --git a/.github/workflows/i18n-weblate-pr.yaml b/.github/workflows/i18n-weblate-pr.yaml index 8f35fe9fd..149bc3f67 100644 --- a/.github/workflows/i18n-weblate-pr.yaml +++ b/.github/workflows/i18n-weblate-pr.yaml @@ -22,7 +22,6 @@ defaults: shell: bash env: - FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: "true" GH_TOKEN: ${{ github.token }} WEBLATE_BRANCH: ${{ github.event.inputs.branch || github.ref_name }} diff --git a/.github/workflows/repair-static-asset-metadata.yaml b/.github/workflows/repair-static-asset-metadata.yaml index 122b000c9..3945bad53 100644 --- a/.github/workflows/repair-static-asset-metadata.yaml +++ b/.github/workflows/repair-static-asset-metadata.yaml @@ -10,9 +10,6 @@ on: required: false default: "assets/" -env: - FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: "true" - jobs: repair: runs-on: ubuntu-24.04 diff --git a/.github/workflows/sync-static-bucket.yaml b/.github/workflows/sync-static-bucket.yaml index 4ba73aafa..51fa6e16b 100644 --- a/.github/workflows/sync-static-bucket.yaml +++ b/.github/workflows/sync-static-bucket.yaml @@ -4,9 +4,6 @@ name: sync static bucket on: workflow_dispatch: -env: - FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: "true" - jobs: push: runs-on: ubuntu-24.04 diff --git a/.github/workflows/ci.yaml b/.github/workflows/tests.yaml similarity index 90% rename from .github/workflows/ci.yaml rename to .github/workflows/tests.yaml index 716a795c2..dafc4df16 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/tests.yaml @@ -1,11 +1,17 @@ # SPDX-License-Identifier: AGPL-3.0-or-later -name: CI +name: Tests on: - workflow_dispatch: + pull_request: + +permissions: + contents: read + +concurrency: + group: ${{ github.workflow }}-${{ github.event.pull_request.number }} + cancel-in-progress: true env: - FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: "true" GHCR_REGISTRY: ghcr.io/${{ github.repository_owner }} jobs: @@ -20,6 +26,7 @@ jobs: uses: dtolnay/rust-toolchain@b3b07ba8b418998c39fb20f53e8b695cdcc8de1b with: toolchain: "1.93.0" + targets: wasm32-unknown-unknown - name: Install pnpm uses: pnpm/action-setup@c5ba7f7862a0f64c1b1a05fbac13e0b8e86ba08c @@ -51,6 +58,7 @@ jobs: uses: dtolnay/rust-toolchain@b3b07ba8b418998c39fb20f53e8b695cdcc8de1b with: toolchain: "1.93.0" + targets: wasm32-unknown-unknown - name: Install pnpm uses: pnpm/action-setup@c5ba7f7862a0f64c1b1a05fbac13e0b8e86ba08c @@ -84,6 +92,15 @@ jobs: toolchain: stable components: clippy, rustfmt + - name: Install pnpm + uses: pnpm/action-setup@c5ba7f7862a0f64c1b1a05fbac13e0b8e86ba08c + + - name: Install Node.js + uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 + with: + node-version: '24' + cache: 'pnpm' + - name: Cache cargo uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 with: @@ -95,6 +112,21 @@ jobs: restore-keys: | rust-${{ runner.os }}- + - name: Install native dependencies + run: | + sudo apt-get update + sudo apt-get install -y --no-install-recommends \ + pkg-config \ + build-essential \ + libcurl4-openssl-dev \ + libvips-dev \ + libavfilter-dev \ + libheif-dev \ + libwebp-dev + + - name: Install Node.js dependencies + run: pnpm --filter fluxer_admin --filter fluxer_marketing install + - name: Check formatting run: cargo fmt --all -- --check @@ -104,33 +136,6 @@ jobs: - name: Run tests run: cargo test --workspace - marketing-docker: - runs-on: blacksmith-4vcpu-ubuntu-2404 - timeout-minutes: 45 - steps: - - name: Checkout code - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd - - - name: Set up Rust toolchain (CI helpers) - uses: dtolnay/rust-toolchain@b3b07ba8b418998c39fb20f53e8b695cdcc8de1b - with: - toolchain: "1.93.0" - - - name: Set up Docker Buildx - uses: docker/setup-buildx-action@8d2750c68a42422c14e847fe6c8ac0403b4cbd6f - - - name: Build marketing image - run: | - BUILD_VERSION="$(cargo run --locked --quiet --manifest-path tools/ci/Cargo.toml -- resolve-calver)" - docker build \ - -f fluxer_marketing/Dockerfile \ - -t "fluxer-marketing:${BUILD_VERSION}" \ - --build-arg "BUILD_VERSION=${BUILD_VERSION}" \ - . - env: - DOCKER_BUILD_SUMMARY: false - DOCKER_BUILD_RECORD_UPLOAD: false - gateway: runs-on: ubuntu-24.04 timeout-minutes: 25 @@ -190,6 +195,7 @@ jobs: uses: dtolnay/rust-toolchain@b3b07ba8b418998c39fb20f53e8b695cdcc8de1b with: toolchain: "1.93.0" + targets: wasm32-unknown-unknown - name: Install pnpm uses: pnpm/action-setup@c5ba7f7862a0f64c1b1a05fbac13e0b8e86ba08c @@ -291,6 +297,9 @@ jobs: *marketing*) EXTRA_SETS+=(--set-string app.name=marketing --set-string "app.tag=${HELM_TEST_BUILD_VERSION}" --set-string app.config=stable --set-string "app.build.version=${HELM_TEST_BUILD_VERSION}") ;; + *docs*) + EXTRA_SETS+=(--set-string app.name=docs --set-string "app.tag=${HELM_TEST_BUILD_VERSION}" --set-string app.config=stable --set-string "app.build.version=${HELM_TEST_BUILD_VERSION}") + ;; *media-proxy*) EXTRA_SETS+=(--set-string "mediaProxy.tag=${HELM_TEST_BUILD_VERSION}" --set-string "staticProxy.tag=${HELM_TEST_BUILD_VERSION}" --set-string "mediaProxy.build.version=${HELM_TEST_BUILD_VERSION}" --set-string "staticProxy.build.version=${HELM_TEST_BUILD_VERSION}") ;; diff --git a/fluxer_admin/src/api/types/instance_config.rs b/fluxer_admin/src/api/types/instance_config.rs index b339346f7..bcf34ce13 100644 --- a/fluxer_admin/src/api/types/instance_config.rs +++ b/fluxer_admin/src/api/types/instance_config.rs @@ -178,7 +178,7 @@ pub struct InstanceMediaResponse { pub attachment_decay: InstanceAttachmentDecayResponse, } -#[derive(Clone, Debug, Deserialize, Serialize)] +#[derive(Clone, Debug, Default, Deserialize, Serialize)] pub struct InstanceAttachmentDecayResponse { pub enabled: Option, pub min_size_mb: Option, @@ -193,23 +193,6 @@ pub struct InstanceAttachmentDecayResponse { pub effective: InstanceAttachmentDecayEffectiveResponse, } -impl Default for InstanceAttachmentDecayResponse { - fn default() -> Self { - Self { - enabled: None, - min_size_mb: None, - max_size_mb: None, - max_eligible_size_mb: None, - min_lifetime_days: None, - max_lifetime_days: None, - curve: None, - renew_threshold_days: None, - renew_window_days: None, - effective: InstanceAttachmentDecayEffectiveResponse::default(), - } - } -} - #[derive(Clone, Debug, Deserialize, Serialize)] pub struct InstanceAttachmentDecayEffectiveResponse { #[serde(default)] @@ -297,7 +280,7 @@ impl PremiumMode { } } -#[derive(Clone, Debug, Deserialize, Serialize)] +#[derive(Clone, Debug, Default, Deserialize, Serialize)] pub struct AppPublicConfigResponse { #[serde(default)] pub branding: AppBrandingConfigResponse, @@ -309,17 +292,6 @@ pub struct AppPublicConfigResponse { pub registration: AppRegistrationConfigResponse, } -impl Default for AppPublicConfigResponse { - fn default() -> Self { - Self { - branding: AppBrandingConfigResponse::default(), - setup: AppSetupConfigResponse::default(), - legal: AppLegalConfigResponse::default(), - registration: AppRegistrationConfigResponse::default(), - } - } -} - #[derive(Clone, Debug, Deserialize, Serialize)] pub struct AppBrandingConfigResponse { #[serde(default = "default_product_name")] diff --git a/fluxer_api/pkgs/cache/package.json b/fluxer_api/pkgs/cache/package.json index 60bb299b0..34ec62bc9 100644 --- a/fluxer_api/pkgs/cache/package.json +++ b/fluxer_api/pkgs/cache/package.json @@ -7,8 +7,6 @@ "./*": "./*" }, "scripts": { - "test": "vitest run", - "test:watch": "vitest", "typecheck": "tsgo --noEmit" }, "dependencies": { @@ -16,8 +14,6 @@ }, "devDependencies": { "@types/node": "catalog:", - "@typescript/native-preview": "catalog:", - "vite-tsconfig-paths": "catalog:", - "vitest": "catalog:" + "@typescript/native-preview": "catalog:" } } diff --git a/fluxer_api/pkgs/cache/vitest.config.ts b/fluxer_api/pkgs/cache/vitest.config.ts deleted file mode 100644 index 08796abc6..000000000 --- a/fluxer_api/pkgs/cache/vitest.config.ts +++ /dev/null @@ -1,27 +0,0 @@ -// SPDX-License-Identifier: AGPL-3.0-or-later - -import path from 'node:path'; -import {fileURLToPath} from 'node:url'; -import tsconfigPaths from 'vite-tsconfig-paths'; -import {defineConfig} from 'vitest/config'; - -const __dirname = path.dirname(fileURLToPath(import.meta.url)); - -export default defineConfig({ - plugins: [ - tsconfigPaths({ - root: path.resolve(__dirname, '../..'), - }), - ], - test: { - globals: true, - environment: 'node', - include: ['**/*.{test,spec}.{ts,tsx}'], - exclude: ['node_modules', 'dist'], - coverage: { - provider: 'v8', - reporter: ['text', 'json', 'html'], - exclude: ['**/*.test.tsx', '**/*.spec.tsx', 'node_modules/'], - }, - }, -}); diff --git a/fluxer_api/pkgs/email/src/email_i18n/EmailI18n.ts b/fluxer_api/pkgs/email/src/email_i18n/EmailI18n.ts index 77c9bd5ae..4b691f447 100644 --- a/fluxer_api/pkgs/email/src/email_i18n/EmailI18n.ts +++ b/fluxer_api/pkgs/email/src/email_i18n/EmailI18n.ts @@ -48,10 +48,6 @@ export function getEmailTemplate( return emailI18n.getTemplate(templateKey, locale, {...DEFAULT_EMAIL_TEMPLATE_VARIABLES, ...variables}); } -export function hasEmailLocale(locale: string): boolean { - return emailI18n.hasLocale(locale); -} - export function resetEmailI18n(): void { emailI18n.reset(); } diff --git a/fluxer_api/pkgs/email/src/email_i18n/locales/ar.ts b/fluxer_api/pkgs/email/src/email_i18n/locales/ar.ts index 2b295e27c..cc0029a5f 100644 --- a/fluxer_api/pkgs/email/src/email_i18n/locales/ar.ts +++ b/fluxer_api/pkgs/email/src/email_i18n/locales/ar.ts @@ -2,7 +2,7 @@ import {defineEmailI18nLocaleMessages} from '../EmailI18nMessages'; -export const EMAIL_I18N_AR_MESSAGES = defineEmailI18nLocaleMessages({ +const EMAIL_I18N_AR_MESSAGES = defineEmailI18nLocaleMessages({ "account_disabled_suspicious": { "subject": "تم تعطيل حسابك في {product_name} مؤقتًا", "body": "مرحباً {username}،\n\nلقد قمنا بتعطيل حسابك في {product_name} مؤقتًا لأننا اكتشفنا نشاطًا مشبوهًا.\n\n{reason, select,\n null {}\n other {السبب: {reason}}\n}\n\nلاستعادة الوصول إلى حسابك، ستحتاج إلى إعادة تعيين كلمة المرور الخاصة بك:\n\n{forgotUrl}\n\nبعد إعادة تعيين كلمة المرور الخاصة بك، ستتمكن من تسجيل الدخول مرة أخرى.\n\nإذا كنت تعتقد أن هذا حدث عن طريق الخطأ، يرجى الاتصال بفريق الدعم لدينا.\n\n– فريق أمان {product_name}" diff --git a/fluxer_api/pkgs/email/src/email_i18n/locales/bg.ts b/fluxer_api/pkgs/email/src/email_i18n/locales/bg.ts index 1eb0ca0bd..baf93af19 100644 --- a/fluxer_api/pkgs/email/src/email_i18n/locales/bg.ts +++ b/fluxer_api/pkgs/email/src/email_i18n/locales/bg.ts @@ -2,7 +2,7 @@ import {defineEmailI18nLocaleMessages} from '../EmailI18nMessages'; -export const EMAIL_I18N_BG_MESSAGES = defineEmailI18nLocaleMessages({ +const EMAIL_I18N_BG_MESSAGES = defineEmailI18nLocaleMessages({ "account_disabled_suspicious": { "subject": "Акаунтът ти във {product_name} е временно деактивиран", "body": "Здравей, {username},\n\nВременно деактивирахме акаунта ти във {product_name}, защото открихме подозрителна активност.\n\n{reason, select,\n null {}\n other {Причина: {reason}}\n}\n\nЗа да възстановиш достъпа до акаунта си, трябва да нулираш паролата си:\n\n{forgotUrl}\n\nСлед като нулираш паролата си, ще можеш да влезеш отново.\n\nАко смяташ, че това е грешка, свържи се с нашия екип за поддръжка.\n\n– Екип за безопасност на {product_name}" diff --git a/fluxer_api/pkgs/email/src/email_i18n/locales/cs.ts b/fluxer_api/pkgs/email/src/email_i18n/locales/cs.ts index c63bf8979..42aba3a79 100644 --- a/fluxer_api/pkgs/email/src/email_i18n/locales/cs.ts +++ b/fluxer_api/pkgs/email/src/email_i18n/locales/cs.ts @@ -2,7 +2,7 @@ import {defineEmailI18nLocaleMessages} from '../EmailI18nMessages'; -export const EMAIL_I18N_CS_MESSAGES = defineEmailI18nLocaleMessages({ +const EMAIL_I18N_CS_MESSAGES = defineEmailI18nLocaleMessages({ "account_disabled_suspicious": { "subject": "Tvůj účet {product_name} byl dočasně deaktivován", "body": "Ahoj {username},\n\nDočasně jsme deaktivovali tvůj účet {product_name}, protože jsme zaznamenali podezřelou aktivitu.\n\n{reason, select,\n null {}\n other {Důvod: {reason}}\n}\n\nPro opětovný přístup k účtu si budeš muset resetovat heslo:\n\n{forgotUrl}\n\nPo resetování hesla se budeš moci znovu přihlásit.\n\nPokud se domníváš, že se jedná o chybu, kontaktuj prosím náš tým podpory.\n\n– Bezpečnostní tým {product_name}" diff --git a/fluxer_api/pkgs/email/src/email_i18n/locales/da.ts b/fluxer_api/pkgs/email/src/email_i18n/locales/da.ts index ccdc12385..2d2b6b5b0 100644 --- a/fluxer_api/pkgs/email/src/email_i18n/locales/da.ts +++ b/fluxer_api/pkgs/email/src/email_i18n/locales/da.ts @@ -2,7 +2,7 @@ import {defineEmailI18nLocaleMessages} from '../EmailI18nMessages'; -export const EMAIL_I18N_DA_MESSAGES = defineEmailI18nLocaleMessages({ +const EMAIL_I18N_DA_MESSAGES = defineEmailI18nLocaleMessages({ "account_disabled_suspicious": { "subject": "Din {product_name}-konto er midlertidigt deaktiveret", "body": "Hej {username},\n\nVi har midlertidigt deaktiveret din {product_name}-konto, fordi vi har registreret mistænkelig aktivitet.\n\n{reason, select,\n null {}\n other {Årsag: {reason}}\n}\n\nFor at få adgang til din konto igen skal du nulstille din adgangskode:\n\n{forgotUrl}\n\nNår du har nulstillet din adgangskode, kan du logge ind igen.\n\nHvis du mener, at dette er sket ved en fejl, kan du kontakte vores supportteam.\n\n– {product_name} Safety Team" diff --git a/fluxer_api/pkgs/email/src/email_i18n/locales/de.ts b/fluxer_api/pkgs/email/src/email_i18n/locales/de.ts index cbce52da4..e77d1218e 100644 --- a/fluxer_api/pkgs/email/src/email_i18n/locales/de.ts +++ b/fluxer_api/pkgs/email/src/email_i18n/locales/de.ts @@ -2,7 +2,7 @@ import {defineEmailI18nLocaleMessages} from '../EmailI18nMessages'; -export const EMAIL_I18N_DE_MESSAGES = defineEmailI18nLocaleMessages({ +const EMAIL_I18N_DE_MESSAGES = defineEmailI18nLocaleMessages({ "account_disabled_suspicious": { "subject": "Dein {product_name}-Konto wurde vorübergehend deaktiviert", "body": "Hallo {username},\n\nwir haben dein {product_name}-Konto vorübergehend deaktiviert, da wir verdächtige Aktivitäten festgestellt haben.\n\n{reason, select,\n null {}\n other {Grund: {reason}}\n}\n\nUm wieder Zugriff auf dein Konto zu erhalten, musst du dein Passwort zurücksetzen:\n\n{forgotUrl}\n\nNachdem du dein Passwort zurückgesetzt hast, kannst du dich wieder anmelden.\n\nWenn du glaubst, dass dies ein Fehler war, kontaktiere bitte unser Support-Team.\n\n– {product_name}-Sicherheitsteam" diff --git a/fluxer_api/pkgs/email/src/email_i18n/locales/el.ts b/fluxer_api/pkgs/email/src/email_i18n/locales/el.ts index 7449c1056..4cc176e8e 100644 --- a/fluxer_api/pkgs/email/src/email_i18n/locales/el.ts +++ b/fluxer_api/pkgs/email/src/email_i18n/locales/el.ts @@ -2,7 +2,7 @@ import {defineEmailI18nLocaleMessages} from '../EmailI18nMessages'; -export const EMAIL_I18N_EL_MESSAGES = defineEmailI18nLocaleMessages({ +const EMAIL_I18N_EL_MESSAGES = defineEmailI18nLocaleMessages({ "account_disabled_suspicious": { "subject": "Ο λογαριασμός σου στο {product_name} έχει απενεργοποιηθεί προσωρινά", "body": "Γεια σου {username},\n\nΑπενεργοποιήσαμε προσωρινά τον λογαριασμό σου στο {product_name} επειδή εντοπίσαμε ύποπτη δραστηριότητα.\n\n{reason, select,\n null {}\n other {Λόγος: {reason}}\n}\n\nΓια να αποκτήσεις ξανά πρόσβαση στον λογαριασμό σου, θα πρέπει να επαναφέρεις τον κωδικό πρόσβασής σου:\n\n{forgotUrl}\n\nΑφού επαναφέρεις τον κωδικό πρόσβασής σου, θα μπορείς να συνδεθείς ξανά.\n\nΕάν πιστεύεις ότι αυτό έγινε κατά λάθος, επικοινώνησε με την ομάδα υποστήριξής μας.\n\n– Ομάδα Ασφαλείας {product_name}" diff --git a/fluxer_api/pkgs/email/src/email_i18n/locales/en-GB.ts b/fluxer_api/pkgs/email/src/email_i18n/locales/en-GB.ts index 2cbdc6dd8..ce462a131 100644 --- a/fluxer_api/pkgs/email/src/email_i18n/locales/en-GB.ts +++ b/fluxer_api/pkgs/email/src/email_i18n/locales/en-GB.ts @@ -2,7 +2,7 @@ import {defineEmailI18nLocaleMessages} from '../EmailI18nMessages'; -export const EMAIL_I18N_EN_GB_MESSAGES = defineEmailI18nLocaleMessages({ +const EMAIL_I18N_EN_GB_MESSAGES = defineEmailI18nLocaleMessages({ "account_disabled_suspicious": { "subject": "Your {product_name} account has been temporarily disabled", "body": "Hello {username},\n\nWe temporarily disabled your {product_name} account because we detected suspicious activity.\n\n{reason, select,\n null {}\n other {Reason: {reason}}\n}\n\nTo regain access to your account, you'll need to reset your password:\n\n{forgotUrl}\n\nAfter you reset your password, you'll be able to log in again.\n\nIf you believe this was done in error, please contact our support team.\n\n– {product_name} Safety Team" diff --git a/fluxer_api/pkgs/email/src/email_i18n/locales/es-419.ts b/fluxer_api/pkgs/email/src/email_i18n/locales/es-419.ts index 9cf3a21fa..dd3107780 100644 --- a/fluxer_api/pkgs/email/src/email_i18n/locales/es-419.ts +++ b/fluxer_api/pkgs/email/src/email_i18n/locales/es-419.ts @@ -2,7 +2,7 @@ import {defineEmailI18nLocaleMessages} from '../EmailI18nMessages'; -export const EMAIL_I18N_ES_419_MESSAGES = defineEmailI18nLocaleMessages({ +const EMAIL_I18N_ES_419_MESSAGES = defineEmailI18nLocaleMessages({ "account_disabled_suspicious": { "subject": "Tu cuenta de {product_name} ha sido deshabilitada temporalmente", "body": "Hola {username}:\n\nDeshabilitamos temporalmente tu cuenta de {product_name} porque detectamos actividad sospechosa.\n\n{reason, select,\n null {}\n other {Motivo: {reason}}\n}\n\nPara recuperar el acceso a tu cuenta, deberás restablecer tu contraseña:\n\n{forgotUrl}\n\nDespués de restablecer tu contraseña, podrás iniciar sesión de nuevo.\n\nSi crees que esto fue un error, comunícate con nuestro equipo de soporte.\n\n– Equipo de Seguridad de {product_name}" diff --git a/fluxer_api/pkgs/email/src/email_i18n/locales/es-ES.ts b/fluxer_api/pkgs/email/src/email_i18n/locales/es-ES.ts index 38ba09bb4..ec52f8b8d 100644 --- a/fluxer_api/pkgs/email/src/email_i18n/locales/es-ES.ts +++ b/fluxer_api/pkgs/email/src/email_i18n/locales/es-ES.ts @@ -2,7 +2,7 @@ import {defineEmailI18nLocaleMessages} from '../EmailI18nMessages'; -export const EMAIL_I18N_ES_ES_MESSAGES = defineEmailI18nLocaleMessages({ +const EMAIL_I18N_ES_ES_MESSAGES = defineEmailI18nLocaleMessages({ "account_disabled_suspicious": { "subject": "Tu cuenta de {product_name} ha sido deshabilitada temporalmente", "body": "Hola {username}:\n\nHemos deshabilitado temporalmente tu cuenta de {product_name} porque hemos detectado actividad sospechosa.\n\n{reason, select,\n null {}\n other {Motivo: {reason}}\n}\n\nPara recuperar el acceso a tu cuenta, tendrás que restablecer tu contraseña:\n\n{forgotUrl}\n\nDespués de restablecer tu contraseña, podrás iniciar sesión de nuevo.\n\nSi crees que esto ha sido un error, ponte en contacto con nuestro equipo de soporte.\n\n– Equipo de Seguridad de {product_name}" diff --git a/fluxer_api/pkgs/email/src/email_i18n/locales/fi.ts b/fluxer_api/pkgs/email/src/email_i18n/locales/fi.ts index 1ebde5119..14ad577b9 100644 --- a/fluxer_api/pkgs/email/src/email_i18n/locales/fi.ts +++ b/fluxer_api/pkgs/email/src/email_i18n/locales/fi.ts @@ -2,7 +2,7 @@ import {defineEmailI18nLocaleMessages} from '../EmailI18nMessages'; -export const EMAIL_I18N_FI_MESSAGES = defineEmailI18nLocaleMessages({ +const EMAIL_I18N_FI_MESSAGES = defineEmailI18nLocaleMessages({ "account_disabled_suspicious": { "subject": "Käyttäjätilisi {product_name}-palvelussa on tilapäisesti poistettu käytöstä", "body": "Hei {username},\n\nOlemme poistaneet {product_name}-tilisi tilapäisesti käytöstä, koska havaitsimme epäilyttävää toimintaa.\n\n{reason, select,\n null {}\n other {Syy: {reason}}\n}\n\nPäästäksesi takaisin tilillesi sinun on nollattava salasanasi:\n\n{forgotUrl}\n\nKun olet nollannut salasanasi, voit kirjautua sisään uudelleen.\n\nJos uskot, että tämä oli virhe, ota yhteyttä tukitiimiimme.\n\n– {product_name}-turvallisuustiimi" diff --git a/fluxer_api/pkgs/email/src/email_i18n/locales/fr.ts b/fluxer_api/pkgs/email/src/email_i18n/locales/fr.ts index 6891dce8d..4467d5309 100644 --- a/fluxer_api/pkgs/email/src/email_i18n/locales/fr.ts +++ b/fluxer_api/pkgs/email/src/email_i18n/locales/fr.ts @@ -2,7 +2,7 @@ import {defineEmailI18nLocaleMessages} from '../EmailI18nMessages'; -export const EMAIL_I18N_FR_MESSAGES = defineEmailI18nLocaleMessages({ +const EMAIL_I18N_FR_MESSAGES = defineEmailI18nLocaleMessages({ "account_disabled_suspicious": { "subject": "Ton compte {product_name} a été temporairement désactivé", "body": "Bonjour {username},\n\nNous avons temporairement désactivé ton compte {product_name} car nous avons détecté une activité suspecte.\n\n{reason, select,\n null {}\n other {Raison : {reason}}\n}\n\nPour retrouver l'accès à ton compte, tu devras réinitialiser ton mot de passe :\n\n{forgotUrl}\n\nAprès avoir réinitialisé ton mot de passe, tu pourras te connecter à nouveau.\n\nSi tu penses qu'il s'agit d'une erreur, contacte notre équipe d'assistance.\n\n– Équipe de sécurité de {product_name}" diff --git a/fluxer_api/pkgs/email/src/email_i18n/locales/he.ts b/fluxer_api/pkgs/email/src/email_i18n/locales/he.ts index b59b12777..0f79ad66c 100644 --- a/fluxer_api/pkgs/email/src/email_i18n/locales/he.ts +++ b/fluxer_api/pkgs/email/src/email_i18n/locales/he.ts @@ -2,7 +2,7 @@ import {defineEmailI18nLocaleMessages} from '../EmailI18nMessages'; -export const EMAIL_I18N_HE_MESSAGES = defineEmailI18nLocaleMessages({ +const EMAIL_I18N_HE_MESSAGES = defineEmailI18nLocaleMessages({ "account_disabled_suspicious": { "subject": "חשבון ה-{product_name} שלך הושבת זמנית", "body": "שלום {username},\n\nחשבון ה-{product_name} שלך הושבת זמנית עקב זיהוי פעילות חשודה.\n\n{reason, select,\n null {}\n other {סיבה: {reason}}\n}\n\nכדי לקבל בחזרה גישה לחשבון, יש לאפס את הסיסמה:\n\n{forgotUrl}\n\nלאחר איפוס הסיסמה, ניתן יהיה להתחבר שוב.\n\nאם אתם חושבים שזו טעות, צרו קשר עם צוות התמיכה שלנו.\n\nצוות הבטיחות של {product_name}" diff --git a/fluxer_api/pkgs/email/src/email_i18n/locales/hi.ts b/fluxer_api/pkgs/email/src/email_i18n/locales/hi.ts index 6cb1d831c..db0771476 100644 --- a/fluxer_api/pkgs/email/src/email_i18n/locales/hi.ts +++ b/fluxer_api/pkgs/email/src/email_i18n/locales/hi.ts @@ -2,7 +2,7 @@ import {defineEmailI18nLocaleMessages} from '../EmailI18nMessages'; -export const EMAIL_I18N_HI_MESSAGES = defineEmailI18nLocaleMessages({ +const EMAIL_I18N_HI_MESSAGES = defineEmailI18nLocaleMessages({ "account_disabled_suspicious": { "subject": "आपका {product_name} अकाउंट अस्थायी रूप से डिसेबल कर दिया गया है", "body": "नमस्ते {username},\n\nहमने आपके {product_name} अकाउंट को अस्थायी रूप से डिसेबल कर दिया है क्योंकि हमें संदिग्ध एक्टिविटी देखी गई है।\n\n{reason, select,\n null {}\n other {वजह: {reason}}\n}\n\nअपने अकाउंट का एक्सेस फिर से पाने के लिए, आपको अपना पासवर्ड रीसेट करना होगा:\n\n{forgotUrl}\n\nअपना पासवर्ड रीसेट करने के बाद, आप फिर से लॉगिन कर पाएंगे।\n\nअगर आपको लगता है कि यह गलती से हुआ है, तो कृपया हमारी सपोर्ट टीम से संपर्क करें।\n\n– {product_name} सेफ्टी टीम" diff --git a/fluxer_api/pkgs/email/src/email_i18n/locales/hr.ts b/fluxer_api/pkgs/email/src/email_i18n/locales/hr.ts index 3c4c68850..09e46ef81 100644 --- a/fluxer_api/pkgs/email/src/email_i18n/locales/hr.ts +++ b/fluxer_api/pkgs/email/src/email_i18n/locales/hr.ts @@ -2,7 +2,7 @@ import {defineEmailI18nLocaleMessages} from '../EmailI18nMessages'; -export const EMAIL_I18N_HR_MESSAGES = defineEmailI18nLocaleMessages({ +const EMAIL_I18N_HR_MESSAGES = defineEmailI18nLocaleMessages({ "account_disabled_suspicious": { "subject": "Tvoj {product_name} račun je privremeno onemogućen", "body": "Pozdrav {username},\n\nPrivremeno smo onemogućili tvoj {product_name} račun jer smo otkrili sumnjivu aktivnost.\n\n{reason, select,\n null {}\n other {Razlog: {reason}}\n}\n\nDa bi ponovno pristupio svom računu, morat ćeš poništiti lozinku:\n\n{forgotUrl}\n\nNakon što poništiš lozinku, moći ćeš se ponovno prijaviti.\n\nAko misliš da je ovo pogreška, kontaktiraj naš tim za podršku.\n\n– {product_name} Sigurnosni Tim" diff --git a/fluxer_api/pkgs/email/src/email_i18n/locales/hu.ts b/fluxer_api/pkgs/email/src/email_i18n/locales/hu.ts index f3204ee22..7a038a53a 100644 --- a/fluxer_api/pkgs/email/src/email_i18n/locales/hu.ts +++ b/fluxer_api/pkgs/email/src/email_i18n/locales/hu.ts @@ -2,7 +2,7 @@ import {defineEmailI18nLocaleMessages} from '../EmailI18nMessages'; -export const EMAIL_I18N_HU_MESSAGES = defineEmailI18nLocaleMessages({ +const EMAIL_I18N_HU_MESSAGES = defineEmailI18nLocaleMessages({ "account_disabled_suspicious": { "subject": "A {product_name} fiókodat ideiglenesen letiltottuk", "body": "Szia {username},\n\nIdeiglenesen letiltottuk a {product_name} fiókodat, mert gyanús tevékenységet észleltünk.\n\n{reason, select,\n null {}\n other {Indok: {reason}}\n}\n\nA fiókodhoz való hozzáférés visszaszerzéséhez vissza kell állítanod a jelszavadat:\n\n{forgotUrl}\n\nA jelszó visszaállítása után újra be tudsz jelentkezni.\n\nHa úgy gondolod, hogy ez tévedésből történt, vedd fel a kapcsolatot a támogatási csapatunkkal.\n\n– {product_name} Biztonsági Csapat" diff --git a/fluxer_api/pkgs/email/src/email_i18n/locales/id.ts b/fluxer_api/pkgs/email/src/email_i18n/locales/id.ts index 8f8c50cb5..8c921c60c 100644 --- a/fluxer_api/pkgs/email/src/email_i18n/locales/id.ts +++ b/fluxer_api/pkgs/email/src/email_i18n/locales/id.ts @@ -2,7 +2,7 @@ import {defineEmailI18nLocaleMessages} from '../EmailI18nMessages'; -export const EMAIL_I18N_ID_MESSAGES = defineEmailI18nLocaleMessages({ +const EMAIL_I18N_ID_MESSAGES = defineEmailI18nLocaleMessages({ "account_disabled_suspicious": { "subject": "Akun {product_name}mu telah dinonaktifkan sementara", "body": "Halo {username},\n\nKami menonaktifkan sementara akun {product_name}mu karena kami mendeteksi aktivitas mencurigakan.\n\n{reason, select,\n null {}\n other {Alasan: {reason}}\n}\n\nUntuk mendapatkan kembali akses ke akunmu, kamu perlu mengatur ulang kata sandimu:\n\n{forgotUrl}\n\nSetelah kamu mengatur ulang kata sandimu, kamu akan bisa masuk lagi.\n\nKalau kamu merasa ini salah, hubungi tim dukungan kami.\n\n– Tim Keamanan {product_name}" diff --git a/fluxer_api/pkgs/email/src/email_i18n/locales/it.ts b/fluxer_api/pkgs/email/src/email_i18n/locales/it.ts index 1f69a3436..e89420d76 100644 --- a/fluxer_api/pkgs/email/src/email_i18n/locales/it.ts +++ b/fluxer_api/pkgs/email/src/email_i18n/locales/it.ts @@ -2,7 +2,7 @@ import {defineEmailI18nLocaleMessages} from '../EmailI18nMessages'; -export const EMAIL_I18N_IT_MESSAGES = defineEmailI18nLocaleMessages({ +const EMAIL_I18N_IT_MESSAGES = defineEmailI18nLocaleMessages({ "account_disabled_suspicious": { "subject": "Il tuo account {product_name} è stato temporaneamente disabilitato", "body": "Ciao {username},\n\nAbbiamo temporaneamente disabilitato il tuo account {product_name} perché abbiamo rilevato attività sospette.\n\n{reason, select,\n null {}\n other {Motivo: {reason}}\n}\n\nPer riottenere l'accesso al tuo account, dovrai reimpostare la password:\n\n{forgotUrl}\n\nDopo aver reimpostato la password, potrai accedere di nuovo.\n\nSe ritieni che ciò sia stato fatto per errore, contatta il nostro team di supporto.\n\n– Team di Sicurezza {product_name}" diff --git a/fluxer_api/pkgs/email/src/email_i18n/locales/ja.ts b/fluxer_api/pkgs/email/src/email_i18n/locales/ja.ts index ac92d6884..3bc35cdcf 100644 --- a/fluxer_api/pkgs/email/src/email_i18n/locales/ja.ts +++ b/fluxer_api/pkgs/email/src/email_i18n/locales/ja.ts @@ -2,7 +2,7 @@ import {defineEmailI18nLocaleMessages} from '../EmailI18nMessages'; -export const EMAIL_I18N_JA_MESSAGES = defineEmailI18nLocaleMessages({ +const EMAIL_I18N_JA_MESSAGES = defineEmailI18nLocaleMessages({ "account_disabled_suspicious": { "subject": "{product_name}アカウントが一時的に無効になりました", "body": "こんにちは、{username}さん\n\n不審なアクティビティが検出されたため、{product_name}アカウントを一時的に無効にしました。\n\n{reason, select,\n null {}\n other {理由: {reason}}\n}\n\nアカウントに再度アクセスするには、パスワードをリセットする必要があります。\n\n{forgotUrl}\n\nパスワードをリセットすると、再度ログインできるようになります。\n\nこの措置が誤りであると思われる場合は、サポートチームにお問い合わせください。\n\n– {product_name}安全チーム" diff --git a/fluxer_api/pkgs/email/src/email_i18n/locales/ko.ts b/fluxer_api/pkgs/email/src/email_i18n/locales/ko.ts index f1fac054a..ff0f766cd 100644 --- a/fluxer_api/pkgs/email/src/email_i18n/locales/ko.ts +++ b/fluxer_api/pkgs/email/src/email_i18n/locales/ko.ts @@ -2,7 +2,7 @@ import {defineEmailI18nLocaleMessages} from '../EmailI18nMessages'; -export const EMAIL_I18N_KO_MESSAGES = defineEmailI18nLocaleMessages({ +const EMAIL_I18N_KO_MESSAGES = defineEmailI18nLocaleMessages({ "account_disabled_suspicious": { "subject": "{product_name} 계정이 일시적으로 비활성화되었어요", "body": "안녕하세요, {username}님.\n\n의심스러운 활동이 감지되어 {product_name} 계정을 일시적으로 비활성화했어요.\n\n{reason, select,\n null {}\n other {사유: {reason}}\n}\n\n계정에 다시 액세스하려면 비밀번호를 재설정해야 해요:\n\n{forgotUrl}\n\n비밀번호를 재설정한 후 다시 로그인할 수 있어요.\n\n실수로 비활성화되었다고 생각되면 고객지원팀에 문의해 주세요.\n\n– {product_name} 안전팀" diff --git a/fluxer_api/pkgs/email/src/email_i18n/locales/lt.ts b/fluxer_api/pkgs/email/src/email_i18n/locales/lt.ts index 8cd1657b8..61edd6f55 100644 --- a/fluxer_api/pkgs/email/src/email_i18n/locales/lt.ts +++ b/fluxer_api/pkgs/email/src/email_i18n/locales/lt.ts @@ -2,7 +2,7 @@ import {defineEmailI18nLocaleMessages} from '../EmailI18nMessages'; -export const EMAIL_I18N_LT_MESSAGES = defineEmailI18nLocaleMessages({ +const EMAIL_I18N_LT_MESSAGES = defineEmailI18nLocaleMessages({ "account_disabled_suspicious": { "subject": "Tavo {product_name} paskyra laikinai išjungta", "body": "Sveikas, {username},\n\nLaikinai išjungėme tavo {product_name} paskyrą, nes aptikome įtartiną veiklą.\n\n{reason, select,\n null {}\n other {Priežastis: {reason}}\n}\n\nNorėdamas atgauti prieigą prie paskyros, turėsi iš naujo nustatyti slaptažodį:\n\n{forgotUrl}\n\nNustatęs slaptažodį iš naujo, galėsi vėl prisijungti.\n\nJei manai, kad tai įvyko per klaidą, susisiek su mūsų palaikymo komanda.\n\n– {product_name} saugos komanda" diff --git a/fluxer_api/pkgs/email/src/email_i18n/locales/nl.ts b/fluxer_api/pkgs/email/src/email_i18n/locales/nl.ts index ed02578f0..ed18ced33 100644 --- a/fluxer_api/pkgs/email/src/email_i18n/locales/nl.ts +++ b/fluxer_api/pkgs/email/src/email_i18n/locales/nl.ts @@ -2,7 +2,7 @@ import {defineEmailI18nLocaleMessages} from '../EmailI18nMessages'; -export const EMAIL_I18N_NL_MESSAGES = defineEmailI18nLocaleMessages({ +const EMAIL_I18N_NL_MESSAGES = defineEmailI18nLocaleMessages({ "account_disabled_suspicious": { "subject": "Je {product_name}-account is tijdelijk uitgeschakeld", "body": "Hallo {username},\n\nWe hebben je {product_name}-account tijdelijk uitgeschakeld omdat we verdachte activiteit hebben gedetecteerd.\n\n{reason, select,\n null {}\n other {Reden: {reason}}\n}\n\nOm weer toegang te krijgen tot je account, moet je je wachtwoord opnieuw instellen:\n\n{forgotUrl}\n\nNadat je je wachtwoord opnieuw hebt ingesteld, kun je weer inloggen.\n\nAls je denkt dat dit een fout is, neem dan contact op met ons support-team.\n\n– {product_name} Safety Team" diff --git a/fluxer_api/pkgs/email/src/email_i18n/locales/no.ts b/fluxer_api/pkgs/email/src/email_i18n/locales/no.ts index 6db865c31..0427488c3 100644 --- a/fluxer_api/pkgs/email/src/email_i18n/locales/no.ts +++ b/fluxer_api/pkgs/email/src/email_i18n/locales/no.ts @@ -2,7 +2,7 @@ import {defineEmailI18nLocaleMessages} from '../EmailI18nMessages'; -export const EMAIL_I18N_NO_MESSAGES = defineEmailI18nLocaleMessages({ +const EMAIL_I18N_NO_MESSAGES = defineEmailI18nLocaleMessages({ "account_disabled_suspicious": { "subject": "{product_name}-kontoen din er midlertidig deaktivert", "body": "Hei {username},\n\nVi deaktiverte {product_name}-kontoen din midlertidig fordi vi oppdaget mistenkelig aktivitet.\n\n{reason, select,\n null {}\n other {Årsak: {reason}}\n}\n\nFor å få tilgang til kontoen din igjen, må du tilbakestille passordet ditt:\n\n{forgotUrl}\n\nEtter at du har tilbakestilt passordet ditt, kan du logge inn igjen.\n\nHvis du mener dette er en feil, kontakt kundestøtte.\n\n– {product_name} sikkerhetsteam" diff --git a/fluxer_api/pkgs/email/src/email_i18n/locales/pl.ts b/fluxer_api/pkgs/email/src/email_i18n/locales/pl.ts index eca60b01e..bfac94b8f 100644 --- a/fluxer_api/pkgs/email/src/email_i18n/locales/pl.ts +++ b/fluxer_api/pkgs/email/src/email_i18n/locales/pl.ts @@ -2,7 +2,7 @@ import {defineEmailI18nLocaleMessages} from '../EmailI18nMessages'; -export const EMAIL_I18N_PL_MESSAGES = defineEmailI18nLocaleMessages({ +const EMAIL_I18N_PL_MESSAGES = defineEmailI18nLocaleMessages({ "account_disabled_suspicious": { "subject": "Twoje konto {product_name} zostało tymczasowo wyłączone", "body": "Witaj {username},\n\nTymczasowo wyłączyliśmy Twoje konto {product_name}, ponieważ wykryliśmy podejrzaną aktywność.\n\n{reason, select,\n null {}\n other {Powód: {reason}}\n}\n\nAby odzyskać dostęp do konta, musisz zresetować hasło:\n\n{forgotUrl}\n\nPo zresetowaniu hasła będziesz mógł ponownie się zalogować.\n\nJeśli uważasz, że to błąd, skontaktuj się z naszym zespołem wsparcia.\n\n– Zespół Bezpieczeństwa {product_name}" diff --git a/fluxer_api/pkgs/email/src/email_i18n/locales/pt-BR.ts b/fluxer_api/pkgs/email/src/email_i18n/locales/pt-BR.ts index 52c00d5d6..5cda64ee4 100644 --- a/fluxer_api/pkgs/email/src/email_i18n/locales/pt-BR.ts +++ b/fluxer_api/pkgs/email/src/email_i18n/locales/pt-BR.ts @@ -2,7 +2,7 @@ import {defineEmailI18nLocaleMessages} from '../EmailI18nMessages'; -export const EMAIL_I18N_PT_BR_MESSAGES = defineEmailI18nLocaleMessages({ +const EMAIL_I18N_PT_BR_MESSAGES = defineEmailI18nLocaleMessages({ "account_disabled_suspicious": { "subject": "Sua conta do {product_name} foi desativada temporariamente", "body": "Olá, {username},\n\nDesativamos temporariamente sua conta do {product_name} porque detectamos atividades suspeitas.\n\n{reason, select,\n null {}\n other {Motivo: {reason}}\n}\n\nPara acessar sua conta novamente, você precisará redefinir sua senha:\n\n{forgotUrl}\n\nDepois de redefinir sua senha, você poderá entrar novamente.\n\nSe você acredita que isso foi um erro, entre em contato com nossa equipe de suporte.\n\n– Equipe de Segurança do {product_name}" diff --git a/fluxer_api/pkgs/email/src/email_i18n/locales/ro.ts b/fluxer_api/pkgs/email/src/email_i18n/locales/ro.ts index 301cc32e5..c22a14428 100644 --- a/fluxer_api/pkgs/email/src/email_i18n/locales/ro.ts +++ b/fluxer_api/pkgs/email/src/email_i18n/locales/ro.ts @@ -2,7 +2,7 @@ import {defineEmailI18nLocaleMessages} from '../EmailI18nMessages'; -export const EMAIL_I18N_RO_MESSAGES = defineEmailI18nLocaleMessages({ +const EMAIL_I18N_RO_MESSAGES = defineEmailI18nLocaleMessages({ "account_disabled_suspicious": { "subject": "Contul tău {product_name} a fost dezactivat temporar", "body": "Salut {username},\n\nAm dezactivat temporar contul tău {product_name} deoarece am detectat activitate suspectă.\n\n{reason, select,\n null {}\n other {Motiv: {reason}}\n}\n\nPentru a recăpăta accesul la contul tău, va trebui să-ți resetezi parola:\n\n{forgotUrl}\n\nDupă ce îți resetezi parola, te vei putea conecta din nou.\n\nDacă crezi că aceasta a fost o eroare, te rugăm să contactezi echipa noastră de suport.\n\n– {product_name} Safety Team" diff --git a/fluxer_api/pkgs/email/src/email_i18n/locales/ru.ts b/fluxer_api/pkgs/email/src/email_i18n/locales/ru.ts index 02a5272f5..4d4fe9a4a 100644 --- a/fluxer_api/pkgs/email/src/email_i18n/locales/ru.ts +++ b/fluxer_api/pkgs/email/src/email_i18n/locales/ru.ts @@ -2,7 +2,7 @@ import {defineEmailI18nLocaleMessages} from '../EmailI18nMessages'; -export const EMAIL_I18N_RU_MESSAGES = defineEmailI18nLocaleMessages({ +const EMAIL_I18N_RU_MESSAGES = defineEmailI18nLocaleMessages({ "account_disabled_suspicious": { "subject": "Твой аккаунт {product_name} временно отключён", "body": "Привет, {username},\n\nМы временно отключили твой аккаунт {product_name}, так как обнаружили подозрительную активность.\n\n{reason, select,\n null {}\n other {Причина: {reason}}\n}\n\nЧтобы восстановить доступ к аккаунту, тебе нужно сбросить пароль:\n\n{forgotUrl}\n\nПосле сброса пароля ты сможешь снова войти в аккаунт.\n\nЕсли ты считаешь, что это ошибка, пожалуйста, свяжись с нашей службой поддержки.\n\n– Команда безопасности {product_name}" diff --git a/fluxer_api/pkgs/email/src/email_i18n/locales/sv-SE.ts b/fluxer_api/pkgs/email/src/email_i18n/locales/sv-SE.ts index 16a6d2ed6..62a456009 100644 --- a/fluxer_api/pkgs/email/src/email_i18n/locales/sv-SE.ts +++ b/fluxer_api/pkgs/email/src/email_i18n/locales/sv-SE.ts @@ -2,7 +2,7 @@ import {defineEmailI18nLocaleMessages} from '../EmailI18nMessages'; -export const EMAIL_I18N_SV_SE_MESSAGES = defineEmailI18nLocaleMessages({ +const EMAIL_I18N_SV_SE_MESSAGES = defineEmailI18nLocaleMessages({ "account_disabled_suspicious": { "subject": "Ditt {product_name}-konto har tillfälligt inaktiverats", "body": "Hej {username},\n\nVi har tillfälligt inaktiverat ditt {product_name}-konto eftersom vi upptäckte misstänkt aktivitet.\n\n{reason, select,\n null {}\n other {Anledning: {reason}}\n}\n\nFör att återfå åtkomst till ditt konto måste du återställa ditt lösenord:\n\n{forgotUrl}\n\nEfter att du har återställt ditt lösenord kan du logga in igen.\n\nOm du anser att detta har skett av misstag, kontakta vårt supportteam.\n\n– {product_name} Safety Team" diff --git a/fluxer_api/pkgs/email/src/email_i18n/locales/th.ts b/fluxer_api/pkgs/email/src/email_i18n/locales/th.ts index 0c8ed74cf..588b48054 100644 --- a/fluxer_api/pkgs/email/src/email_i18n/locales/th.ts +++ b/fluxer_api/pkgs/email/src/email_i18n/locales/th.ts @@ -2,7 +2,7 @@ import {defineEmailI18nLocaleMessages} from '../EmailI18nMessages'; -export const EMAIL_I18N_TH_MESSAGES = defineEmailI18nLocaleMessages({ +const EMAIL_I18N_TH_MESSAGES = defineEmailI18nLocaleMessages({ "account_disabled_suspicious": { "subject": "บัญชี {product_name} ของคุณถูกปิดใช้งานชั่วคราว", "body": "สวัสดี {username},\n\nเราปิดใช้งานบัญชี {product_name} ของคุณชั่วคราว เนื่องจากเราตรวจพบกิจกรรมที่น่าสงสัย\n\n{reason, select,\n null {}\n other {เหตุผล: {reason}}\n}\n\nหากต้องการเข้าถึงบัญชีอีกครั้ง ให้รีเซ็ตรหัสผ่าน:\n\n{forgotUrl}\n\nหลังจากรีเซ็ตรหัสผ่านแล้ว คุณจะสามารถเข้าสู่ระบบได้อีกครั้ง\n\nหากคุณเชื่อว่านี่เป็นข้อผิดพลาด โปรดติดต่อทีมสนับสนุนของเรา\n\n– ทีมความปลอดภัย {product_name}" diff --git a/fluxer_api/pkgs/email/src/email_i18n/locales/tr.ts b/fluxer_api/pkgs/email/src/email_i18n/locales/tr.ts index 0b75a7cde..94f84508b 100644 --- a/fluxer_api/pkgs/email/src/email_i18n/locales/tr.ts +++ b/fluxer_api/pkgs/email/src/email_i18n/locales/tr.ts @@ -2,7 +2,7 @@ import {defineEmailI18nLocaleMessages} from '../EmailI18nMessages'; -export const EMAIL_I18N_TR_MESSAGES = defineEmailI18nLocaleMessages({ +const EMAIL_I18N_TR_MESSAGES = defineEmailI18nLocaleMessages({ "account_disabled_suspicious": { "subject": "{product_name} hesabın geçici olarak devre dışı bırakıldı", "body": "Merhaba {username},\n\nŞüpheli etkinlik tespit ettiğimiz için {product_name} hesabını geçici olarak devre dışı bıraktık.\n\n{reason, select,\n null {}\n other {Sebep: {reason}}\n}\n\nHesabına tekrar erişmek için şifreni sıfırlaman gerekiyor:\n\n{forgotUrl}\n\nŞifreni sıfırladıktan sonra tekrar giriş yapabilirsin.\n\nBunun bir hata olduğunu düşünüyorsan, lütfen destek ekibimizle iletişime geç.\n\n– {product_name} Güvenlik Ekibi" diff --git a/fluxer_api/pkgs/email/src/email_i18n/locales/uk.ts b/fluxer_api/pkgs/email/src/email_i18n/locales/uk.ts index 2fbe016a2..7e7d8438a 100644 --- a/fluxer_api/pkgs/email/src/email_i18n/locales/uk.ts +++ b/fluxer_api/pkgs/email/src/email_i18n/locales/uk.ts @@ -2,7 +2,7 @@ import {defineEmailI18nLocaleMessages} from '../EmailI18nMessages'; -export const EMAIL_I18N_UK_MESSAGES = defineEmailI18nLocaleMessages({ +const EMAIL_I18N_UK_MESSAGES = defineEmailI18nLocaleMessages({ "account_disabled_suspicious": { "subject": "Твій акаунт {product_name} тимчасово вимкнено", "body": "Привіт, {username},\n\nМи тимчасово вимкнули твій акаунт {product_name}, оскільки виявили підозрілу активність.\n\n{reason, select,\n null {}\n other {Причина: {reason}}\n}\n\nЩоб відновити доступ до акаунту, тобі потрібно скинути пароль:\n\n{forgotUrl}\n\nПісля скидання пароля ти зможеш знову увійти.\n\nЯкщо ти вважаєш, що це помилка, будь ласка, зв'яжися з нашою службою підтримки.\n\n– Команда безпеки {product_name}" diff --git a/fluxer_api/pkgs/email/src/email_i18n/locales/vi.ts b/fluxer_api/pkgs/email/src/email_i18n/locales/vi.ts index 05dbe8653..ebb25815a 100644 --- a/fluxer_api/pkgs/email/src/email_i18n/locales/vi.ts +++ b/fluxer_api/pkgs/email/src/email_i18n/locales/vi.ts @@ -2,7 +2,7 @@ import {defineEmailI18nLocaleMessages} from '../EmailI18nMessages'; -export const EMAIL_I18N_VI_MESSAGES = defineEmailI18nLocaleMessages({ +const EMAIL_I18N_VI_MESSAGES = defineEmailI18nLocaleMessages({ "account_disabled_suspicious": { "subject": "Tài khoản {product_name} của bạn đã bị vô hiệu hóa tạm thời", "body": "Xin chào {username},\n\nChúng tôi đã tạm thời vô hiệu hóa tài khoản {product_name} của bạn vì phát hiện hoạt động đáng ngờ.\n\n{reason, select,\n null {}\n other {Lý do: {reason}}\n}\n\nĐể truy cập lại tài khoản, bạn cần đặt lại mật khẩu:\n\n{forgotUrl}\n\nSau khi đặt lại mật khẩu, bạn sẽ có thể đăng nhập lại.\n\nNếu bạn cho rằng đây là lỗi, vui lòng liên hệ đội ngũ hỗ trợ của chúng tôi.\n\n– Đội ngũ An toàn {product_name}" diff --git a/fluxer_api/pkgs/email/src/email_i18n/locales/zh-CN.ts b/fluxer_api/pkgs/email/src/email_i18n/locales/zh-CN.ts index edca18ca9..e6fd1e237 100644 --- a/fluxer_api/pkgs/email/src/email_i18n/locales/zh-CN.ts +++ b/fluxer_api/pkgs/email/src/email_i18n/locales/zh-CN.ts @@ -2,7 +2,7 @@ import {defineEmailI18nLocaleMessages} from '../EmailI18nMessages'; -export const EMAIL_I18N_ZH_CN_MESSAGES = defineEmailI18nLocaleMessages({ +const EMAIL_I18N_ZH_CN_MESSAGES = defineEmailI18nLocaleMessages({ "account_disabled_suspicious": { "subject": "你的 {product_name} 账号已被暂时禁用", "body": "你好 {username},\n\n我们检测到你的 {product_name} 账号存在可疑活动,因此暂时禁用了你的账号。\n\n{reason, select,\n null {}\n other {原因: {reason}}\n}\n\n要重新获得账号访问权限,你需要重置密码:\n\n{forgotUrl}\n\n重置密码后,你将能够再次登录。\n\n如果你认为这是误操作,请联系我们的支持团队。\n\n– {product_name} 安全团队" diff --git a/fluxer_api/pkgs/email/src/email_i18n/locales/zh-TW.ts b/fluxer_api/pkgs/email/src/email_i18n/locales/zh-TW.ts index 5e65bca89..5c2798e46 100644 --- a/fluxer_api/pkgs/email/src/email_i18n/locales/zh-TW.ts +++ b/fluxer_api/pkgs/email/src/email_i18n/locales/zh-TW.ts @@ -2,7 +2,7 @@ import {defineEmailI18nLocaleMessages} from '../EmailI18nMessages'; -export const EMAIL_I18N_ZH_TW_MESSAGES = defineEmailI18nLocaleMessages({ +const EMAIL_I18N_ZH_TW_MESSAGES = defineEmailI18nLocaleMessages({ "account_disabled_suspicious": { "subject": "您的 {product_name} 帳號已暫時停用", "body": "哈囉 {username},\n\n我們偵測到您的 {product_name} 帳號有可疑活動,因此已暫時停用您的帳號。\n\n{reason, select,\n null {}\n other {原因:{reason}}\n}\n\n若要重新取得帳號存取權,您需要重設密碼:\n\n{forgotUrl}\n\n重設密碼後,您將可以再次登入。\n\n如果您認為這是錯誤操作,請聯絡我們的支援團隊。\n\n– {product_name} 安全團隊" diff --git a/fluxer_api/pkgs/rate_limit/src/RateLimitService.ts b/fluxer_api/pkgs/rate_limit/src/RateLimitService.ts index 42526db45..0c3cfb61b 100644 --- a/fluxer_api/pkgs/rate_limit/src/RateLimitService.ts +++ b/fluxer_api/pkgs/rate_limit/src/RateLimitService.ts @@ -16,112 +16,8 @@ interface IRateLimitStore { scan(pattern: string, count: number): Promise>; } -interface InMemoryLeakyBucketState { - level: number; - updatedAtMs: number; -} - interface RateLimitServiceOptions { globalWindowMs?: number; - getCurrentTimeMs?: () => number; -} - -class InMemoryRateLimitStore implements IRateLimitStore { - private readonly leakyBucketState = new Map(); - - constructor(private readonly getCurrentTimeMs: () => number = () => Date.now()) {} - - async checkLeakyBucketLimit(key: string, limit: number, windowMs: number, cost: number): Promise { - const nowMs = this.getCurrentTimeMs(); - const capacity = Math.max(1, Math.floor(limit)); - const leakWindowMs = Math.max(1, Math.floor(windowMs)); - let bucket = this.leakyBucketState.get(key); - if (!bucket) { - bucket = {level: 0, updatedAtMs: nowMs}; - this.leakyBucketState.set(key, bucket); - } - drainLeakyBucket(bucket, capacity, leakWindowMs, nowMs); - if (cost <= 0) { - const remaining = Math.max(0, Math.floor(capacity - bucket.level)); - const resetAfterMs = leakyBucketResetAfterMs(bucket, capacity, leakWindowMs); - return createStoreResult(true, capacity, remaining, nowMs, resetAfterMs, 0); - } - if (cost !== 1) { - throw new Error(`Unsupported leaky bucket cost: ${cost}`); - } - if (bucket.level + cost > capacity) { - const retryAfterMs = leakyBucketRetryAfterMs(bucket, capacity, leakWindowMs, cost); - const resetAfterMs = leakyBucketResetAfterMs(bucket, capacity, leakWindowMs); - return createStoreResult(false, capacity, 0, nowMs, Math.max(resetAfterMs, retryAfterMs), retryAfterMs); - } - bucket.level += cost; - const remaining = Math.max(0, Math.floor(capacity - bucket.level)); - const resetAfterMs = leakyBucketResetAfterMs(bucket, capacity, leakWindowMs); - return createStoreResult(true, capacity, remaining, nowMs, resetAfterMs, 0); - } - - async del(...keys: Array): Promise { - let deleted = 0; - for (const key of keys) { - const deletedBucket = this.leakyBucketState.delete(key); - if (deletedBucket) { - deleted++; - } - } - return deleted; - } - - async scan(pattern: string, count: number): Promise> { - const limit = Math.max(1, Math.floor(count)); - const matcher = compileGlobMatcher(pattern); - const matches = new Set(); - for (const key of this.leakyBucketState.keys()) { - if (matcher(key)) { - matches.add(key); - if (matches.size >= limit) break; - } - } - return Array.from(matches); - } -} - -function compileGlobMatcher(pattern: string): (key: string) => boolean { - const escaped = pattern - .replace(/[.+^${}()|[\]\\]/g, '\\$&') - .replace(/\*/g, '.*') - .replace(/\?/g, '.'); - const regex = new RegExp(`^${escaped}$`); - return (key: string) => regex.test(key); -} - -function drainLeakyBucket(bucket: InMemoryLeakyBucketState, capacity: number, windowMs: number, nowMs: number): void { - const elapsed = nowMs - bucket.updatedAtMs; - if (elapsed <= 0) { - return; - } - const leaked = (elapsed / windowMs) * capacity; - bucket.level = Math.max(0, bucket.level - leaked); - bucket.updatedAtMs = nowMs; -} - -function leakyBucketRetryAfterMs( - bucket: InMemoryLeakyBucketState, - capacity: number, - windowMs: number, - cost: number, -): number { - const overflow = bucket.level + cost - capacity; - if (overflow <= 0) { - return 0; - } - return Math.max(1, Math.ceil(overflow / (capacity / windowMs))); -} - -function leakyBucketResetAfterMs(bucket: InMemoryLeakyBucketState, capacity: number, windowMs: number): number { - if (bucket.level <= 0) { - return 0; - } - return Math.max(0, Math.ceil(bucket.level / (capacity / windowMs))); } function millisecondsToDecimalSeconds(milliseconds: number): number { @@ -131,24 +27,6 @@ function millisecondsToDecimalSeconds(milliseconds: number): number { return milliseconds / 1000; } -function createStoreResult( - allowed: boolean, - limit: number, - remaining: number, - nowMs: number, - resetAfterMs: number, - retryAfterMs: number, -): KVRateLimitResult { - return { - allowed, - limit, - remaining, - resetAfterMs, - resetAtMs: nowMs + resetAfterMs, - retryAfterMs, - }; -} - function createRateLimitResult(result: KVRateLimitResult, global?: boolean): RateLimitResult { const resetAfterDecimal = millisecondsToDecimalSeconds(result.resetAfterMs); const retryAfterDecimal = millisecondsToDecimalSeconds(result.retryAfterMs); @@ -224,23 +102,3 @@ export class RateLimitService implements IRateLimitService { return totalDeleted; } } - -function createRateLimitService( - store: IRateLimitStore | null, - options: RateLimitServiceOptions = {}, -): RateLimitService | null { - if (!store) { - return null; - } - return new RateLimitService(store, options); -} - -export function createInMemoryRateLimitService( - enabled: boolean, - options: RateLimitServiceOptions = {}, -): RateLimitService | null { - if (!enabled) { - return null; - } - return createRateLimitService(new InMemoryRateLimitStore(options.getCurrentTimeMs), options); -} diff --git a/fluxer_api/src/api/auth/tests/EmailVerificationFlow.test.ts b/fluxer_api/src/api/auth/tests/EmailVerificationFlow.test.ts index e405cc831..fd57ac6d4 100644 --- a/fluxer_api/src/api/auth/tests/EmailVerificationFlow.test.ts +++ b/fluxer_api/src/api/auth/tests/EmailVerificationFlow.test.ts @@ -30,7 +30,12 @@ describe('Email verification flow', () => { await harness?.shutdown(); }); it('allows resending verification email and verifying email', async () => { - const account = await createTestAccount(harness); + const account = await createTestAccount(harness, {skipEmailVerification: true}); + await createBuilderWithoutAuth(harness) + .post(`/test/users/${account.userId}/security-flags`) + .body({email_verified: false}) + .expect(200) + .execute(); await createBuilder(harness, account.token).post('/auth/verify/resend').body({}).expect(204).execute(); const emails = await listTestEmails(harness, {recipient: account.email}); const verificationEmail = findLastTestEmail(emails, 'email_verification'); diff --git a/fluxer_api/src/api/auth/tests/MfaEmailVerificationRequired.test.ts b/fluxer_api/src/api/auth/tests/MfaEmailVerificationRequired.test.ts index fc65bc5d0..b634c359e 100644 --- a/fluxer_api/src/api/auth/tests/MfaEmailVerificationRequired.test.ts +++ b/fluxer_api/src/api/auth/tests/MfaEmailVerificationRequired.test.ts @@ -22,8 +22,17 @@ describe('MFA requires verified email', () => { afterAll(async () => { await harness?.shutdown(); }); - it('rejects TOTP enablement for unverified accounts', async () => { + async function createUnverifiedAccount() { const account = await createTestAccount(harness, {skipEmailVerification: true}); + await createBuilder(harness, '') + .post(`/test/users/${account.userId}/security-flags`) + .body({email_verified: false}) + .expect(200) + .execute(); + return account; + } + it('rejects TOTP enablement for unverified accounts', async () => { + const account = await createUnverifiedAccount(); const secret = createTotpSecret(); const {json} = await createBuilder(harness, account.token) .post('/users/@me/mfa/totp/enable') @@ -33,7 +42,7 @@ describe('MFA requires verified email', () => { expect(json.code).toBe(APIErrorCodes.MFA_EMAIL_VERIFICATION_REQUIRED); }); it('rejects WebAuthn registration setup for unverified accounts', async () => { - const account = await createTestAccount(harness, {skipEmailVerification: true}); + const account = await createUnverifiedAccount(); const {json} = await createBuilder(harness, account.token) .post('/users/@me/mfa/webauthn/credentials/registration-options') .body({password: account.password}) diff --git a/fluxer_api/src/api/auth/tests/PhoneVerificationFlow.test.ts b/fluxer_api/src/api/auth/tests/PhoneVerificationFlow.test.ts index 051df1dfb..b4de62d39 100644 --- a/fluxer_api/src/api/auth/tests/PhoneVerificationFlow.test.ts +++ b/fluxer_api/src/api/auth/tests/PhoneVerificationFlow.test.ts @@ -187,7 +187,9 @@ describe('Phone verification flow', () => { await allowPhoneVerification(account.userId); const config = getConfig(); const previousInboundNumber = config.sms.inboundChallengeNumber; + const previousInboundPrefixes = config.abusePolicy.phoneVerification.inboundRequiredPrefixes; config.sms.inboundChallengeNumber = '+15551234567'; + config.abusePolicy.phoneVerification.inboundRequiredPrefixes = ['+998']; try { const response = await createBuilder<{ channel: string; @@ -207,6 +209,7 @@ describe('Phone verification flow', () => { expect(response.challenge_code).toMatch(/^\d{6}$/); } finally { config.sms.inboundChallengeNumber = previousInboundNumber; + config.abusePolicy.phoneVerification.inboundRequiredPrefixes = previousInboundPrefixes; } }); it('does not let clients force SMS for inbound-only prefixes', async () => { @@ -214,7 +217,9 @@ describe('Phone verification flow', () => { await allowPhoneVerification(account.userId); const config = getConfig(); const previousInboundNumber = config.sms.inboundChallengeNumber; + const previousInboundPrefixes = config.abusePolicy.phoneVerification.inboundRequiredPrefixes; config.sms.inboundChallengeNumber = '+15551234567'; + config.abusePolicy.phoneVerification.inboundRequiredPrefixes = ['+593']; try { const response = await createBuilder<{ channel: string; @@ -233,6 +238,7 @@ describe('Phone verification flow', () => { }); } finally { config.sms.inboundChallengeNumber = previousInboundNumber; + config.abusePolicy.phoneVerification.inboundRequiredPrefixes = previousInboundPrefixes; } }); }); diff --git a/fluxer_api/src/api/channel/tests/ChannelTestUtils.ts b/fluxer_api/src/api/channel/tests/ChannelTestUtils.ts index e03d54390..67c94e69a 100644 --- a/fluxer_api/src/api/channel/tests/ChannelTestUtils.ts +++ b/fluxer_api/src/api/channel/tests/ChannelTestUtils.ts @@ -308,19 +308,6 @@ export async function createGroupDmChannel( return channel; } -export async function addRecipientToGroupDm( - harness: ApiTestHarness, - token: string, - channelId: string, - userId: string, -): Promise { - await createBuilder(harness, token) - .put(`/channels/${channelId}/recipients/${userId}`) - .body(null) - .expect(204) - .execute(); -} - export async function updateUserSettings( harness: ApiTestHarness, token: string, diff --git a/fluxer_api/src/api/constants/LimitConfig.ts b/fluxer_api/src/api/constants/LimitConfig.ts index 166613db7..400fc6e25 100644 --- a/fluxer_api/src/api/constants/LimitConfig.ts +++ b/fluxer_api/src/api/constants/LimitConfig.ts @@ -1,13 +1,16 @@ // SPDX-License-Identifier: AGPL-3.0-or-later +import {GuildFeatures} from '@fluxer/constants/src/GuildConstants'; import type {LimitKey} from '@fluxer/constants/src/LimitConfigMetadata'; import {LIMIT_KEYS} from '@fluxer/constants/src/LimitConfigMetadata'; +import {MAX_GUILD_MEMBERS_VERY_LARGE_GUILD} from '@fluxer/constants/src/LimitConstants'; import {DEFAULT_RESTRICTED_LIMITS, DEFAULT_STOCK_LIMITS} from '@fluxer/limits/src/LimitDefaults'; import type {LimitConfigSnapshot, LimitRule} from '@fluxer/limits/src/LimitTypes'; const LIMIT_RULE_IDS = { DEFAULT: 'default', HOSTED_UPGRADE: 'premium', + VERY_LARGE_GUILD: 'very_large_guild', } as const; export interface CachedLimitConfig { @@ -73,12 +76,22 @@ export function createDefaultLimitConfig(options?: { id: LIMIT_RULE_IDS.DEFAULT, limits: {...DEFAULT_RESTRICTED_LIMITS}, }, + { + id: LIMIT_RULE_IDS.VERY_LARGE_GUILD, + filters: {guildFeatures: [GuildFeatures.VERY_LARGE_GUILD]}, + limits: {max_guild_members: MAX_GUILD_MEMBERS_VERY_LARGE_GUILD}, + }, ] : [ { id: LIMIT_RULE_IDS.DEFAULT, limits: {...DEFAULT_STOCK_LIMITS}, }, + { + id: LIMIT_RULE_IDS.VERY_LARGE_GUILD, + filters: {guildFeatures: [GuildFeatures.VERY_LARGE_GUILD]}, + limits: {max_guild_members: MAX_GUILD_MEMBERS_VERY_LARGE_GUILD}, + }, ], }; return sanitizeLimitConfigForInstance(cloneLimitConfigSnapshot(hostedDefault), {selfHosted, premiumMode}); diff --git a/fluxer_api/src/api/content_i18n/locales/ar.ts b/fluxer_api/src/api/content_i18n/locales/ar.ts index e129d4185..1fe27796d 100644 --- a/fluxer_api/src/api/content_i18n/locales/ar.ts +++ b/fluxer_api/src/api/content_i18n/locales/ar.ts @@ -2,7 +2,7 @@ import {defineContentI18nLocaleMessages} from '../ContentI18nMessages'; -export const CONTENT_I18N_AR_MESSAGES = defineContentI18nLocaleMessages({ +const CONTENT_I18N_AR_MESSAGES = defineContentI18nLocaleMessages({ "billing.eu_withdrawal_waiver_checkout": "إذا كنت مستهلكًا في الاتحاد الأوروبي/المنطقة الاقتصادية الأوروبية، فإنني أوافق صراحةً على تقديم المحتوى الرقمي لـ {product_name} {premium_tier_name} فورًا، وأقرّ بأنني أفقد حقي القانوني في الانسحاب بمجرد تقديم الوصول. لا يؤثر هذا على حقوق المستهلك الإلزامية الأخرى. اطّلع على [شروط الخدمة]({terms_url}).", "bulk_message_deletion.complete": "انتهينا من حذف رسائلك. أزلنا {message_count, plural, =0 {0 رسالة} one {رسالة واحدة} two {رسالتين} few {# رسائل} many {# رسالة} other {# رسالة}} من {channel_count, plural, =0 {0 مكان} one {مكان واحد} two {مكانين} few {# أماكن} many {# مكانًا} other {# مكان}}.", "content.virus_detected": "تم الإبلاغ عن هذا الملف على أنه قد يكون غير آمن وتمت إزالته.", diff --git a/fluxer_api/src/api/content_i18n/locales/bg.ts b/fluxer_api/src/api/content_i18n/locales/bg.ts index 6eeeab6c1..3c77b5bcb 100644 --- a/fluxer_api/src/api/content_i18n/locales/bg.ts +++ b/fluxer_api/src/api/content_i18n/locales/bg.ts @@ -2,7 +2,7 @@ import {defineContentI18nLocaleMessages} from '../ContentI18nMessages'; -export const CONTENT_I18N_BG_MESSAGES = defineContentI18nLocaleMessages({ +const CONTENT_I18N_BG_MESSAGES = defineContentI18nLocaleMessages({ "billing.eu_withdrawal_waiver_checkout": "Ако съм потребител от ЕС/ЕИП, изрично се съгласявам цифровото съдържание на {product_name} {premium_tier_name} да бъде предоставено незабавно и признавам, че губя законното си право на отказ, след като достъпът бъде предоставен. Това не засяга други задължителни потребителски права. Виж [Условията за ползване]({terms_url}).", "bulk_message_deletion.complete": "Изтриването на съобщенията ти приключи. Премахнахме {message_count, plural, =0 {0 съобщения} one {# съобщение} other {# съобщения}} от {channel_count, plural, =0 {0 места} one {# място} other {# места}}.", "content.virus_detected": "Този файл беше маркиран като потенциално опасен и е премахнат.", diff --git a/fluxer_api/src/api/content_i18n/locales/cs.ts b/fluxer_api/src/api/content_i18n/locales/cs.ts index 401a5174a..0cb08feab 100644 --- a/fluxer_api/src/api/content_i18n/locales/cs.ts +++ b/fluxer_api/src/api/content_i18n/locales/cs.ts @@ -2,7 +2,7 @@ import {defineContentI18nLocaleMessages} from '../ContentI18nMessages'; -export const CONTENT_I18N_CS_MESSAGES = defineContentI18nLocaleMessages({ +const CONTENT_I18N_CS_MESSAGES = defineContentI18nLocaleMessages({ "billing.eu_withdrawal_waiver_checkout": "Pokud jsem spotřebitelem z EU/EHP, výslovně souhlasím s tím, že digitální obsah {product_name} {premium_tier_name} bude poskytnut okamžitě, a beru na vědomí, že po poskytnutí přístupu ztrácím zákonné právo na odstoupení od smlouvy. Tím nejsou dotčena další povinná práva spotřebitele. Viz [Podmínky služby]({terms_url}).", "bulk_message_deletion.complete": "Dokončili jsme mazání tvých zpráv. Odstranili jsme {message_count, plural, =0 {0 zpráv} one {# zprávu} few {# zprávy} many {# zpráv} other {# zpráv}} z {channel_count, plural, =0 {0 míst} one {# místa} few {# míst} many {# míst} other {# míst}}.", "content.virus_detected": "Tento soubor byl označen jako potenciálně nebezpečný a byl odstraněn.", diff --git a/fluxer_api/src/api/content_i18n/locales/da.ts b/fluxer_api/src/api/content_i18n/locales/da.ts index 23b9a160e..e1f1c516c 100644 --- a/fluxer_api/src/api/content_i18n/locales/da.ts +++ b/fluxer_api/src/api/content_i18n/locales/da.ts @@ -2,7 +2,7 @@ import {defineContentI18nLocaleMessages} from '../ContentI18nMessages'; -export const CONTENT_I18N_DA_MESSAGES = defineContentI18nLocaleMessages({ +const CONTENT_I18N_DA_MESSAGES = defineContentI18nLocaleMessages({ "billing.eu_withdrawal_waiver_checkout": "Hvis jeg er en EU/EØS-forbruger, giver jeg udtrykkeligt samtykke til, at {product_name}s {premium_tier_name}-abonnement digitalt indhold leveres øjeblikkeligt, og jeg anerkender, at jeg mister min lovbestemte fortrydelsesret, når adgangen gives. Dette påvirker ikke andre ufravigelige forbrugerrettigheder. Se [servicevilkårene]({terms_url}).", "bulk_message_deletion.complete": "Vi er færdige med at slette dine beskeder. Vi fjernede {message_count, plural, =0 {0 beskeder} one {# besked} other {# beskeder}} fra {channel_count, plural, =0 {0 steder} one {# sted} other {# steder}}.", "content.virus_detected": "Den fil blev markeret som potentielt usikker og er blevet fjernet.", diff --git a/fluxer_api/src/api/content_i18n/locales/de.ts b/fluxer_api/src/api/content_i18n/locales/de.ts index 8b5abe710..52a6536c6 100644 --- a/fluxer_api/src/api/content_i18n/locales/de.ts +++ b/fluxer_api/src/api/content_i18n/locales/de.ts @@ -2,7 +2,7 @@ import {defineContentI18nLocaleMessages} from '../ContentI18nMessages'; -export const CONTENT_I18N_DE_MESSAGES = defineContentI18nLocaleMessages({ +const CONTENT_I18N_DE_MESSAGES = defineContentI18nLocaleMessages({ "billing.eu_withdrawal_waiver_checkout": "Als EU/EWR-Verbraucher stimmst du ausdrücklich zu, dass {product_name} {premium_tier_name} digitale Inhalte sofort bereitgestellt werden, und erkennst an, dass dein gesetzliches Widerrufsrecht erlischt, sobald der Zugriff gewährt wird. Dies berührt nicht andere zwingende Verbraucherrechte. Sieh dir die [Nutzungsbedingungen]({terms_url}) an.", "bulk_message_deletion.complete": "Wir haben deine Nachrichten gelöscht. Entfernt wurden {message_count, plural, =0 {0 Nachrichten} one {# Nachricht} other {# Nachrichten}} aus {channel_count, plural, =0 {0 Orten} one {# Ort} other {# Orten}}.", "content.virus_detected": "Diese Datei wurde als potenziell unsicher eingestuft und entfernt.", diff --git a/fluxer_api/src/api/content_i18n/locales/el.ts b/fluxer_api/src/api/content_i18n/locales/el.ts index 4ef66eece..a60ca9335 100644 --- a/fluxer_api/src/api/content_i18n/locales/el.ts +++ b/fluxer_api/src/api/content_i18n/locales/el.ts @@ -2,7 +2,7 @@ import {defineContentI18nLocaleMessages} from '../ContentI18nMessages'; -export const CONTENT_I18N_EL_MESSAGES = defineContentI18nLocaleMessages({ +const CONTENT_I18N_EL_MESSAGES = defineContentI18nLocaleMessages({ "billing.eu_withdrawal_waiver_checkout": "Αν είμαι καταναλωτής ΕΕ/ΕΟΧ, συναινώ ρητά στην άμεση παροχή του ψηφιακού περιεχομένου του πλάνου {premium_tier_name} του {product_name} και αναγνωρίζω ότι χάνω το νόμιμο δικαίωμα υπαναχώρησης μόλις παρασχεθεί η πρόσβαση. Αυτό δεν επηρεάζει άλλα υποχρεωτικά δικαιώματα των καταναλωτών. Ανατρέξτε στους [Όρους Παροχής Υπηρεσιών]({terms_url}).", "bulk_message_deletion.complete": "Ολοκληρώσαμε τη διαγραφή των μηνυμάτων σου. Αφαιρέσαμε {message_count, plural, =0 {0 μηνύματα} one {# μήνυμα} other {# μηνύματα}} από {channel_count, plural, =0 {0 τοποθεσίες} one {# τοποθεσία} other {# τοποθεσίες}}.", "content.virus_detected": "Αυτό το αρχείο επισημάνθηκε ως δυνητικά μη ασφαλές και έχει αφαιρεθεί.", diff --git a/fluxer_api/src/api/content_i18n/locales/en-GB.ts b/fluxer_api/src/api/content_i18n/locales/en-GB.ts index 90a8c689a..0bf79c1dc 100644 --- a/fluxer_api/src/api/content_i18n/locales/en-GB.ts +++ b/fluxer_api/src/api/content_i18n/locales/en-GB.ts @@ -2,7 +2,7 @@ import {defineContentI18nLocaleMessages} from '../ContentI18nMessages'; -export const CONTENT_I18N_EN_GB_MESSAGES = defineContentI18nLocaleMessages({ +const CONTENT_I18N_EN_GB_MESSAGES = defineContentI18nLocaleMessages({ "billing.eu_withdrawal_waiver_checkout": "If I am an EU/EEA consumer, I expressly consent to {product_name} {premium_tier_name} digital content being provided immediately and acknowledge that I lose my statutory withdrawal right once access is provided. This does not affect other mandatory consumer rights. See the [Terms of Service]({terms_url}).", "bulk_message_deletion.complete": "We've finished deleting your messages. We removed {message_count, plural, =0 {0 messages} one {# message} other {# messages}} from {channel_count, plural, =0 {0 places} one {# place} other {# places}}.", "content.virus_detected": "That file was flagged as potentially unsafe and has been removed.", diff --git a/fluxer_api/src/api/content_i18n/locales/es-419.ts b/fluxer_api/src/api/content_i18n/locales/es-419.ts index 11c4e822e..bd0daf4c9 100644 --- a/fluxer_api/src/api/content_i18n/locales/es-419.ts +++ b/fluxer_api/src/api/content_i18n/locales/es-419.ts @@ -2,7 +2,7 @@ import {defineContentI18nLocaleMessages} from '../ContentI18nMessages'; -export const CONTENT_I18N_ES_419_MESSAGES = defineContentI18nLocaleMessages({ +const CONTENT_I18N_ES_419_MESSAGES = defineContentI18nLocaleMessages({ "billing.eu_withdrawal_waiver_checkout": "Si soy un consumidor de la UE/EEE, doy mi consentimiento expreso para que el contenido digital de {product_name} {premium_tier_name} se proporcione de inmediato y reconozco que pierdo mi derecho legal de desistimiento una vez que se otorgue el acceso. Esto no afecta otros derechos de consumo obligatorios. Consulta los [Términos de servicio]({terms_url}).", "bulk_message_deletion.complete": "Terminamos de eliminar tus mensajes. Eliminamos {message_count, plural, =0 {0 mensajes} one {# mensaje} other {# mensajes}} de {channel_count, plural, =0 {0 lugares} one {# lugar} other {# lugares}}.", "content.virus_detected": "Ese archivo fue marcado como potencialmente inseguro y se ha eliminado.", diff --git a/fluxer_api/src/api/content_i18n/locales/es-ES.ts b/fluxer_api/src/api/content_i18n/locales/es-ES.ts index 03c7dd092..18219b489 100644 --- a/fluxer_api/src/api/content_i18n/locales/es-ES.ts +++ b/fluxer_api/src/api/content_i18n/locales/es-ES.ts @@ -2,7 +2,7 @@ import {defineContentI18nLocaleMessages} from '../ContentI18nMessages'; -export const CONTENT_I18N_ES_ES_MESSAGES = defineContentI18nLocaleMessages({ +const CONTENT_I18N_ES_ES_MESSAGES = defineContentI18nLocaleMessages({ "billing.eu_withdrawal_waiver_checkout": "Si soy un consumidor de la UE/EEE, doy mi consentimiento expreso para que el contenido digital de {product_name} {premium_tier_name} se proporcione de inmediato y reconozco que pierdo mi derecho legal de desistimiento una vez que se conceda el acceso. Esto no afecta a otros derechos de consumo obligatorios. Consulta los [Términos del servicio]({terms_url}).", "bulk_message_deletion.complete": "Hemos terminado de eliminar tus mensajes. Hemos eliminado {message_count, plural, =0 {0 mensajes} one {# mensaje} other {# mensajes}} de {channel_count, plural, =0 {0 sitios} one {# sitio} other {# sitios}}.", "content.virus_detected": "Ese archivo se ha marcado como potencialmente inseguro y se ha eliminado.", diff --git a/fluxer_api/src/api/content_i18n/locales/fi.ts b/fluxer_api/src/api/content_i18n/locales/fi.ts index a025c2da0..4bf384cf9 100644 --- a/fluxer_api/src/api/content_i18n/locales/fi.ts +++ b/fluxer_api/src/api/content_i18n/locales/fi.ts @@ -2,7 +2,7 @@ import {defineContentI18nLocaleMessages} from '../ContentI18nMessages'; -export const CONTENT_I18N_FI_MESSAGES = defineContentI18nLocaleMessages({ +const CONTENT_I18N_FI_MESSAGES = defineContentI18nLocaleMessages({ "billing.eu_withdrawal_waiver_checkout": "Jos olen EU/ETA-kuluttaja, annan nimenomaisen suostumukseni sille, että {product_name}-tuotteen {premium_tier_name} digitaalinen sisältö toimitetaan välittömästi, ja hyväksyn, että menetän lakisääteisen peruutusoikeuteni, kun pääsy on myönnetty. Tämä ei vaikuta muihin pakollisiin kuluttajaoikeuksiin. Katso [käyttöehdot]({terms_url}).", "bulk_message_deletion.complete": "Olemme poistaneet viestisi. Poistimme {message_count, plural, =0 {0 viestiä} one {# viestin} other {# viestiä}} {channel_count, plural, =0 {0 paikasta} one {# paikasta} other {# paikasta}}.", "content.virus_detected": "Tiedosto merkittiin mahdollisesti vaaralliseksi ja se on poistettu.", diff --git a/fluxer_api/src/api/content_i18n/locales/fr.ts b/fluxer_api/src/api/content_i18n/locales/fr.ts index 35fad87e3..b29f11106 100644 --- a/fluxer_api/src/api/content_i18n/locales/fr.ts +++ b/fluxer_api/src/api/content_i18n/locales/fr.ts @@ -2,7 +2,7 @@ import {defineContentI18nLocaleMessages} from '../ContentI18nMessages'; -export const CONTENT_I18N_FR_MESSAGES = defineContentI18nLocaleMessages({ +const CONTENT_I18N_FR_MESSAGES = defineContentI18nLocaleMessages({ "billing.eu_withdrawal_waiver_checkout": "En tant que consommateur UE/EEE, je consens expressément à ce que le contenu numérique {product_name} {premium_tier_name} soit fourni immédiatement et reconnais perdre mon droit de rétractation légal dès l'accès fourni. Cela n'affecte pas les autres droits impératifs des consommateurs. Voir les [Conditions d'utilisation]({terms_url}).", "bulk_message_deletion.complete": "Nous avons terminé la suppression de tes messages. Nous avons retiré {message_count, plural, =0 {0 message} one {# message} other {# messages}} dans {channel_count, plural, =0 {0 endroit} one {# endroit} other {# endroits}}.", "content.virus_detected": "Ce fichier a été signalé comme potentiellement dangereux et a été supprimé.", diff --git a/fluxer_api/src/api/content_i18n/locales/he.ts b/fluxer_api/src/api/content_i18n/locales/he.ts index 58780f632..079376eb7 100644 --- a/fluxer_api/src/api/content_i18n/locales/he.ts +++ b/fluxer_api/src/api/content_i18n/locales/he.ts @@ -2,7 +2,7 @@ import {defineContentI18nLocaleMessages} from '../ContentI18nMessages'; -export const CONTENT_I18N_HE_MESSAGES = defineContentI18nLocaleMessages({ +const CONTENT_I18N_HE_MESSAGES = defineContentI18nLocaleMessages({ "billing.eu_withdrawal_waiver_checkout": "אם אני צרכן באיחוד האירופי/EEA, אני מסכים במפורש לכך שתוכן דיגיטלי של {product_name} {premium_tier_name} יסופק באופן מיידי ומאשר שאני מאבד את זכות הביטול הסטטוטורית שלי מרגע שהגישה ניתנת. אין בכך כדי לפגוע בזכויות צרכניות מחייבות אחרות. ראו [תנאי השירות]({terms_url}).", "bulk_message_deletion.complete": "סיימנו למחוק את ההודעות שלך. הסרנו {message_count, plural, =0 {0 הודעות} one {הודעה אחת} two {שתי הודעות} other {# הודעות}} מתוך {channel_count, plural, =0 {0 מקומות} one {מקום אחד} two {שני מקומות} other {# מקומות}}.", "content.virus_detected": "הקובץ הזה סומן כחשוד והוסר.", diff --git a/fluxer_api/src/api/content_i18n/locales/hi.ts b/fluxer_api/src/api/content_i18n/locales/hi.ts index 73709aeed..0b86f7086 100644 --- a/fluxer_api/src/api/content_i18n/locales/hi.ts +++ b/fluxer_api/src/api/content_i18n/locales/hi.ts @@ -2,7 +2,7 @@ import {defineContentI18nLocaleMessages} from '../ContentI18nMessages'; -export const CONTENT_I18N_HI_MESSAGES = defineContentI18nLocaleMessages({ +const CONTENT_I18N_HI_MESSAGES = defineContentI18nLocaleMessages({ "billing.eu_withdrawal_waiver_checkout": "अगर मैं EU/EEA का उपभोक्ता हूँ, तो मैं {product_name} {premium_tier_name} डिजिटल कंटेंट को तुरंत उपलब्ध कराने के लिए स्पष्ट रूप से सहमति देता हूँ और स्वीकार करता हूँ कि एक्सेस मिलने के बाद मेरा वैधानिक वापसी का अधिकार समाप्त हो जाता है। इससे अन्य अनिवार्य उपभोक्ता अधिकार प्रभावित नहीं होते। [सेवा की शर्तें]({terms_url}) देखें।", "bulk_message_deletion.complete": "हमने आपके संदेश हटाने का काम पूरा कर लिया है। हमने {channel_count, plural, =0 {0 जगहों से} one {# जगह से} other {# जगहों से}} {message_count, plural, =0 {0 संदेश} one {# संदेश} other {# संदेश}} हटा दिए।", "content.virus_detected": "वह फाइल संभावित रूप से असुरक्षित पाई गई और उसे हटा दिया गया है।", diff --git a/fluxer_api/src/api/content_i18n/locales/hr.ts b/fluxer_api/src/api/content_i18n/locales/hr.ts index 42e1642d5..7f04264c4 100644 --- a/fluxer_api/src/api/content_i18n/locales/hr.ts +++ b/fluxer_api/src/api/content_i18n/locales/hr.ts @@ -2,7 +2,7 @@ import {defineContentI18nLocaleMessages} from '../ContentI18nMessages'; -export const CONTENT_I18N_HR_MESSAGES = defineContentI18nLocaleMessages({ +const CONTENT_I18N_HR_MESSAGES = defineContentI18nLocaleMessages({ "billing.eu_withdrawal_waiver_checkout": "Ako si potrošač iz EU/EEA, izričito pristaješ na trenutačnu isporuku digitalnog sadržaja {product_name} pretplate {premium_tier_name} i prihvaćaš da gubiš zakonsko pravo na odustanak čim ti se omogući pristup. To ne utječe na ostala obvezna potrošačka prava. Pogledaj [Uvjete pružanja usluge]({terms_url}).", "bulk_message_deletion.complete": "Završili smo s brisanjem tvojih poruka. Uklonili smo {message_count, plural, =0 {0 poruka} one {# poruku} few {# poruke} other {# poruka}} iz {channel_count, plural, =0 {0 mjesta} one {# mjesta} few {# mjesta} other {# mjesta}}.", "content.virus_detected": "Ta je datoteka označena kao potencijalno nesigurna i uklonjena je.", diff --git a/fluxer_api/src/api/content_i18n/locales/hu.ts b/fluxer_api/src/api/content_i18n/locales/hu.ts index b2a86f369..3dc475ebb 100644 --- a/fluxer_api/src/api/content_i18n/locales/hu.ts +++ b/fluxer_api/src/api/content_i18n/locales/hu.ts @@ -2,7 +2,7 @@ import {defineContentI18nLocaleMessages} from '../ContentI18nMessages'; -export const CONTENT_I18N_HU_MESSAGES = defineContentI18nLocaleMessages({ +const CONTENT_I18N_HU_MESSAGES = defineContentI18nLocaleMessages({ "billing.eu_withdrawal_waiver_checkout": "Ha EU/EGT-fogyasztó vagyok, kifejezetten hozzájárulok ahhoz, hogy a {product_name} {premium_tier_name} digitális tartalmat azonnal biztosítsák, és tudomásul veszem, hogy a hozzáférés megadásával elveszítem a törvényes elállási jogomat. Ez nem érinti a többi kötelező fogyasztói jogot. Lásd a [Felhasználási feltételeket]({terms_url}).", "bulk_message_deletion.complete": "Befejeztük az üzeneteid törlését. Eltávolítottunk {message_count, plural, =0 {0 üzenetet} one {# üzenetet} other {# üzenetet}} {channel_count, plural, =0 {0 helyről} one {# helyről} other {# helyről}}.", "content.virus_detected": "A fájl potenciálisan veszélyesnek minősült, ezért eltávolítottuk.", diff --git a/fluxer_api/src/api/content_i18n/locales/id.ts b/fluxer_api/src/api/content_i18n/locales/id.ts index ecca95343..21b65a313 100644 --- a/fluxer_api/src/api/content_i18n/locales/id.ts +++ b/fluxer_api/src/api/content_i18n/locales/id.ts @@ -2,7 +2,7 @@ import {defineContentI18nLocaleMessages} from '../ContentI18nMessages'; -export const CONTENT_I18N_ID_MESSAGES = defineContentI18nLocaleMessages({ +const CONTENT_I18N_ID_MESSAGES = defineContentI18nLocaleMessages({ "billing.eu_withdrawal_waiver_checkout": "Jika saya konsumen EU/EEA, saya setuju konten digital {product_name} paket {premium_tier_name} diberikan segera dan mengakui bahwa saya kehilangan hak pembatalan begitu akses diberikan. Ini tidak memengaruhi hak konsumen wajib lainnya. Lihat [Ketentuan Layanan]({terms_url}).", "bulk_message_deletion.complete": "Kami sudah selesai menghapus pesanmu. Kami menghapus {message_count, plural, =0 {0 pesan} other {# pesan}} dari {channel_count, plural, =0 {0 tempat} other {# tempat}}.", "content.virus_detected": "File itu terdeteksi tidak aman dan telah dihapus.", diff --git a/fluxer_api/src/api/content_i18n/locales/it.ts b/fluxer_api/src/api/content_i18n/locales/it.ts index 659d870aa..32e481705 100644 --- a/fluxer_api/src/api/content_i18n/locales/it.ts +++ b/fluxer_api/src/api/content_i18n/locales/it.ts @@ -2,7 +2,7 @@ import {defineContentI18nLocaleMessages} from '../ContentI18nMessages'; -export const CONTENT_I18N_IT_MESSAGES = defineContentI18nLocaleMessages({ +const CONTENT_I18N_IT_MESSAGES = defineContentI18nLocaleMessages({ "billing.eu_withdrawal_waiver_checkout": "Se sono un consumatore UE/SEE, acconsento espressamente alla fornitura immediata del contenuto digitale {product_name} {premium_tier_name} e riconosco di perdere il mio diritto di recesso legale una volta che l'accesso viene fornito. Ciò non pregiudica altri diritti dei consumatori previsti dalla legge. Vedi i [Termini di servizio]({terms_url}).", "bulk_message_deletion.complete": "Abbiamo finito di eliminare i tuoi messaggi. Abbiamo rimosso {message_count, plural, =0 {0 messaggi} one {# messaggio} other {# messaggi}} da {channel_count, plural, =0 {0 posti} one {# posto} other {# posti}}.", "content.virus_detected": "Il file è stato segnalato come potenzialmente pericoloso ed è stato rimosso.", diff --git a/fluxer_api/src/api/content_i18n/locales/ja.ts b/fluxer_api/src/api/content_i18n/locales/ja.ts index 1ad0088b9..a22aeba09 100644 --- a/fluxer_api/src/api/content_i18n/locales/ja.ts +++ b/fluxer_api/src/api/content_i18n/locales/ja.ts @@ -2,7 +2,7 @@ import {defineContentI18nLocaleMessages} from '../ContentI18nMessages'; -export const CONTENT_I18N_JA_MESSAGES = defineContentI18nLocaleMessages({ +const CONTENT_I18N_JA_MESSAGES = defineContentI18nLocaleMessages({ "billing.eu_withdrawal_waiver_checkout": "私が EU/EEA の消費者である場合、{product_name} {premium_tier_name} のデジタルコンテンツが直ちに提供されることに明示的に同意し、アクセスが提供された時点で法定のクーリングオフ権を失うことを承諾します。これはその他の強制的な消費者権利に影響を与えません。[利用規約]({terms_url})をご確認ください。", "bulk_message_deletion.complete": "メッセージの削除が完了しました。{channel_count, plural, =0 {0 件の場所から} other {# 件の場所から}}{message_count, plural, =0 {0 件のメッセージを削除しました} other {# 件のメッセージを削除しました}}。", "content.virus_detected": "そのファイルは安全でないと判断されたため、削除されました。", diff --git a/fluxer_api/src/api/content_i18n/locales/ko.ts b/fluxer_api/src/api/content_i18n/locales/ko.ts index 0c33faf21..ce940e316 100644 --- a/fluxer_api/src/api/content_i18n/locales/ko.ts +++ b/fluxer_api/src/api/content_i18n/locales/ko.ts @@ -2,7 +2,7 @@ import {defineContentI18nLocaleMessages} from '../ContentI18nMessages'; -export const CONTENT_I18N_KO_MESSAGES = defineContentI18nLocaleMessages({ +const CONTENT_I18N_KO_MESSAGES = defineContentI18nLocaleMessages({ "billing.eu_withdrawal_waiver_checkout": "EU/EEA 소비자로서 {product_name} {premium_tier_name} 디지털 콘텐츠를 즉시 제공받는 데 명시적으로 동의하며, 액세스가 제공된 후에는 법정 철회권을 상실함을 인정합니다. 이는 다른 필수 소비자 권리에 영향을 미치지 않습니다. [서비스 약관]({terms_url})을 확인하세요.", "bulk_message_deletion.complete": "메시지 삭제를 완료했습니다. {channel_count, plural, =0 {0 곳에서} other {# 곳에서}} {message_count, plural, =0 {0 개의 메시지를 삭제했습니다} other {# 개의 메시지를 삭제했습니다}}.", "content.virus_detected": "해당 파일은 잠재적으로 안전하지 않은 것으로 확인되어 삭제되었어요.", diff --git a/fluxer_api/src/api/content_i18n/locales/lt.ts b/fluxer_api/src/api/content_i18n/locales/lt.ts index 53a45fb57..451645374 100644 --- a/fluxer_api/src/api/content_i18n/locales/lt.ts +++ b/fluxer_api/src/api/content_i18n/locales/lt.ts @@ -2,7 +2,7 @@ import {defineContentI18nLocaleMessages} from '../ContentI18nMessages'; -export const CONTENT_I18N_LT_MESSAGES = defineContentI18nLocaleMessages({ +const CONTENT_I18N_LT_MESSAGES = defineContentI18nLocaleMessages({ "billing.eu_withdrawal_waiver_checkout": "Jei esu ES/EEE vartotojas, aiškiai sutinku, kad {product_name} {premium_tier_name} skaitmeninis turinys būtų suteiktas nedelsiant ir pripažįstu, kad, suteikus prieigą, netenku teisės atsisakyti sutarties. Tai neturi įtakos kitoms privalomoms vartotojų teisėms. Žr. [Paslaugų teikimo sąlygas]({terms_url}).", "bulk_message_deletion.complete": "Baigėme trinti tavo žinutes. Pašalinome {message_count, plural, =0 {0 žinučių} one {# žinutę} few {# žinutes} many {# žinutės} other {# žinučių}} iš {channel_count, plural, =0 {0 vietų} one {# vietos} few {# vietų} many {# vietos} other {# vietų}}.", "content.virus_detected": "Failas buvo pažymėtas kaip galimai nesaugus ir pašalintas.", diff --git a/fluxer_api/src/api/content_i18n/locales/nl.ts b/fluxer_api/src/api/content_i18n/locales/nl.ts index 1855859eb..cd35692a2 100644 --- a/fluxer_api/src/api/content_i18n/locales/nl.ts +++ b/fluxer_api/src/api/content_i18n/locales/nl.ts @@ -2,7 +2,7 @@ import {defineContentI18nLocaleMessages} from '../ContentI18nMessages'; -export const CONTENT_I18N_NL_MESSAGES = defineContentI18nLocaleMessages({ +const CONTENT_I18N_NL_MESSAGES = defineContentI18nLocaleMessages({ "billing.eu_withdrawal_waiver_checkout": "Als ik een EU/EER-consument ben, geef ik uitdrukkelijk toestemming dat de digitale inhoud van {product_name} {premium_tier_name} onmiddellijk wordt geleverd en erken ik dat ik mijn wettelijke herroepingsrecht verlies zodra toegang wordt verleend. Dit heeft geen invloed op andere dwingende consumentenrechten. Zie de [Servicevoorwaarden]({terms_url}).", "bulk_message_deletion.complete": "We zijn klaar met het verwijderen van je berichten. We hebben {message_count, plural, =0 {0 berichten} one {# bericht} other {# berichten}} verwijderd uit {channel_count, plural, =0 {0 plekken} one {# plek} other {# plekken}}.", "content.virus_detected": "Dat bestand is gemarkeerd als mogelijk onveilig en is verwijderd.", diff --git a/fluxer_api/src/api/content_i18n/locales/no.ts b/fluxer_api/src/api/content_i18n/locales/no.ts index b9420fc89..3a2a15a08 100644 --- a/fluxer_api/src/api/content_i18n/locales/no.ts +++ b/fluxer_api/src/api/content_i18n/locales/no.ts @@ -2,7 +2,7 @@ import {defineContentI18nLocaleMessages} from '../ContentI18nMessages'; -export const CONTENT_I18N_NO_MESSAGES = defineContentI18nLocaleMessages({ +const CONTENT_I18N_NO_MESSAGES = defineContentI18nLocaleMessages({ "billing.eu_withdrawal_waiver_checkout": "Hvis jeg er en EU/EØS-forbruker, samtykker jeg uttrykkelig til at {product_name} {premium_tier_name} digitalt innhold leveres umiddelbart, og erkjenner at jeg mister min lovbestemte angrerett når tilgangen er gitt. Dette påvirker ikke andre lovpålagte forbrukerrettigheter. Se [tjenestevilkårene]({terms_url}).", "bulk_message_deletion.complete": "Vi er ferdige med å slette meldingene dine. Vi fjernet {message_count, plural, =0 {0 meldinger} one {# melding} other {# meldinger}} fra {channel_count, plural, =0 {0 steder} one {# sted} other {# steder}}.", "content.virus_detected": "Filen ble flagget som potensielt utrygg og er fjernet.", diff --git a/fluxer_api/src/api/content_i18n/locales/pl.ts b/fluxer_api/src/api/content_i18n/locales/pl.ts index de33b28fa..8b1a46985 100644 --- a/fluxer_api/src/api/content_i18n/locales/pl.ts +++ b/fluxer_api/src/api/content_i18n/locales/pl.ts @@ -2,7 +2,7 @@ import {defineContentI18nLocaleMessages} from '../ContentI18nMessages'; -export const CONTENT_I18N_PL_MESSAGES = defineContentI18nLocaleMessages({ +const CONTENT_I18N_PL_MESSAGES = defineContentI18nLocaleMessages({ "billing.eu_withdrawal_waiver_checkout": "Jako konsument z UE/EOG zgadzam się na natychmiastowe dostarczenie treści cyfrowych {product_name} {premium_tier_name} i przyjmuję do wiadomości, że po uzyskaniu dostępu tracę ustawowe prawo do odstąpienia od umowy. Nie wpływa to na inne obowiązkowe prawa konsumenta. Zobacz [Warunki użytkowania]({terms_url}).", "bulk_message_deletion.complete": "Zakończyliśmy usuwanie Twoich wiadomości. Usunęliśmy {message_count, plural, =0 {0 wiadomości} one {# wiadomość} few {# wiadomości} many {# wiadomości} other {# wiadomości}} z {channel_count, plural, =0 {0 miejsc} one {# miejsca} few {# miejsc} many {# miejsc} other {# miejsc}}.", "content.virus_detected": "Ten plik został oznaczony jako potencjalnie niebezpieczny i został usunięty.", diff --git a/fluxer_api/src/api/content_i18n/locales/pt-BR.ts b/fluxer_api/src/api/content_i18n/locales/pt-BR.ts index 99df284de..6dd390272 100644 --- a/fluxer_api/src/api/content_i18n/locales/pt-BR.ts +++ b/fluxer_api/src/api/content_i18n/locales/pt-BR.ts @@ -2,7 +2,7 @@ import {defineContentI18nLocaleMessages} from '../ContentI18nMessages'; -export const CONTENT_I18N_PT_BR_MESSAGES = defineContentI18nLocaleMessages({ +const CONTENT_I18N_PT_BR_MESSAGES = defineContentI18nLocaleMessages({ "billing.eu_withdrawal_waiver_checkout": "Se eu for um consumidor da UE/EEE, consinto expressamente que o conteúdo digital {product_name} {premium_tier_name} seja fornecido imediatamente e reconheço que perco meu direito legal de arrependimento assim que o acesso for concedido. Isso não afeta outros direitos obrigatórios do consumidor. Consulte os [Termos de Serviço]({terms_url}).", "bulk_message_deletion.complete": "Terminamos de excluir suas mensagens. Removemos {message_count, plural, =0 {0 mensagens} one {# mensagem} other {# mensagens}} de {channel_count, plural, =0 {0 lugares} one {# lugar} other {# lugares}}.", "content.virus_detected": "Esse arquivo foi sinalizado como potencialmente inseguro e foi removido.", diff --git a/fluxer_api/src/api/content_i18n/locales/ro.ts b/fluxer_api/src/api/content_i18n/locales/ro.ts index aaa9cb507..99d9d05f8 100644 --- a/fluxer_api/src/api/content_i18n/locales/ro.ts +++ b/fluxer_api/src/api/content_i18n/locales/ro.ts @@ -2,7 +2,7 @@ import {defineContentI18nLocaleMessages} from '../ContentI18nMessages'; -export const CONTENT_I18N_RO_MESSAGES = defineContentI18nLocaleMessages({ +const CONTENT_I18N_RO_MESSAGES = defineContentI18nLocaleMessages({ "billing.eu_withdrawal_waiver_checkout": "Dacă sunt un consumator din UE/SEE, îmi exprim consimțământul expres ca conținutul digital {product_name} {premium_tier_name} să fie furnizat imediat și recunosc că pierd dreptul legal de retragere odată ce accesul este acordat. Acest lucru nu afectează alte drepturi obligatorii ale consumatorilor. Vezi [Termenii și condițiile]({terms_url}).", "bulk_message_deletion.complete": "Am terminat de șters mesajele tale. Am eliminat {message_count, plural, =0 {0 de mesaje} one {# mesaj} few {# mesaje} other {# de mesaje}} din {channel_count, plural, =0 {0 de locuri} one {# loc} few {# locuri} other {# de locuri}}.", "content.virus_detected": "Acest fișier a fost marcat ca potențial nesigur și a fost eliminat.", diff --git a/fluxer_api/src/api/content_i18n/locales/ru.ts b/fluxer_api/src/api/content_i18n/locales/ru.ts index b4992b14c..02d9f9ebb 100644 --- a/fluxer_api/src/api/content_i18n/locales/ru.ts +++ b/fluxer_api/src/api/content_i18n/locales/ru.ts @@ -2,7 +2,7 @@ import {defineContentI18nLocaleMessages} from '../ContentI18nMessages'; -export const CONTENT_I18N_RU_MESSAGES = defineContentI18nLocaleMessages({ +const CONTENT_I18N_RU_MESSAGES = defineContentI18nLocaleMessages({ "billing.eu_withdrawal_waiver_checkout": "Если ты являешься потребителем из ЕС/ЕЭЗ, ты даёшь явное согласие на немедленное предоставление цифрового контента {product_name} {premium_tier_name} и понимаешь, что теряешь законное право на отмены после получения доступа. Это не затрагивает другие обязательные права потребителя. См. [Условия предоставления услуг]({terms_url}).", "bulk_message_deletion.complete": "Мы завершили удаление ваших сообщений. Удалено {message_count, plural, =0 {0 сообщений} one {# сообщение} few {# сообщения} many {# сообщений} other {# сообщений}} из {channel_count, plural, =0 {0 мест} one {# места} few {# мест} many {# мест} other {# мест}}.", "content.virus_detected": "Этот файл был отмечен как потенциально опасный и удалён.", diff --git a/fluxer_api/src/api/content_i18n/locales/sv-SE.ts b/fluxer_api/src/api/content_i18n/locales/sv-SE.ts index 3d29d645a..c10a045c3 100644 --- a/fluxer_api/src/api/content_i18n/locales/sv-SE.ts +++ b/fluxer_api/src/api/content_i18n/locales/sv-SE.ts @@ -2,7 +2,7 @@ import {defineContentI18nLocaleMessages} from '../ContentI18nMessages'; -export const CONTENT_I18N_SV_SE_MESSAGES = defineContentI18nLocaleMessages({ +const CONTENT_I18N_SV_SE_MESSAGES = defineContentI18nLocaleMessages({ "billing.eu_withdrawal_waiver_checkout": "Om jag är en EU/EES-konsument samtycker jag uttryckligen till att {product_name} {premium_tier_name} digitalt innehåll tillhandahålls omedelbart och bekräftar att jag förlorar min lagstadgade ångerrätt när åtkomst ges. Detta påverkar inte andra tvingande konsumenträttigheter. Se [användarvillkoren]({terms_url}).", "bulk_message_deletion.complete": "Vi har raderat dina meddelanden. Vi tog bort {message_count, plural, =0 {0 meddelanden} one {# meddelande} other {# meddelanden}} från {channel_count, plural, =0 {0 platser} one {# plats} other {# platser}}.", "content.virus_detected": "Filen flaggades som potentiellt osäker och har tagits bort.", diff --git a/fluxer_api/src/api/content_i18n/locales/th.ts b/fluxer_api/src/api/content_i18n/locales/th.ts index da3fdebfa..e872caa13 100644 --- a/fluxer_api/src/api/content_i18n/locales/th.ts +++ b/fluxer_api/src/api/content_i18n/locales/th.ts @@ -2,7 +2,7 @@ import {defineContentI18nLocaleMessages} from '../ContentI18nMessages'; -export const CONTENT_I18N_TH_MESSAGES = defineContentI18nLocaleMessages({ +const CONTENT_I18N_TH_MESSAGES = defineContentI18nLocaleMessages({ "billing.eu_withdrawal_waiver_checkout": "หากฉันเป็นผู้บริโภคใน EU/EEA ฉันยินยอมให้มีการให้บริการเนื้อหาดิจิทัล {product_name} {premium_tier_name} ทันที และรับทราบว่าฉันสูญเสียสิทธิ์ในการถอนตัวตามกฎหมายเมื่อมีการให้สิทธิ์การเข้าถึงแล้ว ซึ่งไม่กระทบต่อสิทธิ์ผู้บริโภคอื่นๆ ที่จำเป็น ดู[ข้อกำหนดในการให้บริการ]({terms_url})", "bulk_message_deletion.complete": "ลบข้อความของคุณเรียบร้อยแล้ว เราลบ {message_count, plural, =0 {0 ข้อความ} other {# ข้อความ}} จาก {channel_count, plural, =0 {0 ที่} other {# ที่}}", "content.virus_detected": "ไฟล์นั้นถูกตรวจพบว่าอาจไม่ปลอดภัยและถูกลบออกแล้ว", diff --git a/fluxer_api/src/api/content_i18n/locales/tr.ts b/fluxer_api/src/api/content_i18n/locales/tr.ts index 01da5096b..0692d22eb 100644 --- a/fluxer_api/src/api/content_i18n/locales/tr.ts +++ b/fluxer_api/src/api/content_i18n/locales/tr.ts @@ -2,7 +2,7 @@ import {defineContentI18nLocaleMessages} from '../ContentI18nMessages'; -export const CONTENT_I18N_TR_MESSAGES = defineContentI18nLocaleMessages({ +const CONTENT_I18N_TR_MESSAGES = defineContentI18nLocaleMessages({ "billing.eu_withdrawal_waiver_checkout": "AB/EEA tüketicisiysem, {product_name} {premium_tier_name} dijital içeriğinin hemen sağlanmasına açıkça onay veriyorum ve erişim sağlandıktan sonra yasal cayma hakkımı kaybettiğimi kabul ediyorum. Bu, diğer zorunlu tüketici haklarını etkilemez. [Hizmet Şartları]({terms_url}) sayfasına bakın.", "bulk_message_deletion.complete": "Mesajlarını silme işlemini tamamladık. {channel_count, plural, =0 {0 yerden} one {# yerden} other {# yerden}} {message_count, plural, =0 {0 mesaj} one {# mesaj} other {# mesaj}} kaldırdık.", "content.virus_detected": "Bu dosya potansiyel olarak güvensiz olarak işaretlendi ve kaldırıldı.", diff --git a/fluxer_api/src/api/content_i18n/locales/uk.ts b/fluxer_api/src/api/content_i18n/locales/uk.ts index b51aa89fa..e66b53ac9 100644 --- a/fluxer_api/src/api/content_i18n/locales/uk.ts +++ b/fluxer_api/src/api/content_i18n/locales/uk.ts @@ -2,7 +2,7 @@ import {defineContentI18nLocaleMessages} from '../ContentI18nMessages'; -export const CONTENT_I18N_UK_MESSAGES = defineContentI18nLocaleMessages({ +const CONTENT_I18N_UK_MESSAGES = defineContentI18nLocaleMessages({ "billing.eu_withdrawal_waiver_checkout": "Якщо я є споживачем з ЄС/ЄЕЗ, я надаю явну згоду на негайне надання цифрового контенту {product_name} {premium_tier_name} і визнаю, що втрачаю своє законне право на відмову після отримання доступу. Це не впливає на інші обов'язкові права споживача. Див. [Умови надання послуг]({terms_url}).", "bulk_message_deletion.complete": "Ми завершили видалення твоїх повідомлень. Видалено {message_count, plural, =0 {0 повідомлень} one {# повідомлення} few {# повідомлення} many {# повідомлень} other {# повідомлень}} з {channel_count, plural, =0 {0 місць} one {# місця} few {# місць} many {# місць} other {# місць}}.", "content.virus_detected": "Цей файл позначено як потенційно небезпечний, і його вилучено.", diff --git a/fluxer_api/src/api/content_i18n/locales/vi.ts b/fluxer_api/src/api/content_i18n/locales/vi.ts index b4ff6dbaf..32890755c 100644 --- a/fluxer_api/src/api/content_i18n/locales/vi.ts +++ b/fluxer_api/src/api/content_i18n/locales/vi.ts @@ -2,7 +2,7 @@ import {defineContentI18nLocaleMessages} from '../ContentI18nMessages'; -export const CONTENT_I18N_VI_MESSAGES = defineContentI18nLocaleMessages({ +const CONTENT_I18N_VI_MESSAGES = defineContentI18nLocaleMessages({ "billing.eu_withdrawal_waiver_checkout": "Nếu tôi là người tiêu dùng EU/EEA, tôi đồng ý rõ ràng rằng nội dung kỹ thuật số {product_name} {premium_tier_name} được cung cấp ngay lập tức và thừa nhận rằng tôi mất quyền hủy bỏ theo luật định sau khi có quyền truy cập. Điều này không ảnh hưởng đến các quyền lợi người tiêu dùng bắt buộc khác. Xem [Điều khoản dịch vụ]({terms_url}).", "bulk_message_deletion.complete": "Chúng tôi đã xóa xong tin nhắn của bạn. Đã xóa {message_count, plural, =0 {0 tin nhắn} other {# tin nhắn}} khỏi {channel_count, plural, =0 {0 nơi} other {# nơi}}.", "content.virus_detected": "Tệp đó bị gắn cờ là có khả năng không an toàn và đã bị xóa.", diff --git a/fluxer_api/src/api/content_i18n/locales/zh-CN.ts b/fluxer_api/src/api/content_i18n/locales/zh-CN.ts index 39944c9f3..0c1d8b729 100644 --- a/fluxer_api/src/api/content_i18n/locales/zh-CN.ts +++ b/fluxer_api/src/api/content_i18n/locales/zh-CN.ts @@ -2,7 +2,7 @@ import {defineContentI18nLocaleMessages} from '../ContentI18nMessages'; -export const CONTENT_I18N_ZH_CN_MESSAGES = defineContentI18nLocaleMessages({ +const CONTENT_I18N_ZH_CN_MESSAGES = defineContentI18nLocaleMessages({ "billing.eu_withdrawal_waiver_checkout": "如果我是欧盟/欧洲经济区消费者,我明确同意立即提供 {product_name} {premium_tier_name} 数字内容,并知晓一旦获得访问权限,我将失去法定撤销权。这不影响其他强制性消费者权利。请参阅[服务条款]({terms_url})。", "bulk_message_deletion.complete": "我们已删除你的消息。从 {channel_count, plural, =0 {0 个位置} other {# 个位置}} 中移除了 {message_count, plural, =0 {0 条消息} other {# 条消息}}。", "content.virus_detected": "该文件被标记为可能存在风险,已被移除。", diff --git a/fluxer_api/src/api/content_i18n/locales/zh-TW.ts b/fluxer_api/src/api/content_i18n/locales/zh-TW.ts index dad1be8db..cb8f2dc63 100644 --- a/fluxer_api/src/api/content_i18n/locales/zh-TW.ts +++ b/fluxer_api/src/api/content_i18n/locales/zh-TW.ts @@ -2,7 +2,7 @@ import {defineContentI18nLocaleMessages} from '../ContentI18nMessages'; -export const CONTENT_I18N_ZH_TW_MESSAGES = defineContentI18nLocaleMessages({ +const CONTENT_I18N_ZH_TW_MESSAGES = defineContentI18nLocaleMessages({ "billing.eu_withdrawal_waiver_checkout": "若我是歐盟/歐洲經濟區消費者,我明確同意立即提供 {product_name} {premium_tier_name} 數位內容,並了解一旦取得存取權,即喪失法定撤回權。這不影響其他強制性消費者權益。請參閱[服務條款]({terms_url})。", "bulk_message_deletion.complete": "我們已刪除你的訊息。從 {channel_count, plural, =0 {0 個位置} other {# 個位置}} 中移除了 {message_count, plural, =0 {0 則訊息} other {# 則訊息}}。", "content.virus_detected": "該檔案已被標記為可能不安全,並已移除。", diff --git a/fluxer_api/src/api/database/CassandraQueryExecution.ts b/fluxer_api/src/api/database/CassandraQueryExecution.ts index 189cbc6aa..0f28642e5 100644 --- a/fluxer_api/src/api/database/CassandraQueryExecution.ts +++ b/fluxer_api/src/api/database/CassandraQueryExecution.ts @@ -51,10 +51,6 @@ export function setCassandraQueryExecutorForTesting(executor: CassandraQueryExec injectedExecutorForTesting = executor; } -export function hasCassandraQueryExecutorForTesting(): boolean { - return injectedExecutorForTesting !== null; -} - export function resetCassandraQueryExecutorForTesting(): void { injectedExecutorForTesting?.reset?.(); } diff --git a/fluxer_api/src/api/limits/tests/LimitConfigDefaults.test.ts b/fluxer_api/src/api/limits/tests/LimitConfigDefaults.test.ts index 905393308..54caa4ba5 100644 --- a/fluxer_api/src/api/limits/tests/LimitConfigDefaults.test.ts +++ b/fluxer_api/src/api/limits/tests/LimitConfigDefaults.test.ts @@ -1,5 +1,7 @@ // SPDX-License-Identifier: AGPL-3.0-or-later +import {GuildFeatures} from '@fluxer/constants/src/GuildConstants'; +import {MAX_GUILD_MEMBERS_VERY_LARGE_GUILD} from '@fluxer/constants/src/LimitConstants'; import type {LimitConfigSnapshot, LimitRule} from '@fluxer/limits/src/LimitTypes'; import {describe, expect, test} from 'vitest'; import {createDefaultLimitConfig, mergeWithCurrentDefaults} from '../../constants/LimitConfig'; @@ -13,17 +15,27 @@ interface LegacyLimitConfigSnapshot extends Omit { } describe('Limit config defaults', () => { - test('hosted defaults include only premium and default tier limit rules', () => { + test('hosted defaults include premium, default, and very large guild limit rules', () => { const config = createDefaultLimitConfig({selfHosted: false}); const premiumRule = config.rules.find((rule) => rule.id === 'premium'); const defaultRule = config.rules.find((rule) => rule.id === 'default'); + const veryLargeGuildRule = config.rules.find((rule) => rule.id === 'very_large_guild'); expect(premiumRule).toBeDefined(); expect(defaultRule).toBeDefined(); - expect(config.rules.map((rule) => rule.id)).toEqual(['premium', 'default']); + expect(veryLargeGuildRule).toMatchObject({ + filters: {guildFeatures: [GuildFeatures.VERY_LARGE_GUILD]}, + limits: {max_guild_members: MAX_GUILD_MEMBERS_VERY_LARGE_GUILD}, + }); + expect(config.rules.map((rule) => rule.id)).toEqual(['premium', 'default', 'very_large_guild']); }); - test('self-hosted defaults include only default tier limit rule', () => { + test('self-hosted defaults include default and very large guild limit rules', () => { const config = createDefaultLimitConfig({selfHosted: true}); - expect(config.rules.map((rule) => rule.id)).toEqual(['default']); + const veryLargeGuildRule = config.rules.find((rule) => rule.id === 'very_large_guild'); + expect(veryLargeGuildRule).toMatchObject({ + filters: {guildFeatures: [GuildFeatures.VERY_LARGE_GUILD]}, + limits: {max_guild_members: MAX_GUILD_MEMBERS_VERY_LARGE_GUILD}, + }); + expect(config.rules.map((rule) => rule.id)).toEqual(['default', 'very_large_guild']); }); }); diff --git a/fluxer_app/src/features/app/components/HookOrderStability.test.ts b/fluxer_app/src/features/app/components/HookOrderStability.test.ts index 52e63fd55..5898cc3fb 100644 --- a/fluxer_app/src/features/app/components/HookOrderStability.test.ts +++ b/fluxer_app/src/features/app/components/HookOrderStability.test.ts @@ -205,5 +205,5 @@ function findHookOrderHazards(): Array { describe('React hook order stability', () => { it('keeps guard returns outside hook-bearing component bodies', () => { expect(findHookOrderHazards()).toEqual([]); - }); + }, 10_000); }); diff --git a/fluxer_gateway/rebar.config b/fluxer_gateway/rebar.config index e05a16718..8ae82e969 100644 --- a/fluxer_gateway/rebar.config +++ b/fluxer_gateway/rebar.config @@ -93,7 +93,7 @@ ]}, {plt_apps, all_deps}, {plt_extra_apps, [ - crypto, enats, inets, jose, public_key, ranch, ssl + crypto, enats, erlcass, inets, jose, public_key, ranch, ssl ]}, {warnings_file, "dialyzer.ignore-warnings"} ]}. diff --git a/fluxer_gateway/src/cache/clustered_ets_cache.erl b/fluxer_gateway/src/cache/clustered_ets_cache.erl index 195493bbf..e503de467 100644 --- a/fluxer_gateway/src/cache/clustered_ets_cache.erl +++ b/fluxer_gateway/src/cache/clustered_ets_cache.erl @@ -205,11 +205,9 @@ active_nodes_for_role(undefined) -> active_nodes_for_role(Role) -> gateway_node_router:active_nodes(Role). --spec select_owner_nodes(term(), [node()], pos_integer()) -> [node()]. +-spec select_owner_nodes(term(), [node(), ...], pos_integer()) -> [node()]. select_owner_nodes(Key, CandidateNodes, ReplicaCount) -> case lists:usort(CandidateNodes) of - [] -> - []; [SingleNode] -> [SingleNode]; UniqueNodes when ReplicaCount =:= 1 -> diff --git a/fluxer_gateway/src/fluxer_gateway.app.src b/fluxer_gateway/src/fluxer_gateway.app.src index 03dfc6655..fbf84e394 100644 --- a/fluxer_gateway/src/fluxer_gateway.app.src +++ b/fluxer_gateway/src/fluxer_gateway.app.src @@ -15,6 +15,7 @@ ranch, cowboy, ezstd, + erlcass, base64url, enats ]}, diff --git a/fluxer_gateway/src/gateway/gateway_handler_resume.erl b/fluxer_gateway/src/gateway/gateway_handler_resume.erl index e9d761631..479289cfa 100644 --- a/fluxer_gateway/src/gateway/gateway_handler_resume.erl +++ b/fluxer_gateway/src/gateway/gateway_handler_resume.erl @@ -180,7 +180,7 @@ resume_lookup_trace_meta(SessionId) -> session_pid_trace_meta(Pid) -> node_trace_meta(session, node(Pid)). --spec node_trace_meta(term(), node()) -> map(). +-spec node_trace_meta(atom(), node()) -> map(). node_trace_meta(Operation, NodeName) -> #{ remote => #{ @@ -189,13 +189,9 @@ node_trace_meta(Operation, NodeName) -> } }. --spec trace_key(term()) -> binary(). -trace_key(Value) when is_binary(Value) -> - Value; -trace_key(Value) when is_atom(Value) -> - atom_to_binary(Value, utf8); +-spec trace_key(atom()) -> binary(). trace_key(Value) -> - list_to_binary(io_lib:format("~p", [Value])). + atom_to_binary(Value, utf8). -spec node_pod_name_or_name(node()) -> binary(). node_pod_name_or_name(NodeName) -> diff --git a/fluxer_gateway/src/gateway/gateway_hotpatch_loader.erl b/fluxer_gateway/src/gateway/gateway_hotpatch_loader.erl index 8dc722003..c6b81d49d 100644 --- a/fluxer_gateway/src/gateway/gateway_hotpatch_loader.erl +++ b/fluxer_gateway/src/gateway/gateway_hotpatch_loader.erl @@ -89,7 +89,6 @@ beam_module_from_info(Info) -> beam_md5(Beam) when is_binary(Beam) -> case beam_lib:md5(Beam) of {ok, {_Module, Md5}} when is_binary(Md5) -> {ok, Md5}; - {ok, Md5} when is_binary(Md5) -> {ok, Md5}; Error -> {error, {beam_md5_failed, Error}} end. diff --git a/fluxer_gateway/src/gateway/gateway_hotpatch_store.erl b/fluxer_gateway/src/gateway/gateway_hotpatch_store.erl index 3f8065ef0..7759c70de 100644 --- a/fluxer_gateway/src/gateway/gateway_hotpatch_store.erl +++ b/fluxer_gateway/src/gateway/gateway_hotpatch_store.erl @@ -42,8 +42,7 @@ fetch_events(BuildSha) when is_binary(BuildSha) -> case erlcass:execute(?STMT_FETCH_EVENTS, [BuildSha]) of {ok, _Columns, Rows} -> {ok, normalize_event_rows(Rows)}; ok -> {ok, []}; - {error, Reason} -> {error, Reason}; - Other -> {error, {unexpected_fetch_result, Other}} + {error, Reason} -> {error, Reason} end. -spec append_event(binary(), binary(), binary(), binary(), binary()) -> @@ -99,8 +98,7 @@ execute_append_event(EventId, Params) -> case erlcass:execute(?STMT_APPEND_EVENT, Params) of ok -> {ok, EventId}; {ok, _Columns, _Rows} -> {ok, EventId}; - {error, Reason} -> {error, Reason}; - Other -> {error, {unexpected_append_result, Other}} + {error, Reason} -> {error, Reason} end. -spec audit_applied(binary(), binary(), binary(), map(), ok | {error, term()}) -> @@ -116,8 +114,7 @@ audit_applied(BuildSha, NodeName, EventId, Summary, Result) when case erlcass:execute(?STMT_AUDIT_APPLIED, Params) of ok -> ok; {ok, _Columns, _Rows} -> ok; - {error, Reason} -> {error, Reason}; - Other -> {error, {unexpected_audit_result, Other}} + {error, Reason} -> {error, Reason} end. -spec normalize_event_rows([list()]) -> [map()]. diff --git a/fluxer_gateway/src/gateway/gateway_nats_pool.erl b/fluxer_gateway/src/gateway/gateway_nats_pool.erl index 6fe440af7..ed9e6235f 100644 --- a/fluxer_gateway/src/gateway/gateway_nats_pool.erl +++ b/fluxer_gateway/src/gateway/gateway_nats_pool.erl @@ -15,6 +15,9 @@ {no_opaque, [ handle_info/2, handle_connect_ok/4, + handle_connect_ok_entry/5, + accept_connect_ok/4, + ignore_stale_connect_ok/2, handle_ready/4, handle_conn_event_down/2, handle_slot_monitor_down/5, diff --git a/fluxer_gateway/src/gateway/gateway_rollout_config.erl b/fluxer_gateway/src/gateway/gateway_rollout_config.erl index c21d0feda..f21594c6d 100644 --- a/fluxer_gateway/src/gateway/gateway_rollout_config.erl +++ b/fluxer_gateway/src/gateway/gateway_rollout_config.erl @@ -340,8 +340,7 @@ subscribe_to_nats(State) -> subscribe_to_rollout_subject() -> try gateway_nats_rpc:subscribe(?NATS_SUBJECT, <<>>) of {ok, Sid} -> {ok, Sid}; - {error, Reason} -> {error, Reason}; - Other -> {error, Other} + {error, Reason} -> {error, Reason} catch Class:Reason -> {error, {Class, Reason}} end. diff --git a/fluxer_gateway/src/guild/guild_common.erl b/fluxer_gateway/src/guild/guild_common.erl index a941f8ece..205048a53 100644 --- a/fluxer_gateway/src/guild/guild_common.erl +++ b/fluxer_gateway/src/guild/guild_common.erl @@ -52,9 +52,7 @@ upsert_voice_state(ConnectionId, VoiceState, State) -> end, State#{voice_states => VoiceStates}. --spec strip_members - (map()) -> map(); - (term()) -> term(). +-spec strip_members(term()) -> term(). strip_members(Data) when is_map(Data) -> Data1 = maps:remove(<<"members">>, Data), maps:remove(<<"member_role_index">>, Data1); diff --git a/fluxer_gateway/src/guild/guild_data_index.erl b/fluxer_gateway/src/guild/guild_data_index.erl index 2a0d49ccd..bdbd8750d 100644 --- a/fluxer_gateway/src/guild/guild_data_index.erl +++ b/fluxer_gateway/src/guild/guild_data_index.erl @@ -34,9 +34,7 @@ -export_type([guild_data/0]). --spec normalize_data - (map()) -> guild_data(); - (term()) -> term(). +-spec normalize_data(term()) -> term(). normalize_data(Data) when is_map(Data) -> Data0 = case guild_data_normalize:guild_data(Data) of diff --git a/fluxer_gateway/src/guild/guild_data_index_channels.erl b/fluxer_gateway/src/guild/guild_data_index_channels.erl index 102409069..c19ad19fd 100644 --- a/fluxer_gateway/src/guild/guild_data_index_channels.erl +++ b/fluxer_gateway/src/guild/guild_data_index_channels.erl @@ -40,9 +40,7 @@ channel_index(Data) when is_map(Data) -> channel_index(_) -> #{}. --spec put_channels - (term(), guild_data()) -> guild_data(); - (term(), term()) -> term(). +-spec put_channels(term(), term()) -> term(). put_channels(Channels, Data) when is_map(Data) -> ChannelList = lists:filtermap( fun normalize_channel_item/1, diff --git a/fluxer_gateway/src/guild/guild_data_index_roles.erl b/fluxer_gateway/src/guild/guild_data_index_roles.erl index 89b7df70f..198a57047 100644 --- a/fluxer_gateway/src/guild/guild_data_index_roles.erl +++ b/fluxer_gateway/src/guild/guild_data_index_roles.erl @@ -37,9 +37,7 @@ role_index(Data) when is_map(Data) -> role_index(_) -> #{}. --spec put_roles - (term(), guild_data()) -> guild_data(); - (term(), term()) -> term(). +-spec put_roles(term(), term()) -> term(). put_roles(Roles, Data) when is_map(Data) -> RoleList = [ normalize_role(Role) diff --git a/fluxer_gateway/src/guild/guild_data_normalize.erl b/fluxer_gateway/src/guild/guild_data_normalize.erl index d48ee7df6..73a8a93f8 100644 --- a/fluxer_gateway/src/guild/guild_data_normalize.erl +++ b/fluxer_gateway/src/guild/guild_data_normalize.erl @@ -10,16 +10,13 @@ channel/1 ]). --spec guild_data - (map()) -> map(); - (term()) -> term(). +-spec guild_data(term()) -> term(). guild_data(Data) when is_map(Data) -> normalize_nested_map(<<"guild">>, fun guild/1, Data); guild_data(Data) -> Data. --spec member - (map()) -> map(); - (term()) -> term(). + +-spec member(term()) -> term(). member(Member) when is_map(Member) -> Member1 = normalize_nested_map(<<"user">>, fun user/1, Member), Member2 = normalize_snowflake_list_field(<<"roles">>, Member1), @@ -30,9 +27,7 @@ member(Member) when is_map(Member) -> member(Member) -> Member. --spec role - (map()) -> map(); - (term()) -> term(). +-spec role(term()) -> term(). role(Role) when is_map(Role) -> Role1 = normalize_required_snowflake_field(<<"id">>, Role), Role2 = normalize_permission_field(<<"permissions">>, Role1), @@ -44,9 +39,7 @@ role(Role) when is_map(Role) -> role(Role) -> Role. --spec channel - (map()) -> map(); - (term()) -> term(). +-spec channel(term()) -> term(). channel(Channel) when is_map(Channel) -> Channel1 = normalize_required_snowflake_field(<<"id">>, Channel), Channel2 = normalize_optional_snowflake_field(<<"guild_id">>, Channel1), diff --git a/fluxer_gateway/src/guild/guild_member_list_oset.erl b/fluxer_gateway/src/guild/guild_member_list_oset.erl index 9064cbfd3..9f53cdde1 100644 --- a/fluxer_gateway/src/guild/guild_member_list_oset.erl +++ b/fluxer_gateway/src/guild/guild_member_list_oset.erl @@ -36,8 +36,7 @@ from_sorted(OSet, Keys) -> -spec destroy(oset()) -> ok. destroy(OSet) -> try guild_member_list_oset_nif:destroy(OSet) of - ok -> ok; - _ -> ok + ok -> ok catch _:_ -> ok end. diff --git a/fluxer_gateway/src/guild/guild_member_list_oset_nif.erl b/fluxer_gateway/src/guild/guild_member_list_oset_nif.erl index 1b78b9961..fab0fa495 100644 --- a/fluxer_gateway/src/guild/guild_member_list_oset_nif.erl +++ b/fluxer_gateway/src/guild/guild_member_list_oset_nif.erl @@ -79,18 +79,18 @@ range(_OSet, _Start, _Count) -> to_list(_OSet) -> erlang:nif_error(nif_not_loaded). --spec nif_path() -> file:filename(). +-spec nif_path() -> file:filename_all(). nif_path() -> filename:join(priv_dir(), ?NIF_NAME). --spec priv_dir() -> file:filename(). +-spec priv_dir() -> file:filename_all(). priv_dir() -> case code:priv_dir(fluxer_gateway) of {error, _Reason} -> priv_dir_from_beam(); Dir -> Dir end. --spec priv_dir_from_beam() -> file:filename(). +-spec priv_dir_from_beam() -> file:filename_all(). priv_dir_from_beam() -> case code:which(?MODULE) of Beam when is_list(Beam) -> diff --git a/fluxer_gateway/src/guild/guild_presence_reconcile.erl b/fluxer_gateway/src/guild/guild_presence_reconcile.erl index 76c0b506e..a9893f0a7 100644 --- a/fluxer_gateway/src/guild/guild_presence_reconcile.erl +++ b/fluxer_gateway/src/guild/guild_presence_reconcile.erl @@ -44,12 +44,12 @@ start_async(State) -> UserIds -> spawn_reconcile_fetch(UserIds, self()) end. --spec spawn_reconcile_fetch([user_id()], pid()) -> ok. +-spec spawn_reconcile_fetch([user_id(), ...], pid()) -> ok. spawn_reconcile_fetch(UserIds, Parent) -> _ = spawn(fun() -> fetch_and_reply(UserIds, Parent) end), ok. --spec fetch_and_reply([user_id()], pid()) -> ok. +-spec fetch_and_reply([user_id(), ...], pid()) -> ok. fetch_and_reply(UserIds, Parent) -> Parent ! {presence_reconcile_apply, authoritative_presence_map(UserIds)}, ok. @@ -183,9 +183,7 @@ authoritative_presence(UserId) -> exit:_ -> undefined end. --spec authoritative_presence_map([user_id()]) -> presence_by_id(). -authoritative_presence_map([]) -> - #{}; +-spec authoritative_presence_map([user_id(), ...]) -> presence_by_id(). authoritative_presence_map(UserIds) -> lists:foldl(fun add_presence_to_map/2, #{}, safe_bulk_get(UserIds)). @@ -199,8 +197,7 @@ add_presence_to_map(Presence, Acc) -> -spec safe_bulk_get([user_id()]) -> [presence()]. safe_bulk_get(UserIds) -> try presence_cache:bulk_get(UserIds) of - Presences when is_list(Presences) -> Presences; - _ -> [] + Presences -> Presences catch error:_ -> []; exit:_ -> [] diff --git a/fluxer_gateway/src/push/push_fcm_payload.erl b/fluxer_gateway/src/push/push_fcm_payload.erl index c807bf1e3..d0583b2b5 100644 --- a/fluxer_gateway/src/push/push_fcm_payload.erl +++ b/fluxer_gateway/src/push/push_fcm_payload.erl @@ -162,9 +162,7 @@ sanitize_text(Bin) when is_binary(Bin) -> safe_codepoints_to_binary(Codepoints, Bin); _ -> Bin - end; -sanitize_text(Other) -> - Other. + end. -spec safe_codepoints_to_binary([integer()], binary()) -> binary(). safe_codepoints_to_binary(Codepoints, Fallback) -> diff --git a/fluxer_gateway/src/push/push_markdown_plaintext.erl b/fluxer_gateway/src/push/push_markdown_plaintext.erl index 2583ccf08..5638d6f6e 100644 --- a/fluxer_gateway/src/push/push_markdown_plaintext.erl +++ b/fluxer_gateway/src/push/push_markdown_plaintext.erl @@ -35,8 +35,7 @@ render_bounded_context(Content, ContextJson) when byte_size(ContextJson) =< ?MAX_CONTEXT_JSON_BYTES -> try push_markdown_plaintext_nif:render_push_preview_nif(Content, ContextJson) of - Preview when is_binary(Preview) -> Preview; - _ -> strip_to_safe(Content) + Preview when is_binary(Preview) -> Preview catch _:_ -> strip_to_safe(Content) end; diff --git a/fluxer_gateway/src/push/push_markdown_plaintext_nif.erl b/fluxer_gateway/src/push/push_markdown_plaintext_nif.erl index 3c14082c0..05f32bcae 100644 --- a/fluxer_gateway/src/push/push_markdown_plaintext_nif.erl +++ b/fluxer_gateway/src/push/push_markdown_plaintext_nif.erl @@ -20,24 +20,24 @@ init() -> -spec available() -> boolean(). available() -> - false. + erlang:nif_error(nif_not_loaded). -spec render_push_preview_nif(binary(), binary()) -> binary(). render_push_preview_nif(_Content, _ContextJson) -> erlang:nif_error(nif_not_loaded). --spec nif_path() -> file:filename(). +-spec nif_path() -> file:filename_all(). nif_path() -> filename:join(priv_dir(), ?NIF_NAME). --spec priv_dir() -> file:filename(). +-spec priv_dir() -> file:filename_all(). priv_dir() -> case code:priv_dir(fluxer_gateway) of {error, _Reason} -> priv_dir_from_beam(); Dir -> Dir end. --spec priv_dir_from_beam() -> file:filename(). +-spec priv_dir_from_beam() -> file:filename_all(). priv_dir_from_beam() -> case code:which(?MODULE) of Beam when is_list(Beam) -> diff --git a/fluxer_gateway/src/push/push_notification_format.erl b/fluxer_gateway/src/push/push_notification_format.erl index d537155b1..1fbcb8b3d 100644 --- a/fluxer_gateway/src/push/push_notification_format.erl +++ b/fluxer_gateway/src/push/push_notification_format.erl @@ -167,9 +167,7 @@ user_nickname(UserId0, UserNicknames) when is_map(UserNicknames) -> case user_id_binary(UserId0) of Id when is_binary(Id) -> maps:get(Id, UserNicknames, undefined); undefined -> undefined - end; -user_nickname(_UserId0, _UserNicknames) -> - undefined. + end. -spec user_id_binary(term()) -> binary() | undefined. user_id_binary(UserId) when is_integer(UserId), UserId > 0 -> @@ -266,9 +264,7 @@ channel_names_from_guild_data(ChannelIds, GuildData) when is_map(GuildData) -> fun(ChannelId, Acc) -> put_index_channel_name(ChannelId, ChannelIndex, Acc) end, #{}, ChannelIds - ); -channel_names_from_guild_data(_ChannelIds, _GuildData) -> - #{}. + ). -spec put_index_channel_name(integer(), map(), map()) -> map(). put_index_channel_name(ChannelId, ChannelIndex, Acc) -> diff --git a/fluxer_gateway/src/session/session_manager_shard_start.erl b/fluxer_gateway/src/session/session_manager_shard_start.erl index 7e5574e12..787addb78 100644 --- a/fluxer_gateway/src/session/session_manager_shard_start.erl +++ b/fluxer_gateway/src/session/session_manager_shard_start.erl @@ -171,8 +171,6 @@ rollback_on_start_failure({reply, {success, Pid}, _State} = Result, _UserId) whe Result; rollback_on_start_failure({reply, {error, _Reason}, _State} = Result, UserId) -> session_abuse_protection:decrement_user_sessions(UserId), - Result; -rollback_on_start_failure(Result, _UserId) -> Result. -spec validate_identify_payload(term()) -> diff --git a/fluxer_gateway/src/session/session_ready_collect.erl b/fluxer_gateway/src/session/session_ready_collect.erl index d182ea754..8b011c841 100644 --- a/fluxer_gateway/src/session/session_ready_collect.erl +++ b/fluxer_gateway/src/session/session_ready_collect.erl @@ -82,10 +82,6 @@ user_id(User) when is_map(User) -> user_id(_) -> undefined. --spec presence_visible(map()) -> boolean(). -presence_visible(P) -> - presence_utils:is_visible_presence(P). - -spec dedup_presences([map()]) -> [map()]. dedup_presences(Presences) -> Map = lists:foldl(fun add_presence_by_id/2, #{}, Presences), @@ -325,15 +321,6 @@ ensure_relationship_id(Rel, UserId) -> -ifdef(TEST). -include_lib("eunit/include/eunit.hrl"). -presence_visible_test() -> - ?assertEqual(true, presence_visible(#{<<"status">> => <<"online">>})), - ?assertEqual(true, presence_visible(#{<<"status">> => <<"idle">>})), - ?assertEqual(true, presence_visible(#{<<"status">> => <<"dnd">>})), - ?assertEqual(false, presence_visible(#{<<"status">> => <<"offline">>})), - ?assertEqual(false, presence_visible(#{<<"status">> => <<"invisible">>})), - ?assertEqual(false, presence_visible(#{})), - ok. - presence_user_id_rejects_malformed_id_test() -> ?assertEqual(undefined, presence_user_id(#{<<"user">> => #{<<"id">> => <<"001">>}})). diff --git a/fluxer_gateway/src/telemetry/process_registry.erl b/fluxer_gateway/src/telemetry/process_registry.erl index b672ad647..2e58cc8a6 100644 --- a/fluxer_gateway/src/telemetry/process_registry.erl +++ b/fluxer_gateway/src/telemetry/process_registry.erl @@ -199,10 +199,7 @@ cleanup_on_down(DeadPid, ProcessMap) -> ProcessMap ). --spec cleanup_on_down - (process_prefix(), pid(), #{binary() => {pid(), reference()}}) -> - #{binary() => {pid(), reference()}}; - (process_prefix(), pid(), process_map()) -> process_map(). +-spec cleanup_on_down(process_prefix(), pid(), process_map()) -> process_map(). cleanup_on_down(Prefix, DeadPid, ProcessMap) -> maps:fold( fun diff --git a/fluxer_gateway/test/gateway_handler_tests.erl b/fluxer_gateway/test/gateway_handler_tests.erl index add5a274a..9cf6cf478 100644 --- a/fluxer_gateway/test/gateway_handler_tests.erl +++ b/fluxer_gateway/test/gateway_handler_tests.erl @@ -4,6 +4,9 @@ -typing([eqwalizer]). -include_lib("eunit/include/eunit.hrl"). +-define(TEST_GATEWAY_RATE_LIMIT_MAX_EVENTS, 600). +-define(TEST_IDENTIFY_MAX_PER_IP, 300). + websocket_info_session_reconnect_sends_reconnect_then_close_test() -> assert_reconnect_close( gateway_handler:websocket_info(session_reconnect, new_json_state()), @@ -191,7 +194,7 @@ adjust_status_test() -> check_rate_limit_blocks_general_flood_test() -> with_rate_limits_enabled(fun() -> Now = erlang:system_time(millisecond), - Events = lists:duplicate(120, Now - 1000), + Events = lists:duplicate(?TEST_GATEWAY_RATE_LIMIT_MAX_EVENTS, Now - 1000), State = (gateway_handler:new_state())#{ rate_limit_state => #{events => Events, op_events => #{}} }, @@ -406,19 +409,21 @@ validate_identify_data_rejects_invalid_shard_test() -> handle_identify_runs_identify_rate_check_at_zero_rollout_test() -> session_abuse_protection:ensure_tables(), OldConfig = gateway_rollout_config:get(), - IP = <<"203.0.113.55">>, + IP = unique_test_peer_ip(<<"zero-rollout-identify">>), try persistent_term:put(gateway_rollout_config, OldConfig#{ <<"session_rollout_percentage">> => 0 }), lists:foreach( fun(_) -> - gateway_handler_identify:handle_identify( - valid_identify_data(#{}), IP, new_json_state() - ) + ?assertEqual(ok, session_abuse_protection:check_identify_rate(IP)) end, - lists:seq(1, 60) + lists:seq(1, ?TEST_IDENTIFY_MAX_PER_IP - 1) ), + {ok, HeldState} = gateway_handler_identify:handle_identify( + valid_identify_data(#{}), IP, new_json_state() + ), + cancel_pending_identify_timer(HeldState), ?assertEqual( {error, identify_rate_limited}, session_abuse_protection:check_identify_rate(IP) @@ -520,3 +525,7 @@ restore_env(Key, false) -> os:unsetenv(Key); restore_env(Key, Value) -> os:putenv(Key, Value). + +unique_test_peer_ip(Prefix) -> + Suffix = integer_to_binary(erlang:unique_integer([positive])), + <>. diff --git a/packages/errors/src/i18n/locales/ar.ts b/packages/errors/src/i18n/locales/ar.ts index c27f46db4..1254938f0 100644 --- a/packages/errors/src/i18n/locales/ar.ts +++ b/packages/errors/src/i18n/locales/ar.ts @@ -2,7 +2,7 @@ import {defineErrorI18nLocaleMessages} from '../ErrorI18nMessages'; -export const ERROR_I18N_AR_MESSAGES = defineErrorI18nLocaleMessages({ +const ERROR_I18N_AR_MESSAGES = defineErrorI18nLocaleMessages({ "account.already_verified": "تم التحقق من حسابك بالفعل.", "account.communication_disabled": "المراسلة معطلة.", "account.disabled": "هذا الحساب معطل.", diff --git a/packages/errors/src/i18n/locales/bg.ts b/packages/errors/src/i18n/locales/bg.ts index 24213b2a7..0aac9c321 100644 --- a/packages/errors/src/i18n/locales/bg.ts +++ b/packages/errors/src/i18n/locales/bg.ts @@ -2,7 +2,7 @@ import {defineErrorI18nLocaleMessages} from '../ErrorI18nMessages'; -export const ERROR_I18N_BG_MESSAGES = defineErrorI18nLocaleMessages({ +const ERROR_I18N_BG_MESSAGES = defineErrorI18nLocaleMessages({ "account.already_verified": "Акаунтът ти вече е потвърден.", "account.communication_disabled": "Комуникацията е деактивирана.", "account.disabled": "Този акаунт е деактивиран.", diff --git a/packages/errors/src/i18n/locales/cs.ts b/packages/errors/src/i18n/locales/cs.ts index 0168643c8..c6610717e 100644 --- a/packages/errors/src/i18n/locales/cs.ts +++ b/packages/errors/src/i18n/locales/cs.ts @@ -2,7 +2,7 @@ import {defineErrorI18nLocaleMessages} from '../ErrorI18nMessages'; -export const ERROR_I18N_CS_MESSAGES = defineErrorI18nLocaleMessages({ +const ERROR_I18N_CS_MESSAGES = defineErrorI18nLocaleMessages({ "account.already_verified": "Tvůj účet je již ověřen.", "account.communication_disabled": "Komunikace je zakázána.", "account.disabled": "Tento účet byl deaktivován.", diff --git a/packages/errors/src/i18n/locales/da.ts b/packages/errors/src/i18n/locales/da.ts index 7e496513f..8f7dfd3a7 100644 --- a/packages/errors/src/i18n/locales/da.ts +++ b/packages/errors/src/i18n/locales/da.ts @@ -2,7 +2,7 @@ import {defineErrorI18nLocaleMessages} from '../ErrorI18nMessages'; -export const ERROR_I18N_DA_MESSAGES = defineErrorI18nLocaleMessages({ +const ERROR_I18N_DA_MESSAGES = defineErrorI18nLocaleMessages({ "account.already_verified": "Din konto er allerede bekræftet.", "account.communication_disabled": "Kommunikation er slået fra.", "account.disabled": "Denne konto er blevet slået fra.", diff --git a/packages/errors/src/i18n/locales/de.ts b/packages/errors/src/i18n/locales/de.ts index 58d8e660f..091dadf21 100644 --- a/packages/errors/src/i18n/locales/de.ts +++ b/packages/errors/src/i18n/locales/de.ts @@ -2,7 +2,7 @@ import {defineErrorI18nLocaleMessages} from '../ErrorI18nMessages'; -export const ERROR_I18N_DE_MESSAGES = defineErrorI18nLocaleMessages({ +const ERROR_I18N_DE_MESSAGES = defineErrorI18nLocaleMessages({ "account.already_verified": "Dein Konto ist bereits bestätigt.", "account.communication_disabled": "Kommunikation ist deaktiviert.", "account.disabled": "Dieses Konto wurde deaktiviert.", diff --git a/packages/errors/src/i18n/locales/el.ts b/packages/errors/src/i18n/locales/el.ts index 51b8c29e2..62b0959ca 100644 --- a/packages/errors/src/i18n/locales/el.ts +++ b/packages/errors/src/i18n/locales/el.ts @@ -2,7 +2,7 @@ import {defineErrorI18nLocaleMessages} from '../ErrorI18nMessages'; -export const ERROR_I18N_EL_MESSAGES = defineErrorI18nLocaleMessages({ +const ERROR_I18N_EL_MESSAGES = defineErrorI18nLocaleMessages({ "account.already_verified": "Ο λογαριασμός σου έχει ήδη επαληθευτεί.", "account.communication_disabled": "Η επικοινωνία είναι απενεργοποιημένη.", "account.disabled": "Αυτός ο λογαριασμός έχει απενεργοποιηθεί.", diff --git a/packages/errors/src/i18n/locales/en-GB.ts b/packages/errors/src/i18n/locales/en-GB.ts index e83d5d328..905dc2261 100644 --- a/packages/errors/src/i18n/locales/en-GB.ts +++ b/packages/errors/src/i18n/locales/en-GB.ts @@ -2,7 +2,7 @@ import {defineErrorI18nLocaleMessages} from '../ErrorI18nMessages'; -export const ERROR_I18N_EN_GB_MESSAGES = defineErrorI18nLocaleMessages({ +const ERROR_I18N_EN_GB_MESSAGES = defineErrorI18nLocaleMessages({ "account.already_verified": "Your account is already verified.", "account.communication_disabled": "Communication is disabled.", "account.disabled": "This account has been disabled.", diff --git a/packages/errors/src/i18n/locales/es-419.ts b/packages/errors/src/i18n/locales/es-419.ts index c4a6af87f..8c898d911 100644 --- a/packages/errors/src/i18n/locales/es-419.ts +++ b/packages/errors/src/i18n/locales/es-419.ts @@ -2,7 +2,7 @@ import {defineErrorI18nLocaleMessages} from '../ErrorI18nMessages'; -export const ERROR_I18N_ES_419_MESSAGES = defineErrorI18nLocaleMessages({ +const ERROR_I18N_ES_419_MESSAGES = defineErrorI18nLocaleMessages({ "account.already_verified": "Tu cuenta ya está verificada.", "account.communication_disabled": "La comunicación está deshabilitada.", "account.disabled": "Esta cuenta ha sido deshabilitada.", diff --git a/packages/errors/src/i18n/locales/es-ES.ts b/packages/errors/src/i18n/locales/es-ES.ts index 2f4ff7fa6..ede0d2c39 100644 --- a/packages/errors/src/i18n/locales/es-ES.ts +++ b/packages/errors/src/i18n/locales/es-ES.ts @@ -2,7 +2,7 @@ import {defineErrorI18nLocaleMessages} from '../ErrorI18nMessages'; -export const ERROR_I18N_ES_ES_MESSAGES = defineErrorI18nLocaleMessages({ +const ERROR_I18N_ES_ES_MESSAGES = defineErrorI18nLocaleMessages({ "account.already_verified": "Tu cuenta ya está verificada.", "account.communication_disabled": "La comunicación está deshabilitada.", "account.disabled": "Esta cuenta ha sido deshabilitada.", diff --git a/packages/errors/src/i18n/locales/fi.ts b/packages/errors/src/i18n/locales/fi.ts index f793b0fb5..5f6607757 100644 --- a/packages/errors/src/i18n/locales/fi.ts +++ b/packages/errors/src/i18n/locales/fi.ts @@ -2,7 +2,7 @@ import {defineErrorI18nLocaleMessages} from '../ErrorI18nMessages'; -export const ERROR_I18N_FI_MESSAGES = defineErrorI18nLocaleMessages({ +const ERROR_I18N_FI_MESSAGES = defineErrorI18nLocaleMessages({ "account.already_verified": "Tilisi on jo vahvistettu.", "account.communication_disabled": "Viestintä on poistettu käytöstä.", "account.disabled": "Tämä tili on poistettu käytöstä.", diff --git a/packages/errors/src/i18n/locales/fr.ts b/packages/errors/src/i18n/locales/fr.ts index 1765a0ec0..21d772927 100644 --- a/packages/errors/src/i18n/locales/fr.ts +++ b/packages/errors/src/i18n/locales/fr.ts @@ -2,7 +2,7 @@ import {defineErrorI18nLocaleMessages} from '../ErrorI18nMessages'; -export const ERROR_I18N_FR_MESSAGES = defineErrorI18nLocaleMessages({ +const ERROR_I18N_FR_MESSAGES = defineErrorI18nLocaleMessages({ "account.already_verified": "Ton compte est déjà vérifié.", "account.communication_disabled": "La communication est désactivée.", "account.disabled": "Ce compte a été désactivé.", diff --git a/packages/errors/src/i18n/locales/he.ts b/packages/errors/src/i18n/locales/he.ts index 04dbe562d..e13cde454 100644 --- a/packages/errors/src/i18n/locales/he.ts +++ b/packages/errors/src/i18n/locales/he.ts @@ -2,7 +2,7 @@ import {defineErrorI18nLocaleMessages} from '../ErrorI18nMessages'; -export const ERROR_I18N_HE_MESSAGES = defineErrorI18nLocaleMessages({ +const ERROR_I18N_HE_MESSAGES = defineErrorI18nLocaleMessages({ "account.already_verified": "החשבון כבר מאומת.", "account.communication_disabled": "התקשורת מושבתת.", "account.disabled": "החשבון הזה הושבת.", diff --git a/packages/errors/src/i18n/locales/hi.ts b/packages/errors/src/i18n/locales/hi.ts index 0e19b1fd4..ede072e8d 100644 --- a/packages/errors/src/i18n/locales/hi.ts +++ b/packages/errors/src/i18n/locales/hi.ts @@ -2,7 +2,7 @@ import {defineErrorI18nLocaleMessages} from '../ErrorI18nMessages'; -export const ERROR_I18N_HI_MESSAGES = defineErrorI18nLocaleMessages({ +const ERROR_I18N_HI_MESSAGES = defineErrorI18nLocaleMessages({ "account.already_verified": "आपका अकाउंट पहले से वेरिफाई किया जा चुका है.", "account.communication_disabled": "कम्युनिकेशन डिसेबल कर दिया गया है.", "account.disabled": "यह अकाउंट डिसेबल कर दिया गया है.", diff --git a/packages/errors/src/i18n/locales/hr.ts b/packages/errors/src/i18n/locales/hr.ts index c301dca42..1cf0a3d73 100644 --- a/packages/errors/src/i18n/locales/hr.ts +++ b/packages/errors/src/i18n/locales/hr.ts @@ -2,7 +2,7 @@ import {defineErrorI18nLocaleMessages} from '../ErrorI18nMessages'; -export const ERROR_I18N_HR_MESSAGES = defineErrorI18nLocaleMessages({ +const ERROR_I18N_HR_MESSAGES = defineErrorI18nLocaleMessages({ "account.already_verified": "Tvoj je račun već potvrđen.", "account.communication_disabled": "Komunikacija je isključena.", "account.disabled": "Ovaj je račun isključen.", diff --git a/packages/errors/src/i18n/locales/hu.ts b/packages/errors/src/i18n/locales/hu.ts index 99191c360..3bc1653a1 100644 --- a/packages/errors/src/i18n/locales/hu.ts +++ b/packages/errors/src/i18n/locales/hu.ts @@ -2,7 +2,7 @@ import {defineErrorI18nLocaleMessages} from '../ErrorI18nMessages'; -export const ERROR_I18N_HU_MESSAGES = defineErrorI18nLocaleMessages({ +const ERROR_I18N_HU_MESSAGES = defineErrorI18nLocaleMessages({ "account.already_verified": "Fiókod már ellenőrizve van.", "account.communication_disabled": "A kommunikáció letiltva.", "account.disabled": "Ez a fiók le van tiltva.", diff --git a/packages/errors/src/i18n/locales/id.ts b/packages/errors/src/i18n/locales/id.ts index 96d9add12..305cd453f 100644 --- a/packages/errors/src/i18n/locales/id.ts +++ b/packages/errors/src/i18n/locales/id.ts @@ -2,7 +2,7 @@ import {defineErrorI18nLocaleMessages} from '../ErrorI18nMessages'; -export const ERROR_I18N_ID_MESSAGES = defineErrorI18nLocaleMessages({ +const ERROR_I18N_ID_MESSAGES = defineErrorI18nLocaleMessages({ "account.already_verified": "Akunmu sudah terverifikasi.", "account.communication_disabled": "Komunikasi dinonaktifkan.", "account.disabled": "Akun ini telah dinonaktifkan.", diff --git a/packages/errors/src/i18n/locales/it.ts b/packages/errors/src/i18n/locales/it.ts index 599a9d54e..abd87b973 100644 --- a/packages/errors/src/i18n/locales/it.ts +++ b/packages/errors/src/i18n/locales/it.ts @@ -2,7 +2,7 @@ import {defineErrorI18nLocaleMessages} from '../ErrorI18nMessages'; -export const ERROR_I18N_IT_MESSAGES = defineErrorI18nLocaleMessages({ +const ERROR_I18N_IT_MESSAGES = defineErrorI18nLocaleMessages({ "account.already_verified": "Il tuo account è già verificato.", "account.communication_disabled": "La comunicazione è disabilitata.", "account.disabled": "Questo account è stato disabilitato.", diff --git a/packages/errors/src/i18n/locales/ja.ts b/packages/errors/src/i18n/locales/ja.ts index a1118ea6b..7d5b312c2 100644 --- a/packages/errors/src/i18n/locales/ja.ts +++ b/packages/errors/src/i18n/locales/ja.ts @@ -2,7 +2,7 @@ import {defineErrorI18nLocaleMessages} from '../ErrorI18nMessages'; -export const ERROR_I18N_JA_MESSAGES = defineErrorI18nLocaleMessages({ +const ERROR_I18N_JA_MESSAGES = defineErrorI18nLocaleMessages({ "account.already_verified": "アカウントはすでに認証済みです。", "account.communication_disabled": "メッセージ機能が無効です。", "account.disabled": "このアカウントは無効になっています。", diff --git a/packages/errors/src/i18n/locales/ko.ts b/packages/errors/src/i18n/locales/ko.ts index 1cc09b497..3c014bbf3 100644 --- a/packages/errors/src/i18n/locales/ko.ts +++ b/packages/errors/src/i18n/locales/ko.ts @@ -2,7 +2,7 @@ import {defineErrorI18nLocaleMessages} from '../ErrorI18nMessages'; -export const ERROR_I18N_KO_MESSAGES = defineErrorI18nLocaleMessages({ +const ERROR_I18N_KO_MESSAGES = defineErrorI18nLocaleMessages({ "account.already_verified": "계정이 이미 인증되었어요.", "account.communication_disabled": "메시지 보내기가 비활성화되었어요.", "account.disabled": "이 계정은 비활성화되었어요.", diff --git a/packages/errors/src/i18n/locales/lt.ts b/packages/errors/src/i18n/locales/lt.ts index 7e00622f0..6e13e4a5e 100644 --- a/packages/errors/src/i18n/locales/lt.ts +++ b/packages/errors/src/i18n/locales/lt.ts @@ -2,7 +2,7 @@ import {defineErrorI18nLocaleMessages} from '../ErrorI18nMessages'; -export const ERROR_I18N_LT_MESSAGES = defineErrorI18nLocaleMessages({ +const ERROR_I18N_LT_MESSAGES = defineErrorI18nLocaleMessages({ "account.already_verified": "Tavo paskyra jau patvirtinta.", "account.communication_disabled": "Bendravimas išjungtas.", "account.disabled": "Ši paskyra buvo išjungta.", diff --git a/packages/errors/src/i18n/locales/nl.ts b/packages/errors/src/i18n/locales/nl.ts index 8f668fb4f..c49c69893 100644 --- a/packages/errors/src/i18n/locales/nl.ts +++ b/packages/errors/src/i18n/locales/nl.ts @@ -2,7 +2,7 @@ import {defineErrorI18nLocaleMessages} from '../ErrorI18nMessages'; -export const ERROR_I18N_NL_MESSAGES = defineErrorI18nLocaleMessages({ +const ERROR_I18N_NL_MESSAGES = defineErrorI18nLocaleMessages({ "account.already_verified": "Je account is al bevestigd.", "account.communication_disabled": "Communicatie is uitgeschakeld.", "account.disabled": "Dit account is uitgeschakeld.", diff --git a/packages/errors/src/i18n/locales/no.ts b/packages/errors/src/i18n/locales/no.ts index d8155188d..9c596d619 100644 --- a/packages/errors/src/i18n/locales/no.ts +++ b/packages/errors/src/i18n/locales/no.ts @@ -2,7 +2,7 @@ import {defineErrorI18nLocaleMessages} from '../ErrorI18nMessages'; -export const ERROR_I18N_NO_MESSAGES = defineErrorI18nLocaleMessages({ +const ERROR_I18N_NO_MESSAGES = defineErrorI18nLocaleMessages({ "account.already_verified": "Kontoen din er allerede bekreftet.", "account.communication_disabled": "Kommunikasjon er deaktivert.", "account.disabled": "Denne kontoen er deaktivert.", diff --git a/packages/errors/src/i18n/locales/pl.ts b/packages/errors/src/i18n/locales/pl.ts index 623bc0e48..35357fd8a 100644 --- a/packages/errors/src/i18n/locales/pl.ts +++ b/packages/errors/src/i18n/locales/pl.ts @@ -2,7 +2,7 @@ import {defineErrorI18nLocaleMessages} from '../ErrorI18nMessages'; -export const ERROR_I18N_PL_MESSAGES = defineErrorI18nLocaleMessages({ +const ERROR_I18N_PL_MESSAGES = defineErrorI18nLocaleMessages({ "account.already_verified": "Twoje konto jest już zweryfikowane.", "account.communication_disabled": "Komunikacja wyłączona.", "account.disabled": "Konto wyłączone.", diff --git a/packages/errors/src/i18n/locales/pt-BR.ts b/packages/errors/src/i18n/locales/pt-BR.ts index e7ded9d96..2c8728e2f 100644 --- a/packages/errors/src/i18n/locales/pt-BR.ts +++ b/packages/errors/src/i18n/locales/pt-BR.ts @@ -2,7 +2,7 @@ import {defineErrorI18nLocaleMessages} from '../ErrorI18nMessages'; -export const ERROR_I18N_PT_BR_MESSAGES = defineErrorI18nLocaleMessages({ +const ERROR_I18N_PT_BR_MESSAGES = defineErrorI18nLocaleMessages({ "account.already_verified": "Sua conta já está verificada.", "account.communication_disabled": "A comunicação está desativada.", "account.disabled": "Esta conta foi desativada.", diff --git a/packages/errors/src/i18n/locales/ro.ts b/packages/errors/src/i18n/locales/ro.ts index 442b27c53..f824139ea 100644 --- a/packages/errors/src/i18n/locales/ro.ts +++ b/packages/errors/src/i18n/locales/ro.ts @@ -2,7 +2,7 @@ import {defineErrorI18nLocaleMessages} from '../ErrorI18nMessages'; -export const ERROR_I18N_RO_MESSAGES = defineErrorI18nLocaleMessages({ +const ERROR_I18N_RO_MESSAGES = defineErrorI18nLocaleMessages({ "account.already_verified": "Contul tău este deja verificat.", "account.communication_disabled": "Comunicarea este dezactivată.", "account.disabled": "Acest cont a fost dezactivat.", diff --git a/packages/errors/src/i18n/locales/ru.ts b/packages/errors/src/i18n/locales/ru.ts index 30edd020a..e888617c8 100644 --- a/packages/errors/src/i18n/locales/ru.ts +++ b/packages/errors/src/i18n/locales/ru.ts @@ -2,7 +2,7 @@ import {defineErrorI18nLocaleMessages} from '../ErrorI18nMessages'; -export const ERROR_I18N_RU_MESSAGES = defineErrorI18nLocaleMessages({ +const ERROR_I18N_RU_MESSAGES = defineErrorI18nLocaleMessages({ "account.already_verified": "Твой аккаунт уже подтверждён.", "account.communication_disabled": "Общение отключено.", "account.disabled": "Этот аккаунт был отключён.", diff --git a/packages/errors/src/i18n/locales/sv-SE.ts b/packages/errors/src/i18n/locales/sv-SE.ts index c5dcdc637..598eeb0b8 100644 --- a/packages/errors/src/i18n/locales/sv-SE.ts +++ b/packages/errors/src/i18n/locales/sv-SE.ts @@ -2,7 +2,7 @@ import {defineErrorI18nLocaleMessages} from '../ErrorI18nMessages'; -export const ERROR_I18N_SV_SE_MESSAGES = defineErrorI18nLocaleMessages({ +const ERROR_I18N_SV_SE_MESSAGES = defineErrorI18nLocaleMessages({ "account.already_verified": "Ditt konto är redan verifierat.", "account.communication_disabled": "Kommunikationen är inaktiverad.", "account.disabled": "Detta konto har inaktiverats.", diff --git a/packages/errors/src/i18n/locales/th.ts b/packages/errors/src/i18n/locales/th.ts index 42c99f45e..9dd51273e 100644 --- a/packages/errors/src/i18n/locales/th.ts +++ b/packages/errors/src/i18n/locales/th.ts @@ -2,7 +2,7 @@ import {defineErrorI18nLocaleMessages} from '../ErrorI18nMessages'; -export const ERROR_I18N_TH_MESSAGES = defineErrorI18nLocaleMessages({ +const ERROR_I18N_TH_MESSAGES = defineErrorI18nLocaleMessages({ "account.already_verified": "บัญชีของคุณได้รับการยืนยันแล้ว", "account.communication_disabled": "ปิดใช้งานการสื่อสารแล้ว", "account.disabled": "บัญชีนี้ถูกปิดใช้งานแล้ว", diff --git a/packages/errors/src/i18n/locales/tr.ts b/packages/errors/src/i18n/locales/tr.ts index 7bf2ca8b7..f68905cb6 100644 --- a/packages/errors/src/i18n/locales/tr.ts +++ b/packages/errors/src/i18n/locales/tr.ts @@ -2,7 +2,7 @@ import {defineErrorI18nLocaleMessages} from '../ErrorI18nMessages'; -export const ERROR_I18N_TR_MESSAGES = defineErrorI18nLocaleMessages({ +const ERROR_I18N_TR_MESSAGES = defineErrorI18nLocaleMessages({ "account.already_verified": "Hesabın zaten doğrulandı.", "account.communication_disabled": "İletişim devre dışı bırakıldı.", "account.disabled": "Bu hesap devre dışı bırakıldı.", diff --git a/packages/errors/src/i18n/locales/uk.ts b/packages/errors/src/i18n/locales/uk.ts index f52790217..7af6e857e 100644 --- a/packages/errors/src/i18n/locales/uk.ts +++ b/packages/errors/src/i18n/locales/uk.ts @@ -2,7 +2,7 @@ import {defineErrorI18nLocaleMessages} from '../ErrorI18nMessages'; -export const ERROR_I18N_UK_MESSAGES = defineErrorI18nLocaleMessages({ +const ERROR_I18N_UK_MESSAGES = defineErrorI18nLocaleMessages({ "account.already_verified": "Твій акаунт уже підтверджено.", "account.communication_disabled": "Спілкування вимкнено.", "account.disabled": "Цей акаунт вимкнено.", diff --git a/packages/errors/src/i18n/locales/vi.ts b/packages/errors/src/i18n/locales/vi.ts index 9b4b0d7db..704ce5da0 100644 --- a/packages/errors/src/i18n/locales/vi.ts +++ b/packages/errors/src/i18n/locales/vi.ts @@ -2,7 +2,7 @@ import {defineErrorI18nLocaleMessages} from '../ErrorI18nMessages'; -export const ERROR_I18N_VI_MESSAGES = defineErrorI18nLocaleMessages({ +const ERROR_I18N_VI_MESSAGES = defineErrorI18nLocaleMessages({ "account.already_verified": "Tài khoản của bạn đã được xác minh.", "account.communication_disabled": "Tính năng giao tiếp đã bị tắt.", "account.disabled": "Tài khoản này đã bị vô hiệu hóa.", diff --git a/packages/errors/src/i18n/locales/zh-CN.ts b/packages/errors/src/i18n/locales/zh-CN.ts index cc6582394..76813e550 100644 --- a/packages/errors/src/i18n/locales/zh-CN.ts +++ b/packages/errors/src/i18n/locales/zh-CN.ts @@ -2,7 +2,7 @@ import {defineErrorI18nLocaleMessages} from '../ErrorI18nMessages'; -export const ERROR_I18N_ZH_CN_MESSAGES = defineErrorI18nLocaleMessages({ +const ERROR_I18N_ZH_CN_MESSAGES = defineErrorI18nLocaleMessages({ "account.already_verified": "你的账号已验证。", "account.communication_disabled": "通信已禁用。", "account.disabled": "此账号已被禁用。", diff --git a/packages/errors/src/i18n/locales/zh-TW.ts b/packages/errors/src/i18n/locales/zh-TW.ts index 18d988ba2..31a06a05c 100644 --- a/packages/errors/src/i18n/locales/zh-TW.ts +++ b/packages/errors/src/i18n/locales/zh-TW.ts @@ -2,7 +2,7 @@ import {defineErrorI18nLocaleMessages} from '../ErrorI18nMessages'; -export const ERROR_I18N_ZH_TW_MESSAGES = defineErrorI18nLocaleMessages({ +const ERROR_I18N_ZH_TW_MESSAGES = defineErrorI18nLocaleMessages({ "account.already_verified": "你的帳號已驗證。", "account.communication_disabled": "通訊功能已停用。", "account.disabled": "這個帳號已停用。", diff --git a/packages/i18n/scripts/SyncStaticI18nCatalogs.ts b/packages/i18n/scripts/SyncStaticI18nCatalogs.ts index 40d62736e..ece96eb1d 100644 --- a/packages/i18n/scripts/SyncStaticI18nCatalogs.ts +++ b/packages/i18n/scripts/SyncStaticI18nCatalogs.ts @@ -246,7 +246,7 @@ function renderTs(config: StaticCatalogConfig, locale: StaticLocale, catalog: Ca const name = exportName(config, locale); return `${GENERATED_HEADER}import {${config.defineFunctionName}} from '${config.defineImportPath}'; -export const ${name} = ${config.defineFunctionName}(${JSON.stringify(catalog, null, '\t')}); +const ${name} = ${config.defineFunctionName}(${JSON.stringify(catalog, null, '\t')}); export default ${name}; `; diff --git a/packages/voice_engine_v2/src/simulation/SimulatorPorts.ts b/packages/voice_engine_v2/src/simulation/SimulatorPorts.ts index 27ff1c2de..742519bc6 100644 --- a/packages/voice_engine_v2/src/simulation/SimulatorPorts.ts +++ b/packages/voice_engine_v2/src/simulation/SimulatorPorts.ts @@ -33,7 +33,7 @@ import type { import type {VoiceEngineV2ClockPort, VoiceEngineV2RandomPort} from '../runtime/platformPort'; const SIMULATOR_CLOCK_MAX_NS = 1_000_000_000_000; -export const SIMULATOR_NS_PER_MS = 1_000_000; +const SIMULATOR_NS_PER_MS = 1_000_000; const SIMULATOR_RANDOM_MULTIPLIER = 0x5deece66d; const SIMULATOR_RANDOM_INCREMENT = 0xbn; const SIMULATOR_RANDOM_MASK = (1n << 48n) - 1n; diff --git a/packages/voice_engine_v2/src/testing/determinism.test.ts b/packages/voice_engine_v2/src/testing/determinism.test.ts index 5f474ef25..8726825e9 100644 --- a/packages/voice_engine_v2/src/testing/determinism.test.ts +++ b/packages/voice_engine_v2/src/testing/determinism.test.ts @@ -1,8 +1,5 @@ // SPDX-License-Identifier: AGPL-3.0-or-later -import {createRequire} from 'node:module'; -import path from 'node:path'; -import {fileURLToPath} from 'node:url'; import {describe, expect, it} from 'vitest'; import appVoiceSessionFixtureJson from '../../fixtures/event_logs/app_voice_session.json'; import {coalesceVoiceEngineV2OutboundStats} from '../policies/voiceStats'; @@ -15,10 +12,6 @@ import { import {replayVoiceEngineV2EventLogFixture, type VoiceEngineV2EventLogFixture} from './eventLogReplay'; const fixture = appVoiceSessionFixtureJson as unknown as VoiceEngineV2EventLogFixture; -const require = createRequire(import.meta.url); -const __filename = fileURLToPath(import.meta.url); -const __dirname = path.dirname(__filename); -const ruleModule = require('../eslint/no-determinism-leaks.cjs'); describe('voice engine v2 determinism guarantees', () => { it('produces byte-identical snapshot output across fresh replay runs', () => { @@ -73,37 +66,6 @@ describe('voice engine v2 determinism guarantees', () => { expect(observed[0]).toBe(500); }); - it('detects deliberate Math.random() leaks via the standalone scanner', () => { - const fixtureSource = [ - 'export function deliberateLeak() {', - ' const value = Math.random();', - ' return value;', - '}', - '', - ].join('\n'); - const guardedPath = path.resolve(__dirname, '..', 'policies', '_fixture_determinism_leak.ts'); - - const findings = ruleModule.findDeterminismLeaks(guardedPath, fixtureSource); - - expect(findings.length).toBeGreaterThanOrEqual(1); - expect(findings.some((finding: {message: string}) => finding.message.includes('Math.random'))).toBe(true); - }); - - it('flags Date.now() and crypto.randomUUID() in policies but exempts platformPort and tests', () => { - const source = 'const a = Date.now();\nconst b = crypto.randomUUID();\nconst c = performance.now();'; - const guardedRuntime = path.resolve(__dirname, '..', 'runtime', '_fixture_leak.ts'); - const exemptPlatform = path.resolve(__dirname, '..', 'runtime', 'platformPort.ts'); - const exemptTest = path.resolve(__dirname, '..', 'runtime', 'something.test.ts'); - - const inRuntime = ruleModule.findDeterminismLeaks(guardedRuntime, source); - const inPlatform = ruleModule.findDeterminismLeaks(exemptPlatform, source); - const inTest = ruleModule.findDeterminismLeaks(exemptTest, source); - - expect(inRuntime.length).toBeGreaterThanOrEqual(3); - expect(inPlatform).toEqual([]); - expect(inTest).toEqual([]); - }); - it('exposes injectable Clock and Random ports through the runtime options surface', () => { const platform = createVoiceEngineV2DeterministicPlatformPort(42); diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 5379259ef..2ff700cb9 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -630,12 +630,6 @@ importers: '@typescript/native-preview': specifier: 'catalog:' version: 7.0.0-dev.20260224.1 - vite-tsconfig-paths: - specifier: 'catalog:' - version: 6.1.1(typescript@5.9.3)(vite@7.3.1(@types/node@25.3.0)(jiti@2.6.1)(lightningcss@1.31.1)(tsx@4.21.0)(yaml@2.8.2)) - vitest: - specifier: 'catalog:' - version: 4.0.18(@opentelemetry/api@1.9.0)(@types/node@25.3.0)(@vitest/browser-playwright@4.0.18)(happy-dom@20.7.0)(jiti@2.6.1)(jsdom@28.1.0)(lightningcss@1.31.1)(msw@2.12.10(@types/node@25.3.0)(typescript@5.9.3))(tsx@4.21.0)(yaml@2.8.2) fluxer_api/pkgs/captcha: dependencies: diff --git a/tools/ci/src/app_proxy.rs b/tools/ci/src/app_proxy.rs index 28f6445b8..11c744663 100644 --- a/tools/ci/src/app_proxy.rs +++ b/tools/ci/src/app_proxy.rs @@ -169,12 +169,12 @@ fn ghcr_owner() -> Result { } } - if let Ok(repository) = env::var("GITHUB_REPOSITORY") { - if let Some((owner, _)) = repository.split_once('/') { - let owner = owner.trim(); - if !owner.is_empty() { - return Ok(owner.to_string()); - } + if let Ok(repository) = env::var("GITHUB_REPOSITORY") + && let Some((owner, _)) = repository.split_once('/') + { + let owner = owner.trim(); + if !owner.is_empty() { + return Ok(owner.to_string()); } } diff --git a/tools/ci/src/ci_workflow.rs b/tools/ci/src/ci_workflow.rs index fa8533410..d6051bae1 100644 --- a/tools/ci/src/ci_workflow.rs +++ b/tools/ci/src/ci_workflow.rs @@ -1,6 +1,7 @@ // SPDX-License-Identifier: AGPL-3.0-or-later use crate::common::{CommandSpec, run_command}; +use crate::desktop::write_build_channel_file; use crate::gateway::{GatewayStep, run_gateway_step}; use anyhow::{Context, Result}; use clap::{Args, ValueEnum}; @@ -48,7 +49,9 @@ pub async fn run_ci(args: CiArgs) -> Result<()> { .current_dir(root), ), CiStep::Typecheck => { + ensure_desktop_build_channel_file(&root)?; run_generators(&root, true)?; + run_app_test_artifact_generators(&root)?; run_command( CommandSpec::new("pnpm") .args(["-r", "--if-present", "typecheck"]) @@ -57,6 +60,7 @@ pub async fn run_ci(args: CiArgs) -> Result<()> { } CiStep::Test => { run_generators(&root, false)?; + run_app_test_artifact_generators(&root)?; run_workspace_tests(&root)?; run_command(with_test_env( CommandSpec::new("pnpm") @@ -65,11 +69,9 @@ pub async fn run_ci(args: CiArgs) -> Result<()> { )) } CiStep::Knip => { - run_command( - CommandSpec::new("pnpm") - .args(["--filter", "fluxer_app", "i18n:compile"]) - .current_dir(&root), - )?; + run_app_test_artifact_generators(&root)?; + ensure_desktop_build_channel_file(&root)?; + run_fluxer_app_script(&root, "i18n:compile")?; run_command( CommandSpec::new("pnpm") .args(["exec", "knip"]) @@ -91,6 +93,24 @@ pub async fn run_ci(args: CiArgs) -> Result<()> { } } +fn ensure_desktop_build_channel_file(root: &Path) -> Result<()> { + let channel = env::var("BUILD_CHANNEL").unwrap_or_else(|_| "stable".to_string()); + write_build_channel_file(&root.join("fluxer_desktop"), &channel) +} + +fn run_app_test_artifact_generators(root: &Path) -> Result<()> { + run_fluxer_app_script(root, "wasm:codegen")?; + run_fluxer_app_script(root, "generate:masks") +} + +fn run_fluxer_app_script(root: &Path, script: &str) -> Result<()> { + run_command( + CommandSpec::new("pnpm") + .args(["--filter", "fluxer_app", script]) + .current_dir(root), + ) +} + pub async fn run_ci_scripts(args: CiScriptsArgs) -> Result<()> { let root = repo_root()?; match args.step { @@ -223,18 +243,19 @@ mod tests { .env .into_iter() .collect::>(); + let default_nats_url = OsString::from(default_test_nats_url()); assert_eq!( env.get(&OsString::from("FLUXER_NATS_URL")), - Some(&OsString::from("nats://nats:4222")) + Some(&default_nats_url) ); assert_eq!( env.get(&OsString::from("FLUXER_NATS_CORE_URL")), - Some(&OsString::from("nats://nats:4222")) + Some(&default_nats_url) ); assert_eq!( env.get(&OsString::from("FLUXER_NATS_JETSTREAM_URL")), - Some(&OsString::from("nats://nats:4222")) + Some(&default_nats_url) ); assert_eq!( env.get(&OsString::from("API_TEST_MAX_WORKERS")), diff --git a/tools/ci/src/desktop.rs b/tools/ci/src/desktop.rs index 77b7e258a..9fdc551ce 100644 --- a/tools/ci/src/desktop.rs +++ b/tools/ci/src/desktop.rs @@ -378,7 +378,7 @@ fn resolve_desktop_dir() -> Result { )) } -fn write_build_channel_file(root: &Path, channel: &str) -> Result<()> { +pub(crate) fn write_build_channel_file(root: &Path, channel: &str) -> Result<()> { ensure!( matches!(channel, "stable" | "canary"), "Invalid BUILD_CHANNEL: {channel}. Must be 'stable' or 'canary'." @@ -2703,7 +2703,7 @@ fn write_macos_releases( }], }); write_json_pretty(&dest.join("RELEASES.json"), &releases)?; - fs::copy(dest.join("RELEASES.json"), dest.join("releases.json"))?; + write_json_pretty(&dest.join("releases.json"), &releases)?; Ok(()) }