From b03de03465c92bc3a5323f488fdcd43779f2456c Mon Sep 17 00:00:00 2001 From: wobsoriano Date: Thu, 1 Oct 2026 19:18:36 -0700 Subject: [PATCH 01/31] ci(e2e): replace maestro with tester.army e2e in the expo native e2e --- .changeset/expo-native-e2e-runner.md | 2 + .github/workflows/expo-native-build.yml | 76 +- integration/tests/expo-native/.gitignore | 3 +- .../tests/expo-native/boot-ios-simulators.sh | 8 +- integration/tests/expo-native/config.yaml | 15 - integration/tests/expo-native/e2e.config.ts | 15 + .../flows/authview-detach-reattach.e2e.ts | 24 + .../flows/authview-detach-reattach.yaml | 46 - .../flows/embedded-profile-host-back.e2e.ts | 28 + .../flows/embedded-profile-host-back.yaml | 58 - .../google-sign-in-missing-credentials.e2e.ts | 11 + .../google-sign-in-missing-credentials.yaml | 9 - .../tests/expo-native/flows/sign-in.e2e.ts | 17 + .../tests/expo-native/flows/sign-in.yaml | 19 - .../tests/expo-native/flows/subflows.ts | 124 ++ .../expo-native/flows/subflows/_warmup.yaml | 16 - .../flows/subflows/assert-signed-in.yaml | 9 - .../flows/subflows/assert-signed-out.yaml | 6 - .../expo-native/flows/subflows/open-app.yaml | 21 - .../subflows/sign-in-email-password.yaml | 125 -- .../user-button-sign-out-re-sign-in.e2e.ts | 21 + .../user-button-sign-out-re-sign-in.yaml | 36 - .../flows/user-profile-custom-pages.e2e.ts | 26 + .../flows/user-profile-custom-pages.yaml | 45 - integration/tests/expo-native/package.json | 14 + integration/tests/expo-native/pnpm-lock.yaml | 1287 +++++++++++++++++ .../tests/expo-native/pnpm-workspace.yaml | 11 + .../tests/expo-native/run-android-flows.sh | 6 +- integration/tests/expo-native/run-flows.sh | 128 +- package.json | 4 +- 30 files changed, 1634 insertions(+), 576 deletions(-) create mode 100644 .changeset/expo-native-e2e-runner.md delete mode 100644 integration/tests/expo-native/config.yaml create mode 100644 integration/tests/expo-native/e2e.config.ts create mode 100644 integration/tests/expo-native/flows/authview-detach-reattach.e2e.ts delete mode 100644 integration/tests/expo-native/flows/authview-detach-reattach.yaml create mode 100644 integration/tests/expo-native/flows/embedded-profile-host-back.e2e.ts delete mode 100644 integration/tests/expo-native/flows/embedded-profile-host-back.yaml create mode 100644 integration/tests/expo-native/flows/google-sign-in-missing-credentials.e2e.ts delete mode 100644 integration/tests/expo-native/flows/google-sign-in-missing-credentials.yaml create mode 100644 integration/tests/expo-native/flows/sign-in.e2e.ts delete mode 100644 integration/tests/expo-native/flows/sign-in.yaml create mode 100644 integration/tests/expo-native/flows/subflows.ts delete mode 100644 integration/tests/expo-native/flows/subflows/_warmup.yaml delete mode 100644 integration/tests/expo-native/flows/subflows/assert-signed-in.yaml delete mode 100644 integration/tests/expo-native/flows/subflows/assert-signed-out.yaml delete mode 100644 integration/tests/expo-native/flows/subflows/open-app.yaml delete mode 100644 integration/tests/expo-native/flows/subflows/sign-in-email-password.yaml create mode 100644 integration/tests/expo-native/flows/user-button-sign-out-re-sign-in.e2e.ts delete mode 100644 integration/tests/expo-native/flows/user-button-sign-out-re-sign-in.yaml create mode 100644 integration/tests/expo-native/flows/user-profile-custom-pages.e2e.ts delete mode 100644 integration/tests/expo-native/flows/user-profile-custom-pages.yaml create mode 100644 integration/tests/expo-native/package.json create mode 100644 integration/tests/expo-native/pnpm-lock.yaml create mode 100644 integration/tests/expo-native/pnpm-workspace.yaml diff --git a/.changeset/expo-native-e2e-runner.md b/.changeset/expo-native-e2e-runner.md new file mode 100644 index 00000000000..a845151cc84 --- /dev/null +++ b/.changeset/expo-native-e2e-runner.md @@ -0,0 +1,2 @@ +--- +--- diff --git a/.github/workflows/expo-native-build.yml b/.github/workflows/expo-native-build.yml index bf96461fe88..831fe6619cd 100644 --- a/.github/workflows/expo-native-build.yml +++ b/.github/workflows/expo-native-build.yml @@ -27,10 +27,8 @@ env: SDK_PACK_DIR: /tmp/clerk-expo-pack E2E_INSTANCE_NAME: clerkstage-with-native-components BAPI_URL: https://api.clerkstage.dev - MAESTRO_VERSION: '2.10.0' - MAESTRO_CLI_NO_ANALYTICS: '1' - MAESTRO_SHARDS: '2' - MAESTRO_DRIVER_STARTUP_TIMEOUT: '180000' + E2E_SHARDS: '2' + E2E_TELEMETRY_DISABLED: '1' jobs: native-build: @@ -106,9 +104,9 @@ jobs: # Bump the version when native build commands change. key: expo-native-build-v1-${{ runner.os }}-${{ matrix.expo-sdk }}-${{ matrix.platform }}-${{ matrix.run-e2e == true && 'e2e' || 'build' }}-${{ env.E2E_INSTANCE_NAME }}-${{ steps.native-build-key.outputs.hash }} - - if: steps.native-build-cache.outputs.cache-hit != 'true' + - if: steps.native-build-cache.outputs.cache-hit != 'true' || matrix.run-e2e == true uses: pnpm/action-setup@b906affcce14559ad1aafd4ab0e942779e9f58b1 # v4 - - if: steps.native-build-cache.outputs.cache-hit != 'true' + - if: steps.native-build-cache.outputs.cache-hit != 'true' || matrix.run-e2e == true uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4 with: node-version: 24.15.0 @@ -140,7 +138,7 @@ jobs: GOOGLE_SIGNIN_TARBALL="$(ls "$SDK_PACK_DIR"/clerk-expo-google-signin-*.tgz)" pnpm add "$SDK_TARBALL" "$GOOGLE_SIGNIN_TARBALL" -w # expo-dev-client makes even release builds boot into the dev - # launcher (unreachable Metro in CI), which stalls every Maestro + # launcher (unreachable Metro in CI), which stalls every e2e # flow on a blank screen. Skip it on e2e jobs only. DEV_CLIENT="expo-dev-client" if [ "$RUN_E2E" = "true" ]; then DEV_CLIENT=""; fi @@ -228,29 +226,19 @@ jobs: - name: Boot iOS simulators if: matrix.platform == 'ios' && matrix.run-e2e == true && steps.keys.outputs.pk != '' - run: ${{ env.E2E_DIR }}/boot-ios-simulators.sh boot "$MAESTRO_SHARDS" + run: ${{ env.E2E_DIR }}/boot-ios-simulators.sh boot "$E2E_SHARDS" - - name: Cache maestro CLI + - name: Install e2e runner if: steps.keys.outputs.pk != '' + working-directory: ${{ env.E2E_DIR }} + run: pnpm install --frozen-lockfile + + - name: Cache iOS automation runner + if: matrix.platform == 'ios' && steps.keys.outputs.pk != '' uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4 with: - path: ~/.maestro - key: maestro-${{ runner.os }}-${{ env.MAESTRO_VERSION }} - - - name: Install maestro CLI - if: steps.keys.outputs.pk != '' - run: | - if [ -x "$HOME/.maestro/bin/maestro" ]; then - echo "Using cached Maestro" - else - archive="$RUNNER_TEMP/maestro.zip" - curl -fLs --retry 3 --retry-delay 5 -o "$archive" \ - "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/mobile-dev-inc/Maestro/releases/download/cli-$MAESTRO_VERSION/maestro.zip" - unzip -q "$archive" -d "$RUNNER_TEMP/maestro-dist" - mv "$RUNNER_TEMP/maestro-dist/maestro" "$HOME/.maestro" - fi - echo "$HOME/.maestro/bin" >> "$GITHUB_PATH" - test "$("$HOME/.maestro/bin/maestro" --version)" = "$MAESTRO_VERSION" + path: ~/.agent-device + key: agent-device-${{ runner.os }}-${{ hashFiles(format('{0}/pnpm-lock.yaml', env.E2E_DIR)) }} # Provisioned as late as possible so live credentials exist for the # shortest window. @@ -281,7 +269,7 @@ jobs: echo "user_id=$user_id" } >> "$GITHUB_OUTPUT" - - name: Run iOS e2e (Maestro) + - name: Run iOS e2e id: run_e2e_ios if: matrix.platform == 'ios' && steps.user.outputs.user_id != '' working-directory: ${{ env.FIXTURE_DIR }} @@ -290,18 +278,17 @@ jobs: CLERK_TEST_PASSWORD: ${{ steps.user.outputs.password }} run: | "$GITHUB_WORKSPACE/$E2E_DIR/boot-ios-simulators.sh" wait - mkdir -p "$RUNNER_TEMP/maestro-debug" + mkdir -p "$RUNNER_TEMP/e2e-device-logs" log_pids=() trap 'kill "${log_pids[@]}" 2>/dev/null || true; wait "${log_pids[@]}" 2>/dev/null || true' EXIT - for udid in ${MAESTRO_UDID//,/ }; do + for udid in ${CLERK_TEST_DEVICES//,/ }; do xcrun simctl install "$udid" ios/build/Build/Products/Release-iphonesimulator/ClerkExpoNativeBuildFixture.app xcrun simctl spawn "$udid" log stream --style compact \ --predicate 'processImagePath CONTAINS "ClerkExpoNativeBuildFixture"' \ - > "$RUNNER_TEMP/maestro-debug/$udid-console.log" 2>&1 & + > "$RUNNER_TEMP/e2e-device-logs/$udid-console.log" 2>&1 & log_pids+=($!) done - PLATFORM=ios MAESTRO_DEBUG_OUTPUT="$RUNNER_TEMP/maestro-debug" \ - "$GITHUB_WORKSPACE/$E2E_DIR/run-flows.sh" + PLATFORM=ios "$GITHUB_WORKSPACE/$E2E_DIR/run-flows.sh" - name: Enable KVM if: matrix.platform == 'android' && steps.user.outputs.user_id != '' @@ -332,7 +319,7 @@ jobs: disable-animations: false script: echo "Generated AVD snapshot for caching." - - name: Run Android e2e (Maestro) + - name: Run Android e2e id: run_e2e_android if: matrix.platform == 'android' && steps.user.outputs.user_id != '' uses: reactivecircus/android-emulator-runner@a421e43855164a8197daf9d8d40fe71c6996bb0d # v2 @@ -351,7 +338,7 @@ jobs: # scalar (>-) plus && keeps everything in one shell invocation. script: >- cd integration/tests/expo-native && - MAESTRO_DEBUG_OUTPUT="$RUNNER_TEMP/maestro-debug" ./run-android-flows.sh + E2E_DEVICE_LOGS="$RUNNER_TEMP/e2e-device-logs" ./run-android-flows.sh "$GITHUB_WORKSPACE/$FIXTURE_DIR/android/app/build/outputs/apk/release/app-release.apk" # Runs before the artifact upload so the credentials are already dead @@ -368,25 +355,28 @@ jobs: # Test reports record flow env (and typed input) in plaintext; # add-mask only covers step logs, not artifact contents. Must run whenever # the upload does, or a passing run uploads the password. - - name: Scrub test credentials from Maestro debug output + - name: Scrub test credentials from e2e output id: scrub if: always() && steps.user.outputs.user_id != '' env: CLERK_TEST_PASSWORD: ${{ steps.user.outputs.password }} run: | - [ -d "$RUNNER_TEMP/maestro-debug" ] || exit 0 [ -n "$CLERK_TEST_PASSWORD" ] || exit 0 + mkdir -p "$E2E_DIR/.e2e" "$RUNNER_TEMP/e2e-device-logs" # shellcheck disable=SC2016 - find "$RUNNER_TEMP/maestro-debug" -type f \ - \( -name '*.html' -o -name '*.json' -o -name '*.log' -o -name '*.txt' -o -name '*.xml' -o -name '*.yaml' \) \ + find "$E2E_DIR/.e2e" "$RUNNER_TEMP/e2e-device-logs" -type f \ + \( -name '*.json' -o -name '*.log' -o -name '*.md' -o -name '*.txt' -o -name '*.xml' \) \ -exec perl -pi -e 's/\Q$ENV{CLERK_TEST_PASSWORD}\E/[REDACTED]/g' {} + - - name: Upload Maestro artifacts + - name: Upload e2e artifacts if: always() && steps.scrub.outcome == 'success' uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4 with: - name: maestro-${{ matrix.platform }} - path: ${{ runner.temp }}/maestro-debug + name: e2e-${{ matrix.platform }} + include-hidden-files: true + path: | + ${{ env.E2E_DIR }}/.e2e + ${{ runner.temp }}/e2e-device-logs if-no-files-found: warn retention-days: 7 @@ -398,7 +388,7 @@ jobs: run: | outcome="$IOS_OUTCOME" [ "$outcome" = "skipped" ] && outcome="$ANDROID_OUTCOME" - echo "## Maestro e2e (${{ matrix.platform }}): $outcome" >> "$GITHUB_STEP_SUMMARY" + echo "## Native e2e (${{ matrix.platform }}): $outcome" >> "$GITHUB_STEP_SUMMARY" if [ "$outcome" = "failure" ]; then - echo "::error::Maestro e2e failed. See the maestro-${{ matrix.platform }} artifact." + echo "::error::Native e2e failed. See the e2e-${{ matrix.platform }} artifact." fi diff --git a/integration/tests/expo-native/.gitignore b/integration/tests/expo-native/.gitignore index e33609d251c..36abc8bac36 100644 --- a/integration/tests/expo-native/.gitignore +++ b/integration/tests/expo-native/.gitignore @@ -1 +1,2 @@ -*.png +/.e2e/ +/node_modules/ diff --git a/integration/tests/expo-native/boot-ios-simulators.sh b/integration/tests/expo-native/boot-ios-simulators.sh index 139335fd1b3..2c216a2c608 100755 --- a/integration/tests/expo-native/boot-ios-simulators.sh +++ b/integration/tests/expo-native/boot-ios-simulators.sh @@ -14,14 +14,14 @@ boot() { udids+=("$(xcrun simctl create "$model $i" "$device_type" "$runtime")") xcrun simctl boot "${udids[$((i - 1))]}" done - MAESTRO_UDID=$(IFS=,; echo "${udids[*]}") - echo "Booting $count x $model on $runtime: $MAESTRO_UDID" - if [ -n "${GITHUB_ENV:-}" ]; then echo "MAESTRO_UDID=$MAESTRO_UDID" >> "$GITHUB_ENV"; fi + CLERK_TEST_DEVICES=$(IFS=,; echo "${udids[*]}") + echo "Booting $count x $model on $runtime: $CLERK_TEST_DEVICES" + if [ -n "${GITHUB_ENV:-}" ]; then echo "CLERK_TEST_DEVICES=$CLERK_TEST_DEVICES" >> "$GITHUB_ENV"; fi } wait_ready() { local udid key - IFS=, read -r -a udids <<< "${MAESTRO_UDID:?MAESTRO_UDID is required}" + IFS=, read -r -a udids <<< "${CLERK_TEST_DEVICES:?CLERK_TEST_DEVICES is required}" for udid in "${udids[@]}"; do xcrun simctl bootstatus "$udid" -b & local pid=$! elapsed=0 diff --git a/integration/tests/expo-native/config.yaml b/integration/tests/expo-native/config.yaml deleted file mode 100644 index 94e3659b694..00000000000 --- a/integration/tests/expo-native/config.yaml +++ /dev/null @@ -1,15 +0,0 @@ -# Maestro workspace config: https://docs.maestro.dev/reference/workspace-configuration -# Top-level files under flows/ are cross-platform tests; flows/subflows/ holds -# runFlow-only pieces that discovery never runs standalone. Selectors use -# English text/labels: clerk-android ships no testTag/resource-ids (clerk-ios -# does expose accessibility identifiers like clerk.auth.start.identifier, but -# shared flows can't rely on iOS-only ids), and both native SDKs localize all -# strings, so devices must run the en locale. -appId: com.clerk.exponativebuildfixture -flows: - - 'flows/*.yaml' -platform: - ios: - disableAnimations: true - android: - disableAnimations: true diff --git a/integration/tests/expo-native/e2e.config.ts b/integration/tests/expo-native/e2e.config.ts new file mode 100644 index 00000000000..c817a6fda8a --- /dev/null +++ b/integration/tests/expo-native/e2e.config.ts @@ -0,0 +1,15 @@ +import { mobile } from '@e2e-dev/mobile'; +import type { E2EConfig } from 'e2e'; + +const app = { bundleId: 'com.clerk.exponativebuildfixture' }; +const devices = process.env.CLERK_TEST_DEVICES?.split(','); + +export default { + tests: 'flows/*.e2e.ts', + targets: [ + { name: 'ios', engine: mobile({ platform: 'ios', device: devices }), app }, + { name: 'android', engine: mobile({ platform: 'android', device: devices }), app }, + ], + workers: devices?.length ?? 1, + timeout: 300_000, +} satisfies E2EConfig; diff --git a/integration/tests/expo-native/flows/authview-detach-reattach.e2e.ts b/integration/tests/expo-native/flows/authview-detach-reattach.e2e.ts new file mode 100644 index 00000000000..a3b7cbaa203 --- /dev/null +++ b/integration/tests/expo-native/flows/authview-detach-reattach.e2e.ts @@ -0,0 +1,24 @@ +import { test } from '@e2e-dev/mobile'; +import { expect } from 'e2e'; + +import { assertSignedIn, assertSignedOut, openApp, signInEmailPassword } from './subflows.ts'; + +test('AuthView survives detach and reattach', async fixtures => { + const { device, platform, screen } = fixtures; + await openApp(fixtures); + await screen.getByTestId('open-auth-view-button').tap(); + await expect(screen.getByText(/^Welcome! Sign in to continue\.?$/)).toBeVisible({ timeout: 25_000 }); + await expect(screen.getByText('E2E Custom Logo')).toBeVisible({ timeout: 10_000 }); + if (platform === 'android') { + await device.back(); + } else { + await screen.getByRole('button', 'Close').tap(); + } + await expect(screen.getByTestId('open-auth-view-button')).toBeVisible({ timeout: 15_000 }); + await screen.getByTestId('open-auth-view-button').tap(); + await expect(screen.getByText('E2E Custom Logo')).toBeVisible({ timeout: 15_000 }); + await signInEmailPassword(fixtures); + await assertSignedIn(fixtures); + await screen.getByTestId('sign-out-button').tap(); + await assertSignedOut(fixtures); +}); diff --git a/integration/tests/expo-native/flows/authview-detach-reattach.yaml b/integration/tests/expo-native/flows/authview-detach-reattach.yaml deleted file mode 100644 index ecb1c592d98..00000000000 --- a/integration/tests/expo-native/flows/authview-detach-reattach.yaml +++ /dev/null @@ -1,46 +0,0 @@ -# Dismiss the native AuthView mid-flow and reopen it: the native view must -# survive detach/reattach and still complete a sign-in afterwards. Dismissal -# is the platform-native gesture: Android's system back button (doubling as -# the back-dismisses-AuthView regression), iOS's sheet Close control -# (clerk-ios exposes the stable clerk.dismissButton identifier). -# Also asserts the custom `logo` React element is rehosted into the native -# logo slot with a nonzero size, both on first mount and after reattach. -appId: com.clerk.exponativebuildfixture -name: AuthView survives detach and reattach ---- -- runFlow: subflows/open-app.yaml -- tapOn: - id: 'open-auth-view-button' -- extendedWaitUntil: - visible: 'Welcome! Sign in to continue\.?' - timeout: 25000 -# Retrying wait (not assertVisible): the rehosted logo is sized on the first -# RN layout pass, so it can lag the welcome copy by a frame or two. -- extendedWaitUntil: - visible: 'E2E Custom Logo' - timeout: 10000 -- runFlow: - when: - platform: Android - commands: - - back -- runFlow: - when: - platform: iOS - commands: - - tapOn: - id: 'clerk.dismissButton' -- extendedWaitUntil: - visible: - id: 'open-auth-view-button' - timeout: 15000 -- tapOn: - id: 'open-auth-view-button' -- extendedWaitUntil: - visible: 'E2E Custom Logo' - timeout: 15000 -- runFlow: subflows/sign-in-email-password.yaml -- runFlow: subflows/assert-signed-in.yaml -- tapOn: - id: 'sign-out-button' -- runFlow: subflows/assert-signed-out.yaml diff --git a/integration/tests/expo-native/flows/embedded-profile-host-back.e2e.ts b/integration/tests/expo-native/flows/embedded-profile-host-back.e2e.ts new file mode 100644 index 00000000000..775e21cbb5c --- /dev/null +++ b/integration/tests/expo-native/flows/embedded-profile-host-back.e2e.ts @@ -0,0 +1,28 @@ +import { test } from '@e2e-dev/mobile'; +import { expect } from 'e2e'; + +import { assertSignedIn, assertSignedOut, openApp, signInEmailPassword, tapBack } from './subflows.ts'; + +const internalPush = { + android: { root: 'Edit profile', row: 'Manage account', detail: /^(EMAIL ADDRESSES|Add email address)$/ }, + ios: { root: 'Security', row: 'Security', detail: /^(Password|Passkeys|Two-step verification|Active devices)$/i }, +}; + +test('Embedded UserProfileView host back round trip', async fixtures => { + const { platform, screen } = fixtures; + const { root, row, detail } = internalPush[platform as keyof typeof internalPush]; + await openApp(fixtures); + await screen.getByTestId('open-auth-view-button').tap(); + await signInEmailPassword(fixtures); + await assertSignedIn(fixtures); + await screen.getByTestId('open-embedded-profile-button').tap(); + await expect(screen.getByText(root)).toBeVisible({ timeout: 20_000 }); + await screen.getByText(row).tap(); + await expect(screen.getByText(detail).first()).toBeVisible({ timeout: 15_000 }); + await tapBack(fixtures); + await expect(screen.getByText(root)).toBeVisible({ timeout: 15_000 }); + await tapBack(fixtures); + await expect(screen.getByTestId('open-embedded-profile-button')).toBeVisible({ timeout: 15_000 }); + await screen.getByTestId('sign-out-button').tap(); + await assertSignedOut(fixtures); +}); diff --git a/integration/tests/expo-native/flows/embedded-profile-host-back.yaml b/integration/tests/expo-native/flows/embedded-profile-host-back.yaml deleted file mode 100644 index 360a99e8ed7..00000000000 --- a/integration/tests/expo-native/flows/embedded-profile-host-back.yaml +++ /dev/null @@ -1,58 +0,0 @@ -# Embedded UserProfileView (onHostBack): internal navigation stays native, -# and the host-supplied root back button closes the screen from JS. -appId: com.clerk.exponativebuildfixture -name: Embedded UserProfileView host back round trip ---- -- runFlow: subflows/open-app.yaml -- tapOn: - id: 'open-auth-view-button' -- runFlow: subflows/sign-in-email-password.yaml -- runFlow: subflows/assert-signed-in.yaml -- tapOn: - id: 'open-embedded-profile-button' -# The internal push differs per platform: clerk-ios pushes a Security screen -# from the profile root, clerk-android uses tabs at the root and pushes the -# Manage account screen instead. The double-Back contract below is the same: -# both back buttons read 'Back' but only one exists at a time, so the first -# tap pops Clerk's internal stack and the second is the host chevron firing -# onHostBack. -- runFlow: - when: - platform: iOS - commands: - - extendedWaitUntil: - visible: 'Security' - timeout: 20000 - - tapOn: - text: 'Security' - - extendedWaitUntil: - visible: 'Password|Passkeys|Two-step verification|Active devices' - timeout: 15000 - - tapOn: 'Back' - - extendedWaitUntil: - visible: 'Security' - timeout: 15000 -- runFlow: - when: - platform: Android - commands: - - extendedWaitUntil: - visible: 'Edit profile' - timeout: 20000 - - tapOn: - text: 'Manage account' - - extendedWaitUntil: - visible: 'EMAIL ADDRESSES|Add email address' - timeout: 15000 - - tapOn: 'Back' - - extendedWaitUntil: - visible: 'Edit profile' - timeout: 15000 -- tapOn: 'Back' -- extendedWaitUntil: - visible: - id: 'open-embedded-profile-button' - timeout: 15000 -- tapOn: - id: 'sign-out-button' -- runFlow: subflows/assert-signed-out.yaml diff --git a/integration/tests/expo-native/flows/google-sign-in-missing-credentials.e2e.ts b/integration/tests/expo-native/flows/google-sign-in-missing-credentials.e2e.ts new file mode 100644 index 00000000000..a8db92316af --- /dev/null +++ b/integration/tests/expo-native/flows/google-sign-in-missing-credentials.e2e.ts @@ -0,0 +1,11 @@ +import { test } from '@e2e-dev/mobile'; +import { expect } from 'e2e'; + +import { openApp } from './subflows.ts'; + +test('useSignInWithGoogle surfaces the missing-credentials error', async fixtures => { + const { screen } = fixtures; + await openApp(fixtures); + await screen.getByTestId('google-sign-in-button').tap(); + await expect(screen.getByText(/Google Sign-In credentials not found/)).toBeVisible({ timeout: 15_000 }); +}); diff --git a/integration/tests/expo-native/flows/google-sign-in-missing-credentials.yaml b/integration/tests/expo-native/flows/google-sign-in-missing-credentials.yaml deleted file mode 100644 index 417319758f3..00000000000 --- a/integration/tests/expo-native/flows/google-sign-in-missing-credentials.yaml +++ /dev/null @@ -1,9 +0,0 @@ -appId: com.clerk.exponativebuildfixture -name: useSignInWithGoogle surfaces the missing-credentials error ---- -- runFlow: subflows/open-app.yaml -- tapOn: - id: 'google-sign-in-button' -- extendedWaitUntil: - visible: '.*Google Sign-In credentials not found.*' - timeout: 15000 diff --git a/integration/tests/expo-native/flows/sign-in.e2e.ts b/integration/tests/expo-native/flows/sign-in.e2e.ts new file mode 100644 index 00000000000..bb89eb604fe --- /dev/null +++ b/integration/tests/expo-native/flows/sign-in.e2e.ts @@ -0,0 +1,17 @@ +import { test } from '@e2e-dev/mobile'; +import { expect } from 'e2e'; + +import { assertSignedIn, assertSignedOut, openApp, signInEmailPassword } from './subflows.ts'; + +test('Native AuthView sign-in syncs to JS and survives a restart', async fixtures => { + const { app, screen } = fixtures; + await openApp(fixtures); + await screen.getByTestId('open-auth-view-button').tap(); + await signInEmailPassword(fixtures); + await assertSignedIn(fixtures); + await app.restart(); + await expect(screen.getByText('signed in')).toBeVisible({ timeout: 45_000 }); + await expect(screen.getByTestId('user-id')).toBeVisible(); + await screen.getByTestId('sign-out-button').tap(); + await assertSignedOut(fixtures); +}); diff --git a/integration/tests/expo-native/flows/sign-in.yaml b/integration/tests/expo-native/flows/sign-in.yaml deleted file mode 100644 index 19aeba4c21a..00000000000 --- a/integration/tests/expo-native/flows/sign-in.yaml +++ /dev/null @@ -1,19 +0,0 @@ -# Native sign-in observed by JS, kept across a restart without clearing state, then JS sign-out. -appId: com.clerk.exponativebuildfixture -name: Native AuthView sign-in syncs to JS and survives a restart ---- -- runFlow: subflows/open-app.yaml -- tapOn: - id: 'open-auth-view-button' -- runFlow: subflows/sign-in-email-password.yaml -- runFlow: subflows/assert-signed-in.yaml -- stopApp -- launchApp -- extendedWaitUntil: - visible: 'signed in' - timeout: 45000 -- assertVisible: - id: 'user-id' -- tapOn: - id: 'sign-out-button' -- runFlow: subflows/assert-signed-out.yaml diff --git a/integration/tests/expo-native/flows/subflows.ts b/integration/tests/expo-native/flows/subflows.ts new file mode 100644 index 00000000000..a25deea5a68 --- /dev/null +++ b/integration/tests/expo-native/flows/subflows.ts @@ -0,0 +1,124 @@ +import type { Device } from '@e2e-dev/mobile'; +import type { Locator, TestFixtures } from 'e2e'; +import { expect } from 'e2e'; + +export type Fixtures = TestFixtures & { device: Device }; + +const email = process.env.CLERK_TEST_EMAIL ?? ''; +const password = process.env.CLERK_TEST_PASSWORD ?? ''; + +export async function openApp({ app, device, platform, screen }: Fixtures) { + await app.open(); + if (platform === 'ios') { + await device.clearKeychain(); + } + await app.clearState(); + await expect(screen.getByText(/^signed (in|out)$/)).toBeVisible({ timeout: 45_000 }); + await expect(screen.getByText('signed out')).toBeVisible(); +} + +export async function assertSignedIn({ screen }: Fixtures) { + await expect(screen.getByText('signed in')).toBeVisible({ timeout: 30_000 }); + await expect(screen.getByTestId('user-id')).toBeVisible(); +} + +export async function assertSignedOut({ screen }: Fixtures) { + await expect(screen.getByText('signed out')).toBeVisible({ timeout: 20_000 }); +} + +export async function tapBack({ screen }: Fixtures) { + const back = screen.getByLabel('Back'); + await expect(back).toBeVisible(); + const box = await back.boundingBox(); + if (!box) { + throw new Error('Back control has no bounding box'); + } + await screen.tapAt({ x: box.x + box.width / 2, y: box.y + box.height / 2 }); +} + +async function fill(field: Locator, value: string) { + await field.fill(value).catch((error: { code?: string }) => { + if (error.code !== 'ENGINE_FAILURE') { + throw error; + } + return field.fill(value); + }); +} + +async function skipPasskeyFirstFactor({ platform, screen }: Fixtures) { + if (platform === 'ios') { + const error = screen.getByText('Whoops, something is wrong'); + await expect(error).toBeVisible({ timeout: 10_000 }); + for (let attempt = 0; attempt < 3 && (await error.isVisible()); attempt++) { + await screen.getByRole('button', 'Close').last().tap(); + await expect(error) + .toBeHidden({ timeout: 3000 }) + .catch(() => {}); + } + } + await screen.getByText(/^Use (a different|another) method$/).tap(); + await screen.getByText('Sign in with your password').tap(); +} + +async function enterEmailCode({ screen }: Fixtures) { + if (await screen.getByText('Check your email').isVisible()) { + await fill(screen.getByRole('textbox'), '424242'); + } +} + +async function dismissPasswordManager({ screen }: Fixtures) { + if ( + await screen + .getByText(/Google Password Manager/) + .first() + .isVisible() + ) { + await screen + .getByText(/^(Not now|Never)$/i) + .first() + .tap(); + } + if ( + await screen + .getByText(/^(Save Password|Strong Password|Use Strong Password|AutoFill Passwords)$/i) + .first() + .isVisible() + ) { + const dismiss = screen.getByText(/^(Not Now|Never for This Website|Don.t Save)$/i).first(); + if (await dismiss.isVisible()) { + await dismiss.tap(); + } + } +} + +const afterPassword = + /^(Check your email|signed in|Save Password|Strong Password|Use Strong Password|AutoFill Passwords)$|Google Password Manager/i; + +export async function signInEmailPassword(fixtures: Fixtures) { + const { screen } = fixtures; + await expect(screen.getByText(/^Welcome! Sign in to continue\.?$/)).toBeVisible({ timeout: 25_000 }); + const identifierPlaceholder = screen.getByText(/^Enter your email( or username)?$/); + if (await identifierPlaceholder.isVisible()) { + await identifierPlaceholder.tap(); + } + const identifier = screen.getByDisplayValue(email); + if (!(await identifier.isVisible())) { + await fill(screen.getByRole('textbox'), email); + } + await expect(identifier).toBeVisible(); + await screen.getByText('Continue').tap(); + const firstFactor = screen.getByText(/^(Enter your password|Check your email|Use your passkey)$/).first(); + await expect(firstFactor).toBeVisible({ timeout: 15_000 }); + if (await screen.getByText('Use your passkey').isVisible()) { + await skipPasskeyFirstFactor(fixtures); + await expect(screen.getByText('Enter your password').first()).toBeVisible({ timeout: 15_000 }); + } + await enterEmailCode(fixtures); + if (await screen.getByText('Enter your password').first().isVisible()) { + await fill(screen.getByRole('textbox'), password); + await screen.getByText('Continue').tap(); + await expect(screen.getByText(afterPassword).first()).toBeVisible({ timeout: 15_000 }); + } + await enterEmailCode(fixtures); + await dismissPasswordManager(fixtures); +} diff --git a/integration/tests/expo-native/flows/subflows/_warmup.yaml b/integration/tests/expo-native/flows/subflows/_warmup.yaml deleted file mode 100644 index 6c880b05805..00000000000 --- a/integration/tests/expo-native/flows/subflows/_warmup.yaml +++ /dev/null @@ -1,16 +0,0 @@ -# Cold-boot warmup, not a test. Lets the JS bundle parse and the a11y tree -# populate once, so the first real flow doesn't eat the cold-start cost and -# flake its in-flow waits. Excluded from the per-flow loop (lives in subflows/). -appId: com.clerk.exponativebuildfixture ---- -# Android can kill a fresh launch when pm clear's task removal lands after am start. -- retry: - maxRetries: 1 - commands: - - launchApp: - clearState: true - clearKeychain: true - - extendedWaitUntil: - visible: - id: 'auth-state' - timeout: 90000 diff --git a/integration/tests/expo-native/flows/subflows/assert-signed-in.yaml b/integration/tests/expo-native/flows/subflows/assert-signed-in.yaml deleted file mode 100644 index 65bcc55159d..00000000000 --- a/integration/tests/expo-native/flows/subflows/assert-signed-in.yaml +++ /dev/null @@ -1,9 +0,0 @@ -# Subflow: assert the JS layer observed the native sign-in (bridge sync). -# extendedWaitUntil retries until timeout; assertVisible does not. -appId: com.clerk.exponativebuildfixture ---- -- extendedWaitUntil: - visible: 'signed in' - timeout: 30000 -- assertVisible: - id: 'user-id' diff --git a/integration/tests/expo-native/flows/subflows/assert-signed-out.yaml b/integration/tests/expo-native/flows/subflows/assert-signed-out.yaml deleted file mode 100644 index 72986f7cae9..00000000000 --- a/integration/tests/expo-native/flows/subflows/assert-signed-out.yaml +++ /dev/null @@ -1,6 +0,0 @@ -# Subflow: assert the JS layer is signed out. -appId: com.clerk.exponativebuildfixture ---- -- extendedWaitUntil: - visible: 'signed out' - timeout: 20000 diff --git a/integration/tests/expo-native/flows/subflows/open-app.yaml b/integration/tests/expo-native/flows/subflows/open-app.yaml deleted file mode 100644 index 308bc4836f9..00000000000 --- a/integration/tests/expo-native/flows/subflows/open-app.yaml +++ /dev/null @@ -1,21 +0,0 @@ -# Subflow: launch from a clean state and land signed out. -appId: com.clerk.exponativebuildfixture ---- -# Android can kill a fresh launch when pm clear's task removal lands after am start. -- retry: - maxRetries: 1 - commands: - - launchApp: - clearState: true - clearKeychain: true - - extendedWaitUntil: - visible: - id: 'auth-state' - timeout: 30000 -# Text-only matching from here on: iOS failed combined id+text filters on RN -# Text elements in CI while id-only and text-only both match. Also wait out -# clerk-js init ('loading') with a retrying wait; assertVisible never retries. -- extendedWaitUntil: - visible: 'signed (in|out)' - timeout: 45000 -- assertVisible: 'signed out' diff --git a/integration/tests/expo-native/flows/subflows/sign-in-email-password.yaml b/integration/tests/expo-native/flows/subflows/sign-in-email-password.yaml deleted file mode 100644 index 17b4f364ac9..00000000000 --- a/integration/tests/expo-native/flows/subflows/sign-in-email-password.yaml +++ /dev/null @@ -1,125 +0,0 @@ -# Subflow: enter email + password into the native AuthView and submit. -# Requires CLERK_TEST_EMAIL and CLERK_TEST_PASSWORD env vars. -appId: com.clerk.exponativebuildfixture ---- -- extendedWaitUntil: - visible: 'Welcome! Sign in to continue\.?' - timeout: 25000 -# The AuthView sometimes renders its welcome text a beat before the email -# field; don't tap until the field is actually present. The placeholder -# varies by instance config (email-only vs email+username). -- extendedWaitUntil: - visible: 'Enter your email( or username)?' - timeout: 25000 -# Clear any pre-populated identifier (Clerk persists the last-used one in -# secure-store, surviving clearState). On iOS eraseText is cursor-dependent, -# so Select-all via the edit menu when it shows (the menu is unreliable on a -# remounted AuthView). On Android eraseText clears the whole field, and the -# long-press can open Gboard's features panel over the screen instead of the -# edit menu, so skip the menu dance there. The retry gates on reaching the -# password step, so a mangled identifier gets a clean second attempt. -- retry: - maxRetries: 2 - commands: - - tapOn: - text: 'Enter your email( or username)?' - - waitForAnimationToEnd: - timeout: 2000 - # A remounted AuthView prefills the last-used identifier, which is the - # same email this flow signs in with, and clearing a prefilled field is - # cursor-position dependent on Android. Only clear and retype when the - # field does not already hold the right value. - - runFlow: - when: - notVisible: ${CLERK_TEST_EMAIL} - commands: - - runFlow: - when: - platform: iOS - commands: - - longPressOn: - text: 'Enter your email( or username)?' - - runFlow: - when: - visible: 'Select All' - commands: - - tapOn: - text: 'Select All' - - eraseText: 60 - - inputText: ${CLERK_TEST_EMAIL} - # Wait for the typed value to land before tapping: the tap can race the - # recomposition that enables the button, and this also catches a mangled - # identifier inside the retry instead of at the next screen's timeout. - - extendedWaitUntil: - visible: ${CLERK_TEST_EMAIL} - timeout: 5000 - - waitForAnimationToEnd: - timeout: 2000 - - tapOn: - text: 'Continue' - index: 0 - # Which first factor comes next depends on instance config AND SDK: - # clerk-ios can go email-code-first where clerk-android goes - # password-first. Accept either screen. - - extendedWaitUntil: - visible: 'Enter your password|Check your email' - timeout: 15000 -# Email-code-first: for +clerk_test@ emails the documented test code is -# 424242: https://clerk.com/docs/testing/test-emails-and-phones -- runFlow: - when: - visible: 'Check your email' - commands: - - inputText: '424242' - - waitForAnimationToEnd: - timeout: 5000 -- runFlow: - when: - visible: 'Enter your password' - commands: - - tapOn: - text: 'Enter your password' - - inputText: ${CLERK_TEST_PASSWORD} - # The password is masked so its value can't be asserted; settle for the - # screen going stable so the tap doesn't race the enabling recomposition. - - waitForAnimationToEnd: - timeout: 2000 - - tapOn: - text: 'Continue' - index: 0 - - waitForAnimationToEnd: - timeout: 5000 - # The screen stays stable while the sign-in request is in flight, so the - # animation wait alone can return before the next screen exists. Wait for - # either outcome so the conditional below sees the real screen. - - extendedWaitUntil: - visible: 'Check your email|signed in' - timeout: 15000 - optional: true -# Some instances ask for the email code after the password instead. -- runFlow: - when: - visible: 'Check your email' - commands: - - inputText: '424242' - - waitForAnimationToEnd: - timeout: 5000 -# Android Google Password Manager may prompt to save the password. -- runFlow: - when: - visible: '.*Google Password Manager.*' - commands: - - tapOn: - text: 'Not now|Never' - - waitForAnimationToEnd: - timeout: 2000 -# iOS system Save Password / iCloud Keychain prompt overlays the app. -- runFlow: - when: - visible: 'Save Password|Strong Password|Use Strong Password|AutoFill Passwords' - commands: - - tapOn: - text: 'Not Now|Never for This Website|Don.t Save' - optional: true - - waitForAnimationToEnd: - timeout: 2000 diff --git a/integration/tests/expo-native/flows/user-button-sign-out-re-sign-in.e2e.ts b/integration/tests/expo-native/flows/user-button-sign-out-re-sign-in.e2e.ts new file mode 100644 index 00000000000..c70176dc994 --- /dev/null +++ b/integration/tests/expo-native/flows/user-button-sign-out-re-sign-in.e2e.ts @@ -0,0 +1,21 @@ +import { test } from '@e2e-dev/mobile'; +import { expect } from 'e2e'; + +import { assertSignedIn, assertSignedOut, openApp, signInEmailPassword } from './subflows.ts'; + +test('UserButton native sign-out, then same-process re-sign-in', async fixtures => { + const { screen } = fixtures; + await openApp(fixtures); + await screen.getByTestId('open-auth-view-button').tap(); + await signInEmailPassword(fixtures); + await assertSignedIn(fixtures); + await screen.getByLabel(/^Open (account|user profile)$/).tap(); + await expect(screen.getByText('Manage account')).toBeVisible({ timeout: 15_000 }); + await screen.getByText('Sign out').tap(); + await assertSignedOut(fixtures); + await screen.getByTestId('open-auth-view-button').tap(); + await signInEmailPassword(fixtures); + await assertSignedIn(fixtures); + await screen.getByTestId('sign-out-button').tap(); + await assertSignedOut(fixtures); +}); diff --git a/integration/tests/expo-native/flows/user-button-sign-out-re-sign-in.yaml b/integration/tests/expo-native/flows/user-button-sign-out-re-sign-in.yaml deleted file mode 100644 index eb1a2a12cb7..00000000000 --- a/integration/tests/expo-native/flows/user-button-sign-out-re-sign-in.yaml +++ /dev/null @@ -1,36 +0,0 @@ -# Native UserButton -> account sheet -> native sign-out, asserting the JS -# layer observes it (the reverse bridge direction from sign-in.yaml). -# clerk-android exposes no test identifiers (no testTag / resource-ids), so -# shared selectors are English text / accessibility labels. -# -# Ends with a second sign-in in the SAME app process (no restart, no -# clearState): a past regression had the second native sign-in complete -# natively while the JS SDK never observed it. Every other flow cold-launches -# with clearState, so this is the only place that path is exercised. -appId: com.clerk.exponativebuildfixture -name: UserButton native sign-out, then same-process re-sign-in ---- -- runFlow: subflows/open-app.yaml -- tapOn: - id: 'open-auth-view-button' -- runFlow: subflows/sign-in-email-password.yaml -- runFlow: subflows/assert-signed-in.yaml -# iOS labels the trigger "Open account"; Android "Open user profile". -- tapOn: - text: 'Open (account|user profile)' -- extendedWaitUntil: - visible: 'Manage account' - timeout: 15000 -- assertVisible: 'Sign out' -- tapOn: - text: 'Sign out' -- runFlow: subflows/assert-signed-out.yaml -# Second sign-in without restarting the app: the remounted AuthView must -# work and the JS layer must observe the new session. -- tapOn: - id: 'open-auth-view-button' -- runFlow: subflows/sign-in-email-password.yaml -- runFlow: subflows/assert-signed-in.yaml -- tapOn: - id: 'sign-out-button' -- runFlow: subflows/assert-signed-out.yaml diff --git a/integration/tests/expo-native/flows/user-profile-custom-pages.e2e.ts b/integration/tests/expo-native/flows/user-profile-custom-pages.e2e.ts new file mode 100644 index 00000000000..ef809547cfc --- /dev/null +++ b/integration/tests/expo-native/flows/user-profile-custom-pages.e2e.ts @@ -0,0 +1,26 @@ +import { test } from '@e2e-dev/mobile'; +import { expect } from 'e2e'; + +import { assertSignedIn, assertSignedOut, openApp, signInEmailPassword, tapBack } from './subflows.ts'; + +test('UserProfileView renders a custom page', async fixtures => { + const { device, platform, screen } = fixtures; + await openApp(fixtures); + await screen.getByTestId('open-auth-view-button').tap(); + await signInEmailPassword(fixtures); + await assertSignedIn(fixtures); + await screen.getByTestId('open-embedded-profile-button').tap(); + await expect(screen.getByText('E2E Custom Page')).toBeVisible({ timeout: 20_000 }); + await screen.getByText('E2E Custom Page').tap(); + await expect(screen.getByText('Rehosted RN body')).toBeVisible({ timeout: 15_000 }); + if (platform === 'android') { + await device.back(); + } else { + await tapBack(fixtures); + } + await expect(screen.getByText('E2E Custom Page')).toBeVisible({ timeout: 15_000 }); + await tapBack(fixtures); + await expect(screen.getByTestId('open-embedded-profile-button')).toBeVisible({ timeout: 15_000 }); + await screen.getByTestId('sign-out-button').tap(); + await assertSignedOut(fixtures); +}); diff --git a/integration/tests/expo-native/flows/user-profile-custom-pages.yaml b/integration/tests/expo-native/flows/user-profile-custom-pages.yaml deleted file mode 100644 index 0b408084b51..00000000000 --- a/integration/tests/expo-native/flows/user-profile-custom-pages.yaml +++ /dev/null @@ -1,45 +0,0 @@ -# A custom page's React Native content is mounted as a child of the native host -# and rehosted into the destination its row pushes, then survives the trip back. -appId: com.clerk.exponativebuildfixture -name: UserProfileView renders a custom page ---- -- runFlow: subflows/open-app.yaml -- tapOn: - id: 'open-auth-view-button' -- runFlow: subflows/sign-in-email-password.yaml -- runFlow: subflows/assert-signed-in.yaml -- tapOn: - id: 'open-embedded-profile-button' -# Retrying wait: the row list lands a frame after the native profile paints. -- extendedWaitUntil: - visible: 'E2E Custom Page' - timeout: 20000 -- tapOn: - text: 'E2E Custom Page' -- extendedWaitUntil: - visible: 'Rehosted RN body' - timeout: 15000 -# The Android destination is a bare AndroidView with no back chrome, unlike the -# iOS page which clerk-ios pushes onto its own NavigationStack. -- runFlow: - when: - platform: iOS - commands: - - tapOn: 'Back' -- runFlow: - when: - platform: Android - commands: - - back -- extendedWaitUntil: - visible: 'E2E Custom Page' - timeout: 15000 -# The host chevron firing onHostBack, which reads 'Back' on both platforms. -- tapOn: 'Back' -- extendedWaitUntil: - visible: - id: 'open-embedded-profile-button' - timeout: 15000 -- tapOn: - id: 'sign-out-button' -- runFlow: subflows/assert-signed-out.yaml diff --git a/integration/tests/expo-native/package.json b/integration/tests/expo-native/package.json new file mode 100644 index 00000000000..a8a7e7fbe07 --- /dev/null +++ b/integration/tests/expo-native/package.json @@ -0,0 +1,14 @@ +{ + "name": "clerk-expo-native-e2e", + "private": true, + "type": "module", + "scripts": { + "test:android": "e2e run --target android", + "test:ios": "e2e run --target ios" + }, + "devDependencies": { + "@e2e-dev/mobile": "0.8.1", + "e2e": "0.15.1" + }, + "packageManager": "pnpm@10.34.5+sha512.a4ee05f2f73658255bd6a89859c065a45c28a57daefae2c893a168ee2b73168c37b91e83e57ea67654ad03f03031746430e8bce38e362e042605fb8abc80192e" +} diff --git a/integration/tests/expo-native/pnpm-lock.yaml b/integration/tests/expo-native/pnpm-lock.yaml new file mode 100644 index 00000000000..b896eaf79e8 --- /dev/null +++ b/integration/tests/expo-native/pnpm-lock.yaml @@ -0,0 +1,1287 @@ +lockfileVersion: '9.0' + +settings: + autoInstallPeers: true + excludeLinksFromLockfile: false + +importers: + + .: + devDependencies: + '@e2e-dev/mobile': + specifier: 0.8.1 + version: 0.8.1(e2e@0.15.1) + e2e: + specifier: 0.15.1 + version: 0.15.1 + +packages: + + '@ai-sdk/provider@4.0.18': + resolution: {integrity: sha512-+GZJIgz1jk86pwEbb3f1BD2bdoSKyWE4Jg4YUc7NMnMozbWemSKYZcw2F4nMaO5qwsL5A8RmioAKW81YktRpIQ==} + engines: {node: '>=22'} + + '@clack/core@1.5.1': + resolution: {integrity: sha512-iHTrHA8MtVuLl2TfZySmcKv1qO2PoyC9Z7pfSDozEuV5vtY3/wcOPKJXlqJ5Oq2Cx5DDGQGAMVx6HZfRRoVEbQ==} + engines: {node: '>= 20.12.0'} + + '@clack/prompts@1.8.1': + resolution: {integrity: sha512-dlT1m5e/0yUL0kRNcQn7yGLVThkgbB0Ga/1AmfDDC/8ik6AIiSf2QLQO2zPYvefsHP0aFgxO93cVLCCfDp7kzQ==} + engines: {node: '>= 20.12.0'} + + '@e2e-dev/mobile@0.8.1': + resolution: {integrity: sha512-aUbqIUxgeyxebNtySH7Cw+IvZPauHqOM5oUBTCzF8YMpInjqs8vi7iiW6eiZsQPxrINTy/3KoSvIAnPU8bXFYg==} + engines: {node: '>=22.12.0'} + peerDependencies: + ai: ^7.0.0 + e2e: '>=0.15.0 <1' + peerDependenciesMeta: + ai: + optional: true + + '@esbuild/aix-ppc64@0.28.2': + resolution: {integrity: sha512-XExcO+dvLKvVtNTibSTBej1NCAbaGhWn9Ww1ZPx80qsahhPFe/8jgWP0IchNe0F3HwkU7n8ejhH8bjonqht8mQ==} + engines: {node: '>=18'} + cpu: [ppc64] + os: [aix] + + '@esbuild/android-arm64@0.28.2': + resolution: {integrity: sha512-5YfKeeI8qWfBZIX+u2xZC3Zlb3Os/gLS2sbEKM+I4ZOcsWmHS2WLysCcQZDAFRslDUU5Oiq44gf6PYN1vGwG5A==} + engines: {node: '>=18'} + cpu: [arm64] + os: [android] + + '@esbuild/android-arm@0.28.2': + resolution: {integrity: sha512-kXXoiPVVGQcnIYGOeaovwOURpniDBpSq4A03qkQ+BMQqtGG6HYap3xne9C1O1yo4TR3qxlCX5IqqmX6fFo2Lqg==} + engines: {node: '>=18'} + cpu: [arm] + os: [android] + + '@esbuild/android-x64@0.28.2': + resolution: {integrity: sha512-O387ite7SzUyCcy3JQX4P4bLtEA7bLLkx+esve5JHnyYfNTxcVpXZo9jhdB0lTKN44gztELTdU7nS8Nr16Fs1Q==} + engines: {node: '>=18'} + cpu: [x64] + os: [android] + + '@esbuild/darwin-arm64@0.28.2': + resolution: {integrity: sha512-n4KqkOQrraxHJcgjM1RvwbigfQKIKJVpM7xp+KsxiyUSrRdIXnt73VhrPAx0fV44hgfmIVKjxMN9J1t5jySVkw==} + engines: {node: '>=18'} + cpu: [arm64] + os: [darwin] + + '@esbuild/darwin-x64@0.28.2': + resolution: {integrity: sha512-uq6suIWYP37qzGddBKPw5QEQPi6HiLGsO7UmkpfyaYNQ3D+rN6w6WfwH+nuqcGXWvawGwxOEroO4YGnFh95azw==} + engines: {node: '>=18'} + cpu: [x64] + os: [darwin] + + '@esbuild/freebsd-arm64@0.28.2': + resolution: {integrity: sha512-n+I0BTSRIoy+d6RPKnEVwql5UwBJolytvY4mAOIEJorKlqgPII8ix6slVVrfZ5Tnj7glIZvloylbB/EJPMWEXw==} + engines: {node: '>=18'} + cpu: [arm64] + os: [freebsd] + + '@esbuild/freebsd-x64@0.28.2': + resolution: {integrity: sha512-78XJTJkvPs0kz2w61301PJjXl4g7q3JqiYMZ/M/yVI73EHBrCRTgkhu9oqG7vPqq+a/yadEW8aD+agKlk5xrmg==} + engines: {node: '>=18'} + cpu: [x64] + os: [freebsd] + + '@esbuild/linux-arm64@0.28.2': + resolution: {integrity: sha512-pW4AC0P3it8c7do9MVM4p51FzHzdM/TZrerurgRcHJ2WTa1VQ1CIq18xncfpBJw4ojkiZZrKW2yIBWBP92j6Ug==} + engines: {node: '>=18'} + cpu: [arm64] + os: [linux] + + '@esbuild/linux-arm@0.28.2': + resolution: {integrity: sha512-XlDnu2q5yoqems+xay6wSAcg9DDD7K9RLKZEBOMZm3ckNpJBvOX20tSfby8KfrrhINDyv9V2YVZKY/SpoGJI8w==} + engines: {node: '>=18'} + cpu: [arm] + os: [linux] + + '@esbuild/linux-ia32@0.28.2': + resolution: {integrity: sha512-CYbnj78HsIeA+DhgUKgFCfvNsTHFhMMrinUrMZpDXJXKN8T3XViTZ/+wtHeVxEWY8ewSzTFN+nRmSwO2tZaLUQ==} + engines: {node: '>=18'} + cpu: [ia32] + os: [linux] + + '@esbuild/linux-loong64@0.28.2': + resolution: {integrity: sha512-buwkd8nsph4R+ajRvw0qM5Hja/TXQow3ptzWO2EbG/cqcIkHloRrdlBtQlshyYGTNFvfkfJ5tpPLVkY4DtsPfQ==} + engines: {node: '>=18'} + cpu: [loong64] + os: [linux] + + '@esbuild/linux-mips64el@0.28.2': + resolution: {integrity: sha512-ZVykbDyk7519VwiNb9Lcj9m8XM6v5V9uKPvrEMkkEedVewf+0itkhahp4HDpgERXhwLRpWFypsGbG/J8s0QjJA==} + engines: {node: '>=18'} + cpu: [mips64el] + os: [linux] + + '@esbuild/linux-ppc64@0.28.2': + resolution: {integrity: sha512-CAXl+Dtd9UUuJd8pKKdwh6MLm3MUMiqMPmhZ3tTSXPqfyQ3vDl6R5hZdZ/kYojK4ofXtdfSv1tFq8XzWx3heNQ==} + engines: {node: '>=18'} + cpu: [ppc64] + os: [linux] + + '@esbuild/linux-riscv64@0.28.2': + resolution: {integrity: sha512-GeXCej4IQtU1B+QlDV8W/RRvbzI3O/Stss+/bCXv4lZls5WGRtu2a+3JkA3i4qIUlMXpcHebWpF8AkJhATowuA==} + engines: {node: '>=18'} + cpu: [riscv64] + os: [linux] + + '@esbuild/linux-s390x@0.28.2': + resolution: {integrity: sha512-3H1weTYZPxt/WOhByszQZybS9w5lKzUn1FDMsgEChbHWQwHYQQRfBxgCcZvPhjHfKyJjIievvMmEUawJrdY9Dg==} + engines: {node: '>=18'} + cpu: [s390x] + os: [linux] + + '@esbuild/linux-x64@0.28.2': + resolution: {integrity: sha512-4xTZr1FUmSoQW4XIWmit3tzQrUTZM+N3P0XV8xROKYF50XfI7xeO90+1bZvNwxIufQ9hDQVRJH5YhgPVF8A/HQ==} + engines: {node: '>=18'} + cpu: [x64] + os: [linux] + + '@esbuild/netbsd-arm64@0.28.2': + resolution: {integrity: sha512-sSATRjPeDBg3pdgHoQfoYBob11Kk1FGa9lui5RIHZCoCkJa9QKlvl3/vKz2usCmYYjs7ymJR/2Nnsqe+Hjt5nw==} + engines: {node: '>=18'} + cpu: [arm64] + os: [netbsd] + + '@esbuild/netbsd-x64@0.28.2': + resolution: {integrity: sha512-lqnzCV+mM0gIADaKihiCg6ifgfU2L3h5E33rNQBN1Y4MaVGnzryzmvvf7UHxprpQdE8hpqLolJ9Rl+SkIRDpyw==} + engines: {node: '>=18'} + cpu: [x64] + os: [netbsd] + + '@esbuild/openbsd-arm64@0.28.2': + resolution: {integrity: sha512-AL2qJILH7lNjrDmCQDvdxMfAUIv8KMNZOvrwAQ8i8//ntL9FflhOyMJ8OZSMBb8/AWXe3/5v5S20y3zCoZWKoQ==} + engines: {node: '>=18'} + cpu: [arm64] + os: [openbsd] + + '@esbuild/openbsd-x64@0.28.2': + resolution: {integrity: sha512-QtiuPytchRyC4rwUKhexJdQKvDuZ6hWloi3igqPQNUJCS1/v9EiO3UTOXR6A3FoMo4fnAKbWJdqaIwhOzh8qEw==} + engines: {node: '>=18'} + cpu: [x64] + os: [openbsd] + + '@esbuild/openharmony-arm64@0.28.2': + resolution: {integrity: sha512-WkhYDmpTjLvGlScA1rwjRUmhl4k8oXR3cIbtqWmELgU/dFeHHlEllxDvdWcNJV9rbzCexB5vz8gtNewWLgCT7Q==} + engines: {node: '>=18'} + cpu: [arm64] + os: [openharmony] + + '@esbuild/sunos-x64@0.28.2': + resolution: {integrity: sha512-GPMSkTOtMnv2U2F8gxe4Io6qmVs+YKyp832Etqqxr0hFngmXQ3rzwytelm3GIn7T4VviRUlf3sOgBOiTdvaf7g==} + engines: {node: '>=18'} + cpu: [x64] + os: [sunos] + + '@esbuild/win32-arm64@0.28.2': + resolution: {integrity: sha512-PIhhEkE9uPBleRBrQEJpUn7MBnibZzbGzYWPmY3x+YoVg/95zbjB4CxPPOQ8l5tYYM4mMaCthF8/1DIfBQQyWQ==} + engines: {node: '>=18'} + cpu: [arm64] + os: [win32] + + '@esbuild/win32-ia32@0.28.2': + resolution: {integrity: sha512-YmJbfTlvU7Sdn9BB+4PRES4oB6pxgS37MAONj+hBr/cpXS1aBPKXxNnDbu+QCWPj0o9dgyxeq79g6c5P8KeuYA==} + engines: {node: '>=18'} + cpu: [ia32] + os: [win32] + + '@esbuild/win32-x64@0.28.2': + resolution: {integrity: sha512-5ebpxr3nWMzrL/rnUI755Jkuee0bHL/Gq0WTF9lvcpv73wAp5eu8MfBUgWK9bhWvZjj7yX8etf/8tI8Ney695g==} + engines: {node: '>=18'} + cpu: [x64] + os: [win32] + + '@hono/node-server@2.1.3': + resolution: {integrity: sha512-TA//nWMqPhbfdfneACk6t5a9eqbS9lABEPyKn0/xZTah3H3U2XaVg85rJFl0/Fyit0I552YDHgXGVSf3GwqbUw==} + engines: {node: '>=20'} + peerDependencies: + hono: ^4 + + '@modelcontextprotocol/sdk@1.30.1': + resolution: {integrity: sha512-H2HxLvC3HDNybePJaLdSrU1hhUK5iQw+WvV1b01myFyI7sdVGe1u/IPTE5D9fGCiJDVtgMV/lmFkQXLmQyIFYA==} + engines: {node: '>=18'} + peerDependencies: + '@cfworker/json-schema': ^4.1.1 + zod: ^3.25 || ^4.0 + peerDependenciesMeta: + '@cfworker/json-schema': + optional: true + + '@standard-schema/spec@1.1.0': + resolution: {integrity: sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w==} + + '@types/chai@5.2.3': + resolution: {integrity: sha512-Mw558oeA9fFbv65/y4mHtXDs9bPnFMZAL/jxdPFUpOHHIXX91mcgEHbS5Lahr+pwZFR8A7GQleRWeI6cGFC2UA==} + + '@types/deep-eql@4.0.2': + resolution: {integrity: sha512-c9h9dVVMigMPc4bwTvC5dxqtqJZwQPePsWjPlpSOnojbor6pGqdk541lfA7AqFQr5pB1BRdq0juY9db81BwyFw==} + + '@vitest/expect@5.0.2': + resolution: {integrity: sha512-pd6YDkhOHptwC65NYNpGpNxWlJH9M9Gxwtej73osTddb1NpiE0Jz5CIjTTEGXRgK0YtiSN7qBokmBXZ5uPJL1w==} + + '@vitest/pretty-format@5.0.2': + resolution: {integrity: sha512-YHM+mQQ7N1ROHMugJ7P/M+fC/q1G4zs/iAMZZCvhHcY8WkwPQcXBHD+z18oz+808Cfa12K7jOr3XPQMcLIovjw==} + + '@vitest/spy@5.0.2': + resolution: {integrity: sha512-Ijc7T1nT9efNb5LxvjaBrEqw3f/QwUv5EE0nKqZxgqsaV/FxAAZ8baGylA8X/Z2oS4Lp+K74Jr6dTJsDKxJDeg==} + + '@vitest/utils@5.0.2': + resolution: {integrity: sha512-mgpUtxFhKeOKVaArBVHNJGdYHAeRh135o59l13uVmPUCS1OUtis5pBqXEgE25iqRgFqEBwXvJlkhknRsYnMeqg==} + + accepts@2.0.0: + resolution: {integrity: sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng==} + engines: {node: '>= 0.6'} + + agent-device@0.21.18: + resolution: {integrity: sha512-ptNJ7a4jkAXFLSmZqKJDwxL+YpCEUuZv3oCBY76PwE3b2W+yQqQuG0ej0/bOspIHJRmMGNOkWhtxm3gmRW9hRQ==} + engines: {node: '>=22.12'} + hasBin: true + peerDependencies: + ai: ^6.0.0 || ^7.0.0 + peerDependenciesMeta: + ai: + optional: true + + ajv-formats@3.0.1: + resolution: {integrity: sha512-8iUql50EUR+uUcdRQ3HDqa6EVyo3docL8g5WJ3FNcWmu62IbkGUue/pEyLBW8VGKKucTPgqeks4fIU1DA4yowQ==} + peerDependencies: + ajv: ^8.0.0 + peerDependenciesMeta: + ajv: + optional: true + + ajv@8.20.0: + resolution: {integrity: sha512-Thbli+OlOj+iMPYFBVBfJ3OmCAnaSyNn4M1vz9T6Gka5Jt9ba/HIR56joy65tY6kx/FCF5VXNB819Y7/GUrBGA==} + + assertion-error@2.0.1: + resolution: {integrity: sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==} + engines: {node: '>=12'} + + body-parser@2.3.0: + resolution: {integrity: sha512-2cGmJupaNgg+QUwVLAucDuWuoMZ6EX9iHDRswZ5lsNYEmwPaRknMPCLZz07yTzVq/83p4o/wzbDZbBrTvGGTIw==} + engines: {node: '>=18'} + + bytes@3.1.2: + resolution: {integrity: sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==} + engines: {node: '>= 0.8'} + + call-bind-apply-helpers@1.0.2: + resolution: {integrity: sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==} + engines: {node: '>= 0.4'} + + call-bound@1.0.4: + resolution: {integrity: sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==} + engines: {node: '>= 0.4'} + + chai@6.2.2: + resolution: {integrity: sha512-NUPRluOfOiTKBKvWPtSD4PhFvWCqOi0BGStNWs57X9js7XGTprSmFoz5F0tWhR4WPjNeR9jXqdC7/UpSJTnlRg==} + engines: {node: '>=18'} + + commander@15.0.0: + resolution: {integrity: sha512-z67u4ZhzCL/Tydu1lJARtEZYWbWaN7oYLHbsuzocr6y4N6WZAagG3RQ4FW61V1/0+jImpj293XfrcYnd1qxtPg==} + engines: {node: '>=22.12.0'} + + content-disposition@1.1.0: + resolution: {integrity: sha512-5jRCH9Z/+DRP7rkvY83B+yGIGX96OYdJmzngqnw2SBSxqCFPd0w2km3s5iawpGX8krnwSGmF0FW5Nhr0Hfai3g==} + engines: {node: '>=18'} + + content-type@1.0.5: + resolution: {integrity: sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==} + engines: {node: '>= 0.6'} + + content-type@2.1.0: + resolution: {integrity: sha512-mj7UPXE0jaqaOsukNZRUEfEi2AcL7C/vwmwcHV0O97eO1E1pxBZuyjlZrx5seTaNBg1U6+o35wpa35Qfcc+7ag==} + engines: {node: '>=18'} + + convert-source-map@2.0.0: + resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==} + + cookie-signature@1.2.2: + resolution: {integrity: sha512-D76uU73ulSXrD1UXF4KE2TMxVVwhsnCgfAyTg9k8P6KGZjlXKrOLe4dJQKI3Bxi5wjesZoFXJWElNWBjPZMbhg==} + engines: {node: '>=6.6.0'} + + cookie@0.7.2: + resolution: {integrity: sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==} + engines: {node: '>= 0.6'} + + cors@2.8.6: + resolution: {integrity: sha512-tJtZBBHA6vjIAaF6EnIaq6laBBP9aq/Y3ouVJjEfoHbRBcHBAHYcMh/w8LDrk2PvIMMq8gmopa5D4V8RmbrxGw==} + engines: {node: '>= 0.10'} + + cross-spawn@7.0.6: + resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==} + engines: {node: '>= 8'} + + debug@4.4.3: + resolution: {integrity: sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==} + engines: {node: '>=6.0'} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + + depd@2.0.0: + resolution: {integrity: sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==} + engines: {node: '>= 0.8'} + + dunder-proto@1.0.1: + resolution: {integrity: sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==} + engines: {node: '>= 0.4'} + + e2e@0.15.1: + resolution: {integrity: sha512-HYuc4xFbLqG4TMZkzZEZEoYa20qKvqyZ9nodDOZ8Yo05YlspzC4GV4guEql1pVIdspqj0fDMINx2rsn3REVrHA==} + engines: {node: '>=22.12.0'} + hasBin: true + peerDependencies: + '@ai-sdk/openai': ^4.0.0 + '@ai-sdk/openai-compatible': ^3.0.0 + '@ai-sdk/xai': ^5.0.0 + ai: ^7.0.0 + peerDependenciesMeta: + '@ai-sdk/openai': + optional: true + '@ai-sdk/openai-compatible': + optional: true + '@ai-sdk/xai': + optional: true + ai: + optional: true + + ee-first@1.1.1: + resolution: {integrity: sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==} + + encodeurl@2.0.0: + resolution: {integrity: sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==} + engines: {node: '>= 0.8'} + + es-define-property@1.0.1: + resolution: {integrity: sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==} + engines: {node: '>= 0.4'} + + es-errors@1.3.0: + resolution: {integrity: sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==} + engines: {node: '>= 0.4'} + + es-object-atoms@1.1.2: + resolution: {integrity: sha512-HWcBoN6NileqtSydK2FqHbS/LoDd2pqrnQHLyJzBj4kOp/ky2MWMN694xOfkK8/SnUsW2DH7EfyVlydKCsm1Zw==} + engines: {node: '>= 0.4'} + + esbuild@0.28.2: + resolution: {integrity: sha512-HKVLS8dvII+xoKW9kmqxbRKrnWEXfJJr/FZhhJmiqIB0e053QNYFqOBouTMO/k5sID4MvCiUCvv8b9M4h32wIA==} + engines: {node: '>=18'} + hasBin: true + + escape-html@1.0.3: + resolution: {integrity: sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==} + + etag@1.8.1: + resolution: {integrity: sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==} + engines: {node: '>= 0.6'} + + eventsource-parser@3.1.1: + resolution: {integrity: sha512-EKN1vKAMcZ8MlYMpaNuxN6R9yakzH6uajHcHVTqWJzvu5pWw9DyhbP35HH8MVBQ+dZjAfDxk+A8NiR9KWaXiyQ==} + engines: {node: '>=18.0.0'} + + eventsource@3.0.7: + resolution: {integrity: sha512-CRT1WTyuQoD771GW56XEZFQ/ZoSfWid1alKGDYMmkt2yl8UXrVR4pspqWNEcqKvVIzg6PAltWjxcSSPrboA4iA==} + engines: {node: '>=18.0.0'} + + express-rate-limit@8.7.0: + resolution: {integrity: sha512-hOwV7WOxXfjRpAM1DSJWZDXx3GhplwD8IfwuwvogD8i1Qnkgosw/H45s4ZnFAUHDAhPjlY9hLBvJhKmGMyY26g==} + engines: {node: '>= 16'} + peerDependencies: + express: '>= 4.11' + + express@5.2.1: + resolution: {integrity: sha512-hIS4idWWai69NezIdRt2xFVofaF4j+6INOpJlVOLDO8zXGpUVEVzIYk12UUi2JzjEzWL3IOAxcTubgz9Po0yXw==} + engines: {node: '>= 18'} + + fast-deep-equal@3.1.3: + resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} + + fast-string-truncated-width@3.0.3: + resolution: {integrity: sha512-0jjjIEL6+0jag3l2XWWizO64/aZVtpiGE3t0Zgqxv0DPuxiMjvB3M24fCyhZUO4KomJQPj3LTSUnDP3GpdwC0g==} + + fast-string-width@3.0.2: + resolution: {integrity: sha512-gX8LrtNEI5hq8DVUfRQMbr5lpaS4nMIWV+7XEbXk2b8kiQIizgnlr12B4dA3ZEx3308ze0O4Q1R+cHts8kyUJg==} + + fast-uri@3.1.8: + resolution: {integrity: sha512-GZMtZUTNRpOVIECoXwLNZS5xUGE+mVNbTB8h/7Rwh2TFWcBQiPzTgyZi05BF9UMZKkLJv8XBRJTlU7zg8+ZfMg==} + + fast-wrap-ansi@0.2.2: + resolution: {integrity: sha512-7F2Fl+TjRSenLqlU3UjSH0iyqopqoZIu7eZVpEirP2g1GtWa2G/ecEmBdgz31+Mxr+ELclgg6sokpSFIQiZ02Q==} + + finalhandler@2.1.1: + resolution: {integrity: sha512-S8KoZgRZN+a5rNwqTxlZZePjT/4cnm0ROV70LedRHZ0p8u9fRID0hJUZQpkKLzro8LfmC8sx23bY6tVNxv8pQA==} + engines: {node: '>= 18.0.0'} + + forwarded@0.2.0: + resolution: {integrity: sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==} + engines: {node: '>= 0.6'} + + fresh@2.0.0: + resolution: {integrity: sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A==} + engines: {node: '>= 0.8'} + + fsevents@2.3.3: + resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} + engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} + os: [darwin] + + function-bind@1.1.2: + resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==} + + get-intrinsic@1.3.0: + resolution: {integrity: sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==} + engines: {node: '>= 0.4'} + + get-proto@1.0.1: + resolution: {integrity: sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==} + engines: {node: '>= 0.4'} + + gopd@1.2.0: + resolution: {integrity: sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==} + engines: {node: '>= 0.4'} + + has-symbols@1.1.0: + resolution: {integrity: sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==} + engines: {node: '>= 0.4'} + + hasown@2.0.4: + resolution: {integrity: sha512-T2UbfbBEF32wiepXIsMlTW9+dDYC6wMh/t/vYA4tuOMKqWz/n3vr1NFSxQiyP+zk2mXsoMA/i/7qV6LKut1t1A==} + engines: {node: '>= 0.4'} + + hono@4.13.11: + resolution: {integrity: sha512-/SMX/RQNJn7oNmFwH6DtwDqcrzZU2otm1FD6OJe2cWF6cfy/F8hq0XVBv7xW3FTJshRQwuBnXHDq2kNsdZnshg==} + engines: {node: '>=16.9.0'} + + http-errors@2.0.1: + resolution: {integrity: sha512-4FbRdAX+bSdmo4AUFuS0WNiPz8NgFt+r8ThgNWmlrjQjt1Q7ZR9+zTlce2859x4KSXrwIsaeTqDoKQmtP8pLmQ==} + engines: {node: '>= 0.8'} + + iconv-lite@0.7.3: + resolution: {integrity: sha512-IKXpvIzjnC9XTAUbVBcMfGS0EPaIXtW6v+zr+RRp+hqULEpo0owZax6wyRwPOJbWbzjYspQwusTsfVr0ifh4uQ==} + engines: {node: '>=0.10.0'} + + inherits@2.0.4: + resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} + + ip-address@10.7.2: + resolution: {integrity: sha512-7H/2gFSIitxc0hG3nOI1glS8QLo/EHBFFLk8vEUjXY/xu0AdL8jZ9U1IzO2PUm0d2D/ofQcAifb0g6OBkt8U7w==} + engines: {node: '>= 12'} + + ipaddr.js@1.9.1: + resolution: {integrity: sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==} + engines: {node: '>= 0.10'} + + is-promise@4.0.0: + resolution: {integrity: sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ==} + + isexe@2.0.0: + resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} + + jose@6.2.12: + resolution: {integrity: sha512-9NiFmJEex0sy2Dk58j2UGBSHgUs2ypF9eZSu4L6vjOX3Dp96Sw1F3uL+H+D1sx02jZZdzUT0HgvCy59CuvXcWw==} + + json-schema-traverse@1.0.0: + resolution: {integrity: sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==} + + json-schema-typed@8.0.2: + resolution: {integrity: sha512-fQhoXdcvc3V28x7C7BMs4P5+kNlgUURe2jmUT1T//oBRMDrqy1QPelJimwZGo7Hg9VPV3EQV5Bnq4hbFy2vetA==} + + json-schema@0.4.0: + resolution: {integrity: sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA==} + + math-intrinsics@1.1.0: + resolution: {integrity: sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==} + engines: {node: '>= 0.4'} + + media-typer@1.1.1: + resolution: {integrity: sha512-yz3xRaG20c6/BOzvYoDaGtPmGscs7YivItZEEqe6GbwNfHuxu9YNmvnEkMzKldAGY4/80pRcQRZSEnhquk9XuQ==} + engines: {node: '>= 0.8'} + + merge-descriptors@2.0.0: + resolution: {integrity: sha512-Snk314V5ayFLhp3fkUREub6WtjBfPdCPY1Ln8/8munuLuiYhsABgBVWsozAG+MWMbVEvcdcpbi9R7ww22l9Q3g==} + engines: {node: '>=18'} + + mime-db@1.54.0: + resolution: {integrity: sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==} + engines: {node: '>= 0.6'} + + mime-types@3.0.2: + resolution: {integrity: sha512-Lbgzdk0h4juoQ9fCKXW4by0UJqj+nOOrI9MJ1sSj4nI8aI2eo1qmvQEie4VD1glsS250n15LsWsYtCugiStS5A==} + engines: {node: '>=18'} + + ms@2.1.3: + resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} + + negotiator@1.1.0: + resolution: {integrity: sha512-NMPBRMJgiQHjbd8phG3Vebdx4kZ1H121rbl5IkMqeOsahptB9BKo/d7oJ3zTXqTgagn2bWlNSXkh0QUGM31RYg==} + engines: {node: '>=18'} + + object-assign@4.1.1: + resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==} + engines: {node: '>=0.10.0'} + + object-inspect@1.13.4: + resolution: {integrity: sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==} + engines: {node: '>= 0.4'} + + on-finished@2.4.1: + resolution: {integrity: sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==} + engines: {node: '>= 0.8'} + + once@1.4.0: + resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==} + + parseurl@1.3.3: + resolution: {integrity: sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==} + engines: {node: '>= 0.8'} + + path-key@3.1.1: + resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} + engines: {node: '>=8'} + + path-to-regexp@8.4.2: + resolution: {integrity: sha512-qRcuIdP69NPm4qbACK+aDogI5CBDMi1jKe0ry5rSQJz8JVLsC7jV8XpiJjGRLLol3N+R5ihGYcrPLTno6pAdBA==} + + picocolors@1.1.1: + resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} + + pkce-challenge@5.0.1: + resolution: {integrity: sha512-wQ0b/W4Fr01qtpHlqSqspcj3EhBvimsdh0KlHhH8HRZnMsEa0ea2fTULOXOS9ccQr3om+GcGRk4e+isrZWV8qQ==} + engines: {node: '>=16.20.0'} + + pngjs@7.0.0: + resolution: {integrity: sha512-LKWqWJRhstyYo9pGvgor/ivk2w94eSjE3RGVuzLGlr3NmD8bf7RcYGze1mNdEHRP6TRP6rMuDHk5t44hnTRyow==} + engines: {node: '>=14.19.0'} + + proxy-addr@2.0.8: + resolution: {integrity: sha512-5nnx0yGyVUcY6t9RnWcARWtwT9F1D8O9rt08htPvnd49W1IgZtmLkhu9WfMzQj1cFxjHIO6connUNVW5k7AVyQ==} + engines: {node: '>= 0.10'} + + qs@6.16.0: + resolution: {integrity: sha512-h6fhOIaRrID2CbEY2fqs+7t+UXZo+MLAnU5gRIq85uFtdiUPCdsApMlHhXogKVM4HM2DVbIjGNTTYH2OcmP1vA==} + engines: {node: '>=0.6'} + + range-parser@1.3.0: + resolution: {integrity: sha512-hek2mFQpPuI4E1BBKrSto+BU3e3x4xuarsbiwr3+lf7p44juvFMV0XFWQAP3xUyqXA4RrXLIoaSUGbSt056ZMw==} + engines: {node: '>= 0.6'} + + raw-body@3.0.2: + resolution: {integrity: sha512-K5zQjDllxWkf7Z5xJdV0/B0WTNqx6vxG70zJE4N0kBs4LovmEYWJzQGxC9bS9RAKu3bgM40lrd5zoLJ12MQ5BA==} + engines: {node: '>= 0.10'} + + require-from-string@2.0.2: + resolution: {integrity: sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==} + engines: {node: '>=0.10.0'} + + router@2.2.0: + resolution: {integrity: sha512-nLTrUKm2UyiL7rlhapu/Zl45FwNgkZGaCpZbIHajDYgwlJCOzLSk+cIPAnsEqV955GjILJnKbdQC1nVPz+gAYQ==} + engines: {node: '>= 18'} + + safer-buffer@2.1.2: + resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==} + + send@1.2.1: + resolution: {integrity: sha512-1gnZf7DFcoIcajTjTwjwuDjzuz4PPcY2StKPlsGAQ1+YH20IRVrBaXSWmdjowTJ6u8Rc01PoYOGHXfP1mYcZNQ==} + engines: {node: '>= 18'} + + serve-static@2.2.1: + resolution: {integrity: sha512-xRXBn0pPqQTVQiC8wyQrKs2MOlX24zQ0POGaj0kultvoOCstBQM5yvOhAVSUwOMjQtTvsPWoNCHfPGwaaQJhTw==} + engines: {node: '>= 18'} + + setprototypeof@1.2.0: + resolution: {integrity: sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==} + + shebang-command@2.0.0: + resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==} + engines: {node: '>=8'} + + shebang-regex@3.0.0: + resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==} + engines: {node: '>=8'} + + side-channel-list@1.0.1: + resolution: {integrity: sha512-mjn/0bi/oUURjc5Xl7IaWi/OJJJumuoJFQJfDDyO46+hBWsfaVM65TBHq2eoZBhzl9EchxOijpkbRC8SVBQU0w==} + engines: {node: '>= 0.4'} + + side-channel-map@1.0.1: + resolution: {integrity: sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==} + engines: {node: '>= 0.4'} + + side-channel-weakmap@1.0.2: + resolution: {integrity: sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==} + engines: {node: '>= 0.4'} + + side-channel@1.1.1: + resolution: {integrity: sha512-6x6dK6zJdpTzF4sQeNYxwtvBzf6Eg4GtlesS94HOvTudUeyK2WXAaIfmDgsyslYrRBeFIlsi54AYsFGUuhmvrQ==} + engines: {node: '>= 0.4'} + + sisteransi@1.0.5: + resolution: {integrity: sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==} + + statuses@2.0.2: + resolution: {integrity: sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==} + engines: {node: '>= 0.8'} + + tinyrainbow@3.1.1: + resolution: {integrity: sha512-yau8yJdTt989Mm0Bd/236QnzEiPf2xLLTqUZRUJOo/3CB078LSwzei343DgtJVmfJKJE3TMINY1u42SQsP6mXw==} + engines: {node: '>=14.0.0'} + + toidentifier@1.0.1: + resolution: {integrity: sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==} + engines: {node: '>=0.6'} + + tsx@4.23.14: + resolution: {integrity: sha512-yFwMnbAsUFz/T3kR8P2ENc/DDUaYd9tKg4oVYo0lhkX0LlK4UuqYAO6mpQ2y6lmcyip1uPJ34C2kPACopDwG4w==} + engines: {node: '>=18.0.0'} + hasBin: true + + type-is@2.1.0: + resolution: {integrity: sha512-faYHw0anBbc/kWF3zFTEnxSFOAGUX9GFbOBthvDdLsIlEoWOFOtS0zgCiQYwIskL9iGXZL3kAXD8OoZ4GmMATA==} + engines: {node: '>= 18'} + + unpipe@1.0.0: + resolution: {integrity: sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==} + engines: {node: '>= 0.8'} + + vary@1.1.2: + resolution: {integrity: sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==} + engines: {node: '>= 0.8'} + + which@2.0.2: + resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==} + engines: {node: '>= 8'} + hasBin: true + + wrappy@1.0.2: + resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} + + zod-to-json-schema@3.25.2: + resolution: {integrity: sha512-O/PgfnpT1xKSDeQYSCfRI5Gy3hPf91mKVDuYLUHZJMiDFptvP41MSnWofm8dnCm0256ZNfZIM7DSzuSMAFnjHA==} + peerDependencies: + zod: ^3.25.28 || ^4 + + zod@4.6.1: + resolution: {integrity: sha512-341aRWQsve0rvronKNTqZpjmzdbUDlFuzHaI/XLg/Ej82qffDJRRfBTCuv7+9q/rMjB6LSLyEBnW4InJeMtt/Q==} + +snapshots: + + '@ai-sdk/provider@4.0.18': + dependencies: + json-schema: 0.4.0 + + '@clack/core@1.5.1': + dependencies: + fast-wrap-ansi: 0.2.2 + sisteransi: 1.0.5 + + '@clack/prompts@1.8.1': + dependencies: + '@clack/core': 1.5.1 + fast-string-width: 3.0.2 + fast-wrap-ansi: 0.2.2 + sisteransi: 1.0.5 + + '@e2e-dev/mobile@0.8.1(e2e@0.15.1)': + dependencies: + agent-device: 0.21.18 + e2e: 0.15.1 + pngjs: 7.0.0 + zod: 4.6.1 + + '@esbuild/aix-ppc64@0.28.2': + optional: true + + '@esbuild/android-arm64@0.28.2': + optional: true + + '@esbuild/android-arm@0.28.2': + optional: true + + '@esbuild/android-x64@0.28.2': + optional: true + + '@esbuild/darwin-arm64@0.28.2': + optional: true + + '@esbuild/darwin-x64@0.28.2': + optional: true + + '@esbuild/freebsd-arm64@0.28.2': + optional: true + + '@esbuild/freebsd-x64@0.28.2': + optional: true + + '@esbuild/linux-arm64@0.28.2': + optional: true + + '@esbuild/linux-arm@0.28.2': + optional: true + + '@esbuild/linux-ia32@0.28.2': + optional: true + + '@esbuild/linux-loong64@0.28.2': + optional: true + + '@esbuild/linux-mips64el@0.28.2': + optional: true + + '@esbuild/linux-ppc64@0.28.2': + optional: true + + '@esbuild/linux-riscv64@0.28.2': + optional: true + + '@esbuild/linux-s390x@0.28.2': + optional: true + + '@esbuild/linux-x64@0.28.2': + optional: true + + '@esbuild/netbsd-arm64@0.28.2': + optional: true + + '@esbuild/netbsd-x64@0.28.2': + optional: true + + '@esbuild/openbsd-arm64@0.28.2': + optional: true + + '@esbuild/openbsd-x64@0.28.2': + optional: true + + '@esbuild/openharmony-arm64@0.28.2': + optional: true + + '@esbuild/sunos-x64@0.28.2': + optional: true + + '@esbuild/win32-arm64@0.28.2': + optional: true + + '@esbuild/win32-ia32@0.28.2': + optional: true + + '@esbuild/win32-x64@0.28.2': + optional: true + + '@hono/node-server@2.1.3(hono@4.13.11)': + dependencies: + hono: 4.13.11 + + '@modelcontextprotocol/sdk@1.30.1(zod@4.6.1)': + dependencies: + '@hono/node-server': 2.1.3(hono@4.13.11) + ajv: 8.20.0 + ajv-formats: 3.0.1(ajv@8.20.0) + content-type: 1.0.5 + cors: 2.8.6 + cross-spawn: 7.0.6 + eventsource: 3.0.7 + eventsource-parser: 3.1.1 + express: 5.2.1 + express-rate-limit: 8.7.0(express@5.2.1) + hono: 4.13.11 + jose: 6.2.12 + json-schema-typed: 8.0.2 + pkce-challenge: 5.0.1 + raw-body: 3.0.2 + zod: 4.6.1 + zod-to-json-schema: 3.25.2(zod@4.6.1) + transitivePeerDependencies: + - supports-color + + '@standard-schema/spec@1.1.0': {} + + '@types/chai@5.2.3': + dependencies: + '@types/deep-eql': 4.0.2 + assertion-error: 2.0.1 + + '@types/deep-eql@4.0.2': {} + + '@vitest/expect@5.0.2': + dependencies: + '@standard-schema/spec': 1.1.0 + '@types/chai': 5.2.3 + '@vitest/spy': 5.0.2 + '@vitest/utils': 5.0.2 + chai: 6.2.2 + tinyrainbow: 3.1.1 + + '@vitest/pretty-format@5.0.2': + dependencies: + tinyrainbow: 3.1.1 + + '@vitest/spy@5.0.2': {} + + '@vitest/utils@5.0.2': + dependencies: + '@vitest/pretty-format': 5.0.2 + convert-source-map: 2.0.0 + tinyrainbow: 3.1.1 + + accepts@2.0.0: + dependencies: + mime-types: 3.0.2 + negotiator: 1.1.0 + + agent-device@0.21.18: {} + + ajv-formats@3.0.1(ajv@8.20.0): + optionalDependencies: + ajv: 8.20.0 + + ajv@8.20.0: + dependencies: + fast-deep-equal: 3.1.3 + fast-uri: 3.1.8 + json-schema-traverse: 1.0.0 + require-from-string: 2.0.2 + + assertion-error@2.0.1: {} + + body-parser@2.3.0: + dependencies: + bytes: 3.1.2 + content-type: 2.1.0 + debug: 4.4.3 + http-errors: 2.0.1 + iconv-lite: 0.7.3 + on-finished: 2.4.1 + qs: 6.16.0 + raw-body: 3.0.2 + type-is: 2.1.0 + transitivePeerDependencies: + - supports-color + + bytes@3.1.2: {} + + call-bind-apply-helpers@1.0.2: + dependencies: + es-errors: 1.3.0 + function-bind: 1.1.2 + + call-bound@1.0.4: + dependencies: + call-bind-apply-helpers: 1.0.2 + get-intrinsic: 1.3.0 + + chai@6.2.2: {} + + commander@15.0.0: {} + + content-disposition@1.1.0: {} + + content-type@1.0.5: {} + + content-type@2.1.0: {} + + convert-source-map@2.0.0: {} + + cookie-signature@1.2.2: {} + + cookie@0.7.2: {} + + cors@2.8.6: + dependencies: + object-assign: 4.1.1 + vary: 1.1.2 + + cross-spawn@7.0.6: + dependencies: + path-key: 3.1.1 + shebang-command: 2.0.0 + which: 2.0.2 + + debug@4.4.3: + dependencies: + ms: 2.1.3 + + depd@2.0.0: {} + + dunder-proto@1.0.1: + dependencies: + call-bind-apply-helpers: 1.0.2 + es-errors: 1.3.0 + gopd: 1.2.0 + + e2e@0.15.1: + dependencies: + '@ai-sdk/provider': 4.0.18 + '@clack/prompts': 1.8.1 + '@modelcontextprotocol/sdk': 1.30.1(zod@4.6.1) + '@vitest/expect': 5.0.2 + commander: 15.0.0 + picocolors: 1.1.1 + pngjs: 7.0.0 + tsx: 4.23.14 + zod: 4.6.1 + transitivePeerDependencies: + - '@cfworker/json-schema' + - supports-color + + ee-first@1.1.1: {} + + encodeurl@2.0.0: {} + + es-define-property@1.0.1: {} + + es-errors@1.3.0: {} + + es-object-atoms@1.1.2: + dependencies: + es-errors: 1.3.0 + + esbuild@0.28.2: + optionalDependencies: + '@esbuild/aix-ppc64': 0.28.2 + '@esbuild/android-arm': 0.28.2 + '@esbuild/android-arm64': 0.28.2 + '@esbuild/android-x64': 0.28.2 + '@esbuild/darwin-arm64': 0.28.2 + '@esbuild/darwin-x64': 0.28.2 + '@esbuild/freebsd-arm64': 0.28.2 + '@esbuild/freebsd-x64': 0.28.2 + '@esbuild/linux-arm': 0.28.2 + '@esbuild/linux-arm64': 0.28.2 + '@esbuild/linux-ia32': 0.28.2 + '@esbuild/linux-loong64': 0.28.2 + '@esbuild/linux-mips64el': 0.28.2 + '@esbuild/linux-ppc64': 0.28.2 + '@esbuild/linux-riscv64': 0.28.2 + '@esbuild/linux-s390x': 0.28.2 + '@esbuild/linux-x64': 0.28.2 + '@esbuild/netbsd-arm64': 0.28.2 + '@esbuild/netbsd-x64': 0.28.2 + '@esbuild/openbsd-arm64': 0.28.2 + '@esbuild/openbsd-x64': 0.28.2 + '@esbuild/openharmony-arm64': 0.28.2 + '@esbuild/sunos-x64': 0.28.2 + '@esbuild/win32-arm64': 0.28.2 + '@esbuild/win32-ia32': 0.28.2 + '@esbuild/win32-x64': 0.28.2 + + escape-html@1.0.3: {} + + etag@1.8.1: {} + + eventsource-parser@3.1.1: {} + + eventsource@3.0.7: + dependencies: + eventsource-parser: 3.1.1 + + express-rate-limit@8.7.0(express@5.2.1): + dependencies: + debug: 4.4.3 + express: 5.2.1 + ip-address: 10.7.2 + transitivePeerDependencies: + - supports-color + + express@5.2.1: + dependencies: + accepts: 2.0.0 + body-parser: 2.3.0 + content-disposition: 1.1.0 + content-type: 1.0.5 + cookie: 0.7.2 + cookie-signature: 1.2.2 + debug: 4.4.3 + depd: 2.0.0 + encodeurl: 2.0.0 + escape-html: 1.0.3 + etag: 1.8.1 + finalhandler: 2.1.1 + fresh: 2.0.0 + http-errors: 2.0.1 + merge-descriptors: 2.0.0 + mime-types: 3.0.2 + on-finished: 2.4.1 + once: 1.4.0 + parseurl: 1.3.3 + proxy-addr: 2.0.8 + qs: 6.16.0 + range-parser: 1.3.0 + router: 2.2.0 + send: 1.2.1 + serve-static: 2.2.1 + statuses: 2.0.2 + type-is: 2.1.0 + vary: 1.1.2 + transitivePeerDependencies: + - supports-color + + fast-deep-equal@3.1.3: {} + + fast-string-truncated-width@3.0.3: {} + + fast-string-width@3.0.2: + dependencies: + fast-string-truncated-width: 3.0.3 + + fast-uri@3.1.8: {} + + fast-wrap-ansi@0.2.2: + dependencies: + fast-string-width: 3.0.2 + + finalhandler@2.1.1: + dependencies: + debug: 4.4.3 + encodeurl: 2.0.0 + escape-html: 1.0.3 + on-finished: 2.4.1 + parseurl: 1.3.3 + statuses: 2.0.2 + transitivePeerDependencies: + - supports-color + + forwarded@0.2.0: {} + + fresh@2.0.0: {} + + fsevents@2.3.3: + optional: true + + function-bind@1.1.2: {} + + get-intrinsic@1.3.0: + dependencies: + call-bind-apply-helpers: 1.0.2 + es-define-property: 1.0.1 + es-errors: 1.3.0 + es-object-atoms: 1.1.2 + function-bind: 1.1.2 + get-proto: 1.0.1 + gopd: 1.2.0 + has-symbols: 1.1.0 + hasown: 2.0.4 + math-intrinsics: 1.1.0 + + get-proto@1.0.1: + dependencies: + dunder-proto: 1.0.1 + es-object-atoms: 1.1.2 + + gopd@1.2.0: {} + + has-symbols@1.1.0: {} + + hasown@2.0.4: + dependencies: + function-bind: 1.1.2 + + hono@4.13.11: {} + + http-errors@2.0.1: + dependencies: + depd: 2.0.0 + inherits: 2.0.4 + setprototypeof: 1.2.0 + statuses: 2.0.2 + toidentifier: 1.0.1 + + iconv-lite@0.7.3: + dependencies: + safer-buffer: 2.1.2 + + inherits@2.0.4: {} + + ip-address@10.7.2: {} + + ipaddr.js@1.9.1: {} + + is-promise@4.0.0: {} + + isexe@2.0.0: {} + + jose@6.2.12: {} + + json-schema-traverse@1.0.0: {} + + json-schema-typed@8.0.2: {} + + json-schema@0.4.0: {} + + math-intrinsics@1.1.0: {} + + media-typer@1.1.1: {} + + merge-descriptors@2.0.0: {} + + mime-db@1.54.0: {} + + mime-types@3.0.2: + dependencies: + mime-db: 1.54.0 + + ms@2.1.3: {} + + negotiator@1.1.0: + dependencies: + content-type: 2.1.0 + + object-assign@4.1.1: {} + + object-inspect@1.13.4: {} + + on-finished@2.4.1: + dependencies: + ee-first: 1.1.1 + + once@1.4.0: + dependencies: + wrappy: 1.0.2 + + parseurl@1.3.3: {} + + path-key@3.1.1: {} + + path-to-regexp@8.4.2: {} + + picocolors@1.1.1: {} + + pkce-challenge@5.0.1: {} + + pngjs@7.0.0: {} + + proxy-addr@2.0.8: + dependencies: + forwarded: 0.2.0 + ipaddr.js: 1.9.1 + + qs@6.16.0: + dependencies: + es-define-property: 1.0.1 + side-channel: 1.1.1 + + range-parser@1.3.0: {} + + raw-body@3.0.2: + dependencies: + bytes: 3.1.2 + http-errors: 2.0.1 + iconv-lite: 0.7.3 + unpipe: 1.0.0 + + require-from-string@2.0.2: {} + + router@2.2.0: + dependencies: + debug: 4.4.3 + depd: 2.0.0 + is-promise: 4.0.0 + parseurl: 1.3.3 + path-to-regexp: 8.4.2 + transitivePeerDependencies: + - supports-color + + safer-buffer@2.1.2: {} + + send@1.2.1: + dependencies: + debug: 4.4.3 + encodeurl: 2.0.0 + escape-html: 1.0.3 + etag: 1.8.1 + fresh: 2.0.0 + http-errors: 2.0.1 + mime-types: 3.0.2 + ms: 2.1.3 + on-finished: 2.4.1 + range-parser: 1.3.0 + statuses: 2.0.2 + transitivePeerDependencies: + - supports-color + + serve-static@2.2.1: + dependencies: + encodeurl: 2.0.0 + escape-html: 1.0.3 + parseurl: 1.3.3 + send: 1.2.1 + transitivePeerDependencies: + - supports-color + + setprototypeof@1.2.0: {} + + shebang-command@2.0.0: + dependencies: + shebang-regex: 3.0.0 + + shebang-regex@3.0.0: {} + + side-channel-list@1.0.1: + dependencies: + es-errors: 1.3.0 + object-inspect: 1.13.4 + + side-channel-map@1.0.1: + dependencies: + call-bound: 1.0.4 + es-errors: 1.3.0 + get-intrinsic: 1.3.0 + object-inspect: 1.13.4 + + side-channel-weakmap@1.0.2: + dependencies: + call-bound: 1.0.4 + es-errors: 1.3.0 + get-intrinsic: 1.3.0 + object-inspect: 1.13.4 + side-channel-map: 1.0.1 + + side-channel@1.1.1: + dependencies: + es-errors: 1.3.0 + object-inspect: 1.13.4 + side-channel-list: 1.0.1 + side-channel-map: 1.0.1 + side-channel-weakmap: 1.0.2 + + sisteransi@1.0.5: {} + + statuses@2.0.2: {} + + tinyrainbow@3.1.1: {} + + toidentifier@1.0.1: {} + + tsx@4.23.14: + dependencies: + esbuild: 0.28.2 + optionalDependencies: + fsevents: 2.3.3 + + type-is@2.1.0: + dependencies: + content-type: 2.1.0 + media-typer: 1.1.1 + mime-types: 3.0.2 + + unpipe@1.0.0: {} + + vary@1.1.2: {} + + which@2.0.2: + dependencies: + isexe: 2.0.0 + + wrappy@1.0.2: {} + + zod-to-json-schema@3.25.2(zod@4.6.1): + dependencies: + zod: 4.6.1 + + zod@4.6.1: {} diff --git a/integration/tests/expo-native/pnpm-workspace.yaml b/integration/tests/expo-native/pnpm-workspace.yaml new file mode 100644 index 00000000000..690e0a5fae0 --- /dev/null +++ b/integration/tests/expo-native/pnpm-workspace.yaml @@ -0,0 +1,11 @@ +packages: + - '.' + +ignoredBuiltDependencies: + - esbuild + +minimumReleaseAge: 2880 +minimumReleaseAgeExclude: + - '@e2e-dev/mobile' + - agent-device + - e2e diff --git a/integration/tests/expo-native/run-android-flows.sh b/integration/tests/expo-native/run-android-flows.sh index d1751b0bd0b..5487e3f4de4 100755 --- a/integration/tests/expo-native/run-android-flows.sh +++ b/integration/tests/expo-native/run-android-flows.sh @@ -9,10 +9,10 @@ command -v adb >/dev/null 2>&1 || { exit 1 } -shards=${MAESTRO_SHARDS:-1} +shards=${E2E_SHARDS:-1} devices=(emulator-5554) sdk=$(dirname "$(dirname "$(command -v adb)")") -debug=${MAESTRO_DEBUG_OUTPUT:-${TMPDIR:-/tmp}/clerk-expo-maestro-runner} +debug=${E2E_DEVICE_LOGS:-${TMPDIR:-/tmp}/clerk-expo-native-e2e} mkdir -p "$debug" for ((i = 1; i < shards; i++)); do @@ -58,4 +58,4 @@ for device in "${devices[@]}"; do logcat_pids+=($!) done -PLATFORM=android MAESTRO_UDID=$(IFS=,; echo "${devices[*]}") ./run-flows.sh +PLATFORM=android CLERK_TEST_DEVICES=$(IFS=,; echo "${devices[*]}") ./run-flows.sh diff --git a/integration/tests/expo-native/run-flows.sh b/integration/tests/expo-native/run-flows.sh index 26b5fc8f4fa..37f888efa58 100755 --- a/integration/tests/expo-native/run-flows.sh +++ b/integration/tests/expo-native/run-flows.sh @@ -1,130 +1,22 @@ #!/usr/bin/env bash -# Usage: PLATFORM= [MAESTRO_UDID=a,b] [MAESTRO_DEBUG_OUTPUT=dir] ./run-flows.sh +# Usage: PLATFORM= [CLERK_TEST_DEVICES=a,b] ./run-flows.sh set -euo pipefail cd "$(dirname "${BASH_SOURCE[0]}")" -# Runs the official maestro CLI. maestro-runner was tried and reverted: its -# drivers mangle typed text and resolve text selectors by substring, so -# tapOn 'Continue' hits the 'Continue to ' title instead of the button. -command -v maestro >/dev/null 2>&1 || { - echo "maestro is required: https://docs.maestro.dev" - exit 1 -} - : "${PLATFORM:?PLATFORM (ios|android) is required}" : "${CLERK_TEST_EMAIL:?CLERK_TEST_EMAIL is required}" : "${CLERK_TEST_PASSWORD:?CLERK_TEST_PASSWORD is required}" -app_id=com.clerk.exponativebuildfixture -output_root=${MAESTRO_DEBUG_OUTPUT:-${TMPDIR:-/tmp}/clerk-expo-maestro-runner} -IFS=, read -r -a devices <<< "${MAESTRO_UDID:-}" -device_count=${#devices[@]} -[ "$device_count" -gt 0 ] || device_count=1 - -force_stop() { - local device - for device in "${devices[@]:-booted}"; do - if [ "$PLATFORM" = ios ]; then - xcrun simctl terminate "$device" "$app_id" >/dev/null 2>&1 || true - elif [ "$device" = booted ]; then - adb shell am force-stop "$app_id" >/dev/null 2>&1 || true - else - adb -s "$device" shell am force-stop "$app_id" >/dev/null 2>&1 || true - fi - done -} - -run_maestro() { - local output_name=$1 mode=$2 shards=$3 - shift 3 - local shard_args=() - if [ "$shards" -gt 1 ]; then shard_args=("--shard-$mode" "$shards"); fi - maestro ${MAESTRO_UDID:+--udid "$MAESTRO_UDID"} test \ - ${shard_args[@]+"${shard_args[@]}"} \ - --debug-output "$output_root/$output_name" \ - --flatten-debug-output \ - --format JUNIT \ - --output "$output_root/$output_name/report.xml" \ - -e CLERK_TEST_EMAIL="$CLERK_TEST_EMAIL" \ - -e CLERK_TEST_PASSWORD="$CLERK_TEST_PASSWORD" \ - "$@" -} - -report_rows() { - python3 - "$1" <<'PY' -import sys, xml.etree.ElementTree as ET -for case in ET.parse(sys.argv[1]).getroot().iter('testcase'): - print(f"{case.get('file')}\t{case.get('status')}\t{float(case.get('time') or 0):.0f}") -PY -} - -started=$SECONDS -warmup_result=failed -for warmup_attempt in 1 2; do - if run_maestro "warmup-attempt-$warmup_attempt" all "$device_count" flows/subflows/_warmup.yaml; then - warmup_result=passed - break - fi - force_stop - if [ "$warmup_attempt" -eq 1 ]; then - echo "::warning::Warmup failed attempt 1, retrying after 10s..." - sleep 10 - fi -done -echo "Warmup: $warmup_result after $warmup_attempt attempt(s) in $((SECONDS - started))s" -if [ "$warmup_result" != passed ]; then - echo "::error::Warmup failed after 2 attempts; aborting Maestro flows" - exit 1 -fi - -# Force-stop so the first launchApp clearState doesn't race the warm process. -force_stop - -run_maestro flows split "$device_count" flows/*.yaml || true -report_rows "$output_root/flows/report.xml" > "$output_root/attempt-1.tsv" - -failed=() -while IFS=$'\t' read -r file status _; do - [ "$status" = SUCCESS ] || failed+=("$file") -done < "$output_root/attempt-1.tsv" +status=0 +pnpm exec e2e run --target "$PLATFORM" --retries 1 --video=on-first-retry --reporter list,junit,markdown || status=$? -if [ "${#failed[@]}" -gt 0 ]; then - echo "::warning::${#failed[@]} flow(s) failed, rerunning after 10s to tell flaky from deterministic: ${failed[*]}" - force_stop - sleep 10 - shards=$device_count - [ "${#failed[@]}" -lt "$shards" ] && shards=${#failed[@]} - run_maestro rerun split "$shards" "${failed[@]}" || true - report_rows "$output_root/rerun/report.xml" > "$output_root/attempt-2.tsv" +if [ -n "${GITHUB_STEP_SUMMARY:-}" ] && [ -f .e2e/summary.md ]; then + cat .e2e/summary.md >> "$GITHUB_STEP_SUMMARY" fi -if [ -n "${GITHUB_STEP_SUMMARY:-}" ]; then - { - echo "### Maestro flow timings ($device_count device(s))" - echo '| Flow | Result | Attempts | Duration |' - echo '| --- | --- | ---: | ---: |' - } >> "$GITHUB_STEP_SUMMARY" +flaky=$(jq -r '.run.results[] | select(.status == "flaky") | .file' .e2e/report.json 2>/dev/null || true) +if [ -n "$flaky" ]; then + echo "::error::Flaky flow(s), failed then passed on the retry: ${flaky//$'\n'/, }" + [ "$status" -ne 0 ] || status=1 fi - -status=0 -while IFS=$'\t' read -r file result seconds; do - attempts=1 - if [ "$result" = SUCCESS ]; then - result=passed - else - status=1 - result=failed - rerun=$(awk -F'\t' -v f="$file" '$1 == f { print $2 "\t" $3 }' "$output_root/attempt-2.tsv" 2>/dev/null || true) - if [ -n "$rerun" ]; then - attempts=2 - IFS=$'\t' read -r rerun_result seconds <<< "$rerun" - [ "$rerun_result" = SUCCESS ] && result='flaky (failed, then passed on the rerun)' - fi - echo "::error::Flow $file: $result" - fi - echo "Flow $file: $result after $attempts attempt(s) in ${seconds}s" - if [ -n "${GITHUB_STEP_SUMMARY:-}" ]; then - printf '| `%s` | %s | %s | %ss |\n' "$file" "$result" "$attempts" "$seconds" >> "$GITHUB_STEP_SUMMARY" - fi -done < "$output_root/attempt-1.tsv" -exit $status +exit "$status" diff --git a/package.json b/package.json index cf74d032ebc..150db8d5ee4 100644 --- a/package.json +++ b/package.json @@ -46,8 +46,8 @@ "test:integration:custom": "pnpm test:integration:base --grep @custom", "test:integration:deployment:nextjs": "pnpm playwright test --config integration/playwright.deployments.config.ts", "test:integration:electron": "pnpm test:integration:base --grep @electron", - "test:integration:expo-native:android": "PLATFORM=android integration/tests/expo-native/run-flows.sh", - "test:integration:expo-native:ios": "PLATFORM=ios integration/tests/expo-native/run-flows.sh", + "test:integration:expo-native:android": "pnpm --dir integration/tests/expo-native test:android", + "test:integration:expo-native:ios": "pnpm --dir integration/tests/expo-native test:ios", "test:integration:expo-web:disabled": "E2E_APP_ID=expo.expo-web pnpm test:integration:base --grep @expo-web", "test:integration:express": "E2E_APP_ID=express.* pnpm test:integration:base --grep @express", "test:integration:fastify": "E2E_APP_ID=fastify.* pnpm test:integration:base --grep @fastify", From dc38e07fc601f5552f9ba922f20a0f1bef4b4413 Mon Sep 17 00:00:00 2001 From: wobsoriano Date: Thu, 1 Oct 2026 19:28:00 -0700 Subject: [PATCH 02/31] ci(e2e): install the expo native e2e runner at the workspace root --- .github/workflows/expo-native-build.yml | 16 +- .gitignore | 1 + ...2e.config.ts => e2e.expo-native.config.ts} | 2 +- integration/tests/expo-native/.gitignore | 3 +- integration/tests/expo-native/package.json | 14 - integration/tests/expo-native/pnpm-lock.yaml | 1287 ----------------- .../tests/expo-native/pnpm-workspace.yaml | 11 - integration/tests/expo-native/run-flows.sh | 10 +- package.json | 6 +- pnpm-lock.yaml | 853 +++++------ pnpm-workspace.yaml | 3 + 11 files changed, 389 insertions(+), 1817 deletions(-) rename integration/{tests/expo-native/e2e.config.ts => e2e.expo-native.config.ts} (91%) delete mode 100644 integration/tests/expo-native/package.json delete mode 100644 integration/tests/expo-native/pnpm-lock.yaml delete mode 100644 integration/tests/expo-native/pnpm-workspace.yaml diff --git a/.github/workflows/expo-native-build.yml b/.github/workflows/expo-native-build.yml index 831fe6619cd..78e8dae8ab0 100644 --- a/.github/workflows/expo-native-build.yml +++ b/.github/workflows/expo-native-build.yml @@ -113,7 +113,7 @@ jobs: cache: pnpm - name: Install monorepo dependencies - if: steps.native-build-cache.outputs.cache-hit != 'true' + if: steps.native-build-cache.outputs.cache-hit != 'true' || matrix.run-e2e == true run: pnpm install --frozen-lockfile - name: Build and pack Clerk packages @@ -228,17 +228,13 @@ jobs: if: matrix.platform == 'ios' && matrix.run-e2e == true && steps.keys.outputs.pk != '' run: ${{ env.E2E_DIR }}/boot-ios-simulators.sh boot "$E2E_SHARDS" - - name: Install e2e runner - if: steps.keys.outputs.pk != '' - working-directory: ${{ env.E2E_DIR }} - run: pnpm install --frozen-lockfile - - name: Cache iOS automation runner if: matrix.platform == 'ios' && steps.keys.outputs.pk != '' uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4 with: path: ~/.agent-device - key: agent-device-${{ runner.os }}-${{ hashFiles(format('{0}/pnpm-lock.yaml', env.E2E_DIR)) }} + key: agent-device-${{ runner.os }}-${{ hashFiles('pnpm-lock.yaml') }} + restore-keys: agent-device-${{ runner.os }}- # Provisioned as late as possible so live credentials exist for the # shortest window. @@ -362,9 +358,9 @@ jobs: CLERK_TEST_PASSWORD: ${{ steps.user.outputs.password }} run: | [ -n "$CLERK_TEST_PASSWORD" ] || exit 0 - mkdir -p "$E2E_DIR/.e2e" "$RUNNER_TEMP/e2e-device-logs" + mkdir -p integration/.e2e "$RUNNER_TEMP/e2e-device-logs" # shellcheck disable=SC2016 - find "$E2E_DIR/.e2e" "$RUNNER_TEMP/e2e-device-logs" -type f \ + find integration/.e2e "$RUNNER_TEMP/e2e-device-logs" -type f \ \( -name '*.json' -o -name '*.log' -o -name '*.md' -o -name '*.txt' -o -name '*.xml' \) \ -exec perl -pi -e 's/\Q$ENV{CLERK_TEST_PASSWORD}\E/[REDACTED]/g' {} + @@ -375,7 +371,7 @@ jobs: name: e2e-${{ matrix.platform }} include-hidden-files: true path: | - ${{ env.E2E_DIR }}/.e2e + integration/.e2e ${{ runner.temp }}/e2e-device-logs if-no-files-found: warn retention-days: 7 diff --git a/.gitignore b/.gitignore index 24d1b33d3a8..f0aef8bbd7a 100644 --- a/.gitignore +++ b/.gitignore @@ -67,6 +67,7 @@ packages/*/examples/*/package-lock.json packages/*/examples/*/yarn.lock /test-results/ /playwright-report/ +/integration/.e2e/ /playwright/.cache/ # integration testing diff --git a/integration/tests/expo-native/e2e.config.ts b/integration/e2e.expo-native.config.ts similarity index 91% rename from integration/tests/expo-native/e2e.config.ts rename to integration/e2e.expo-native.config.ts index c817a6fda8a..74a31d821f0 100644 --- a/integration/tests/expo-native/e2e.config.ts +++ b/integration/e2e.expo-native.config.ts @@ -5,7 +5,7 @@ const app = { bundleId: 'com.clerk.exponativebuildfixture' }; const devices = process.env.CLERK_TEST_DEVICES?.split(','); export default { - tests: 'flows/*.e2e.ts', + tests: 'tests/expo-native/flows/*.e2e.ts', targets: [ { name: 'ios', engine: mobile({ platform: 'ios', device: devices }), app }, { name: 'android', engine: mobile({ platform: 'android', device: devices }), app }, diff --git a/integration/tests/expo-native/.gitignore b/integration/tests/expo-native/.gitignore index 36abc8bac36..e33609d251c 100644 --- a/integration/tests/expo-native/.gitignore +++ b/integration/tests/expo-native/.gitignore @@ -1,2 +1 @@ -/.e2e/ -/node_modules/ +*.png diff --git a/integration/tests/expo-native/package.json b/integration/tests/expo-native/package.json deleted file mode 100644 index a8a7e7fbe07..00000000000 --- a/integration/tests/expo-native/package.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "name": "clerk-expo-native-e2e", - "private": true, - "type": "module", - "scripts": { - "test:android": "e2e run --target android", - "test:ios": "e2e run --target ios" - }, - "devDependencies": { - "@e2e-dev/mobile": "0.8.1", - "e2e": "0.15.1" - }, - "packageManager": "pnpm@10.34.5+sha512.a4ee05f2f73658255bd6a89859c065a45c28a57daefae2c893a168ee2b73168c37b91e83e57ea67654ad03f03031746430e8bce38e362e042605fb8abc80192e" -} diff --git a/integration/tests/expo-native/pnpm-lock.yaml b/integration/tests/expo-native/pnpm-lock.yaml deleted file mode 100644 index b896eaf79e8..00000000000 --- a/integration/tests/expo-native/pnpm-lock.yaml +++ /dev/null @@ -1,1287 +0,0 @@ -lockfileVersion: '9.0' - -settings: - autoInstallPeers: true - excludeLinksFromLockfile: false - -importers: - - .: - devDependencies: - '@e2e-dev/mobile': - specifier: 0.8.1 - version: 0.8.1(e2e@0.15.1) - e2e: - specifier: 0.15.1 - version: 0.15.1 - -packages: - - '@ai-sdk/provider@4.0.18': - resolution: {integrity: sha512-+GZJIgz1jk86pwEbb3f1BD2bdoSKyWE4Jg4YUc7NMnMozbWemSKYZcw2F4nMaO5qwsL5A8RmioAKW81YktRpIQ==} - engines: {node: '>=22'} - - '@clack/core@1.5.1': - resolution: {integrity: sha512-iHTrHA8MtVuLl2TfZySmcKv1qO2PoyC9Z7pfSDozEuV5vtY3/wcOPKJXlqJ5Oq2Cx5DDGQGAMVx6HZfRRoVEbQ==} - engines: {node: '>= 20.12.0'} - - '@clack/prompts@1.8.1': - resolution: {integrity: sha512-dlT1m5e/0yUL0kRNcQn7yGLVThkgbB0Ga/1AmfDDC/8ik6AIiSf2QLQO2zPYvefsHP0aFgxO93cVLCCfDp7kzQ==} - engines: {node: '>= 20.12.0'} - - '@e2e-dev/mobile@0.8.1': - resolution: {integrity: sha512-aUbqIUxgeyxebNtySH7Cw+IvZPauHqOM5oUBTCzF8YMpInjqs8vi7iiW6eiZsQPxrINTy/3KoSvIAnPU8bXFYg==} - engines: {node: '>=22.12.0'} - peerDependencies: - ai: ^7.0.0 - e2e: '>=0.15.0 <1' - peerDependenciesMeta: - ai: - optional: true - - '@esbuild/aix-ppc64@0.28.2': - resolution: {integrity: sha512-XExcO+dvLKvVtNTibSTBej1NCAbaGhWn9Ww1ZPx80qsahhPFe/8jgWP0IchNe0F3HwkU7n8ejhH8bjonqht8mQ==} - engines: {node: '>=18'} - cpu: [ppc64] - os: [aix] - - '@esbuild/android-arm64@0.28.2': - resolution: {integrity: sha512-5YfKeeI8qWfBZIX+u2xZC3Zlb3Os/gLS2sbEKM+I4ZOcsWmHS2WLysCcQZDAFRslDUU5Oiq44gf6PYN1vGwG5A==} - engines: {node: '>=18'} - cpu: [arm64] - os: [android] - - '@esbuild/android-arm@0.28.2': - resolution: {integrity: sha512-kXXoiPVVGQcnIYGOeaovwOURpniDBpSq4A03qkQ+BMQqtGG6HYap3xne9C1O1yo4TR3qxlCX5IqqmX6fFo2Lqg==} - engines: {node: '>=18'} - cpu: [arm] - os: [android] - - '@esbuild/android-x64@0.28.2': - resolution: {integrity: sha512-O387ite7SzUyCcy3JQX4P4bLtEA7bLLkx+esve5JHnyYfNTxcVpXZo9jhdB0lTKN44gztELTdU7nS8Nr16Fs1Q==} - engines: {node: '>=18'} - cpu: [x64] - os: [android] - - '@esbuild/darwin-arm64@0.28.2': - resolution: {integrity: sha512-n4KqkOQrraxHJcgjM1RvwbigfQKIKJVpM7xp+KsxiyUSrRdIXnt73VhrPAx0fV44hgfmIVKjxMN9J1t5jySVkw==} - engines: {node: '>=18'} - cpu: [arm64] - os: [darwin] - - '@esbuild/darwin-x64@0.28.2': - resolution: {integrity: sha512-uq6suIWYP37qzGddBKPw5QEQPi6HiLGsO7UmkpfyaYNQ3D+rN6w6WfwH+nuqcGXWvawGwxOEroO4YGnFh95azw==} - engines: {node: '>=18'} - cpu: [x64] - os: [darwin] - - '@esbuild/freebsd-arm64@0.28.2': - resolution: {integrity: sha512-n+I0BTSRIoy+d6RPKnEVwql5UwBJolytvY4mAOIEJorKlqgPII8ix6slVVrfZ5Tnj7glIZvloylbB/EJPMWEXw==} - engines: {node: '>=18'} - cpu: [arm64] - os: [freebsd] - - '@esbuild/freebsd-x64@0.28.2': - resolution: {integrity: sha512-78XJTJkvPs0kz2w61301PJjXl4g7q3JqiYMZ/M/yVI73EHBrCRTgkhu9oqG7vPqq+a/yadEW8aD+agKlk5xrmg==} - engines: {node: '>=18'} - cpu: [x64] - os: [freebsd] - - '@esbuild/linux-arm64@0.28.2': - resolution: {integrity: sha512-pW4AC0P3it8c7do9MVM4p51FzHzdM/TZrerurgRcHJ2WTa1VQ1CIq18xncfpBJw4ojkiZZrKW2yIBWBP92j6Ug==} - engines: {node: '>=18'} - cpu: [arm64] - os: [linux] - - '@esbuild/linux-arm@0.28.2': - resolution: {integrity: sha512-XlDnu2q5yoqems+xay6wSAcg9DDD7K9RLKZEBOMZm3ckNpJBvOX20tSfby8KfrrhINDyv9V2YVZKY/SpoGJI8w==} - engines: {node: '>=18'} - cpu: [arm] - os: [linux] - - '@esbuild/linux-ia32@0.28.2': - resolution: {integrity: sha512-CYbnj78HsIeA+DhgUKgFCfvNsTHFhMMrinUrMZpDXJXKN8T3XViTZ/+wtHeVxEWY8ewSzTFN+nRmSwO2tZaLUQ==} - engines: {node: '>=18'} - cpu: [ia32] - os: [linux] - - '@esbuild/linux-loong64@0.28.2': - resolution: {integrity: sha512-buwkd8nsph4R+ajRvw0qM5Hja/TXQow3ptzWO2EbG/cqcIkHloRrdlBtQlshyYGTNFvfkfJ5tpPLVkY4DtsPfQ==} - engines: {node: '>=18'} - cpu: [loong64] - os: [linux] - - '@esbuild/linux-mips64el@0.28.2': - resolution: {integrity: sha512-ZVykbDyk7519VwiNb9Lcj9m8XM6v5V9uKPvrEMkkEedVewf+0itkhahp4HDpgERXhwLRpWFypsGbG/J8s0QjJA==} - engines: {node: '>=18'} - cpu: [mips64el] - os: [linux] - - '@esbuild/linux-ppc64@0.28.2': - resolution: {integrity: sha512-CAXl+Dtd9UUuJd8pKKdwh6MLm3MUMiqMPmhZ3tTSXPqfyQ3vDl6R5hZdZ/kYojK4ofXtdfSv1tFq8XzWx3heNQ==} - engines: {node: '>=18'} - cpu: [ppc64] - os: [linux] - - '@esbuild/linux-riscv64@0.28.2': - resolution: {integrity: sha512-GeXCej4IQtU1B+QlDV8W/RRvbzI3O/Stss+/bCXv4lZls5WGRtu2a+3JkA3i4qIUlMXpcHebWpF8AkJhATowuA==} - engines: {node: '>=18'} - cpu: [riscv64] - os: [linux] - - '@esbuild/linux-s390x@0.28.2': - resolution: {integrity: sha512-3H1weTYZPxt/WOhByszQZybS9w5lKzUn1FDMsgEChbHWQwHYQQRfBxgCcZvPhjHfKyJjIievvMmEUawJrdY9Dg==} - engines: {node: '>=18'} - cpu: [s390x] - os: [linux] - - '@esbuild/linux-x64@0.28.2': - resolution: {integrity: sha512-4xTZr1FUmSoQW4XIWmit3tzQrUTZM+N3P0XV8xROKYF50XfI7xeO90+1bZvNwxIufQ9hDQVRJH5YhgPVF8A/HQ==} - engines: {node: '>=18'} - cpu: [x64] - os: [linux] - - '@esbuild/netbsd-arm64@0.28.2': - resolution: {integrity: sha512-sSATRjPeDBg3pdgHoQfoYBob11Kk1FGa9lui5RIHZCoCkJa9QKlvl3/vKz2usCmYYjs7ymJR/2Nnsqe+Hjt5nw==} - engines: {node: '>=18'} - cpu: [arm64] - os: [netbsd] - - '@esbuild/netbsd-x64@0.28.2': - resolution: {integrity: sha512-lqnzCV+mM0gIADaKihiCg6ifgfU2L3h5E33rNQBN1Y4MaVGnzryzmvvf7UHxprpQdE8hpqLolJ9Rl+SkIRDpyw==} - engines: {node: '>=18'} - cpu: [x64] - os: [netbsd] - - '@esbuild/openbsd-arm64@0.28.2': - resolution: {integrity: sha512-AL2qJILH7lNjrDmCQDvdxMfAUIv8KMNZOvrwAQ8i8//ntL9FflhOyMJ8OZSMBb8/AWXe3/5v5S20y3zCoZWKoQ==} - engines: {node: '>=18'} - cpu: [arm64] - os: [openbsd] - - '@esbuild/openbsd-x64@0.28.2': - resolution: {integrity: sha512-QtiuPytchRyC4rwUKhexJdQKvDuZ6hWloi3igqPQNUJCS1/v9EiO3UTOXR6A3FoMo4fnAKbWJdqaIwhOzh8qEw==} - engines: {node: '>=18'} - cpu: [x64] - os: [openbsd] - - '@esbuild/openharmony-arm64@0.28.2': - resolution: {integrity: sha512-WkhYDmpTjLvGlScA1rwjRUmhl4k8oXR3cIbtqWmELgU/dFeHHlEllxDvdWcNJV9rbzCexB5vz8gtNewWLgCT7Q==} - engines: {node: '>=18'} - cpu: [arm64] - os: [openharmony] - - '@esbuild/sunos-x64@0.28.2': - resolution: {integrity: sha512-GPMSkTOtMnv2U2F8gxe4Io6qmVs+YKyp832Etqqxr0hFngmXQ3rzwytelm3GIn7T4VviRUlf3sOgBOiTdvaf7g==} - engines: {node: '>=18'} - cpu: [x64] - os: [sunos] - - '@esbuild/win32-arm64@0.28.2': - resolution: {integrity: sha512-PIhhEkE9uPBleRBrQEJpUn7MBnibZzbGzYWPmY3x+YoVg/95zbjB4CxPPOQ8l5tYYM4mMaCthF8/1DIfBQQyWQ==} - engines: {node: '>=18'} - cpu: [arm64] - os: [win32] - - '@esbuild/win32-ia32@0.28.2': - resolution: {integrity: sha512-YmJbfTlvU7Sdn9BB+4PRES4oB6pxgS37MAONj+hBr/cpXS1aBPKXxNnDbu+QCWPj0o9dgyxeq79g6c5P8KeuYA==} - engines: {node: '>=18'} - cpu: [ia32] - os: [win32] - - '@esbuild/win32-x64@0.28.2': - resolution: {integrity: sha512-5ebpxr3nWMzrL/rnUI755Jkuee0bHL/Gq0WTF9lvcpv73wAp5eu8MfBUgWK9bhWvZjj7yX8etf/8tI8Ney695g==} - engines: {node: '>=18'} - cpu: [x64] - os: [win32] - - '@hono/node-server@2.1.3': - resolution: {integrity: sha512-TA//nWMqPhbfdfneACk6t5a9eqbS9lABEPyKn0/xZTah3H3U2XaVg85rJFl0/Fyit0I552YDHgXGVSf3GwqbUw==} - engines: {node: '>=20'} - peerDependencies: - hono: ^4 - - '@modelcontextprotocol/sdk@1.30.1': - resolution: {integrity: sha512-H2HxLvC3HDNybePJaLdSrU1hhUK5iQw+WvV1b01myFyI7sdVGe1u/IPTE5D9fGCiJDVtgMV/lmFkQXLmQyIFYA==} - engines: {node: '>=18'} - peerDependencies: - '@cfworker/json-schema': ^4.1.1 - zod: ^3.25 || ^4.0 - peerDependenciesMeta: - '@cfworker/json-schema': - optional: true - - '@standard-schema/spec@1.1.0': - resolution: {integrity: sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w==} - - '@types/chai@5.2.3': - resolution: {integrity: sha512-Mw558oeA9fFbv65/y4mHtXDs9bPnFMZAL/jxdPFUpOHHIXX91mcgEHbS5Lahr+pwZFR8A7GQleRWeI6cGFC2UA==} - - '@types/deep-eql@4.0.2': - resolution: {integrity: sha512-c9h9dVVMigMPc4bwTvC5dxqtqJZwQPePsWjPlpSOnojbor6pGqdk541lfA7AqFQr5pB1BRdq0juY9db81BwyFw==} - - '@vitest/expect@5.0.2': - resolution: {integrity: sha512-pd6YDkhOHptwC65NYNpGpNxWlJH9M9Gxwtej73osTddb1NpiE0Jz5CIjTTEGXRgK0YtiSN7qBokmBXZ5uPJL1w==} - - '@vitest/pretty-format@5.0.2': - resolution: {integrity: sha512-YHM+mQQ7N1ROHMugJ7P/M+fC/q1G4zs/iAMZZCvhHcY8WkwPQcXBHD+z18oz+808Cfa12K7jOr3XPQMcLIovjw==} - - '@vitest/spy@5.0.2': - resolution: {integrity: sha512-Ijc7T1nT9efNb5LxvjaBrEqw3f/QwUv5EE0nKqZxgqsaV/FxAAZ8baGylA8X/Z2oS4Lp+K74Jr6dTJsDKxJDeg==} - - '@vitest/utils@5.0.2': - resolution: {integrity: sha512-mgpUtxFhKeOKVaArBVHNJGdYHAeRh135o59l13uVmPUCS1OUtis5pBqXEgE25iqRgFqEBwXvJlkhknRsYnMeqg==} - - accepts@2.0.0: - resolution: {integrity: sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng==} - engines: {node: '>= 0.6'} - - agent-device@0.21.18: - resolution: {integrity: sha512-ptNJ7a4jkAXFLSmZqKJDwxL+YpCEUuZv3oCBY76PwE3b2W+yQqQuG0ej0/bOspIHJRmMGNOkWhtxm3gmRW9hRQ==} - engines: {node: '>=22.12'} - hasBin: true - peerDependencies: - ai: ^6.0.0 || ^7.0.0 - peerDependenciesMeta: - ai: - optional: true - - ajv-formats@3.0.1: - resolution: {integrity: sha512-8iUql50EUR+uUcdRQ3HDqa6EVyo3docL8g5WJ3FNcWmu62IbkGUue/pEyLBW8VGKKucTPgqeks4fIU1DA4yowQ==} - peerDependencies: - ajv: ^8.0.0 - peerDependenciesMeta: - ajv: - optional: true - - ajv@8.20.0: - resolution: {integrity: sha512-Thbli+OlOj+iMPYFBVBfJ3OmCAnaSyNn4M1vz9T6Gka5Jt9ba/HIR56joy65tY6kx/FCF5VXNB819Y7/GUrBGA==} - - assertion-error@2.0.1: - resolution: {integrity: sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==} - engines: {node: '>=12'} - - body-parser@2.3.0: - resolution: {integrity: sha512-2cGmJupaNgg+QUwVLAucDuWuoMZ6EX9iHDRswZ5lsNYEmwPaRknMPCLZz07yTzVq/83p4o/wzbDZbBrTvGGTIw==} - engines: {node: '>=18'} - - bytes@3.1.2: - resolution: {integrity: sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==} - engines: {node: '>= 0.8'} - - call-bind-apply-helpers@1.0.2: - resolution: {integrity: sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==} - engines: {node: '>= 0.4'} - - call-bound@1.0.4: - resolution: {integrity: sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==} - engines: {node: '>= 0.4'} - - chai@6.2.2: - resolution: {integrity: sha512-NUPRluOfOiTKBKvWPtSD4PhFvWCqOi0BGStNWs57X9js7XGTprSmFoz5F0tWhR4WPjNeR9jXqdC7/UpSJTnlRg==} - engines: {node: '>=18'} - - commander@15.0.0: - resolution: {integrity: sha512-z67u4ZhzCL/Tydu1lJARtEZYWbWaN7oYLHbsuzocr6y4N6WZAagG3RQ4FW61V1/0+jImpj293XfrcYnd1qxtPg==} - engines: {node: '>=22.12.0'} - - content-disposition@1.1.0: - resolution: {integrity: sha512-5jRCH9Z/+DRP7rkvY83B+yGIGX96OYdJmzngqnw2SBSxqCFPd0w2km3s5iawpGX8krnwSGmF0FW5Nhr0Hfai3g==} - engines: {node: '>=18'} - - content-type@1.0.5: - resolution: {integrity: sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==} - engines: {node: '>= 0.6'} - - content-type@2.1.0: - resolution: {integrity: sha512-mj7UPXE0jaqaOsukNZRUEfEi2AcL7C/vwmwcHV0O97eO1E1pxBZuyjlZrx5seTaNBg1U6+o35wpa35Qfcc+7ag==} - engines: {node: '>=18'} - - convert-source-map@2.0.0: - resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==} - - cookie-signature@1.2.2: - resolution: {integrity: sha512-D76uU73ulSXrD1UXF4KE2TMxVVwhsnCgfAyTg9k8P6KGZjlXKrOLe4dJQKI3Bxi5wjesZoFXJWElNWBjPZMbhg==} - engines: {node: '>=6.6.0'} - - cookie@0.7.2: - resolution: {integrity: sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==} - engines: {node: '>= 0.6'} - - cors@2.8.6: - resolution: {integrity: sha512-tJtZBBHA6vjIAaF6EnIaq6laBBP9aq/Y3ouVJjEfoHbRBcHBAHYcMh/w8LDrk2PvIMMq8gmopa5D4V8RmbrxGw==} - engines: {node: '>= 0.10'} - - cross-spawn@7.0.6: - resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==} - engines: {node: '>= 8'} - - debug@4.4.3: - resolution: {integrity: sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==} - engines: {node: '>=6.0'} - peerDependencies: - supports-color: '*' - peerDependenciesMeta: - supports-color: - optional: true - - depd@2.0.0: - resolution: {integrity: sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==} - engines: {node: '>= 0.8'} - - dunder-proto@1.0.1: - resolution: {integrity: sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==} - engines: {node: '>= 0.4'} - - e2e@0.15.1: - resolution: {integrity: sha512-HYuc4xFbLqG4TMZkzZEZEoYa20qKvqyZ9nodDOZ8Yo05YlspzC4GV4guEql1pVIdspqj0fDMINx2rsn3REVrHA==} - engines: {node: '>=22.12.0'} - hasBin: true - peerDependencies: - '@ai-sdk/openai': ^4.0.0 - '@ai-sdk/openai-compatible': ^3.0.0 - '@ai-sdk/xai': ^5.0.0 - ai: ^7.0.0 - peerDependenciesMeta: - '@ai-sdk/openai': - optional: true - '@ai-sdk/openai-compatible': - optional: true - '@ai-sdk/xai': - optional: true - ai: - optional: true - - ee-first@1.1.1: - resolution: {integrity: sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==} - - encodeurl@2.0.0: - resolution: {integrity: sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==} - engines: {node: '>= 0.8'} - - es-define-property@1.0.1: - resolution: {integrity: sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==} - engines: {node: '>= 0.4'} - - es-errors@1.3.0: - resolution: {integrity: sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==} - engines: {node: '>= 0.4'} - - es-object-atoms@1.1.2: - resolution: {integrity: sha512-HWcBoN6NileqtSydK2FqHbS/LoDd2pqrnQHLyJzBj4kOp/ky2MWMN694xOfkK8/SnUsW2DH7EfyVlydKCsm1Zw==} - engines: {node: '>= 0.4'} - - esbuild@0.28.2: - resolution: {integrity: sha512-HKVLS8dvII+xoKW9kmqxbRKrnWEXfJJr/FZhhJmiqIB0e053QNYFqOBouTMO/k5sID4MvCiUCvv8b9M4h32wIA==} - engines: {node: '>=18'} - hasBin: true - - escape-html@1.0.3: - resolution: {integrity: sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==} - - etag@1.8.1: - resolution: {integrity: sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==} - engines: {node: '>= 0.6'} - - eventsource-parser@3.1.1: - resolution: {integrity: sha512-EKN1vKAMcZ8MlYMpaNuxN6R9yakzH6uajHcHVTqWJzvu5pWw9DyhbP35HH8MVBQ+dZjAfDxk+A8NiR9KWaXiyQ==} - engines: {node: '>=18.0.0'} - - eventsource@3.0.7: - resolution: {integrity: sha512-CRT1WTyuQoD771GW56XEZFQ/ZoSfWid1alKGDYMmkt2yl8UXrVR4pspqWNEcqKvVIzg6PAltWjxcSSPrboA4iA==} - engines: {node: '>=18.0.0'} - - express-rate-limit@8.7.0: - resolution: {integrity: sha512-hOwV7WOxXfjRpAM1DSJWZDXx3GhplwD8IfwuwvogD8i1Qnkgosw/H45s4ZnFAUHDAhPjlY9hLBvJhKmGMyY26g==} - engines: {node: '>= 16'} - peerDependencies: - express: '>= 4.11' - - express@5.2.1: - resolution: {integrity: sha512-hIS4idWWai69NezIdRt2xFVofaF4j+6INOpJlVOLDO8zXGpUVEVzIYk12UUi2JzjEzWL3IOAxcTubgz9Po0yXw==} - engines: {node: '>= 18'} - - fast-deep-equal@3.1.3: - resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} - - fast-string-truncated-width@3.0.3: - resolution: {integrity: sha512-0jjjIEL6+0jag3l2XWWizO64/aZVtpiGE3t0Zgqxv0DPuxiMjvB3M24fCyhZUO4KomJQPj3LTSUnDP3GpdwC0g==} - - fast-string-width@3.0.2: - resolution: {integrity: sha512-gX8LrtNEI5hq8DVUfRQMbr5lpaS4nMIWV+7XEbXk2b8kiQIizgnlr12B4dA3ZEx3308ze0O4Q1R+cHts8kyUJg==} - - fast-uri@3.1.8: - resolution: {integrity: sha512-GZMtZUTNRpOVIECoXwLNZS5xUGE+mVNbTB8h/7Rwh2TFWcBQiPzTgyZi05BF9UMZKkLJv8XBRJTlU7zg8+ZfMg==} - - fast-wrap-ansi@0.2.2: - resolution: {integrity: sha512-7F2Fl+TjRSenLqlU3UjSH0iyqopqoZIu7eZVpEirP2g1GtWa2G/ecEmBdgz31+Mxr+ELclgg6sokpSFIQiZ02Q==} - - finalhandler@2.1.1: - resolution: {integrity: sha512-S8KoZgRZN+a5rNwqTxlZZePjT/4cnm0ROV70LedRHZ0p8u9fRID0hJUZQpkKLzro8LfmC8sx23bY6tVNxv8pQA==} - engines: {node: '>= 18.0.0'} - - forwarded@0.2.0: - resolution: {integrity: sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==} - engines: {node: '>= 0.6'} - - fresh@2.0.0: - resolution: {integrity: sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A==} - engines: {node: '>= 0.8'} - - fsevents@2.3.3: - resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} - engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} - os: [darwin] - - function-bind@1.1.2: - resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==} - - get-intrinsic@1.3.0: - resolution: {integrity: sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==} - engines: {node: '>= 0.4'} - - get-proto@1.0.1: - resolution: {integrity: sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==} - engines: {node: '>= 0.4'} - - gopd@1.2.0: - resolution: {integrity: sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==} - engines: {node: '>= 0.4'} - - has-symbols@1.1.0: - resolution: {integrity: sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==} - engines: {node: '>= 0.4'} - - hasown@2.0.4: - resolution: {integrity: sha512-T2UbfbBEF32wiepXIsMlTW9+dDYC6wMh/t/vYA4tuOMKqWz/n3vr1NFSxQiyP+zk2mXsoMA/i/7qV6LKut1t1A==} - engines: {node: '>= 0.4'} - - hono@4.13.11: - resolution: {integrity: sha512-/SMX/RQNJn7oNmFwH6DtwDqcrzZU2otm1FD6OJe2cWF6cfy/F8hq0XVBv7xW3FTJshRQwuBnXHDq2kNsdZnshg==} - engines: {node: '>=16.9.0'} - - http-errors@2.0.1: - resolution: {integrity: sha512-4FbRdAX+bSdmo4AUFuS0WNiPz8NgFt+r8ThgNWmlrjQjt1Q7ZR9+zTlce2859x4KSXrwIsaeTqDoKQmtP8pLmQ==} - engines: {node: '>= 0.8'} - - iconv-lite@0.7.3: - resolution: {integrity: sha512-IKXpvIzjnC9XTAUbVBcMfGS0EPaIXtW6v+zr+RRp+hqULEpo0owZax6wyRwPOJbWbzjYspQwusTsfVr0ifh4uQ==} - engines: {node: '>=0.10.0'} - - inherits@2.0.4: - resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} - - ip-address@10.7.2: - resolution: {integrity: sha512-7H/2gFSIitxc0hG3nOI1glS8QLo/EHBFFLk8vEUjXY/xu0AdL8jZ9U1IzO2PUm0d2D/ofQcAifb0g6OBkt8U7w==} - engines: {node: '>= 12'} - - ipaddr.js@1.9.1: - resolution: {integrity: sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==} - engines: {node: '>= 0.10'} - - is-promise@4.0.0: - resolution: {integrity: sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ==} - - isexe@2.0.0: - resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} - - jose@6.2.12: - resolution: {integrity: sha512-9NiFmJEex0sy2Dk58j2UGBSHgUs2ypF9eZSu4L6vjOX3Dp96Sw1F3uL+H+D1sx02jZZdzUT0HgvCy59CuvXcWw==} - - json-schema-traverse@1.0.0: - resolution: {integrity: sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==} - - json-schema-typed@8.0.2: - resolution: {integrity: sha512-fQhoXdcvc3V28x7C7BMs4P5+kNlgUURe2jmUT1T//oBRMDrqy1QPelJimwZGo7Hg9VPV3EQV5Bnq4hbFy2vetA==} - - json-schema@0.4.0: - resolution: {integrity: sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA==} - - math-intrinsics@1.1.0: - resolution: {integrity: sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==} - engines: {node: '>= 0.4'} - - media-typer@1.1.1: - resolution: {integrity: sha512-yz3xRaG20c6/BOzvYoDaGtPmGscs7YivItZEEqe6GbwNfHuxu9YNmvnEkMzKldAGY4/80pRcQRZSEnhquk9XuQ==} - engines: {node: '>= 0.8'} - - merge-descriptors@2.0.0: - resolution: {integrity: sha512-Snk314V5ayFLhp3fkUREub6WtjBfPdCPY1Ln8/8munuLuiYhsABgBVWsozAG+MWMbVEvcdcpbi9R7ww22l9Q3g==} - engines: {node: '>=18'} - - mime-db@1.54.0: - resolution: {integrity: sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==} - engines: {node: '>= 0.6'} - - mime-types@3.0.2: - resolution: {integrity: sha512-Lbgzdk0h4juoQ9fCKXW4by0UJqj+nOOrI9MJ1sSj4nI8aI2eo1qmvQEie4VD1glsS250n15LsWsYtCugiStS5A==} - engines: {node: '>=18'} - - ms@2.1.3: - resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} - - negotiator@1.1.0: - resolution: {integrity: sha512-NMPBRMJgiQHjbd8phG3Vebdx4kZ1H121rbl5IkMqeOsahptB9BKo/d7oJ3zTXqTgagn2bWlNSXkh0QUGM31RYg==} - engines: {node: '>=18'} - - object-assign@4.1.1: - resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==} - engines: {node: '>=0.10.0'} - - object-inspect@1.13.4: - resolution: {integrity: sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==} - engines: {node: '>= 0.4'} - - on-finished@2.4.1: - resolution: {integrity: sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==} - engines: {node: '>= 0.8'} - - once@1.4.0: - resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==} - - parseurl@1.3.3: - resolution: {integrity: sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==} - engines: {node: '>= 0.8'} - - path-key@3.1.1: - resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} - engines: {node: '>=8'} - - path-to-regexp@8.4.2: - resolution: {integrity: sha512-qRcuIdP69NPm4qbACK+aDogI5CBDMi1jKe0ry5rSQJz8JVLsC7jV8XpiJjGRLLol3N+R5ihGYcrPLTno6pAdBA==} - - picocolors@1.1.1: - resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} - - pkce-challenge@5.0.1: - resolution: {integrity: sha512-wQ0b/W4Fr01qtpHlqSqspcj3EhBvimsdh0KlHhH8HRZnMsEa0ea2fTULOXOS9ccQr3om+GcGRk4e+isrZWV8qQ==} - engines: {node: '>=16.20.0'} - - pngjs@7.0.0: - resolution: {integrity: sha512-LKWqWJRhstyYo9pGvgor/ivk2w94eSjE3RGVuzLGlr3NmD8bf7RcYGze1mNdEHRP6TRP6rMuDHk5t44hnTRyow==} - engines: {node: '>=14.19.0'} - - proxy-addr@2.0.8: - resolution: {integrity: sha512-5nnx0yGyVUcY6t9RnWcARWtwT9F1D8O9rt08htPvnd49W1IgZtmLkhu9WfMzQj1cFxjHIO6connUNVW5k7AVyQ==} - engines: {node: '>= 0.10'} - - qs@6.16.0: - resolution: {integrity: sha512-h6fhOIaRrID2CbEY2fqs+7t+UXZo+MLAnU5gRIq85uFtdiUPCdsApMlHhXogKVM4HM2DVbIjGNTTYH2OcmP1vA==} - engines: {node: '>=0.6'} - - range-parser@1.3.0: - resolution: {integrity: sha512-hek2mFQpPuI4E1BBKrSto+BU3e3x4xuarsbiwr3+lf7p44juvFMV0XFWQAP3xUyqXA4RrXLIoaSUGbSt056ZMw==} - engines: {node: '>= 0.6'} - - raw-body@3.0.2: - resolution: {integrity: sha512-K5zQjDllxWkf7Z5xJdV0/B0WTNqx6vxG70zJE4N0kBs4LovmEYWJzQGxC9bS9RAKu3bgM40lrd5zoLJ12MQ5BA==} - engines: {node: '>= 0.10'} - - require-from-string@2.0.2: - resolution: {integrity: sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==} - engines: {node: '>=0.10.0'} - - router@2.2.0: - resolution: {integrity: sha512-nLTrUKm2UyiL7rlhapu/Zl45FwNgkZGaCpZbIHajDYgwlJCOzLSk+cIPAnsEqV955GjILJnKbdQC1nVPz+gAYQ==} - engines: {node: '>= 18'} - - safer-buffer@2.1.2: - resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==} - - send@1.2.1: - resolution: {integrity: sha512-1gnZf7DFcoIcajTjTwjwuDjzuz4PPcY2StKPlsGAQ1+YH20IRVrBaXSWmdjowTJ6u8Rc01PoYOGHXfP1mYcZNQ==} - engines: {node: '>= 18'} - - serve-static@2.2.1: - resolution: {integrity: sha512-xRXBn0pPqQTVQiC8wyQrKs2MOlX24zQ0POGaj0kultvoOCstBQM5yvOhAVSUwOMjQtTvsPWoNCHfPGwaaQJhTw==} - engines: {node: '>= 18'} - - setprototypeof@1.2.0: - resolution: {integrity: sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==} - - shebang-command@2.0.0: - resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==} - engines: {node: '>=8'} - - shebang-regex@3.0.0: - resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==} - engines: {node: '>=8'} - - side-channel-list@1.0.1: - resolution: {integrity: sha512-mjn/0bi/oUURjc5Xl7IaWi/OJJJumuoJFQJfDDyO46+hBWsfaVM65TBHq2eoZBhzl9EchxOijpkbRC8SVBQU0w==} - engines: {node: '>= 0.4'} - - side-channel-map@1.0.1: - resolution: {integrity: sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==} - engines: {node: '>= 0.4'} - - side-channel-weakmap@1.0.2: - resolution: {integrity: sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==} - engines: {node: '>= 0.4'} - - side-channel@1.1.1: - resolution: {integrity: sha512-6x6dK6zJdpTzF4sQeNYxwtvBzf6Eg4GtlesS94HOvTudUeyK2WXAaIfmDgsyslYrRBeFIlsi54AYsFGUuhmvrQ==} - engines: {node: '>= 0.4'} - - sisteransi@1.0.5: - resolution: {integrity: sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==} - - statuses@2.0.2: - resolution: {integrity: sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==} - engines: {node: '>= 0.8'} - - tinyrainbow@3.1.1: - resolution: {integrity: sha512-yau8yJdTt989Mm0Bd/236QnzEiPf2xLLTqUZRUJOo/3CB078LSwzei343DgtJVmfJKJE3TMINY1u42SQsP6mXw==} - engines: {node: '>=14.0.0'} - - toidentifier@1.0.1: - resolution: {integrity: sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==} - engines: {node: '>=0.6'} - - tsx@4.23.14: - resolution: {integrity: sha512-yFwMnbAsUFz/T3kR8P2ENc/DDUaYd9tKg4oVYo0lhkX0LlK4UuqYAO6mpQ2y6lmcyip1uPJ34C2kPACopDwG4w==} - engines: {node: '>=18.0.0'} - hasBin: true - - type-is@2.1.0: - resolution: {integrity: sha512-faYHw0anBbc/kWF3zFTEnxSFOAGUX9GFbOBthvDdLsIlEoWOFOtS0zgCiQYwIskL9iGXZL3kAXD8OoZ4GmMATA==} - engines: {node: '>= 18'} - - unpipe@1.0.0: - resolution: {integrity: sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==} - engines: {node: '>= 0.8'} - - vary@1.1.2: - resolution: {integrity: sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==} - engines: {node: '>= 0.8'} - - which@2.0.2: - resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==} - engines: {node: '>= 8'} - hasBin: true - - wrappy@1.0.2: - resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} - - zod-to-json-schema@3.25.2: - resolution: {integrity: sha512-O/PgfnpT1xKSDeQYSCfRI5Gy3hPf91mKVDuYLUHZJMiDFptvP41MSnWofm8dnCm0256ZNfZIM7DSzuSMAFnjHA==} - peerDependencies: - zod: ^3.25.28 || ^4 - - zod@4.6.1: - resolution: {integrity: sha512-341aRWQsve0rvronKNTqZpjmzdbUDlFuzHaI/XLg/Ej82qffDJRRfBTCuv7+9q/rMjB6LSLyEBnW4InJeMtt/Q==} - -snapshots: - - '@ai-sdk/provider@4.0.18': - dependencies: - json-schema: 0.4.0 - - '@clack/core@1.5.1': - dependencies: - fast-wrap-ansi: 0.2.2 - sisteransi: 1.0.5 - - '@clack/prompts@1.8.1': - dependencies: - '@clack/core': 1.5.1 - fast-string-width: 3.0.2 - fast-wrap-ansi: 0.2.2 - sisteransi: 1.0.5 - - '@e2e-dev/mobile@0.8.1(e2e@0.15.1)': - dependencies: - agent-device: 0.21.18 - e2e: 0.15.1 - pngjs: 7.0.0 - zod: 4.6.1 - - '@esbuild/aix-ppc64@0.28.2': - optional: true - - '@esbuild/android-arm64@0.28.2': - optional: true - - '@esbuild/android-arm@0.28.2': - optional: true - - '@esbuild/android-x64@0.28.2': - optional: true - - '@esbuild/darwin-arm64@0.28.2': - optional: true - - '@esbuild/darwin-x64@0.28.2': - optional: true - - '@esbuild/freebsd-arm64@0.28.2': - optional: true - - '@esbuild/freebsd-x64@0.28.2': - optional: true - - '@esbuild/linux-arm64@0.28.2': - optional: true - - '@esbuild/linux-arm@0.28.2': - optional: true - - '@esbuild/linux-ia32@0.28.2': - optional: true - - '@esbuild/linux-loong64@0.28.2': - optional: true - - '@esbuild/linux-mips64el@0.28.2': - optional: true - - '@esbuild/linux-ppc64@0.28.2': - optional: true - - '@esbuild/linux-riscv64@0.28.2': - optional: true - - '@esbuild/linux-s390x@0.28.2': - optional: true - - '@esbuild/linux-x64@0.28.2': - optional: true - - '@esbuild/netbsd-arm64@0.28.2': - optional: true - - '@esbuild/netbsd-x64@0.28.2': - optional: true - - '@esbuild/openbsd-arm64@0.28.2': - optional: true - - '@esbuild/openbsd-x64@0.28.2': - optional: true - - '@esbuild/openharmony-arm64@0.28.2': - optional: true - - '@esbuild/sunos-x64@0.28.2': - optional: true - - '@esbuild/win32-arm64@0.28.2': - optional: true - - '@esbuild/win32-ia32@0.28.2': - optional: true - - '@esbuild/win32-x64@0.28.2': - optional: true - - '@hono/node-server@2.1.3(hono@4.13.11)': - dependencies: - hono: 4.13.11 - - '@modelcontextprotocol/sdk@1.30.1(zod@4.6.1)': - dependencies: - '@hono/node-server': 2.1.3(hono@4.13.11) - ajv: 8.20.0 - ajv-formats: 3.0.1(ajv@8.20.0) - content-type: 1.0.5 - cors: 2.8.6 - cross-spawn: 7.0.6 - eventsource: 3.0.7 - eventsource-parser: 3.1.1 - express: 5.2.1 - express-rate-limit: 8.7.0(express@5.2.1) - hono: 4.13.11 - jose: 6.2.12 - json-schema-typed: 8.0.2 - pkce-challenge: 5.0.1 - raw-body: 3.0.2 - zod: 4.6.1 - zod-to-json-schema: 3.25.2(zod@4.6.1) - transitivePeerDependencies: - - supports-color - - '@standard-schema/spec@1.1.0': {} - - '@types/chai@5.2.3': - dependencies: - '@types/deep-eql': 4.0.2 - assertion-error: 2.0.1 - - '@types/deep-eql@4.0.2': {} - - '@vitest/expect@5.0.2': - dependencies: - '@standard-schema/spec': 1.1.0 - '@types/chai': 5.2.3 - '@vitest/spy': 5.0.2 - '@vitest/utils': 5.0.2 - chai: 6.2.2 - tinyrainbow: 3.1.1 - - '@vitest/pretty-format@5.0.2': - dependencies: - tinyrainbow: 3.1.1 - - '@vitest/spy@5.0.2': {} - - '@vitest/utils@5.0.2': - dependencies: - '@vitest/pretty-format': 5.0.2 - convert-source-map: 2.0.0 - tinyrainbow: 3.1.1 - - accepts@2.0.0: - dependencies: - mime-types: 3.0.2 - negotiator: 1.1.0 - - agent-device@0.21.18: {} - - ajv-formats@3.0.1(ajv@8.20.0): - optionalDependencies: - ajv: 8.20.0 - - ajv@8.20.0: - dependencies: - fast-deep-equal: 3.1.3 - fast-uri: 3.1.8 - json-schema-traverse: 1.0.0 - require-from-string: 2.0.2 - - assertion-error@2.0.1: {} - - body-parser@2.3.0: - dependencies: - bytes: 3.1.2 - content-type: 2.1.0 - debug: 4.4.3 - http-errors: 2.0.1 - iconv-lite: 0.7.3 - on-finished: 2.4.1 - qs: 6.16.0 - raw-body: 3.0.2 - type-is: 2.1.0 - transitivePeerDependencies: - - supports-color - - bytes@3.1.2: {} - - call-bind-apply-helpers@1.0.2: - dependencies: - es-errors: 1.3.0 - function-bind: 1.1.2 - - call-bound@1.0.4: - dependencies: - call-bind-apply-helpers: 1.0.2 - get-intrinsic: 1.3.0 - - chai@6.2.2: {} - - commander@15.0.0: {} - - content-disposition@1.1.0: {} - - content-type@1.0.5: {} - - content-type@2.1.0: {} - - convert-source-map@2.0.0: {} - - cookie-signature@1.2.2: {} - - cookie@0.7.2: {} - - cors@2.8.6: - dependencies: - object-assign: 4.1.1 - vary: 1.1.2 - - cross-spawn@7.0.6: - dependencies: - path-key: 3.1.1 - shebang-command: 2.0.0 - which: 2.0.2 - - debug@4.4.3: - dependencies: - ms: 2.1.3 - - depd@2.0.0: {} - - dunder-proto@1.0.1: - dependencies: - call-bind-apply-helpers: 1.0.2 - es-errors: 1.3.0 - gopd: 1.2.0 - - e2e@0.15.1: - dependencies: - '@ai-sdk/provider': 4.0.18 - '@clack/prompts': 1.8.1 - '@modelcontextprotocol/sdk': 1.30.1(zod@4.6.1) - '@vitest/expect': 5.0.2 - commander: 15.0.0 - picocolors: 1.1.1 - pngjs: 7.0.0 - tsx: 4.23.14 - zod: 4.6.1 - transitivePeerDependencies: - - '@cfworker/json-schema' - - supports-color - - ee-first@1.1.1: {} - - encodeurl@2.0.0: {} - - es-define-property@1.0.1: {} - - es-errors@1.3.0: {} - - es-object-atoms@1.1.2: - dependencies: - es-errors: 1.3.0 - - esbuild@0.28.2: - optionalDependencies: - '@esbuild/aix-ppc64': 0.28.2 - '@esbuild/android-arm': 0.28.2 - '@esbuild/android-arm64': 0.28.2 - '@esbuild/android-x64': 0.28.2 - '@esbuild/darwin-arm64': 0.28.2 - '@esbuild/darwin-x64': 0.28.2 - '@esbuild/freebsd-arm64': 0.28.2 - '@esbuild/freebsd-x64': 0.28.2 - '@esbuild/linux-arm': 0.28.2 - '@esbuild/linux-arm64': 0.28.2 - '@esbuild/linux-ia32': 0.28.2 - '@esbuild/linux-loong64': 0.28.2 - '@esbuild/linux-mips64el': 0.28.2 - '@esbuild/linux-ppc64': 0.28.2 - '@esbuild/linux-riscv64': 0.28.2 - '@esbuild/linux-s390x': 0.28.2 - '@esbuild/linux-x64': 0.28.2 - '@esbuild/netbsd-arm64': 0.28.2 - '@esbuild/netbsd-x64': 0.28.2 - '@esbuild/openbsd-arm64': 0.28.2 - '@esbuild/openbsd-x64': 0.28.2 - '@esbuild/openharmony-arm64': 0.28.2 - '@esbuild/sunos-x64': 0.28.2 - '@esbuild/win32-arm64': 0.28.2 - '@esbuild/win32-ia32': 0.28.2 - '@esbuild/win32-x64': 0.28.2 - - escape-html@1.0.3: {} - - etag@1.8.1: {} - - eventsource-parser@3.1.1: {} - - eventsource@3.0.7: - dependencies: - eventsource-parser: 3.1.1 - - express-rate-limit@8.7.0(express@5.2.1): - dependencies: - debug: 4.4.3 - express: 5.2.1 - ip-address: 10.7.2 - transitivePeerDependencies: - - supports-color - - express@5.2.1: - dependencies: - accepts: 2.0.0 - body-parser: 2.3.0 - content-disposition: 1.1.0 - content-type: 1.0.5 - cookie: 0.7.2 - cookie-signature: 1.2.2 - debug: 4.4.3 - depd: 2.0.0 - encodeurl: 2.0.0 - escape-html: 1.0.3 - etag: 1.8.1 - finalhandler: 2.1.1 - fresh: 2.0.0 - http-errors: 2.0.1 - merge-descriptors: 2.0.0 - mime-types: 3.0.2 - on-finished: 2.4.1 - once: 1.4.0 - parseurl: 1.3.3 - proxy-addr: 2.0.8 - qs: 6.16.0 - range-parser: 1.3.0 - router: 2.2.0 - send: 1.2.1 - serve-static: 2.2.1 - statuses: 2.0.2 - type-is: 2.1.0 - vary: 1.1.2 - transitivePeerDependencies: - - supports-color - - fast-deep-equal@3.1.3: {} - - fast-string-truncated-width@3.0.3: {} - - fast-string-width@3.0.2: - dependencies: - fast-string-truncated-width: 3.0.3 - - fast-uri@3.1.8: {} - - fast-wrap-ansi@0.2.2: - dependencies: - fast-string-width: 3.0.2 - - finalhandler@2.1.1: - dependencies: - debug: 4.4.3 - encodeurl: 2.0.0 - escape-html: 1.0.3 - on-finished: 2.4.1 - parseurl: 1.3.3 - statuses: 2.0.2 - transitivePeerDependencies: - - supports-color - - forwarded@0.2.0: {} - - fresh@2.0.0: {} - - fsevents@2.3.3: - optional: true - - function-bind@1.1.2: {} - - get-intrinsic@1.3.0: - dependencies: - call-bind-apply-helpers: 1.0.2 - es-define-property: 1.0.1 - es-errors: 1.3.0 - es-object-atoms: 1.1.2 - function-bind: 1.1.2 - get-proto: 1.0.1 - gopd: 1.2.0 - has-symbols: 1.1.0 - hasown: 2.0.4 - math-intrinsics: 1.1.0 - - get-proto@1.0.1: - dependencies: - dunder-proto: 1.0.1 - es-object-atoms: 1.1.2 - - gopd@1.2.0: {} - - has-symbols@1.1.0: {} - - hasown@2.0.4: - dependencies: - function-bind: 1.1.2 - - hono@4.13.11: {} - - http-errors@2.0.1: - dependencies: - depd: 2.0.0 - inherits: 2.0.4 - setprototypeof: 1.2.0 - statuses: 2.0.2 - toidentifier: 1.0.1 - - iconv-lite@0.7.3: - dependencies: - safer-buffer: 2.1.2 - - inherits@2.0.4: {} - - ip-address@10.7.2: {} - - ipaddr.js@1.9.1: {} - - is-promise@4.0.0: {} - - isexe@2.0.0: {} - - jose@6.2.12: {} - - json-schema-traverse@1.0.0: {} - - json-schema-typed@8.0.2: {} - - json-schema@0.4.0: {} - - math-intrinsics@1.1.0: {} - - media-typer@1.1.1: {} - - merge-descriptors@2.0.0: {} - - mime-db@1.54.0: {} - - mime-types@3.0.2: - dependencies: - mime-db: 1.54.0 - - ms@2.1.3: {} - - negotiator@1.1.0: - dependencies: - content-type: 2.1.0 - - object-assign@4.1.1: {} - - object-inspect@1.13.4: {} - - on-finished@2.4.1: - dependencies: - ee-first: 1.1.1 - - once@1.4.0: - dependencies: - wrappy: 1.0.2 - - parseurl@1.3.3: {} - - path-key@3.1.1: {} - - path-to-regexp@8.4.2: {} - - picocolors@1.1.1: {} - - pkce-challenge@5.0.1: {} - - pngjs@7.0.0: {} - - proxy-addr@2.0.8: - dependencies: - forwarded: 0.2.0 - ipaddr.js: 1.9.1 - - qs@6.16.0: - dependencies: - es-define-property: 1.0.1 - side-channel: 1.1.1 - - range-parser@1.3.0: {} - - raw-body@3.0.2: - dependencies: - bytes: 3.1.2 - http-errors: 2.0.1 - iconv-lite: 0.7.3 - unpipe: 1.0.0 - - require-from-string@2.0.2: {} - - router@2.2.0: - dependencies: - debug: 4.4.3 - depd: 2.0.0 - is-promise: 4.0.0 - parseurl: 1.3.3 - path-to-regexp: 8.4.2 - transitivePeerDependencies: - - supports-color - - safer-buffer@2.1.2: {} - - send@1.2.1: - dependencies: - debug: 4.4.3 - encodeurl: 2.0.0 - escape-html: 1.0.3 - etag: 1.8.1 - fresh: 2.0.0 - http-errors: 2.0.1 - mime-types: 3.0.2 - ms: 2.1.3 - on-finished: 2.4.1 - range-parser: 1.3.0 - statuses: 2.0.2 - transitivePeerDependencies: - - supports-color - - serve-static@2.2.1: - dependencies: - encodeurl: 2.0.0 - escape-html: 1.0.3 - parseurl: 1.3.3 - send: 1.2.1 - transitivePeerDependencies: - - supports-color - - setprototypeof@1.2.0: {} - - shebang-command@2.0.0: - dependencies: - shebang-regex: 3.0.0 - - shebang-regex@3.0.0: {} - - side-channel-list@1.0.1: - dependencies: - es-errors: 1.3.0 - object-inspect: 1.13.4 - - side-channel-map@1.0.1: - dependencies: - call-bound: 1.0.4 - es-errors: 1.3.0 - get-intrinsic: 1.3.0 - object-inspect: 1.13.4 - - side-channel-weakmap@1.0.2: - dependencies: - call-bound: 1.0.4 - es-errors: 1.3.0 - get-intrinsic: 1.3.0 - object-inspect: 1.13.4 - side-channel-map: 1.0.1 - - side-channel@1.1.1: - dependencies: - es-errors: 1.3.0 - object-inspect: 1.13.4 - side-channel-list: 1.0.1 - side-channel-map: 1.0.1 - side-channel-weakmap: 1.0.2 - - sisteransi@1.0.5: {} - - statuses@2.0.2: {} - - tinyrainbow@3.1.1: {} - - toidentifier@1.0.1: {} - - tsx@4.23.14: - dependencies: - esbuild: 0.28.2 - optionalDependencies: - fsevents: 2.3.3 - - type-is@2.1.0: - dependencies: - content-type: 2.1.0 - media-typer: 1.1.1 - mime-types: 3.0.2 - - unpipe@1.0.0: {} - - vary@1.1.2: {} - - which@2.0.2: - dependencies: - isexe: 2.0.0 - - wrappy@1.0.2: {} - - zod-to-json-schema@3.25.2(zod@4.6.1): - dependencies: - zod: 4.6.1 - - zod@4.6.1: {} diff --git a/integration/tests/expo-native/pnpm-workspace.yaml b/integration/tests/expo-native/pnpm-workspace.yaml deleted file mode 100644 index 690e0a5fae0..00000000000 --- a/integration/tests/expo-native/pnpm-workspace.yaml +++ /dev/null @@ -1,11 +0,0 @@ -packages: - - '.' - -ignoredBuiltDependencies: - - esbuild - -minimumReleaseAge: 2880 -minimumReleaseAgeExclude: - - '@e2e-dev/mobile' - - agent-device - - e2e diff --git a/integration/tests/expo-native/run-flows.sh b/integration/tests/expo-native/run-flows.sh index 37f888efa58..c4a41a6c93f 100755 --- a/integration/tests/expo-native/run-flows.sh +++ b/integration/tests/expo-native/run-flows.sh @@ -1,20 +1,20 @@ #!/usr/bin/env bash # Usage: PLATFORM= [CLERK_TEST_DEVICES=a,b] ./run-flows.sh set -euo pipefail -cd "$(dirname "${BASH_SOURCE[0]}")" +cd "$(dirname "${BASH_SOURCE[0]}")/../../.." : "${PLATFORM:?PLATFORM (ios|android) is required}" : "${CLERK_TEST_EMAIL:?CLERK_TEST_EMAIL is required}" : "${CLERK_TEST_PASSWORD:?CLERK_TEST_PASSWORD is required}" status=0 -pnpm exec e2e run --target "$PLATFORM" --retries 1 --video=on-first-retry --reporter list,junit,markdown || status=$? +pnpm exec e2e run --config integration/e2e.expo-native.config.ts --target "$PLATFORM" --retries 1 --video=on-first-retry --reporter list,junit,markdown || status=$? -if [ -n "${GITHUB_STEP_SUMMARY:-}" ] && [ -f .e2e/summary.md ]; then - cat .e2e/summary.md >> "$GITHUB_STEP_SUMMARY" +if [ -n "${GITHUB_STEP_SUMMARY:-}" ] && [ -f integration/.e2e/summary.md ]; then + cat integration/.e2e/summary.md >> "$GITHUB_STEP_SUMMARY" fi -flaky=$(jq -r '.run.results[] | select(.status == "flaky") | .file' .e2e/report.json 2>/dev/null || true) +flaky=$(jq -r '.run.results[] | select(.status == "flaky") | .file' integration/.e2e/report.json 2>/dev/null || true) if [ -n "$flaky" ]; then echo "::error::Flaky flow(s), failed then passed on the retry: ${flaky//$'\n'/, }" [ "$status" -ne 0 ] || status=1 diff --git a/package.json b/package.json index 150db8d5ee4..f5a7b07221d 100644 --- a/package.json +++ b/package.json @@ -46,8 +46,8 @@ "test:integration:custom": "pnpm test:integration:base --grep @custom", "test:integration:deployment:nextjs": "pnpm playwright test --config integration/playwright.deployments.config.ts", "test:integration:electron": "pnpm test:integration:base --grep @electron", - "test:integration:expo-native:android": "pnpm --dir integration/tests/expo-native test:android", - "test:integration:expo-native:ios": "pnpm --dir integration/tests/expo-native test:ios", + "test:integration:expo-native:android": "e2e run --config integration/e2e.expo-native.config.ts --target android", + "test:integration:expo-native:ios": "e2e run --config integration/e2e.expo-native.config.ts --target ios", "test:integration:expo-web:disabled": "E2E_APP_ID=expo.expo-web pnpm test:integration:base --grep @expo-web", "test:integration:express": "E2E_APP_ID=express.* pnpm test:integration:base --grep @express", "test:integration:fastify": "E2E_APP_ID=fastify.* pnpm test:integration:base --grep @fastify", @@ -85,6 +85,7 @@ "@clerk/testing": "workspace:*", "@commitlint/cli": "^20.5.2", "@commitlint/config-conventional": "^20.5.0", + "@e2e-dev/mobile": "0.8.1", "@eslint/eslintrc": "^3.3.5", "@eslint/js": "9.31.0", "@faker-js/faker": "^9.9.0", @@ -108,6 +109,7 @@ "cpy-cli": "^5.0.0", "cross-spawn": "^7.0.6", "dotenv": "^16.6.1", + "e2e": "0.15.1", "eslint": "9.31.0", "eslint-config-prettier": "10.1.8", "eslint-config-turbo": "2.5.5", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 2ac1019b40b..3f009412bb0 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -143,6 +143,9 @@ importers: '@commitlint/config-conventional': specifier: ^20.5.0 version: 20.5.0 + '@e2e-dev/mobile': + specifier: 0.8.1 + version: 0.8.1(e2e@0.15.1(@cfworker/json-schema@4.1.1)) '@eslint/eslintrc': specifier: ^3.3.5 version: 3.3.5 @@ -187,10 +190,10 @@ importers: version: 18.3.7(@types/react@18.3.28) '@vitejs/plugin-react': specifier: ^4.7.0 - version: 4.7.0(vite@8.2.2(@types/node@22.20.1)(esbuild@0.27.7)(jiti@2.7.0)(terser@5.46.1)(tsx@4.20.6)(yaml@2.9.0)) + version: 4.7.0(vite@8.2.2(@types/node@22.20.1)(esbuild@0.27.7)(jiti@2.7.0)(terser@5.46.1)(tsx@4.23.14)(yaml@2.9.0)) '@vitest/browser-playwright': specifier: 5.0.0 - version: 5.0.0(bufferutil@4.1.0)(msw@2.15.0(@types/node@22.20.1)(typescript@6.0.3))(playwright@1.62.1)(utf-8-validate@5.0.10)(vite@8.2.2(@types/node@22.20.1)(esbuild@0.27.7)(jiti@2.7.0)(terser@5.46.1)(tsx@4.20.6)(yaml@2.9.0))(vitest@5.0.0) + version: 5.0.0(bufferutil@4.1.0)(msw@2.15.0(@types/node@22.20.1)(typescript@6.0.3))(playwright@1.62.1)(utf-8-validate@5.0.10)(vite@8.2.2(@types/node@22.20.1)(esbuild@0.27.7)(jiti@2.7.0)(terser@5.46.1)(tsx@4.23.14)(yaml@2.9.0))(vitest@5.0.0) '@vitest/coverage-v8': specifier: 5.0.0 version: 5.0.0(@vitest/browser@5.0.0)(vitest@5.0.0) @@ -212,6 +215,9 @@ importers: dotenv: specifier: ^16.6.1 version: 16.6.1 + e2e: + specifier: 0.15.1 + version: 0.15.1(@cfworker/json-schema@4.1.1) eslint: specifier: 9.31.0 version: 9.31.0(jiti@2.7.0) @@ -328,10 +334,10 @@ importers: version: 1.2.2 tsdown: specifier: catalog:repo - version: 0.22.2(@arethetypeswrong/core@0.18.3)(publint@0.3.18)(tsx@4.20.6)(typescript@6.0.3)(unrun@0.3.1(synckit@0.11.11))(vue-tsc@3.2.4(typescript@6.0.3)) + version: 0.22.2(@arethetypeswrong/core@0.18.3)(publint@0.3.18)(tsx@4.23.14)(typescript@6.0.3)(unrun@0.3.1(synckit@0.11.11))(vue-tsc@3.2.4(typescript@6.0.3)) tsup: specifier: catalog:repo - version: 8.5.1(@microsoft/api-extractor@7.58.7(@types/node@22.20.1))(jiti@2.7.0)(postcss@8.5.26)(tsx@4.20.6)(typescript@6.0.3)(yaml@2.9.0) + version: 8.5.1(@microsoft/api-extractor@7.58.7(@types/node@22.20.1))(jiti@2.7.0)(postcss@8.5.26)(tsx@4.23.14)(typescript@6.0.3)(yaml@2.9.0) turbo: specifier: ^2.10.11 version: 2.10.12 @@ -358,7 +364,7 @@ importers: version: 11.1.1 vitest: specifier: 5.0.0 - version: 5.0.0(@edge-runtime/vm@5.0.0)(@opentelemetry/api@1.9.0)(@types/node@22.20.1)(@vitest/browser-playwright@5.0.0)(@vitest/coverage-v8@5.0.0)(@vitest/ui@5.0.0)(happy-dom@20.10.2(bufferutil@4.1.0)(utf-8-validate@5.0.10))(jsdom@27.0.0(bufferutil@4.1.0)(utf-8-validate@5.0.10))(msw@2.15.0(@types/node@22.20.1)(typescript@6.0.3))(vite@8.2.2(@types/node@22.20.1)(esbuild@0.27.7)(jiti@2.7.0)(terser@5.46.1)(tsx@4.20.6)(yaml@2.9.0)) + version: 5.0.0(@edge-runtime/vm@5.0.0)(@opentelemetry/api@1.9.0)(@types/node@22.20.1)(@vitest/browser-playwright@5.0.0)(@vitest/coverage-v8@5.0.0)(@vitest/ui@5.0.0)(happy-dom@20.10.2(bufferutil@4.1.0)(utf-8-validate@5.0.10))(jsdom@27.0.0(bufferutil@4.1.0)(utf-8-validate@5.0.10))(msw@2.15.0(@types/node@22.20.1)(typescript@6.0.3))(vite@8.2.2(@types/node@22.20.1)(esbuild@0.27.7)(jiti@2.7.0)(terser@5.46.1)(tsx@4.23.14)(yaml@2.9.0)) zx: specifier: catalog:repo version: 8.8.5 @@ -383,7 +389,7 @@ importers: version: link:../ui astro: specifier: ^7.0.0 - version: 7.2.9(@emnapi/core@1.11.1)(@emnapi/runtime@1.11.3)(@types/node@25.6.0)(db0@0.3.4)(idb-keyval@6.2.1)(ioredis@5.11.0)(jiti@2.7.0)(terser@5.46.1)(tsx@4.20.6)(yaml@2.9.0) + version: 7.2.9(@emnapi/core@1.11.1)(@emnapi/runtime@1.11.3)(@types/node@25.6.0)(db0@0.3.4)(idb-keyval@6.2.1)(ioredis@5.11.0)(jiti@2.7.0)(terser@5.46.1)(tsx@4.23.14)(yaml@2.9.0) packages/backend: dependencies: @@ -615,13 +621,13 @@ importers: version: 9.31.0(jiti@2.7.0) tsdown: specifier: catalog:repo - version: 0.22.2(@arethetypeswrong/core@0.18.3)(publint@0.3.18)(tsx@4.20.6)(typescript@6.0.3)(unrun@0.3.1(synckit@0.11.11))(vue-tsc@3.2.4(typescript@6.0.3)) + version: 0.22.2(@arethetypeswrong/core@0.18.3)(publint@0.3.18)(tsx@4.23.14)(typescript@6.0.3)(unrun@0.3.1(synckit@0.11.11))(vue-tsc@3.2.4(typescript@6.0.3)) typescript: specifier: catalog:repo version: 6.0.3 vitest: specifier: 5.0.0 - version: 5.0.0(@edge-runtime/vm@5.0.0)(@opentelemetry/api@1.9.0)(@types/node@22.20.1)(@vitest/browser-playwright@5.0.0)(@vitest/coverage-v8@5.0.0)(@vitest/ui@5.0.0)(happy-dom@20.10.2(bufferutil@4.1.0)(utf-8-validate@5.0.10))(jsdom@27.0.0(bufferutil@4.1.0)(utf-8-validate@5.0.10))(msw@2.15.0(@types/node@22.20.1)(typescript@6.0.3))(vite@8.2.2(@types/node@22.20.1)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.46.1)(tsx@4.20.6)(yaml@2.9.0)) + version: 5.0.0(@edge-runtime/vm@5.0.0)(@opentelemetry/api@1.9.0)(@types/node@22.20.1)(@vitest/browser-playwright@5.0.0)(@vitest/coverage-v8@5.0.0)(@vitest/ui@5.0.0)(happy-dom@20.10.2(bufferutil@4.1.0)(utf-8-validate@5.0.10))(jsdom@27.0.0(bufferutil@4.1.0)(utf-8-validate@5.0.10))(msw@2.15.0(@types/node@22.20.1)(typescript@6.0.3))(vite@8.2.2(@types/node@22.20.1)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.46.1)(tsx@4.23.14)(yaml@2.9.0)) packages/expo: dependencies: @@ -804,7 +810,7 @@ importers: version: 0.19.0 '@stylexjs/unplugin': specifier: 0.19.0 - version: 0.19.0(unplugin@3.3.0(@rspack/core@2.0.6)(esbuild@0.28.1)(rolldown@1.1.0)(rollup@4.61.0)(vite@8.2.2(@types/node@25.6.0)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.46.1)(tsx@4.20.6)(yaml@2.9.0))(webpack@5.102.1(esbuild@0.28.1))) + version: 0.19.0(unplugin@3.3.0(@rspack/core@2.0.6)(esbuild@0.28.1)(rolldown@1.1.0)(rollup@4.61.0)(vite@8.2.2(@types/node@25.6.0)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.46.1)(tsx@4.23.14)(yaml@2.9.0))(webpack@5.102.1(esbuild@0.28.1))) '@testing-library/dom': specifier: ^10.4.1 version: 10.4.1 @@ -849,7 +855,7 @@ importers: version: 18.3.1(react@18.3.1) tsdown: specifier: catalog:repo - version: 0.22.2(@arethetypeswrong/core@0.18.3)(publint@0.3.18)(tsx@4.20.6)(typescript@6.0.3)(unrun@0.3.1(synckit@0.11.11))(vue-tsc@3.2.4(typescript@6.0.3)) + version: 0.22.2(@arethetypeswrong/core@0.18.3)(publint@0.3.18)(tsx@4.23.14)(typescript@6.0.3)(unrun@0.3.1(synckit@0.11.11))(vue-tsc@3.2.4(typescript@6.0.3)) vitest-axe: specifier: ^0.1.0 version: 0.1.0(vitest@5.0.0) @@ -913,7 +919,7 @@ importers: version: link:../vue '@nuxt/kit': specifier: ^4.1.3 - version: 4.5.2(magic-string@1.2.3)(magicast@0.5.4)(rolldown@1.1.0)(unplugin@3.3.0(@rspack/core@2.0.6)(esbuild@0.28.1)(rolldown@1.1.0)(rollup@4.61.0)(vite@8.2.2(@types/node@25.6.0)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.46.1)(tsx@4.20.6)(yaml@2.9.0))(webpack@5.102.1(esbuild@0.28.1))) + version: 4.5.2(magic-string@1.2.3)(magicast@0.5.4)(rolldown@1.1.0)(unplugin@3.3.0(@rspack/core@2.0.6)(esbuild@0.28.1)(rolldown@1.1.0)(rollup@4.61.0)(vite@8.2.2(@types/node@25.6.0)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.46.1)(tsx@4.23.14)(yaml@2.9.0))(webpack@5.102.1(esbuild@0.28.1))) '@nuxt/schema': specifier: ^4.1.3 version: 4.5.2 @@ -923,7 +929,7 @@ importers: version: 1.15.11 nuxt: specifier: ^4.5.1 - version: 4.5.2(@babel/plugin-proposal-decorators@7.28.0(@babel/core@7.29.7))(@babel/plugin-syntax-jsx@7.29.7(@babel/core@7.29.7))(@babel/plugin-syntax-typescript@7.29.7(@babel/core@7.29.7))(@oxc-project/types@0.134.0)(@parcel/watcher@2.5.6)(@rspack/core@2.0.6)(@types/node@25.6.0)(@vue/compiler-sfc@3.5.42)(bufferutil@4.1.0)(cac@6.7.14)(commander@14.0.3)(db0@0.3.4)(esbuild@0.28.1)(eslint@9.31.0(jiti@2.7.0))(idb-keyval@6.2.1)(ioredis@5.11.0)(lightningcss@1.33.0)(magicast@0.5.4)(meow@13.2.0)(optionator@0.9.4)(rolldown@1.1.0)(rollup-plugin-visualizer@7.0.1(rolldown@1.1.0)(rollup@4.61.0))(rollup@4.61.0)(terser@5.46.1)(tsx@4.20.6)(typescript@6.0.3)(utf-8-validate@5.0.10)(vite@8.2.2(@types/node@25.6.0)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.46.1)(tsx@4.20.6)(yaml@2.9.0))(vue-tsc@3.2.4(typescript@6.0.3))(webpack@5.102.1(esbuild@0.28.1))(yaml@2.9.0) + version: 4.5.2(@babel/plugin-proposal-decorators@7.28.0(@babel/core@7.29.7))(@babel/plugin-syntax-jsx@7.29.7(@babel/core@7.29.7))(@babel/plugin-syntax-typescript@7.29.7(@babel/core@7.29.7))(@oxc-project/types@0.134.0)(@parcel/watcher@2.5.6)(@rspack/core@2.0.6)(@types/node@25.6.0)(@vue/compiler-sfc@3.5.42)(bufferutil@4.1.0)(cac@6.7.14)(commander@15.0.0)(db0@0.3.4)(esbuild@0.28.1)(eslint@9.31.0(jiti@2.7.0))(idb-keyval@6.2.1)(ioredis@5.11.0)(lightningcss@1.33.0)(magicast@0.5.4)(meow@13.2.0)(optionator@0.9.4)(rolldown@1.1.0)(rollup-plugin-visualizer@7.0.1(rolldown@1.1.0)(rollup@4.61.0))(rollup@4.61.0)(terser@5.46.1)(tsx@4.23.14)(typescript@6.0.3)(utf-8-validate@5.0.10)(vite@8.2.2(@types/node@25.6.0)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.46.1)(tsx@4.23.14)(yaml@2.9.0))(vue-tsc@3.2.4(typescript@6.0.3))(webpack@5.102.1(esbuild@0.28.1))(yaml@2.9.0) typescript: specifier: catalog:repo version: 6.0.3 @@ -1192,7 +1198,7 @@ importers: version: 1.170.41(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@tanstack/react-start': specifier: 1.168.60 - version: 1.168.60(@rspack/core@2.0.6)(esbuild@0.28.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(rolldown@1.1.0)(rollup@4.61.0)(vite@8.2.2(@types/node@25.6.0)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.46.1)(tsx@4.20.6)(yaml@2.9.0))(webpack@5.102.1(esbuild@0.28.1)) + version: 1.168.60(@rspack/core@2.0.6)(esbuild@0.28.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(rolldown@1.1.0)(rollup@4.61.0)(vite@8.2.2(@types/node@25.6.0)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.46.1)(tsx@4.23.14)(yaml@2.9.0))(webpack@5.102.1(esbuild@0.28.1)) esbuild-plugin-file-path-extensions: specifier: ^2.1.4 version: 2.1.4 @@ -1305,7 +1311,7 @@ importers: version: 10.2.6 tsdown: specifier: catalog:repo - version: 0.22.2(@arethetypeswrong/core@0.18.3)(publint@0.3.18)(tsx@4.20.6)(typescript@6.0.3)(unrun@0.3.1(synckit@0.11.11))(vue-tsc@3.2.4(typescript@6.0.3)) + version: 0.22.2(@arethetypeswrong/core@0.18.3)(publint@0.3.18)(tsx@4.23.14)(typescript@6.0.3)(unrun@0.3.1(synckit@0.11.11))(vue-tsc@3.2.4(typescript@6.0.3)) unplugin: specifier: ^2.3.11 version: 2.3.11 @@ -1370,13 +1376,13 @@ importers: version: 8.1.0(@vue/compiler-sfc@3.5.42)(vue@3.5.33(typescript@6.0.3)) '@vitejs/plugin-vue': specifier: ^6.0.5 - version: 6.0.8(vite@8.2.2(@types/node@25.6.0)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.46.1)(tsx@4.20.6)(yaml@2.9.0))(vue@3.5.33(typescript@6.0.3)) + version: 6.0.8(vite@8.2.2(@types/node@25.6.0)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.46.1)(tsx@4.23.14)(yaml@2.9.0))(vue@3.5.33(typescript@6.0.3)) '@vue.ts/tsx-auto-props': specifier: ^1.0.0-beta.13 - version: 1.0.0-beta.13(@nuxt/kit@4.5.2(magic-string@1.2.3)(magicast@0.5.4)(rolldown@1.1.0)(unplugin@3.3.0(@rspack/core@2.0.6)(esbuild@0.28.1)(rolldown@1.1.0)(rollup@4.61.0)(vite@8.2.2(@types/node@25.6.0)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.46.1)(tsx@4.20.6)(yaml@2.9.0))(webpack@5.102.1(esbuild@0.28.1))))(typescript@6.0.3)(vue@3.5.33(typescript@6.0.3)) + version: 1.0.0-beta.13(@nuxt/kit@4.5.2(magic-string@1.2.3)(magicast@0.5.4)(rolldown@1.1.0)(unplugin@3.3.0(@rspack/core@2.0.6)(esbuild@0.28.1)(rolldown@1.1.0)(rollup@4.61.0)(vite@8.2.2(@types/node@25.6.0)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.46.1)(tsx@4.23.14)(yaml@2.9.0))(webpack@5.102.1(esbuild@0.28.1))))(typescript@6.0.3)(vue@3.5.33(typescript@6.0.3)) unplugin-vue: specifier: 7.0.8 - version: 7.0.8(@types/node@25.6.0)(jiti@2.7.0)(lightningcss@1.33.0)(terser@5.46.1)(tsx@4.20.6)(vue@3.5.33(typescript@6.0.3))(yaml@2.9.0) + version: 7.0.8(@types/node@25.6.0)(jiti@2.7.0)(lightningcss@1.33.0)(terser@5.46.1)(tsx@4.23.14)(vue@3.5.33(typescript@6.0.3))(yaml@2.9.0) vue: specifier: catalog:repo version: 3.5.33(typescript@6.0.3) @@ -1412,6 +1418,10 @@ packages: '@adraffy/ens-normalize@1.11.1': resolution: {integrity: sha512-nhCBV3quEgesuf7c7KYfperqSS14T8bYuvJ8PcLJp6znkZpFc0AuW4qBtr8eKVyPPe/8RSr7sglCWPU5eaxwKQ==} + '@ai-sdk/provider@4.0.18': + resolution: {integrity: sha512-+GZJIgz1jk86pwEbb3f1BD2bdoSKyWE4Jg4YUc7NMnMozbWemSKYZcw2F4nMaO5qwsL5A8RmioAKW81YktRpIQ==} + engines: {node: '>=22'} + '@alloc/quick-lru@5.2.0': resolution: {integrity: sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==} engines: {node: '>=10'} @@ -2366,12 +2376,12 @@ packages: '@changesets/write@0.4.0': resolution: {integrity: sha512-CdTLvIOPiCNuH71pyDu3rA+Q0n65cmAbXnwWH84rKGiFumFzkmHNT8KHTMEchcxN+Kl8I54xGUhJ7l3E7X396Q==} - '@clack/core@1.4.3': - resolution: {integrity: sha512-/kr3UWNtdJfxZtPgDqUOmG2pvwlmcLGheex5yiZKdwbzZJxhV+HMNR9QNmyY5cGwTNV6LrR7Jtp+KjhUAP1qBQ==} + '@clack/core@1.5.1': + resolution: {integrity: sha512-iHTrHA8MtVuLl2TfZySmcKv1qO2PoyC9Z7pfSDozEuV5vtY3/wcOPKJXlqJ5Oq2Cx5DDGQGAMVx6HZfRRoVEbQ==} engines: {node: '>= 20.12.0'} - '@clack/prompts@1.7.0': - resolution: {integrity: sha512-y7/yvZ2TPAnR9+jnc00klvNNLkJiXFFrQA/hlLCcxA9a2A4zQIOimyFQ9XfwYKiGD1fb5GY8vbKIIgO8d5Tb2A==} + '@clack/prompts@1.8.1': + resolution: {integrity: sha512-dlT1m5e/0yUL0kRNcQn7yGLVThkgbB0Ga/1AmfDDC/8ik6AIiSf2QLQO2zPYvefsHP0aFgxO93cVLCCfDp7kzQ==} engines: {node: '>= 20.12.0'} '@cloudflare/kv-asset-handler@0.4.2': @@ -2553,6 +2563,16 @@ packages: '@dxup/unimport@0.1.2': resolution: {integrity: sha512-/B8YJGPzaYq1NbsQmwgP8EZqg40NpTw4ZB3suuI0TplbxKHeK94jeaawLmVhCv+YwUnOpiWEz9U6SeThku/8JQ==} + '@e2e-dev/mobile@0.8.1': + resolution: {integrity: sha512-aUbqIUxgeyxebNtySH7Cw+IvZPauHqOM5oUBTCzF8YMpInjqs8vi7iiW6eiZsQPxrINTy/3KoSvIAnPU8bXFYg==} + engines: {node: '>=22.12.0'} + peerDependencies: + ai: ^7.0.0 + e2e: '>=0.15.0 <1' + peerDependenciesMeta: + ai: + optional: true + '@ecies/ciphers@0.2.6': resolution: {integrity: sha512-patgsRPKGkhhoBjETV4XxD0En4ui5fbX0hzayqI3M8tvNMGUoUvmyYAIWwlxBc1KX5cturfqByYdj5bYGRpN9g==} engines: {bun: '>=1', deno: '>=2.7.10', node: '>=16'} @@ -2655,12 +2675,6 @@ packages: resolution: {integrity: sha512-YAdE/IJSpwbOTiaURNCKECdAwqrJuFiZhylmesBcIRawtYKnBR2wxPhoIewMg+Yu+QuYvHfJNReWpoxGBKOChA==} engines: {node: '>=18'} - '@esbuild/aix-ppc64@0.25.12': - resolution: {integrity: sha512-Hhmwd6CInZ3dwpuGTF8fJG6yoWmsToE+vYgD4nytZVxcu1ulHpUQRAB1UJ8+N1Am3Mz4+xOByoQoSZf4D+CpkA==} - engines: {node: '>=18'} - cpu: [ppc64] - os: [aix] - '@esbuild/aix-ppc64@0.27.7': resolution: {integrity: sha512-EKX3Qwmhz1eMdEJokhALr0YiD0lhQNwDqkPYyPhiSwKrh7/4KRjQc04sZ8db+5DVVnZ1LmbNDI1uAMPEUBnQPg==} engines: {node: '>=18'} @@ -2673,12 +2687,6 @@ packages: cpu: [ppc64] os: [aix] - '@esbuild/android-arm64@0.25.12': - resolution: {integrity: sha512-6AAmLG7zwD1Z159jCKPvAxZd4y/VTO0VkprYy+3N2FtJ8+BQWFXU+OxARIwA46c5tdD9SsKGZ/1ocqBS/gAKHg==} - engines: {node: '>=18'} - cpu: [arm64] - os: [android] - '@esbuild/android-arm64@0.27.7': resolution: {integrity: sha512-62dPZHpIXzvChfvfLJow3q5dDtiNMkwiRzPylSCfriLvZeq0a1bWChrGx/BbUbPwOrsWKMn8idSllklzBy+dgQ==} engines: {node: '>=18'} @@ -2691,12 +2699,6 @@ packages: cpu: [arm64] os: [android] - '@esbuild/android-arm@0.25.12': - resolution: {integrity: sha512-VJ+sKvNA/GE7Ccacc9Cha7bpS8nyzVv0jdVgwNDaR4gDMC/2TTRc33Ip8qrNYUcpkOHUT5OZ0bUcNNVZQ9RLlg==} - engines: {node: '>=18'} - cpu: [arm] - os: [android] - '@esbuild/android-arm@0.27.7': resolution: {integrity: sha512-jbPXvB4Yj2yBV7HUfE2KHe4GJX51QplCN1pGbYjvsyCZbQmies29EoJbkEc+vYuU5o45AfQn37vZlyXy4YJ8RQ==} engines: {node: '>=18'} @@ -2709,12 +2711,6 @@ packages: cpu: [arm] os: [android] - '@esbuild/android-x64@0.25.12': - resolution: {integrity: sha512-5jbb+2hhDHx5phYR2By8GTWEzn6I9UqR11Kwf22iKbNpYrsmRB18aX/9ivc5cabcUiAT/wM+YIZ6SG9QO6a8kg==} - engines: {node: '>=18'} - cpu: [x64] - os: [android] - '@esbuild/android-x64@0.27.7': resolution: {integrity: sha512-x5VpMODneVDb70PYV2VQOmIUUiBtY3D3mPBG8NxVk5CogneYhkR7MmM3yR/uMdITLrC1ml/NV1rj4bMJuy9MCg==} engines: {node: '>=18'} @@ -2727,12 +2723,6 @@ packages: cpu: [x64] os: [android] - '@esbuild/darwin-arm64@0.25.12': - resolution: {integrity: sha512-N3zl+lxHCifgIlcMUP5016ESkeQjLj/959RxxNYIthIg+CQHInujFuXeWbWMgnTo4cp5XVHqFPmpyu9J65C1Yg==} - engines: {node: '>=18'} - cpu: [arm64] - os: [darwin] - '@esbuild/darwin-arm64@0.27.7': resolution: {integrity: sha512-5lckdqeuBPlKUwvoCXIgI2D9/ABmPq3Rdp7IfL70393YgaASt7tbju3Ac+ePVi3KDH6N2RqePfHnXkaDtY9fkw==} engines: {node: '>=18'} @@ -2745,12 +2735,6 @@ packages: cpu: [arm64] os: [darwin] - '@esbuild/darwin-x64@0.25.12': - resolution: {integrity: sha512-HQ9ka4Kx21qHXwtlTUVbKJOAnmG1ipXhdWTmNXiPzPfWKpXqASVcWdnf2bnL73wgjNrFXAa3yYvBSd9pzfEIpA==} - engines: {node: '>=18'} - cpu: [x64] - os: [darwin] - '@esbuild/darwin-x64@0.27.7': resolution: {integrity: sha512-rYnXrKcXuT7Z+WL5K980jVFdvVKhCHhUwid+dDYQpH+qu+TefcomiMAJpIiC2EM3Rjtq0sO3StMV/+3w3MyyqQ==} engines: {node: '>=18'} @@ -2763,12 +2747,6 @@ packages: cpu: [x64] os: [darwin] - '@esbuild/freebsd-arm64@0.25.12': - resolution: {integrity: sha512-gA0Bx759+7Jve03K1S0vkOu5Lg/85dou3EseOGUes8flVOGxbhDDh/iZaoek11Y8mtyKPGF3vP8XhnkDEAmzeg==} - engines: {node: '>=18'} - cpu: [arm64] - os: [freebsd] - '@esbuild/freebsd-arm64@0.27.7': resolution: {integrity: sha512-B48PqeCsEgOtzME2GbNM2roU29AMTuOIN91dsMO30t+Ydis3z/3Ngoj5hhnsOSSwNzS+6JppqWsuhTp6E82l2w==} engines: {node: '>=18'} @@ -2781,12 +2759,6 @@ packages: cpu: [arm64] os: [freebsd] - '@esbuild/freebsd-x64@0.25.12': - resolution: {integrity: sha512-TGbO26Yw2xsHzxtbVFGEXBFH0FRAP7gtcPE7P5yP7wGy7cXK2oO7RyOhL5NLiqTlBh47XhmIUXuGciXEqYFfBQ==} - engines: {node: '>=18'} - cpu: [x64] - os: [freebsd] - '@esbuild/freebsd-x64@0.27.7': resolution: {integrity: sha512-jOBDK5XEjA4m5IJK3bpAQF9/Lelu/Z9ZcdhTRLf4cajlB+8VEhFFRjWgfy3M1O4rO2GQ/b2dLwCUGpiF/eATNQ==} engines: {node: '>=18'} @@ -2799,12 +2771,6 @@ packages: cpu: [x64] os: [freebsd] - '@esbuild/linux-arm64@0.25.12': - resolution: {integrity: sha512-8bwX7a8FghIgrupcxb4aUmYDLp8pX06rGh5HqDT7bB+8Rdells6mHvrFHHW2JAOPZUbnjUpKTLg6ECyzvas2AQ==} - engines: {node: '>=18'} - cpu: [arm64] - os: [linux] - '@esbuild/linux-arm64@0.27.7': resolution: {integrity: sha512-RZPHBoxXuNnPQO9rvjh5jdkRmVizktkT7TCDkDmQ0W2SwHInKCAV95GRuvdSvA7w4VMwfCjUiPwDi0ZO6Nfe9A==} engines: {node: '>=18'} @@ -2817,12 +2783,6 @@ packages: cpu: [arm64] os: [linux] - '@esbuild/linux-arm@0.25.12': - resolution: {integrity: sha512-lPDGyC1JPDou8kGcywY0YILzWlhhnRjdof3UlcoqYmS9El818LLfJJc3PXXgZHrHCAKs/Z2SeZtDJr5MrkxtOw==} - engines: {node: '>=18'} - cpu: [arm] - os: [linux] - '@esbuild/linux-arm@0.27.7': resolution: {integrity: sha512-RkT/YXYBTSULo3+af8Ib0ykH8u2MBh57o7q/DAs3lTJlyVQkgQvlrPTnjIzzRPQyavxtPtfg0EopvDyIt0j1rA==} engines: {node: '>=18'} @@ -2835,12 +2795,6 @@ packages: cpu: [arm] os: [linux] - '@esbuild/linux-ia32@0.25.12': - resolution: {integrity: sha512-0y9KrdVnbMM2/vG8KfU0byhUN+EFCny9+8g202gYqSSVMonbsCfLjUO+rCci7pM0WBEtz+oK/PIwHkzxkyharA==} - engines: {node: '>=18'} - cpu: [ia32] - os: [linux] - '@esbuild/linux-ia32@0.27.7': resolution: {integrity: sha512-GA48aKNkyQDbd3KtkplYWT102C5sn/EZTY4XROkxONgruHPU72l+gW+FfF8tf2cFjeHaRbWpOYa/uRBz/Xq1Pg==} engines: {node: '>=18'} @@ -2853,12 +2807,6 @@ packages: cpu: [ia32] os: [linux] - '@esbuild/linux-loong64@0.25.12': - resolution: {integrity: sha512-h///Lr5a9rib/v1GGqXVGzjL4TMvVTv+s1DPoxQdz7l/AYv6LDSxdIwzxkrPW438oUXiDtwM10o9PmwS/6Z0Ng==} - engines: {node: '>=18'} - cpu: [loong64] - os: [linux] - '@esbuild/linux-loong64@0.27.7': resolution: {integrity: sha512-a4POruNM2oWsD4WKvBSEKGIiWQF8fZOAsycHOt6JBpZ+JN2n2JH9WAv56SOyu9X5IqAjqSIPTaJkqN8F7XOQ5Q==} engines: {node: '>=18'} @@ -2871,12 +2819,6 @@ packages: cpu: [loong64] os: [linux] - '@esbuild/linux-mips64el@0.25.12': - resolution: {integrity: sha512-iyRrM1Pzy9GFMDLsXn1iHUm18nhKnNMWscjmp4+hpafcZjrr2WbT//d20xaGljXDBYHqRcl8HnxbX6uaA/eGVw==} - engines: {node: '>=18'} - cpu: [mips64el] - os: [linux] - '@esbuild/linux-mips64el@0.27.7': resolution: {integrity: sha512-KabT5I6StirGfIz0FMgl1I+R1H73Gp0ofL9A3nG3i/cYFJzKHhouBV5VWK1CSgKvVaG4q1RNpCTR2LuTVB3fIw==} engines: {node: '>=18'} @@ -2889,12 +2831,6 @@ packages: cpu: [mips64el] os: [linux] - '@esbuild/linux-ppc64@0.25.12': - resolution: {integrity: sha512-9meM/lRXxMi5PSUqEXRCtVjEZBGwB7P/D4yT8UG/mwIdze2aV4Vo6U5gD3+RsoHXKkHCfSxZKzmDssVlRj1QQA==} - engines: {node: '>=18'} - cpu: [ppc64] - os: [linux] - '@esbuild/linux-ppc64@0.27.7': resolution: {integrity: sha512-gRsL4x6wsGHGRqhtI+ifpN/vpOFTQtnbsupUF5R5YTAg+y/lKelYR1hXbnBdzDjGbMYjVJLJTd2OFmMewAgwlQ==} engines: {node: '>=18'} @@ -2907,12 +2843,6 @@ packages: cpu: [ppc64] os: [linux] - '@esbuild/linux-riscv64@0.25.12': - resolution: {integrity: sha512-Zr7KR4hgKUpWAwb1f3o5ygT04MzqVrGEGXGLnj15YQDJErYu/BGg+wmFlIDOdJp0PmB0lLvxFIOXZgFRrdjR0w==} - engines: {node: '>=18'} - cpu: [riscv64] - os: [linux] - '@esbuild/linux-riscv64@0.27.7': resolution: {integrity: sha512-hL25LbxO1QOngGzu2U5xeXtxXcW+/GvMN3ejANqXkxZ/opySAZMrc+9LY/WyjAan41unrR3YrmtTsUpwT66InQ==} engines: {node: '>=18'} @@ -2925,12 +2855,6 @@ packages: cpu: [riscv64] os: [linux] - '@esbuild/linux-s390x@0.25.12': - resolution: {integrity: sha512-MsKncOcgTNvdtiISc/jZs/Zf8d0cl/t3gYWX8J9ubBnVOwlk65UIEEvgBORTiljloIWnBzLs4qhzPkJcitIzIg==} - engines: {node: '>=18'} - cpu: [s390x] - os: [linux] - '@esbuild/linux-s390x@0.27.7': resolution: {integrity: sha512-2k8go8Ycu1Kb46vEelhu1vqEP+UeRVj2zY1pSuPdgvbd5ykAw82Lrro28vXUrRmzEsUV0NzCf54yARIK8r0fdw==} engines: {node: '>=18'} @@ -2943,12 +2867,6 @@ packages: cpu: [s390x] os: [linux] - '@esbuild/linux-x64@0.25.12': - resolution: {integrity: sha512-uqZMTLr/zR/ed4jIGnwSLkaHmPjOjJvnm6TVVitAa08SLS9Z0VM8wIRx7gWbJB5/J54YuIMInDquWyYvQLZkgw==} - engines: {node: '>=18'} - cpu: [x64] - os: [linux] - '@esbuild/linux-x64@0.27.7': resolution: {integrity: sha512-hzznmADPt+OmsYzw1EE33ccA+HPdIqiCRq7cQeL1Jlq2gb1+OyWBkMCrYGBJ+sxVzve2ZJEVeePbLM2iEIZSxA==} engines: {node: '>=18'} @@ -2961,12 +2879,6 @@ packages: cpu: [x64] os: [linux] - '@esbuild/netbsd-arm64@0.25.12': - resolution: {integrity: sha512-xXwcTq4GhRM7J9A8Gv5boanHhRa/Q9KLVmcyXHCTaM4wKfIpWkdXiMog/KsnxzJ0A1+nD+zoecuzqPmCRyBGjg==} - engines: {node: '>=18'} - cpu: [arm64] - os: [netbsd] - '@esbuild/netbsd-arm64@0.27.7': resolution: {integrity: sha512-b6pqtrQdigZBwZxAn1UpazEisvwaIDvdbMbmrly7cDTMFnw/+3lVxxCTGOrkPVnsYIosJJXAsILG9XcQS+Yu6w==} engines: {node: '>=18'} @@ -2979,12 +2891,6 @@ packages: cpu: [arm64] os: [netbsd] - '@esbuild/netbsd-x64@0.25.12': - resolution: {integrity: sha512-Ld5pTlzPy3YwGec4OuHh1aCVCRvOXdH8DgRjfDy/oumVovmuSzWfnSJg+VtakB9Cm0gxNO9BzWkj6mtO1FMXkQ==} - engines: {node: '>=18'} - cpu: [x64] - os: [netbsd] - '@esbuild/netbsd-x64@0.27.7': resolution: {integrity: sha512-OfatkLojr6U+WN5EDYuoQhtM+1xco+/6FSzJJnuWiUw5eVcicbyK3dq5EeV/QHT1uy6GoDhGbFpprUiHUYggrw==} engines: {node: '>=18'} @@ -2997,12 +2903,6 @@ packages: cpu: [x64] os: [netbsd] - '@esbuild/openbsd-arm64@0.25.12': - resolution: {integrity: sha512-fF96T6KsBo/pkQI950FARU9apGNTSlZGsv1jZBAlcLL1MLjLNIWPBkj5NlSz8aAzYKg+eNqknrUJ24QBybeR5A==} - engines: {node: '>=18'} - cpu: [arm64] - os: [openbsd] - '@esbuild/openbsd-arm64@0.27.7': resolution: {integrity: sha512-AFuojMQTxAz75Fo8idVcqoQWEHIXFRbOc1TrVcFSgCZtQfSdc1RXgB3tjOn/krRHENUB4j00bfGjyl2mJrU37A==} engines: {node: '>=18'} @@ -3015,12 +2915,6 @@ packages: cpu: [arm64] os: [openbsd] - '@esbuild/openbsd-x64@0.25.12': - resolution: {integrity: sha512-MZyXUkZHjQxUvzK7rN8DJ3SRmrVrke8ZyRusHlP+kuwqTcfWLyqMOE3sScPPyeIXN/mDJIfGXvcMqCgYKekoQw==} - engines: {node: '>=18'} - cpu: [x64] - os: [openbsd] - '@esbuild/openbsd-x64@0.27.7': resolution: {integrity: sha512-+A1NJmfM8WNDv5CLVQYJ5PshuRm/4cI6WMZRg1by1GwPIQPCTs1GLEUHwiiQGT5zDdyLiRM/l1G0Pv54gvtKIg==} engines: {node: '>=18'} @@ -3033,12 +2927,6 @@ packages: cpu: [x64] os: [openbsd] - '@esbuild/openharmony-arm64@0.25.12': - resolution: {integrity: sha512-rm0YWsqUSRrjncSXGA7Zv78Nbnw4XL6/dzr20cyrQf7ZmRcsovpcRBdhD43Nuk3y7XIoW2OxMVvwuRvk9XdASg==} - engines: {node: '>=18'} - cpu: [arm64] - os: [openharmony] - '@esbuild/openharmony-arm64@0.27.7': resolution: {integrity: sha512-+KrvYb/C8zA9CU/g0sR6w2RBw7IGc5J2BPnc3dYc5VJxHCSF1yNMxTV5LQ7GuKteQXZtspjFbiuW5/dOj7H4Yw==} engines: {node: '>=18'} @@ -3051,12 +2939,6 @@ packages: cpu: [arm64] os: [openharmony] - '@esbuild/sunos-x64@0.25.12': - resolution: {integrity: sha512-3wGSCDyuTHQUzt0nV7bocDy72r2lI33QL3gkDNGkod22EsYl04sMf0qLb8luNKTOmgF/eDEDP5BFNwoBKH441w==} - engines: {node: '>=18'} - cpu: [x64] - os: [sunos] - '@esbuild/sunos-x64@0.27.7': resolution: {integrity: sha512-ikktIhFBzQNt/QDyOL580ti9+5mL/YZeUPKU2ivGtGjdTYoqz6jObj6nOMfhASpS4GU4Q/Clh1QtxWAvcYKamA==} engines: {node: '>=18'} @@ -3069,12 +2951,6 @@ packages: cpu: [x64] os: [sunos] - '@esbuild/win32-arm64@0.25.12': - resolution: {integrity: sha512-rMmLrur64A7+DKlnSuwqUdRKyd3UE7oPJZmnljqEptesKM8wx9J8gx5u0+9Pq0fQQW8vqeKebwNXdfOyP+8Bsg==} - engines: {node: '>=18'} - cpu: [arm64] - os: [win32] - '@esbuild/win32-arm64@0.27.7': resolution: {integrity: sha512-7yRhbHvPqSpRUV7Q20VuDwbjW5kIMwTHpptuUzV+AA46kiPze5Z7qgt6CLCK3pWFrHeNfDd1VKgyP4O+ng17CA==} engines: {node: '>=18'} @@ -3087,12 +2963,6 @@ packages: cpu: [arm64] os: [win32] - '@esbuild/win32-ia32@0.25.12': - resolution: {integrity: sha512-HkqnmmBoCbCwxUKKNPBixiWDGCpQGVsrQfJoVGYLPT41XWF8lHuE5N6WhVia2n4o5QK5M4tYr21827fNhi4byQ==} - engines: {node: '>=18'} - cpu: [ia32] - os: [win32] - '@esbuild/win32-ia32@0.27.7': resolution: {integrity: sha512-SmwKXe6VHIyZYbBLJrhOoCJRB/Z1tckzmgTLfFYOfpMAx63BJEaL9ExI8x7v0oAO3Zh6D/Oi1gVxEYr5oUCFhw==} engines: {node: '>=18'} @@ -3105,12 +2975,6 @@ packages: cpu: [ia32] os: [win32] - '@esbuild/win32-x64@0.25.12': - resolution: {integrity: sha512-alJC0uCZpTFrSL0CCDjcgleBXPnCrEAhTBILpeAp7M/OFgoqtAetfBzX0xM00MUsVVPpVjlPuMbREqnZCXaTnA==} - engines: {node: '>=18'} - cpu: [x64] - os: [win32] - '@esbuild/win32-x64@0.27.7': resolution: {integrity: sha512-56hiAJPhwQ1R4i+21FVF7V8kSD5zZTdHcVuRFMW0hn753vVfQN8xlx4uOPT4xoGH0Z/oVATuR82AiqSTDIpaHg==} engines: {node: '>=18'} @@ -3914,8 +3778,8 @@ packages: '@microsoft/tsdoc@0.16.0': resolution: {integrity: sha512-xgAyonlVVS+q7Vc7qLW0UrJU7rSFcETRWsqdXZtjzRU8dF+6CkozTK4V4y1LwOX7j8r/vHphjDeMeGI4tNGeGA==} - '@modelcontextprotocol/sdk@1.26.0': - resolution: {integrity: sha512-Y5RmPncpiDtTXDbLKswIJzTqu2hyBKxTNsgKqKclDbhIgg1wgtf1fRuvxgTnRfcnxtvvgbIEcqUOzZrJ6iSReg==} + '@modelcontextprotocol/sdk@1.30.1': + resolution: {integrity: sha512-H2HxLvC3HDNybePJaLdSrU1hhUK5iQw+WvV1b01myFyI7sdVGe1u/IPTE5D9fGCiJDVtgMV/lmFkQXLmQyIFYA==} engines: {node: '>=18'} peerDependencies: '@cfworker/json-schema': ^4.1.1 @@ -5676,6 +5540,9 @@ packages: '@stablelib/base64@1.0.1': resolution: {integrity: sha512-1bnPQqSxSuc3Ii6MhBysoWCg58j97aUjuCSZrGSmDxNqtytIi0k8utUenAwTZN4V5mXXYGsVUI9zeBqy+jBOSQ==} + '@standard-schema/spec@1.1.0': + resolution: {integrity: sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w==} + '@stripe/react-stripe-js@3.1.1': resolution: {integrity: sha512-+JzYFgUivVD7koqYV7LmLlt9edDMAwKH7XhZAHFQMo7NeRC+6D2JmQGzp9tygWerzwttwFLlExGp4rAOvD6l9g==} peerDependencies: @@ -6698,6 +6565,9 @@ packages: '@vitest/browser': optional: true + '@vitest/expect@5.0.2': + resolution: {integrity: sha512-pd6YDkhOHptwC65NYNpGpNxWlJH9M9Gxwtej73osTddb1NpiE0Jz5CIjTTEGXRgK0YtiSN7qBokmBXZ5uPJL1w==} + '@vitest/istanbul-lib-coverage@1.0.1': resolution: {integrity: sha512-k3DJZ8LhMBK9NS4SclF1ASD3OgXEWDorbIcPTRDK0/Zae6fRvu+fJRxtFdLfHsa9Y24beCdPnoNZ4LviTNstfA==} engines: {node: '>=22'} @@ -6720,9 +6590,15 @@ packages: '@vitest/pretty-format@5.0.0': resolution: {integrity: sha512-PVRNuB3wpReb4SQEs4zTKM4KWFhQ5pw3spE8naoDJNB5T5aWRzGKHwXcLUllr0WeOTXpB6bSr3CJLo5+7XQSSQ==} + '@vitest/pretty-format@5.0.2': + resolution: {integrity: sha512-YHM+mQQ7N1ROHMugJ7P/M+fC/q1G4zs/iAMZZCvhHcY8WkwPQcXBHD+z18oz+808Cfa12K7jOr3XPQMcLIovjw==} + '@vitest/spy@5.0.0': resolution: {integrity: sha512-uy+luWBAPw9XfthoHi5AkfHUnuPYEESjl0p/r+meoBnU8bxg5GDQ3Ey8MjcJ6sqahkL4PFyrvfMJJBw7LbU06g==} + '@vitest/spy@5.0.2': + resolution: {integrity: sha512-Ijc7T1nT9efNb5LxvjaBrEqw3f/QwUv5EE0nKqZxgqsaV/FxAAZ8baGylA8X/Z2oS4Lp+K74Jr6dTJsDKxJDeg==} + '@vitest/ui@5.0.0': resolution: {integrity: sha512-h2FIFwggCY2GxUd2UdQoYNVQkOIqEQLPhNREcl3FUiRsdzQep7NWwYbSmhGEA9nFLPDq5pXzRMcBZQU8Py83sg==} peerDependencies: @@ -6731,6 +6607,9 @@ packages: '@vitest/utils@5.0.0': resolution: {integrity: sha512-dO++xL3vDfvhTAVimfkuQUA3k+JClIF1i1vAkPqpcGAthRmeWnXmHB7YPViPvgCwviX8u7Y5W1u2N//AaQr3fw==} + '@vitest/utils@5.0.2': + resolution: {integrity: sha512-mgpUtxFhKeOKVaArBVHNJGdYHAeRh135o59l13uVmPUCS1OUtis5pBqXEgE25iqRgFqEBwXvJlkhknRsYnMeqg==} + '@volar/language-core@2.4.27': resolution: {integrity: sha512-DjmjBWZ4tJKxfNC1F6HyYERNHPYS7L7OPFyCrestykNdUZMFYzI9WTyvwPcaNaHlrEUwESHYsfEw3isInncZxQ==} @@ -7021,6 +6900,16 @@ packages: resolution: {integrity: sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==} engines: {node: '>= 14'} + agent-device@0.21.18: + resolution: {integrity: sha512-ptNJ7a4jkAXFLSmZqKJDwxL+YpCEUuZv3oCBY76PwE3b2W+yQqQuG0ej0/bOspIHJRmMGNOkWhtxm3gmRW9hRQ==} + engines: {node: '>=22.12'} + hasBin: true + peerDependencies: + ai: ^6.0.0 || ^7.0.0 + peerDependenciesMeta: + ai: + optional: true + agent-install@0.0.5: resolution: {integrity: sha512-nHlms9BkP8ZiY79HrwCGiA2DcNaXrAaJrCM/BEqQ7MEsSKyCk+2A76xPGylIfASZSZE0SaU3T0bNSg4rBPIJAQ==} hasBin: true @@ -7971,6 +7860,10 @@ packages: resolution: {integrity: sha512-H+y0Jo/T1RZ9qPP4Eh1pkcQcLRglraJaSLoyOtHxu6AapkjWVCy2Sit1QQ4x3Dng8qDlSsZEet7g5Pq06MvTgw==} engines: {node: '>=20'} + commander@15.0.0: + resolution: {integrity: sha512-z67u4ZhzCL/Tydu1lJARtEZYWbWaN7oYLHbsuzocr6y4N6WZAagG3RQ4FW61V1/0+jImpj293XfrcYnd1qxtPg==} + engines: {node: '>=22.12.0'} + commander@2.20.3: resolution: {integrity: sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==} @@ -8672,6 +8565,25 @@ packages: duplexer@0.1.2: resolution: {integrity: sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg==} + e2e@0.15.1: + resolution: {integrity: sha512-HYuc4xFbLqG4TMZkzZEZEoYa20qKvqyZ9nodDOZ8Yo05YlspzC4GV4guEql1pVIdspqj0fDMINx2rsn3REVrHA==} + engines: {node: '>=22.12.0'} + hasBin: true + peerDependencies: + '@ai-sdk/openai': ^4.0.0 + '@ai-sdk/openai-compatible': ^3.0.0 + '@ai-sdk/xai': ^5.0.0 + ai: ^7.0.0 + peerDependenciesMeta: + '@ai-sdk/openai': + optional: true + '@ai-sdk/openai-compatible': + optional: true + '@ai-sdk/xai': + optional: true + ai: + optional: true + eastasianwidth@0.2.0: resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==} @@ -8877,11 +8789,6 @@ packages: resolution: {integrity: sha512-lNjylaAsJMprYg28zjUyBivP3y0ms9b7RJZ5tdhDUFLa3sCbqZw4wDnbFUSmnyZYWhCYDPxxp7KkXM2TXGw3PQ==} engines: {node: '>=v14.0.0', npm: '>=7.0.0'} - esbuild@0.25.12: - resolution: {integrity: sha512-bbPBYYrtZbkt6Os6FiTLCTFxvq4tt3JKall1vRwshA3fdVztsLAatFaZobhkBC8/BrPetoa0oksYoKXoG4ryJg==} - engines: {node: '>=18'} - hasBin: true - esbuild@0.27.7: resolution: {integrity: sha512-IxpibTjyVnmrIQo5aqNpCgoACA/dTKLTlhMHihVHhdkxKyPO1uBBthumT0rdHmcsk9uMonIWS0m4FljWzILh3w==} engines: {node: '>=18'} @@ -14304,8 +14211,8 @@ packages: typescript: optional: true - tsx@4.20.6: - resolution: {integrity: sha512-ytQKuwgmrrkDTFP4LjR0ToE2nqgy886GpvRSpU0JAnrdBYppuY5rLkRUYPU1yCryb24SsKBTL/hlDQAEFVwtZg==} + tsx@4.23.14: + resolution: {integrity: sha512-yFwMnbAsUFz/T3kR8P2ENc/DDUaYd9tKg4oVYo0lhkX0LlK4UuqYAO6mpQ2y6lmcyip1uPJ34C2kPACopDwG4w==} engines: {node: '>=18.0.0'} hasBin: true @@ -15459,6 +15366,9 @@ packages: zod@3.25.76: resolution: {integrity: sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==} + zod@4.6.1: + resolution: {integrity: sha512-341aRWQsve0rvronKNTqZpjmzdbUDlFuzHaI/XLg/Ej82qffDJRRfBTCuv7+9q/rMjB6LSLyEBnW4InJeMtt/Q==} + zod@4.6.5: resolution: {integrity: sha512-v5l/aFXZQeai4awLbOpSoHecE9UiMrnfx75tEXLjNonXVARxQ5mOeipTjROUchszUNCqnE+hqAMujRsRHsut2Q==} @@ -15514,6 +15424,10 @@ snapshots: '@adraffy/ens-normalize@1.11.1': {} + '@ai-sdk/provider@4.0.18': + dependencies: + json-schema: 0.4.0 + '@alloc/quick-lru@5.2.0': {} '@andrewbranch/untar.js@1.0.3': {} @@ -16573,11 +16487,11 @@ snapshots: '@blazediff/core@1.10.0': {} - '@bomb.sh/tab@0.0.19(cac@6.7.14)(citty@0.2.2)(commander@14.0.3)': + '@bomb.sh/tab@0.0.19(cac@6.7.14)(citty@0.2.2)(commander@15.0.0)': optionalDependencies: cac: 6.7.14 citty: 0.2.2 - commander: 14.0.3 + commander: 15.0.0 '@braidai/lang@1.1.2': {} @@ -16769,14 +16683,14 @@ snapshots: human-id: 4.1.2 prettier: 2.8.8 - '@clack/core@1.4.3': + '@clack/core@1.5.1': dependencies: fast-wrap-ansi: 0.2.2 sisteransi: 1.0.5 - '@clack/prompts@1.7.0': + '@clack/prompts@1.8.1': dependencies: - '@clack/core': 1.4.3 + '@clack/core': 1.5.1 fast-string-width: 3.0.2 fast-wrap-ansi: 0.2.2 sisteransi: 1.0.5 @@ -17013,17 +16927,17 @@ snapshots: '@dual-bundle/import-meta-resolve@4.2.1': {} - '@dxup/nuxt@0.5.10(@rspack/core@2.0.6)(esbuild@0.28.1)(magicast@0.5.4)(rolldown@1.1.0)(rollup@4.61.0)(vite@8.2.2(@types/node@25.6.0)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.46.1)(tsx@4.20.6)(yaml@2.9.0))(webpack@5.102.1(esbuild@0.28.1))': + '@dxup/nuxt@0.5.10(@rspack/core@2.0.6)(esbuild@0.28.1)(magicast@0.5.4)(rolldown@1.1.0)(rollup@4.61.0)(vite@8.2.2(@types/node@25.6.0)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.46.1)(tsx@4.23.14)(yaml@2.9.0))(webpack@5.102.1(esbuild@0.28.1))': dependencies: '@dxup/unimport': 0.1.2 - '@nuxt/kit': 4.5.2(magic-string@1.2.3)(magicast@0.5.4)(rolldown@1.1.0)(unplugin@3.3.0(@rspack/core@2.0.6)(esbuild@0.28.1)(rolldown@1.1.0)(rollup@4.61.0)(vite@8.2.2(@types/node@25.6.0)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.46.1)(tsx@4.20.6)(yaml@2.9.0))(webpack@5.102.1(esbuild@0.28.1))) + '@nuxt/kit': 4.5.2(magic-string@1.2.3)(magicast@0.5.4)(rolldown@1.1.0)(unplugin@3.3.0(@rspack/core@2.0.6)(esbuild@0.28.1)(rolldown@1.1.0)(rollup@4.61.0)(vite@8.2.2(@types/node@25.6.0)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.46.1)(tsx@4.23.14)(yaml@2.9.0))(webpack@5.102.1(esbuild@0.28.1))) '@vue/compiler-dom': 3.5.42 chokidar: 5.0.0 knitwork: 1.3.0 magic-string: 1.2.3 pathe: 2.0.3 tinyglobby: 0.2.17 - unplugin: 3.3.0(@rspack/core@2.0.6)(esbuild@0.28.1)(rolldown@1.1.0)(rollup@4.61.0)(vite@8.2.2(@types/node@25.6.0)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.46.1)(tsx@4.20.6)(yaml@2.9.0))(webpack@5.102.1(esbuild@0.28.1)) + unplugin: 3.3.0(@rspack/core@2.0.6)(esbuild@0.28.1)(rolldown@1.1.0)(rollup@4.61.0)(vite@8.2.2(@types/node@25.6.0)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.46.1)(tsx@4.23.14)(yaml@2.9.0))(webpack@5.102.1(esbuild@0.28.1)) transitivePeerDependencies: - '@farmfe/core' - '@rspack/core' @@ -17039,6 +16953,13 @@ snapshots: '@dxup/unimport@0.1.2': {} + '@e2e-dev/mobile@0.8.1(e2e@0.15.1(@cfworker/json-schema@4.1.1))': + dependencies: + agent-device: 0.21.18 + e2e: 0.15.1(@cfworker/json-schema@4.1.1) + pngjs: 7.0.0 + zod: 4.6.1 + '@ecies/ciphers@0.2.6(@noble/ciphers@1.3.0)': dependencies: '@noble/ciphers': 1.3.0 @@ -17200,234 +17121,156 @@ snapshots: esquery: 1.6.0 jsdoc-type-pratt-parser: 4.1.0 - '@esbuild/aix-ppc64@0.25.12': - optional: true - '@esbuild/aix-ppc64@0.27.7': optional: true '@esbuild/aix-ppc64@0.28.1': optional: true - '@esbuild/android-arm64@0.25.12': - optional: true - '@esbuild/android-arm64@0.27.7': optional: true '@esbuild/android-arm64@0.28.1': optional: true - '@esbuild/android-arm@0.25.12': - optional: true - '@esbuild/android-arm@0.27.7': optional: true '@esbuild/android-arm@0.28.1': optional: true - '@esbuild/android-x64@0.25.12': - optional: true - '@esbuild/android-x64@0.27.7': optional: true '@esbuild/android-x64@0.28.1': optional: true - '@esbuild/darwin-arm64@0.25.12': - optional: true - '@esbuild/darwin-arm64@0.27.7': optional: true '@esbuild/darwin-arm64@0.28.1': optional: true - '@esbuild/darwin-x64@0.25.12': - optional: true - '@esbuild/darwin-x64@0.27.7': optional: true '@esbuild/darwin-x64@0.28.1': optional: true - '@esbuild/freebsd-arm64@0.25.12': - optional: true - '@esbuild/freebsd-arm64@0.27.7': optional: true '@esbuild/freebsd-arm64@0.28.1': optional: true - '@esbuild/freebsd-x64@0.25.12': - optional: true - '@esbuild/freebsd-x64@0.27.7': optional: true '@esbuild/freebsd-x64@0.28.1': optional: true - '@esbuild/linux-arm64@0.25.12': - optional: true - '@esbuild/linux-arm64@0.27.7': optional: true '@esbuild/linux-arm64@0.28.1': optional: true - '@esbuild/linux-arm@0.25.12': - optional: true - '@esbuild/linux-arm@0.27.7': optional: true '@esbuild/linux-arm@0.28.1': optional: true - '@esbuild/linux-ia32@0.25.12': - optional: true - '@esbuild/linux-ia32@0.27.7': optional: true '@esbuild/linux-ia32@0.28.1': optional: true - '@esbuild/linux-loong64@0.25.12': - optional: true - '@esbuild/linux-loong64@0.27.7': optional: true '@esbuild/linux-loong64@0.28.1': optional: true - '@esbuild/linux-mips64el@0.25.12': - optional: true - '@esbuild/linux-mips64el@0.27.7': optional: true '@esbuild/linux-mips64el@0.28.1': optional: true - '@esbuild/linux-ppc64@0.25.12': - optional: true - '@esbuild/linux-ppc64@0.27.7': optional: true '@esbuild/linux-ppc64@0.28.1': optional: true - '@esbuild/linux-riscv64@0.25.12': - optional: true - '@esbuild/linux-riscv64@0.27.7': optional: true '@esbuild/linux-riscv64@0.28.1': optional: true - '@esbuild/linux-s390x@0.25.12': - optional: true - '@esbuild/linux-s390x@0.27.7': optional: true '@esbuild/linux-s390x@0.28.1': optional: true - '@esbuild/linux-x64@0.25.12': - optional: true - '@esbuild/linux-x64@0.27.7': optional: true '@esbuild/linux-x64@0.28.1': optional: true - '@esbuild/netbsd-arm64@0.25.12': - optional: true - '@esbuild/netbsd-arm64@0.27.7': optional: true '@esbuild/netbsd-arm64@0.28.1': optional: true - '@esbuild/netbsd-x64@0.25.12': - optional: true - '@esbuild/netbsd-x64@0.27.7': optional: true '@esbuild/netbsd-x64@0.28.1': optional: true - '@esbuild/openbsd-arm64@0.25.12': - optional: true - '@esbuild/openbsd-arm64@0.27.7': optional: true '@esbuild/openbsd-arm64@0.28.1': optional: true - '@esbuild/openbsd-x64@0.25.12': - optional: true - '@esbuild/openbsd-x64@0.27.7': optional: true '@esbuild/openbsd-x64@0.28.1': optional: true - '@esbuild/openharmony-arm64@0.25.12': - optional: true - '@esbuild/openharmony-arm64@0.27.7': optional: true '@esbuild/openharmony-arm64@0.28.1': optional: true - '@esbuild/sunos-x64@0.25.12': - optional: true - '@esbuild/sunos-x64@0.27.7': optional: true '@esbuild/sunos-x64@0.28.1': optional: true - '@esbuild/win32-arm64@0.25.12': - optional: true - '@esbuild/win32-arm64@0.27.7': optional: true '@esbuild/win32-arm64@0.28.1': optional: true - '@esbuild/win32-ia32@0.25.12': - optional: true - '@esbuild/win32-ia32@0.27.7': optional: true '@esbuild/win32-ia32@0.28.1': optional: true - '@esbuild/win32-x64@0.25.12': - optional: true - '@esbuild/win32-x64@0.27.7': optional: true @@ -18565,7 +18408,7 @@ snapshots: '@microsoft/tsdoc@0.16.0': optional: true - '@modelcontextprotocol/sdk@1.26.0(@cfworker/json-schema@4.1.1)(zod@3.25.76)': + '@modelcontextprotocol/sdk@1.30.1(@cfworker/json-schema@4.1.1)(zod@3.25.76)': dependencies: '@hono/node-server': 1.19.14(hono@4.13.4) ajv: 8.20.0 @@ -18589,6 +18432,30 @@ snapshots: transitivePeerDependencies: - supports-color + '@modelcontextprotocol/sdk@1.30.1(@cfworker/json-schema@4.1.1)(zod@4.6.1)': + dependencies: + '@hono/node-server': 1.19.14(hono@4.13.4) + ajv: 8.20.0 + ajv-formats: 3.0.1(ajv@8.20.0) + content-type: 1.0.5 + cors: 2.8.6 + cross-spawn: 7.0.6 + eventsource: 3.0.7 + eventsource-parser: 3.0.8 + express: 5.2.1 + express-rate-limit: 8.3.2(express@5.2.1) + hono: 4.13.4 + jose: 6.2.2 + json-schema-typed: 8.0.2 + pkce-challenge: 5.0.1 + raw-body: 3.0.2 + zod: 4.6.1 + zod-to-json-schema: 3.25.2(zod@4.6.1) + optionalDependencies: + '@cfworker/json-schema': 4.1.1 + transitivePeerDependencies: + - supports-color + '@mswjs/interceptors@0.41.9': dependencies: '@open-draft/deferred-promise': 2.2.0 @@ -18956,10 +18823,10 @@ snapshots: '@nolyfill/is-core-module@1.0.39': {} - '@nuxt/cli@3.37.0(@nuxt/schema@4.5.2)(cac@6.7.14)(commander@14.0.3)(magicast@0.5.4)': + '@nuxt/cli@3.37.0(@nuxt/schema@4.5.2)(cac@6.7.14)(commander@15.0.0)(magicast@0.5.4)': dependencies: - '@bomb.sh/tab': 0.0.19(cac@6.7.14)(citty@0.2.2)(commander@14.0.3) - '@clack/prompts': 1.7.0 + '@bomb.sh/tab': 0.0.19(cac@6.7.14)(citty@0.2.2)(commander@15.0.0) + '@clack/prompts': 1.8.1 c12: 3.3.4(magicast@0.5.4) citty: 0.2.2 confbox: 0.2.4 @@ -18996,11 +18863,11 @@ snapshots: '@nuxt/devalue@2.0.2': {} - '@nuxt/devtools-kit@3.4.2(magic-string@1.2.3)(magicast@0.5.4)(rolldown@1.1.0)(unplugin@3.3.0(@rspack/core@2.0.6)(esbuild@0.28.1)(rolldown@1.1.0)(rollup@4.61.0)(vite@8.2.2(@types/node@25.6.0)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.46.1)(tsx@4.20.6)(yaml@2.9.0))(webpack@5.102.1(esbuild@0.28.1)))(vite@8.2.2(@types/node@25.6.0)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.46.1)(tsx@4.20.6)(yaml@2.9.0))': + '@nuxt/devtools-kit@3.4.2(magic-string@1.2.3)(magicast@0.5.4)(rolldown@1.1.0)(unplugin@3.3.0(@rspack/core@2.0.6)(esbuild@0.28.1)(rolldown@1.1.0)(rollup@4.61.0)(vite@8.2.2(@types/node@25.6.0)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.46.1)(tsx@4.23.14)(yaml@2.9.0))(webpack@5.102.1(esbuild@0.28.1)))(vite@8.2.2(@types/node@25.6.0)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.46.1)(tsx@4.23.14)(yaml@2.9.0))': dependencies: - '@nuxt/kit': 4.5.2(magic-string@1.2.3)(magicast@0.5.4)(rolldown@1.1.0)(unplugin@3.3.0(@rspack/core@2.0.6)(esbuild@0.28.1)(rolldown@1.1.0)(rollup@4.61.0)(vite@8.2.2(@types/node@25.6.0)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.46.1)(tsx@4.20.6)(yaml@2.9.0))(webpack@5.102.1(esbuild@0.28.1))) + '@nuxt/kit': 4.5.2(magic-string@1.2.3)(magicast@0.5.4)(rolldown@1.1.0)(unplugin@3.3.0(@rspack/core@2.0.6)(esbuild@0.28.1)(rolldown@1.1.0)(rollup@4.61.0)(vite@8.2.2(@types/node@25.6.0)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.46.1)(tsx@4.23.14)(yaml@2.9.0))(webpack@5.102.1(esbuild@0.28.1))) execa: 8.0.1 - vite: 8.2.2(@types/node@25.6.0)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.46.1)(tsx@4.20.6)(yaml@2.9.0) + vite: 8.2.2(@types/node@25.6.0)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.46.1)(tsx@4.23.14)(yaml@2.9.0) transitivePeerDependencies: - magic-string - magicast @@ -19010,7 +18877,7 @@ snapshots: '@nuxt/devtools-wizard@3.4.2': dependencies: - '@clack/prompts': 1.7.0 + '@clack/prompts': 1.8.1 consola: 3.4.2 diff: 8.0.4 execa: 8.0.1 @@ -19019,11 +18886,11 @@ snapshots: pkg-types: 2.3.1 semver: 7.8.5 - '@nuxt/devtools@3.4.2(bufferutil@4.1.0)(db0@0.3.4)(idb-keyval@6.2.1)(ioredis@5.11.0)(magic-string@1.2.3)(rolldown@1.1.0)(unplugin@3.3.0(@rspack/core@2.0.6)(esbuild@0.28.1)(rolldown@1.1.0)(rollup@4.61.0)(vite@8.2.2(@types/node@25.6.0)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.46.1)(tsx@4.20.6)(yaml@2.9.0))(webpack@5.102.1(esbuild@0.28.1)))(utf-8-validate@5.0.10)(vite@8.2.2(@types/node@25.6.0)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.46.1)(tsx@4.20.6)(yaml@2.9.0))(vue@3.5.42(typescript@6.0.3))': + '@nuxt/devtools@3.4.2(bufferutil@4.1.0)(db0@0.3.4)(idb-keyval@6.2.1)(ioredis@5.11.0)(magic-string@1.2.3)(rolldown@1.1.0)(unplugin@3.3.0(@rspack/core@2.0.6)(esbuild@0.28.1)(rolldown@1.1.0)(rollup@4.61.0)(vite@8.2.2(@types/node@25.6.0)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.46.1)(tsx@4.23.14)(yaml@2.9.0))(webpack@5.102.1(esbuild@0.28.1)))(utf-8-validate@5.0.10)(vite@8.2.2(@types/node@25.6.0)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.46.1)(tsx@4.23.14)(yaml@2.9.0))(vue@3.5.42(typescript@6.0.3))': dependencies: - '@nuxt/devtools-kit': 3.4.2(magic-string@1.2.3)(magicast@0.5.4)(rolldown@1.1.0)(unplugin@3.3.0(@rspack/core@2.0.6)(esbuild@0.28.1)(rolldown@1.1.0)(rollup@4.61.0)(vite@8.2.2(@types/node@25.6.0)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.46.1)(tsx@4.20.6)(yaml@2.9.0))(webpack@5.102.1(esbuild@0.28.1)))(vite@8.2.2(@types/node@25.6.0)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.46.1)(tsx@4.20.6)(yaml@2.9.0)) + '@nuxt/devtools-kit': 3.4.2(magic-string@1.2.3)(magicast@0.5.4)(rolldown@1.1.0)(unplugin@3.3.0(@rspack/core@2.0.6)(esbuild@0.28.1)(rolldown@1.1.0)(rollup@4.61.0)(vite@8.2.2(@types/node@25.6.0)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.46.1)(tsx@4.23.14)(yaml@2.9.0))(webpack@5.102.1(esbuild@0.28.1)))(vite@8.2.2(@types/node@25.6.0)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.46.1)(tsx@4.23.14)(yaml@2.9.0)) '@nuxt/devtools-wizard': 3.4.2 - '@nuxt/kit': 4.5.2(magic-string@1.2.3)(magicast@0.5.4)(rolldown@1.1.0)(unplugin@3.3.0(@rspack/core@2.0.6)(esbuild@0.28.1)(rolldown@1.1.0)(rollup@4.61.0)(vite@8.2.2(@types/node@25.6.0)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.46.1)(tsx@4.20.6)(yaml@2.9.0))(webpack@5.102.1(esbuild@0.28.1))) + '@nuxt/kit': 4.5.2(magic-string@1.2.3)(magicast@0.5.4)(rolldown@1.1.0)(unplugin@3.3.0(@rspack/core@2.0.6)(esbuild@0.28.1)(rolldown@1.1.0)(rollup@4.61.0)(vite@8.2.2(@types/node@25.6.0)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.46.1)(tsx@4.23.14)(yaml@2.9.0))(webpack@5.102.1(esbuild@0.28.1))) '@vue/devtools-core': 8.2.1(vue@3.5.42(typescript@6.0.3)) '@vue/devtools-kit': 8.2.1 birpc: 4.0.0 @@ -19050,9 +18917,9 @@ snapshots: structured-clone-es: 2.0.1 tinyglobby: 0.2.17 unstorage: 1.17.5(db0@0.3.4)(idb-keyval@6.2.1)(ioredis@5.11.0) - vite: 8.2.2(@types/node@25.6.0)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.46.1)(tsx@4.20.6)(yaml@2.9.0) - vite-plugin-inspect: 11.4.1(@nuxt/kit@4.5.2(magic-string@1.2.3)(magicast@0.5.4)(rolldown@1.1.0)(unplugin@3.3.0(@rspack/core@2.0.6)(esbuild@0.28.1)(rolldown@1.1.0)(rollup@4.61.0)(vite@8.2.2(@types/node@25.6.0)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.46.1)(tsx@4.20.6)(yaml@2.9.0))(webpack@5.102.1(esbuild@0.28.1))))(vite@8.2.2(@types/node@25.6.0)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.46.1)(tsx@4.20.6)(yaml@2.9.0)) - vite-plugin-vue-tracer: 1.4.0(vite@8.2.2(@types/node@25.6.0)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.46.1)(tsx@4.20.6)(yaml@2.9.0))(vue@3.5.42(typescript@6.0.3)) + vite: 8.2.2(@types/node@25.6.0)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.46.1)(tsx@4.23.14)(yaml@2.9.0) + vite-plugin-inspect: 11.4.1(@nuxt/kit@4.5.2(magic-string@1.2.3)(magicast@0.5.4)(rolldown@1.1.0)(unplugin@3.3.0(@rspack/core@2.0.6)(esbuild@0.28.1)(rolldown@1.1.0)(rollup@4.61.0)(vite@8.2.2(@types/node@25.6.0)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.46.1)(tsx@4.23.14)(yaml@2.9.0))(webpack@5.102.1(esbuild@0.28.1))))(vite@8.2.2(@types/node@25.6.0)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.46.1)(tsx@4.23.14)(yaml@2.9.0)) + vite-plugin-vue-tracer: 1.4.0(vite@8.2.2(@types/node@25.6.0)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.46.1)(tsx@4.23.14)(yaml@2.9.0))(vue@3.5.42(typescript@6.0.3)) which: 6.0.1 ws: 8.21.3(bufferutil@4.1.0)(utf-8-validate@5.0.10) transitivePeerDependencies: @@ -19084,7 +18951,7 @@ snapshots: - utf-8-validate - vue - '@nuxt/kit@4.5.2(magic-string@1.2.3)(magicast@0.5.4)(rolldown@1.1.0)(unplugin@3.3.0(@rspack/core@2.0.6)(esbuild@0.28.1)(rolldown@1.1.0)(rollup@4.61.0)(vite@8.2.2(@types/node@25.6.0)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.46.1)(tsx@4.20.6)(yaml@2.9.0))(webpack@5.102.1(esbuild@0.28.1)))': + '@nuxt/kit@4.5.2(magic-string@1.2.3)(magicast@0.5.4)(rolldown@1.1.0)(unplugin@3.3.0(@rspack/core@2.0.6)(esbuild@0.28.1)(rolldown@1.1.0)(rollup@4.61.0)(vite@8.2.2(@types/node@25.6.0)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.46.1)(tsx@4.23.14)(yaml@2.9.0))(webpack@5.102.1(esbuild@0.28.1)))': dependencies: c12: 3.3.4(magicast@0.5.4) consola: 3.4.2 @@ -19104,7 +18971,7 @@ snapshots: scule: 1.3.0 tinyglobby: 0.2.17 ufo: 1.6.4 - unctx: 3.0.1(magic-string@1.2.3)(rolldown@1.1.0)(unplugin@3.3.0(@rspack/core@2.0.6)(esbuild@0.28.1)(rolldown@1.1.0)(rollup@4.61.0)(vite@8.2.2(@types/node@25.6.0)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.46.1)(tsx@4.20.6)(yaml@2.9.0))(webpack@5.102.1(esbuild@0.28.1))) + unctx: 3.0.1(magic-string@1.2.3)(rolldown@1.1.0)(unplugin@3.3.0(@rspack/core@2.0.6)(esbuild@0.28.1)(rolldown@1.1.0)(rollup@4.61.0)(vite@8.2.2(@types/node@25.6.0)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.46.1)(tsx@4.23.14)(yaml@2.9.0))(webpack@5.102.1(esbuild@0.28.1))) untyped: 2.0.0 verkit: 0.3.2 transitivePeerDependencies: @@ -19114,11 +18981,11 @@ snapshots: - rolldown - unplugin - '@nuxt/nitro-server@4.5.2(879ff76bb2e0ee98f31f9b2805059646)': + '@nuxt/nitro-server@4.5.2(5d71b80bb60d18d09b48b3f6ca65979c)': dependencies: '@nuxt/devalue': 2.0.2 - '@nuxt/kit': 4.5.2(magic-string@1.2.3)(magicast@0.5.4)(rolldown@1.1.0)(unplugin@3.3.0(@rspack/core@2.0.6)(esbuild@0.28.1)(rolldown@1.1.0)(rollup@4.61.0)(vite@8.2.2(@types/node@25.6.0)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.46.1)(tsx@4.20.6)(yaml@2.9.0))(webpack@5.102.1(esbuild@0.28.1))) - '@unhead/vue': 3.4.0(@oxc-project/types@0.134.0)(@rspack/core@2.0.6)(esbuild@0.28.1)(lightningcss@1.33.0)(rolldown@1.1.0)(rollup@4.61.0)(vite@8.2.2(@types/node@25.6.0)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.46.1)(tsx@4.20.6)(yaml@2.9.0))(vue@3.5.42(typescript@6.0.3))(webpack@5.102.1(esbuild@0.28.1)) + '@nuxt/kit': 4.5.2(magic-string@1.2.3)(magicast@0.5.4)(rolldown@1.1.0)(unplugin@3.3.0(@rspack/core@2.0.6)(esbuild@0.28.1)(rolldown@1.1.0)(rollup@4.61.0)(vite@8.2.2(@types/node@25.6.0)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.46.1)(tsx@4.23.14)(yaml@2.9.0))(webpack@5.102.1(esbuild@0.28.1))) + '@unhead/vue': 3.4.0(@oxc-project/types@0.134.0)(@rspack/core@2.0.6)(esbuild@0.28.1)(lightningcss@1.33.0)(rolldown@1.1.0)(rollup@4.61.0)(vite@8.2.2(@types/node@25.6.0)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.46.1)(tsx@4.23.14)(yaml@2.9.0))(vue@3.5.42(typescript@6.0.3))(webpack@5.102.1(esbuild@0.28.1)) '@vue/shared': 3.5.42 consola: 3.4.2 defu: 6.1.7 @@ -19128,19 +18995,19 @@ snapshots: escape-string-regexp: 5.0.0 exsolve: 1.1.1 h3: 1.15.11 - impound: 1.2.0(@rspack/core@2.0.6)(esbuild@0.28.1)(rolldown@1.1.0)(rollup@4.61.0)(vite@8.2.2(@types/node@25.6.0)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.46.1)(tsx@4.20.6)(yaml@2.9.0))(webpack@5.102.1(esbuild@0.28.1)) + impound: 1.2.0(@rspack/core@2.0.6)(esbuild@0.28.1)(rolldown@1.1.0)(rollup@4.61.0)(vite@8.2.2(@types/node@25.6.0)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.46.1)(tsx@4.23.14)(yaml@2.9.0))(webpack@5.102.1(esbuild@0.28.1)) klona: 2.0.6 mocked-exports: 0.1.1 - nitropack: 2.13.4(@rspack/core@2.0.6)(idb-keyval@6.2.1)(rolldown@1.1.0)(vite@8.2.2(@types/node@25.6.0)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.46.1)(tsx@4.20.6)(yaml@2.9.0))(webpack@5.102.1(esbuild@0.28.1)) + nitropack: 2.13.4(@rspack/core@2.0.6)(idb-keyval@6.2.1)(rolldown@1.1.0)(vite@8.2.2(@types/node@25.6.0)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.46.1)(tsx@4.23.14)(yaml@2.9.0))(webpack@5.102.1(esbuild@0.28.1)) nostics: 1.2.0 - nuxt: 4.5.2(@babel/plugin-proposal-decorators@7.28.0(@babel/core@7.29.7))(@babel/plugin-syntax-jsx@7.29.7(@babel/core@7.29.7))(@babel/plugin-syntax-typescript@7.29.7(@babel/core@7.29.7))(@oxc-project/types@0.134.0)(@parcel/watcher@2.5.6)(@rspack/core@2.0.6)(@types/node@25.6.0)(@vue/compiler-sfc@3.5.42)(bufferutil@4.1.0)(cac@6.7.14)(commander@14.0.3)(db0@0.3.4)(esbuild@0.28.1)(eslint@9.31.0(jiti@2.7.0))(idb-keyval@6.2.1)(ioredis@5.11.0)(lightningcss@1.33.0)(magicast@0.5.4)(meow@13.2.0)(optionator@0.9.4)(rolldown@1.1.0)(rollup-plugin-visualizer@7.0.1(rolldown@1.1.0)(rollup@4.61.0))(rollup@4.61.0)(terser@5.46.1)(tsx@4.20.6)(typescript@6.0.3)(utf-8-validate@5.0.10)(vite@8.2.2(@types/node@25.6.0)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.46.1)(tsx@4.20.6)(yaml@2.9.0))(vue-tsc@3.2.4(typescript@6.0.3))(webpack@5.102.1(esbuild@0.28.1))(yaml@2.9.0) + nuxt: 4.5.2(@babel/plugin-proposal-decorators@7.28.0(@babel/core@7.29.7))(@babel/plugin-syntax-jsx@7.29.7(@babel/core@7.29.7))(@babel/plugin-syntax-typescript@7.29.7(@babel/core@7.29.7))(@oxc-project/types@0.134.0)(@parcel/watcher@2.5.6)(@rspack/core@2.0.6)(@types/node@25.6.0)(@vue/compiler-sfc@3.5.42)(bufferutil@4.1.0)(cac@6.7.14)(commander@15.0.0)(db0@0.3.4)(esbuild@0.28.1)(eslint@9.31.0(jiti@2.7.0))(idb-keyval@6.2.1)(ioredis@5.11.0)(lightningcss@1.33.0)(magicast@0.5.4)(meow@13.2.0)(optionator@0.9.4)(rolldown@1.1.0)(rollup-plugin-visualizer@7.0.1(rolldown@1.1.0)(rollup@4.61.0))(rollup@4.61.0)(terser@5.46.1)(tsx@4.23.14)(typescript@6.0.3)(utf-8-validate@5.0.10)(vite@8.2.2(@types/node@25.6.0)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.46.1)(tsx@4.23.14)(yaml@2.9.0))(vue-tsc@3.2.4(typescript@6.0.3))(webpack@5.102.1(esbuild@0.28.1))(yaml@2.9.0) nypm: 0.6.9 ohash: 2.0.11 pathe: 2.0.3 rou3: 0.9.2 std-env: 4.2.0 ufo: 1.6.4 - unctx: 3.0.1(magic-string@1.2.3)(rolldown@1.1.0)(unplugin@3.3.0(@rspack/core@2.0.6)(esbuild@0.28.1)(rolldown@1.1.0)(rollup@4.61.0)(vite@8.2.2(@types/node@25.6.0)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.46.1)(tsx@4.20.6)(yaml@2.9.0))(webpack@5.102.1(esbuild@0.28.1))) + unctx: 3.0.1(magic-string@1.2.3)(rolldown@1.1.0)(unplugin@3.3.0(@rspack/core@2.0.6)(esbuild@0.28.1)(rolldown@1.1.0)(rollup@4.61.0)(vite@8.2.2(@types/node@25.6.0)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.46.1)(tsx@4.23.14)(yaml@2.9.0))(webpack@5.102.1(esbuild@0.28.1))) unstorage: 1.17.5(db0@0.3.4)(idb-keyval@6.2.1)(ioredis@5.11.0) vue: 3.5.42(typescript@6.0.3) vue-bundle-renderer: 2.3.2 @@ -19207,20 +19074,20 @@ snapshots: pkg-types: 2.3.1 std-env: 4.2.0 - '@nuxt/telemetry@2.8.0(@nuxt/kit@4.5.2(magic-string@1.2.3)(magicast@0.5.4)(rolldown@1.1.0)(unplugin@3.3.0(@rspack/core@2.0.6)(esbuild@0.28.1)(rolldown@1.1.0)(rollup@4.61.0)(vite@8.2.2(@types/node@25.6.0)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.46.1)(tsx@4.20.6)(yaml@2.9.0))(webpack@5.102.1(esbuild@0.28.1))))': + '@nuxt/telemetry@2.8.0(@nuxt/kit@4.5.2(magic-string@1.2.3)(magicast@0.5.4)(rolldown@1.1.0)(unplugin@3.3.0(@rspack/core@2.0.6)(esbuild@0.28.1)(rolldown@1.1.0)(rollup@4.61.0)(vite@8.2.2(@types/node@25.6.0)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.46.1)(tsx@4.23.14)(yaml@2.9.0))(webpack@5.102.1(esbuild@0.28.1))))': dependencies: - '@nuxt/kit': 4.5.2(magic-string@1.2.3)(magicast@0.5.4)(rolldown@1.1.0)(unplugin@3.3.0(@rspack/core@2.0.6)(esbuild@0.28.1)(rolldown@1.1.0)(rollup@4.61.0)(vite@8.2.2(@types/node@25.6.0)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.46.1)(tsx@4.20.6)(yaml@2.9.0))(webpack@5.102.1(esbuild@0.28.1))) + '@nuxt/kit': 4.5.2(magic-string@1.2.3)(magicast@0.5.4)(rolldown@1.1.0)(unplugin@3.3.0(@rspack/core@2.0.6)(esbuild@0.28.1)(rolldown@1.1.0)(rollup@4.61.0)(vite@8.2.2(@types/node@25.6.0)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.46.1)(tsx@4.23.14)(yaml@2.9.0))(webpack@5.102.1(esbuild@0.28.1))) citty: 0.2.2 consola: 3.4.2 ofetch: 2.0.0-alpha.3 rc9: 3.0.1 std-env: 4.2.0 - '@nuxt/vite-builder@4.5.2(200211434b3910e3f7a6f479cdd8d4fb)': + '@nuxt/vite-builder@4.5.2(29f1a007dbea6b2d37230221b704cc42)': dependencies: - '@nuxt/kit': 4.5.2(magic-string@1.2.3)(magicast@0.5.4)(rolldown@1.1.0)(unplugin@3.3.0(@rspack/core@2.0.6)(esbuild@0.28.1)(rolldown@1.1.0)(rollup@4.61.0)(vite@8.2.2(@types/node@25.6.0)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.46.1)(tsx@4.20.6)(yaml@2.9.0))(webpack@5.102.1(esbuild@0.28.1))) - '@vitejs/plugin-vue': 6.0.8(vite@8.2.2(@types/node@25.6.0)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.46.1)(tsx@4.20.6)(yaml@2.9.0))(vue@3.5.42(typescript@6.0.3)) - '@vitejs/plugin-vue-jsx': 5.1.6(vite@8.2.2(@types/node@25.6.0)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.46.1)(tsx@4.20.6)(yaml@2.9.0))(vue@3.5.42(typescript@6.0.3)) + '@nuxt/kit': 4.5.2(magic-string@1.2.3)(magicast@0.5.4)(rolldown@1.1.0)(unplugin@3.3.0(@rspack/core@2.0.6)(esbuild@0.28.1)(rolldown@1.1.0)(rollup@4.61.0)(vite@8.2.2(@types/node@25.6.0)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.46.1)(tsx@4.23.14)(yaml@2.9.0))(webpack@5.102.1(esbuild@0.28.1))) + '@vitejs/plugin-vue': 6.0.8(vite@8.2.2(@types/node@25.6.0)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.46.1)(tsx@4.23.14)(yaml@2.9.0))(vue@3.5.42(typescript@6.0.3)) + '@vitejs/plugin-vue-jsx': 5.1.6(vite@8.2.2(@types/node@25.6.0)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.46.1)(tsx@4.23.14)(yaml@2.9.0))(vue@3.5.42(typescript@6.0.3)) autoprefixer: 10.5.4(postcss@8.5.26) consola: 3.4.2 cssnano: 8.0.10(postcss@8.5.26) @@ -19234,7 +19101,7 @@ snapshots: knitwork: 1.3.0 mlly: 1.8.2 mocked-exports: 0.1.1 - nuxt: 4.5.2(@babel/plugin-proposal-decorators@7.28.0(@babel/core@7.29.7))(@babel/plugin-syntax-jsx@7.29.7(@babel/core@7.29.7))(@babel/plugin-syntax-typescript@7.29.7(@babel/core@7.29.7))(@oxc-project/types@0.134.0)(@parcel/watcher@2.5.6)(@rspack/core@2.0.6)(@types/node@25.6.0)(@vue/compiler-sfc@3.5.42)(bufferutil@4.1.0)(cac@6.7.14)(commander@14.0.3)(db0@0.3.4)(esbuild@0.28.1)(eslint@9.31.0(jiti@2.7.0))(idb-keyval@6.2.1)(ioredis@5.11.0)(lightningcss@1.33.0)(magicast@0.5.4)(meow@13.2.0)(optionator@0.9.4)(rolldown@1.1.0)(rollup-plugin-visualizer@7.0.1(rolldown@1.1.0)(rollup@4.61.0))(rollup@4.61.0)(terser@5.46.1)(tsx@4.20.6)(typescript@6.0.3)(utf-8-validate@5.0.10)(vite@8.2.2(@types/node@25.6.0)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.46.1)(tsx@4.20.6)(yaml@2.9.0))(vue-tsc@3.2.4(typescript@6.0.3))(webpack@5.102.1(esbuild@0.28.1))(yaml@2.9.0) + nuxt: 4.5.2(@babel/plugin-proposal-decorators@7.28.0(@babel/core@7.29.7))(@babel/plugin-syntax-jsx@7.29.7(@babel/core@7.29.7))(@babel/plugin-syntax-typescript@7.29.7(@babel/core@7.29.7))(@oxc-project/types@0.134.0)(@parcel/watcher@2.5.6)(@rspack/core@2.0.6)(@types/node@25.6.0)(@vue/compiler-sfc@3.5.42)(bufferutil@4.1.0)(cac@6.7.14)(commander@15.0.0)(db0@0.3.4)(esbuild@0.28.1)(eslint@9.31.0(jiti@2.7.0))(idb-keyval@6.2.1)(ioredis@5.11.0)(lightningcss@1.33.0)(magicast@0.5.4)(meow@13.2.0)(optionator@0.9.4)(rolldown@1.1.0)(rollup-plugin-visualizer@7.0.1(rolldown@1.1.0)(rollup@4.61.0))(rollup@4.61.0)(terser@5.46.1)(tsx@4.23.14)(typescript@6.0.3)(utf-8-validate@5.0.10)(vite@8.2.2(@types/node@25.6.0)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.46.1)(tsx@4.23.14)(yaml@2.9.0))(vue-tsc@3.2.4(typescript@6.0.3))(webpack@5.102.1(esbuild@0.28.1))(yaml@2.9.0) nypm: 0.6.9 pathe: 2.0.3 pkg-types: 2.3.1 @@ -19244,9 +19111,9 @@ snapshots: std-env: 4.2.0 ufo: 1.6.4 unenv: 2.0.0-rc.24 - vite: 8.2.2(@types/node@25.6.0)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.46.1)(tsx@4.20.6)(yaml@2.9.0) - vite-node: 6.0.0(@types/node@25.6.0)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.46.1)(tsx@4.20.6)(yaml@2.9.0) - vite-plugin-checker: 0.14.5(eslint@9.31.0(jiti@2.7.0))(meow@13.2.0)(optionator@0.9.4)(typescript@6.0.3)(vite@8.2.2(@types/node@25.6.0)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.46.1)(tsx@4.20.6)(yaml@2.9.0))(vue-tsc@3.2.4(typescript@6.0.3)) + vite: 8.2.2(@types/node@25.6.0)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.46.1)(tsx@4.23.14)(yaml@2.9.0) + vite-node: 6.0.0(@types/node@25.6.0)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.46.1)(tsx@4.23.14)(yaml@2.9.0) + vite-plugin-checker: 0.14.5(eslint@9.31.0(jiti@2.7.0))(meow@13.2.0)(optionator@0.9.4)(typescript@6.0.3)(vite@8.2.2(@types/node@25.6.0)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.46.1)(tsx@4.23.14)(yaml@2.9.0))(vue-tsc@3.2.4(typescript@6.0.3)) vue: 3.5.42(typescript@6.0.3) vue-bundle-renderer: 2.3.2 optionalDependencies: @@ -20754,6 +20621,8 @@ snapshots: '@stablelib/base64@1.0.1': {} + '@standard-schema/spec@1.1.0': {} + '@stripe/react-stripe-js@3.1.1(@stripe/stripe-js@5.6.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': dependencies: '@stripe/stripe-js': 5.6.0 @@ -20826,7 +20695,7 @@ snapshots: transitivePeerDependencies: - supports-color - '@stylexjs/unplugin@0.19.0(unplugin@3.3.0(@rspack/core@2.0.6)(esbuild@0.28.1)(rolldown@1.1.0)(rollup@4.61.0)(vite@8.2.2(@types/node@25.6.0)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.46.1)(tsx@4.20.6)(yaml@2.9.0))(webpack@5.102.1(esbuild@0.28.1)))': + '@stylexjs/unplugin@0.19.0(unplugin@3.3.0(@rspack/core@2.0.6)(esbuild@0.28.1)(rolldown@1.1.0)(rollup@4.61.0)(vite@8.2.2(@types/node@25.6.0)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.46.1)(tsx@4.23.14)(yaml@2.9.0))(webpack@5.102.1(esbuild@0.28.1)))': dependencies: '@babel/core': 7.29.7 '@babel/plugin-syntax-flow': 7.27.1(@babel/core@7.29.7) @@ -20835,7 +20704,7 @@ snapshots: '@stylexjs/babel-plugin': 0.19.0 browserslist: 4.28.8 lightningcss: 1.33.0 - unplugin: 3.3.0(@rspack/core@2.0.6)(esbuild@0.28.1)(rolldown@1.1.0)(rollup@4.61.0)(vite@8.2.2(@types/node@25.6.0)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.46.1)(tsx@4.20.6)(yaml@2.9.0))(webpack@5.102.1(esbuild@0.28.1)) + unplugin: 3.3.0(@rspack/core@2.0.6)(esbuild@0.28.1)(rolldown@1.1.0)(rollup@4.61.0)(vite@8.2.2(@types/node@25.6.0)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.46.1)(tsx@4.23.14)(yaml@2.9.0))(webpack@5.102.1(esbuild@0.28.1)) transitivePeerDependencies: - supports-color @@ -21122,14 +20991,14 @@ snapshots: react: 18.3.1 react-dom: 18.3.1(react@18.3.1) - '@tanstack/react-start-rsc@0.1.59(@rspack/core@2.0.6)(esbuild@0.28.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(rolldown@1.1.0)(rollup@4.61.0)(vite@8.2.2(@types/node@25.6.0)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.46.1)(tsx@4.20.6)(yaml@2.9.0))(webpack@5.102.1(esbuild@0.28.1))': + '@tanstack/react-start-rsc@0.1.59(@rspack/core@2.0.6)(esbuild@0.28.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(rolldown@1.1.0)(rollup@4.61.0)(vite@8.2.2(@types/node@25.6.0)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.46.1)(tsx@4.23.14)(yaml@2.9.0))(webpack@5.102.1(esbuild@0.28.1))': dependencies: '@tanstack/react-router': 1.170.41(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@tanstack/router-core': 1.171.34 '@tanstack/router-utils': 1.162.3 '@tanstack/start-client-core': 1.170.34 '@tanstack/start-fn-stubs': 1.162.0 - '@tanstack/start-plugin-core': 1.171.49(@rspack/core@2.0.6)(@tanstack/react-router@1.170.41(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(esbuild@0.28.1)(rolldown@1.1.0)(rollup@4.61.0)(vite@8.2.2(@types/node@25.6.0)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.46.1)(tsx@4.20.6)(yaml@2.9.0))(webpack@5.102.1(esbuild@0.28.1)) + '@tanstack/start-plugin-core': 1.171.49(@rspack/core@2.0.6)(@tanstack/react-router@1.170.41(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(esbuild@0.28.1)(rolldown@1.1.0)(rollup@4.61.0)(vite@8.2.2(@types/node@25.6.0)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.46.1)(tsx@4.23.14)(yaml@2.9.0))(webpack@5.102.1(esbuild@0.28.1)) '@tanstack/start-storage-context': 1.167.36 pathe: 2.0.3 react: 18.3.1 @@ -21160,21 +21029,21 @@ snapshots: transitivePeerDependencies: - crossws - '@tanstack/react-start@1.168.60(@rspack/core@2.0.6)(esbuild@0.28.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(rolldown@1.1.0)(rollup@4.61.0)(vite@8.2.2(@types/node@25.6.0)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.46.1)(tsx@4.20.6)(yaml@2.9.0))(webpack@5.102.1(esbuild@0.28.1))': + '@tanstack/react-start@1.168.60(@rspack/core@2.0.6)(esbuild@0.28.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(rolldown@1.1.0)(rollup@4.61.0)(vite@8.2.2(@types/node@25.6.0)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.46.1)(tsx@4.23.14)(yaml@2.9.0))(webpack@5.102.1(esbuild@0.28.1))': dependencies: '@tanstack/react-router': 1.170.41(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@tanstack/react-start-client': 1.168.39(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@tanstack/react-start-rsc': 0.1.59(@rspack/core@2.0.6)(esbuild@0.28.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(rolldown@1.1.0)(rollup@4.61.0)(vite@8.2.2(@types/node@25.6.0)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.46.1)(tsx@4.20.6)(yaml@2.9.0))(webpack@5.102.1(esbuild@0.28.1)) + '@tanstack/react-start-rsc': 0.1.59(@rspack/core@2.0.6)(esbuild@0.28.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(rolldown@1.1.0)(rollup@4.61.0)(vite@8.2.2(@types/node@25.6.0)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.46.1)(tsx@4.23.14)(yaml@2.9.0))(webpack@5.102.1(esbuild@0.28.1)) '@tanstack/react-start-server': 1.167.46(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@tanstack/router-utils': 1.162.3 '@tanstack/start-client-core': 1.170.34 - '@tanstack/start-plugin-core': 1.171.49(@rspack/core@2.0.6)(@tanstack/react-router@1.170.41(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(esbuild@0.28.1)(rolldown@1.1.0)(rollup@4.61.0)(vite@8.2.2(@types/node@25.6.0)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.46.1)(tsx@4.20.6)(yaml@2.9.0))(webpack@5.102.1(esbuild@0.28.1)) + '@tanstack/start-plugin-core': 1.171.49(@rspack/core@2.0.6)(@tanstack/react-router@1.170.41(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(esbuild@0.28.1)(rolldown@1.1.0)(rollup@4.61.0)(vite@8.2.2(@types/node@25.6.0)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.46.1)(tsx@4.23.14)(yaml@2.9.0))(webpack@5.102.1(esbuild@0.28.1)) '@tanstack/start-server-core': 1.169.39 pathe: 2.0.3 react: 18.3.1 react-dom: 18.3.1(react@18.3.1) optionalDependencies: - vite: 8.2.2(@types/node@25.6.0)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.46.1)(tsx@4.20.6)(yaml@2.9.0) + vite: 8.2.2(@types/node@25.6.0)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.46.1)(tsx@4.23.14)(yaml@2.9.0) transitivePeerDependencies: - '@farmfe/core' - '@rspack/core' @@ -21216,7 +21085,7 @@ snapshots: transitivePeerDependencies: - supports-color - '@tanstack/router-plugin@1.168.42(@rspack/core@2.0.6)(@tanstack/react-router@1.170.41(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(esbuild@0.28.1)(rolldown@1.1.0)(rollup@4.61.0)(vite@8.2.2(@types/node@25.6.0)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.46.1)(tsx@4.20.6)(yaml@2.9.0))(webpack@5.102.1(esbuild@0.28.1))': + '@tanstack/router-plugin@1.168.42(@rspack/core@2.0.6)(@tanstack/react-router@1.170.41(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(esbuild@0.28.1)(rolldown@1.1.0)(rollup@4.61.0)(vite@8.2.2(@types/node@25.6.0)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.46.1)(tsx@4.23.14)(yaml@2.9.0))(webpack@5.102.1(esbuild@0.28.1))': dependencies: '@babel/core': 7.29.7 '@babel/template': 7.29.7 @@ -21225,11 +21094,11 @@ snapshots: '@tanstack/router-generator': 1.167.40 '@tanstack/router-utils': 1.162.3 chokidar: 5.0.0 - unplugin: 3.3.0(@rspack/core@2.0.6)(esbuild@0.28.1)(rolldown@1.1.0)(rollup@4.61.0)(vite@8.2.2(@types/node@25.6.0)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.46.1)(tsx@4.20.6)(yaml@2.9.0))(webpack@5.102.1(esbuild@0.28.1)) + unplugin: 3.3.0(@rspack/core@2.0.6)(esbuild@0.28.1)(rolldown@1.1.0)(rollup@4.61.0)(vite@8.2.2(@types/node@25.6.0)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.46.1)(tsx@4.23.14)(yaml@2.9.0))(webpack@5.102.1(esbuild@0.28.1)) zod: 4.6.5 optionalDependencies: '@tanstack/react-router': 1.170.41(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - vite: 8.2.2(@types/node@25.6.0)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.46.1)(tsx@4.20.6)(yaml@2.9.0) + vite: 8.2.2(@types/node@25.6.0)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.46.1)(tsx@4.23.14)(yaml@2.9.0) webpack: 5.102.1(esbuild@0.28.1) transitivePeerDependencies: - '@farmfe/core' @@ -21263,7 +21132,7 @@ snapshots: '@tanstack/start-fn-stubs@1.162.0': {} - '@tanstack/start-plugin-core@1.171.49(@rspack/core@2.0.6)(@tanstack/react-router@1.170.41(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(esbuild@0.28.1)(rolldown@1.1.0)(rollup@4.61.0)(vite@8.2.2(@types/node@25.6.0)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.46.1)(tsx@4.20.6)(yaml@2.9.0))(webpack@5.102.1(esbuild@0.28.1))': + '@tanstack/start-plugin-core@1.171.49(@rspack/core@2.0.6)(@tanstack/react-router@1.170.41(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(esbuild@0.28.1)(rolldown@1.1.0)(rollup@4.61.0)(vite@8.2.2(@types/node@25.6.0)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.46.1)(tsx@4.23.14)(yaml@2.9.0))(webpack@5.102.1(esbuild@0.28.1))': dependencies: '@babel/code-frame': 7.29.7 '@babel/core': 7.29.7 @@ -21271,7 +21140,7 @@ snapshots: '@jridgewell/remapping': 2.3.5 '@tanstack/router-core': 1.171.34 '@tanstack/router-generator': 1.167.40 - '@tanstack/router-plugin': 1.168.42(@rspack/core@2.0.6)(@tanstack/react-router@1.170.41(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(esbuild@0.28.1)(rolldown@1.1.0)(rollup@4.61.0)(vite@8.2.2(@types/node@25.6.0)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.46.1)(tsx@4.20.6)(yaml@2.9.0))(webpack@5.102.1(esbuild@0.28.1)) + '@tanstack/router-plugin': 1.168.42(@rspack/core@2.0.6)(@tanstack/react-router@1.170.41(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(esbuild@0.28.1)(rolldown@1.1.0)(rollup@4.61.0)(vite@8.2.2(@types/node@25.6.0)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.46.1)(tsx@4.23.14)(yaml@2.9.0))(webpack@5.102.1(esbuild@0.28.1)) '@tanstack/router-utils': 1.162.3 '@tanstack/start-server-core': 1.169.39 exsolve: 1.1.1 @@ -21283,11 +21152,11 @@ snapshots: srvx: 0.11.22 tinyglobby: 0.2.17 ufo: 1.6.4 - vitefu: 1.1.3(vite@8.2.2(@types/node@25.6.0)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.46.1)(tsx@4.20.6)(yaml@2.9.0)) + vitefu: 1.1.3(vite@8.2.2(@types/node@25.6.0)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.46.1)(tsx@4.23.14)(yaml@2.9.0)) xmlbuilder2: 4.0.3 zod: 4.6.5 optionalDependencies: - vite: 8.2.2(@types/node@25.6.0)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.46.1)(tsx@4.20.6)(yaml@2.9.0) + vite: 8.2.2(@types/node@25.6.0)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.46.1)(tsx@4.23.14)(yaml@2.9.0) transitivePeerDependencies: - '@farmfe/core' - '@rspack/core' @@ -21791,17 +21660,17 @@ snapshots: '@ungap/structured-clone@1.3.0': {} - '@unhead/bundler@3.4.0(@oxc-project/types@0.134.0)(@rspack/core@2.0.6)(esbuild@0.28.1)(lightningcss@1.33.0)(rolldown@1.1.0)(rollup@4.61.0)(unhead@3.4.0(@rspack/core@2.0.6)(esbuild@0.28.1)(rolldown@1.1.0)(rollup@4.61.0)(vite@8.2.2(@types/node@25.6.0)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.46.1)(tsx@4.20.6)(yaml@2.9.0))(webpack@5.102.1(esbuild@0.28.1)))(vite@8.2.2(@types/node@25.6.0)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.46.1)(tsx@4.20.6)(yaml@2.9.0))(webpack@5.102.1(esbuild@0.28.1))': + '@unhead/bundler@3.4.0(@oxc-project/types@0.134.0)(@rspack/core@2.0.6)(esbuild@0.28.1)(lightningcss@1.33.0)(rolldown@1.1.0)(rollup@4.61.0)(unhead@3.4.0(@rspack/core@2.0.6)(esbuild@0.28.1)(rolldown@1.1.0)(rollup@4.61.0)(vite@8.2.2(@types/node@25.6.0)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.46.1)(tsx@4.23.14)(yaml@2.9.0))(webpack@5.102.1(esbuild@0.28.1)))(vite@8.2.2(@types/node@25.6.0)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.46.1)(tsx@4.23.14)(yaml@2.9.0))(webpack@5.102.1(esbuild@0.28.1))': dependencies: magic-string: 1.2.3 oxc-walker: 1.1.1(@oxc-project/types@0.134.0)(rolldown@1.1.0) - unhead: 3.4.0(@rspack/core@2.0.6)(esbuild@0.28.1)(rolldown@1.1.0)(rollup@4.61.0)(vite@8.2.2(@types/node@25.6.0)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.46.1)(tsx@4.20.6)(yaml@2.9.0))(webpack@5.102.1(esbuild@0.28.1)) - unplugin: 3.3.0(@rspack/core@2.0.6)(esbuild@0.28.1)(rolldown@1.1.0)(rollup@4.61.0)(vite@8.2.2(@types/node@25.6.0)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.46.1)(tsx@4.20.6)(yaml@2.9.0))(webpack@5.102.1(esbuild@0.28.1)) + unhead: 3.4.0(@rspack/core@2.0.6)(esbuild@0.28.1)(rolldown@1.1.0)(rollup@4.61.0)(vite@8.2.2(@types/node@25.6.0)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.46.1)(tsx@4.23.14)(yaml@2.9.0))(webpack@5.102.1(esbuild@0.28.1)) + unplugin: 3.3.0(@rspack/core@2.0.6)(esbuild@0.28.1)(rolldown@1.1.0)(rollup@4.61.0)(vite@8.2.2(@types/node@25.6.0)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.46.1)(tsx@4.23.14)(yaml@2.9.0))(webpack@5.102.1(esbuild@0.28.1)) optionalDependencies: esbuild: 0.28.1 lightningcss: 1.33.0 rolldown: 1.1.0 - vite: 8.2.2(@types/node@25.6.0)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.46.1)(tsx@4.20.6)(yaml@2.9.0) + vite: 8.2.2(@types/node@25.6.0)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.46.1)(tsx@4.23.14)(yaml@2.9.0) webpack: 5.102.1(esbuild@0.28.1) transitivePeerDependencies: - '@farmfe/core' @@ -21811,15 +21680,15 @@ snapshots: - rollup - unloader - '@unhead/vue@3.4.0(@oxc-project/types@0.134.0)(@rspack/core@2.0.6)(esbuild@0.28.1)(lightningcss@1.33.0)(rolldown@1.1.0)(rollup@4.61.0)(vite@8.2.2(@types/node@25.6.0)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.46.1)(tsx@4.20.6)(yaml@2.9.0))(vue@3.5.42(typescript@6.0.3))(webpack@5.102.1(esbuild@0.28.1))': + '@unhead/vue@3.4.0(@oxc-project/types@0.134.0)(@rspack/core@2.0.6)(esbuild@0.28.1)(lightningcss@1.33.0)(rolldown@1.1.0)(rollup@4.61.0)(vite@8.2.2(@types/node@25.6.0)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.46.1)(tsx@4.23.14)(yaml@2.9.0))(vue@3.5.42(typescript@6.0.3))(webpack@5.102.1(esbuild@0.28.1))': dependencies: - '@unhead/bundler': 3.4.0(@oxc-project/types@0.134.0)(@rspack/core@2.0.6)(esbuild@0.28.1)(lightningcss@1.33.0)(rolldown@1.1.0)(rollup@4.61.0)(unhead@3.4.0(@rspack/core@2.0.6)(esbuild@0.28.1)(rolldown@1.1.0)(rollup@4.61.0)(vite@8.2.2(@types/node@25.6.0)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.46.1)(tsx@4.20.6)(yaml@2.9.0))(webpack@5.102.1(esbuild@0.28.1)))(vite@8.2.2(@types/node@25.6.0)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.46.1)(tsx@4.20.6)(yaml@2.9.0))(webpack@5.102.1(esbuild@0.28.1)) + '@unhead/bundler': 3.4.0(@oxc-project/types@0.134.0)(@rspack/core@2.0.6)(esbuild@0.28.1)(lightningcss@1.33.0)(rolldown@1.1.0)(rollup@4.61.0)(unhead@3.4.0(@rspack/core@2.0.6)(esbuild@0.28.1)(rolldown@1.1.0)(rollup@4.61.0)(vite@8.2.2(@types/node@25.6.0)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.46.1)(tsx@4.23.14)(yaml@2.9.0))(webpack@5.102.1(esbuild@0.28.1)))(vite@8.2.2(@types/node@25.6.0)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.46.1)(tsx@4.23.14)(yaml@2.9.0))(webpack@5.102.1(esbuild@0.28.1)) hookable: 6.1.1 - unhead: 3.4.0(@rspack/core@2.0.6)(esbuild@0.28.1)(rolldown@1.1.0)(rollup@4.61.0)(vite@8.2.2(@types/node@25.6.0)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.46.1)(tsx@4.20.6)(yaml@2.9.0))(webpack@5.102.1(esbuild@0.28.1)) - unplugin: 3.3.0(@rspack/core@2.0.6)(esbuild@0.28.1)(rolldown@1.1.0)(rollup@4.61.0)(vite@8.2.2(@types/node@25.6.0)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.46.1)(tsx@4.20.6)(yaml@2.9.0))(webpack@5.102.1(esbuild@0.28.1)) + unhead: 3.4.0(@rspack/core@2.0.6)(esbuild@0.28.1)(rolldown@1.1.0)(rollup@4.61.0)(vite@8.2.2(@types/node@25.6.0)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.46.1)(tsx@4.23.14)(yaml@2.9.0))(webpack@5.102.1(esbuild@0.28.1)) + unplugin: 3.3.0(@rspack/core@2.0.6)(esbuild@0.28.1)(rolldown@1.1.0)(rollup@4.61.0)(vite@8.2.2(@types/node@25.6.0)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.46.1)(tsx@4.23.14)(yaml@2.9.0))(webpack@5.102.1(esbuild@0.28.1)) vue: 3.5.42(typescript@6.0.3) optionalDependencies: - vite: 8.2.2(@types/node@25.6.0)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.46.1)(tsx@4.20.6)(yaml@2.9.0) + vite: 8.2.2(@types/node@25.6.0)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.46.1)(tsx@4.23.14)(yaml@2.9.0) webpack: 5.102.1(esbuild@0.28.1) transitivePeerDependencies: - '@farmfe/core' @@ -21925,7 +21794,7 @@ snapshots: - rollup - supports-color - '@vitejs/plugin-react@4.7.0(vite@8.2.2(@types/node@22.20.1)(esbuild@0.27.7)(jiti@2.7.0)(terser@5.46.1)(tsx@4.20.6)(yaml@2.9.0))': + '@vitejs/plugin-react@4.7.0(vite@8.2.2(@types/node@22.20.1)(esbuild@0.27.7)(jiti@2.7.0)(terser@5.46.1)(tsx@4.23.14)(yaml@2.9.0))': dependencies: '@babel/core': 7.29.7 '@babel/plugin-transform-react-jsx-self': 7.27.1(@babel/core@7.29.7) @@ -21933,54 +21802,54 @@ snapshots: '@rolldown/pluginutils': 1.0.0-beta.27 '@types/babel__core': 7.20.5 react-refresh: 0.17.0 - vite: 8.2.2(@types/node@22.20.1)(esbuild@0.27.7)(jiti@2.7.0)(terser@5.46.1)(tsx@4.20.6)(yaml@2.9.0) + vite: 8.2.2(@types/node@22.20.1)(esbuild@0.27.7)(jiti@2.7.0)(terser@5.46.1)(tsx@4.23.14)(yaml@2.9.0) transitivePeerDependencies: - supports-color - '@vitejs/plugin-vue-jsx@5.1.6(vite@8.2.2(@types/node@25.6.0)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.46.1)(tsx@4.20.6)(yaml@2.9.0))(vue@3.5.42(typescript@6.0.3))': + '@vitejs/plugin-vue-jsx@5.1.6(vite@8.2.2(@types/node@25.6.0)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.46.1)(tsx@4.23.14)(yaml@2.9.0))(vue@3.5.42(typescript@6.0.3))': dependencies: '@babel/core': 7.29.7 '@babel/plugin-syntax-typescript': 7.29.7(@babel/core@7.29.7) '@babel/plugin-transform-typescript': 7.29.7(@babel/core@7.29.7) '@rolldown/pluginutils': 1.0.1 '@vue/babel-plugin-jsx': 2.0.1(@babel/core@7.29.7) - vite: 8.2.2(@types/node@25.6.0)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.46.1)(tsx@4.20.6)(yaml@2.9.0) + vite: 8.2.2(@types/node@25.6.0)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.46.1)(tsx@4.23.14)(yaml@2.9.0) vue: 3.5.42(typescript@6.0.3) transitivePeerDependencies: - supports-color - '@vitejs/plugin-vue@6.0.8(vite@8.2.2(@types/node@25.6.0)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.46.1)(tsx@4.20.6)(yaml@2.9.0))(vue@3.5.33(typescript@6.0.3))': + '@vitejs/plugin-vue@6.0.8(vite@8.2.2(@types/node@25.6.0)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.46.1)(tsx@4.23.14)(yaml@2.9.0))(vue@3.5.33(typescript@6.0.3))': dependencies: '@rolldown/pluginutils': 1.0.1 - vite: 8.2.2(@types/node@25.6.0)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.46.1)(tsx@4.20.6)(yaml@2.9.0) + vite: 8.2.2(@types/node@25.6.0)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.46.1)(tsx@4.23.14)(yaml@2.9.0) vue: 3.5.33(typescript@6.0.3) - '@vitejs/plugin-vue@6.0.8(vite@8.2.2(@types/node@25.6.0)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.46.1)(tsx@4.20.6)(yaml@2.9.0))(vue@3.5.42(typescript@6.0.3))': + '@vitejs/plugin-vue@6.0.8(vite@8.2.2(@types/node@25.6.0)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.46.1)(tsx@4.23.14)(yaml@2.9.0))(vue@3.5.42(typescript@6.0.3))': dependencies: '@rolldown/pluginutils': 1.0.1 - vite: 8.2.2(@types/node@25.6.0)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.46.1)(tsx@4.20.6)(yaml@2.9.0) + vite: 8.2.2(@types/node@25.6.0)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.46.1)(tsx@4.23.14)(yaml@2.9.0) vue: 3.5.42(typescript@6.0.3) - '@vitest/browser-playwright@5.0.0(bufferutil@4.1.0)(msw@2.15.0(@types/node@22.20.1)(typescript@6.0.3))(playwright@1.62.1)(utf-8-validate@5.0.10)(vite@8.2.2(@types/node@22.20.1)(esbuild@0.27.7)(jiti@2.7.0)(terser@5.46.1)(tsx@4.20.6)(yaml@2.9.0))(vitest@5.0.0)': + '@vitest/browser-playwright@5.0.0(bufferutil@4.1.0)(msw@2.15.0(@types/node@22.20.1)(typescript@6.0.3))(playwright@1.62.1)(utf-8-validate@5.0.10)(vite@8.2.2(@types/node@22.20.1)(esbuild@0.27.7)(jiti@2.7.0)(terser@5.46.1)(tsx@4.23.14)(yaml@2.9.0))(vitest@5.0.0)': dependencies: - '@vitest/browser': 5.0.0(bufferutil@4.1.0)(msw@2.15.0(@types/node@22.20.1)(typescript@6.0.3))(utf-8-validate@5.0.10)(vite@8.2.2(@types/node@22.20.1)(esbuild@0.27.7)(jiti@2.7.0)(terser@5.46.1)(tsx@4.20.6)(yaml@2.9.0))(vitest@5.0.0) - '@vitest/mocker': 5.0.0(msw@2.15.0(@types/node@22.20.1)(typescript@6.0.3))(vite@8.2.2(@types/node@22.20.1)(esbuild@0.27.7)(jiti@2.7.0)(terser@5.46.1)(tsx@4.20.6)(yaml@2.9.0)) + '@vitest/browser': 5.0.0(bufferutil@4.1.0)(msw@2.15.0(@types/node@22.20.1)(typescript@6.0.3))(utf-8-validate@5.0.10)(vite@8.2.2(@types/node@22.20.1)(esbuild@0.27.7)(jiti@2.7.0)(terser@5.46.1)(tsx@4.23.14)(yaml@2.9.0))(vitest@5.0.0) + '@vitest/mocker': 5.0.0(msw@2.15.0(@types/node@22.20.1)(typescript@6.0.3))(vite@8.2.2(@types/node@22.20.1)(esbuild@0.27.7)(jiti@2.7.0)(terser@5.46.1)(tsx@4.23.14)(yaml@2.9.0)) playwright: 1.62.1 tinyrainbow: 3.1.1 - vitest: 5.0.0(@edge-runtime/vm@5.0.0)(@opentelemetry/api@1.9.0)(@types/node@22.20.1)(@vitest/browser-playwright@5.0.0)(@vitest/coverage-v8@5.0.0)(@vitest/ui@5.0.0)(happy-dom@20.10.2(bufferutil@4.1.0)(utf-8-validate@5.0.10))(jsdom@27.0.0(bufferutil@4.1.0)(utf-8-validate@5.0.10))(msw@2.15.0(@types/node@22.20.1)(typescript@6.0.3))(vite@8.2.2(@types/node@22.20.1)(esbuild@0.27.7)(jiti@2.7.0)(terser@5.46.1)(tsx@4.20.6)(yaml@2.9.0)) + vitest: 5.0.0(@edge-runtime/vm@5.0.0)(@opentelemetry/api@1.9.0)(@types/node@22.20.1)(@vitest/browser-playwright@5.0.0)(@vitest/coverage-v8@5.0.0)(@vitest/ui@5.0.0)(happy-dom@20.10.2(bufferutil@4.1.0)(utf-8-validate@5.0.10))(jsdom@27.0.0(bufferutil@4.1.0)(utf-8-validate@5.0.10))(msw@2.15.0(@types/node@22.20.1)(typescript@6.0.3))(vite@8.2.2(@types/node@22.20.1)(esbuild@0.27.7)(jiti@2.7.0)(terser@5.46.1)(tsx@4.23.14)(yaml@2.9.0)) transitivePeerDependencies: - bufferutil - msw - utf-8-validate - vite - '@vitest/browser-playwright@5.0.0(bufferutil@4.1.0)(msw@2.15.0(@types/node@22.20.1)(typescript@6.0.3))(playwright@1.62.1)(utf-8-validate@5.0.10)(vite@8.2.2(@types/node@22.20.1)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.46.1)(tsx@4.20.6)(yaml@2.9.0))(vitest@5.0.0)': + '@vitest/browser-playwright@5.0.0(bufferutil@4.1.0)(msw@2.15.0(@types/node@22.20.1)(typescript@6.0.3))(playwright@1.62.1)(utf-8-validate@5.0.10)(vite@8.2.2(@types/node@22.20.1)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.46.1)(tsx@4.23.14)(yaml@2.9.0))(vitest@5.0.0)': dependencies: - '@vitest/browser': 5.0.0(bufferutil@4.1.0)(msw@2.15.0(@types/node@22.20.1)(typescript@6.0.3))(utf-8-validate@5.0.10)(vite@8.2.2(@types/node@22.20.1)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.46.1)(tsx@4.20.6)(yaml@2.9.0))(vitest@5.0.0) - '@vitest/mocker': 5.0.0(msw@2.15.0(@types/node@22.20.1)(typescript@6.0.3))(vite@8.2.2(@types/node@22.20.1)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.46.1)(tsx@4.20.6)(yaml@2.9.0)) + '@vitest/browser': 5.0.0(bufferutil@4.1.0)(msw@2.15.0(@types/node@22.20.1)(typescript@6.0.3))(utf-8-validate@5.0.10)(vite@8.2.2(@types/node@22.20.1)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.46.1)(tsx@4.23.14)(yaml@2.9.0))(vitest@5.0.0) + '@vitest/mocker': 5.0.0(msw@2.15.0(@types/node@22.20.1)(typescript@6.0.3))(vite@8.2.2(@types/node@22.20.1)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.46.1)(tsx@4.23.14)(yaml@2.9.0)) playwright: 1.62.1 tinyrainbow: 3.1.1 - vitest: 5.0.0(@edge-runtime/vm@5.0.0)(@opentelemetry/api@1.9.0)(@types/node@22.20.1)(@vitest/browser-playwright@5.0.0)(@vitest/coverage-v8@5.0.0)(@vitest/ui@5.0.0)(happy-dom@20.10.2(bufferutil@4.1.0)(utf-8-validate@5.0.10))(jsdom@27.0.0(bufferutil@4.1.0)(utf-8-validate@5.0.10))(msw@2.15.0(@types/node@22.20.1)(typescript@6.0.3))(vite@8.2.2(@types/node@22.20.1)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.46.1)(tsx@4.20.6)(yaml@2.9.0)) + vitest: 5.0.0(@edge-runtime/vm@5.0.0)(@opentelemetry/api@1.9.0)(@types/node@22.20.1)(@vitest/browser-playwright@5.0.0)(@vitest/coverage-v8@5.0.0)(@vitest/ui@5.0.0)(happy-dom@20.10.2(bufferutil@4.1.0)(utf-8-validate@5.0.10))(jsdom@27.0.0(bufferutil@4.1.0)(utf-8-validate@5.0.10))(msw@2.15.0(@types/node@22.20.1)(typescript@6.0.3))(vite@8.2.2(@types/node@22.20.1)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.46.1)(tsx@4.23.14)(yaml@2.9.0)) transitivePeerDependencies: - bufferutil - msw @@ -21988,13 +21857,13 @@ snapshots: - vite optional: true - '@vitest/browser-playwright@5.0.0(bufferutil@4.1.0)(msw@2.15.0(@types/node@25.6.0)(typescript@6.0.3))(playwright@1.62.1)(utf-8-validate@5.0.10)(vite@8.2.2(@types/node@25.6.0)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.46.1)(tsx@4.20.6)(yaml@2.9.0))(vitest@5.0.0)': + '@vitest/browser-playwright@5.0.0(bufferutil@4.1.0)(msw@2.15.0(@types/node@25.6.0)(typescript@6.0.3))(playwright@1.62.1)(utf-8-validate@5.0.10)(vite@8.2.2(@types/node@25.6.0)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.46.1)(tsx@4.23.14)(yaml@2.9.0))(vitest@5.0.0)': dependencies: - '@vitest/browser': 5.0.0(bufferutil@4.1.0)(msw@2.15.0(@types/node@25.6.0)(typescript@6.0.3))(utf-8-validate@5.0.10)(vite@8.2.2(@types/node@25.6.0)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.46.1)(tsx@4.20.6)(yaml@2.9.0))(vitest@5.0.0) - '@vitest/mocker': 5.0.0(msw@2.15.0(@types/node@25.6.0)(typescript@6.0.3))(vite@8.2.2(@types/node@25.6.0)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.46.1)(tsx@4.20.6)(yaml@2.9.0)) + '@vitest/browser': 5.0.0(bufferutil@4.1.0)(msw@2.15.0(@types/node@25.6.0)(typescript@6.0.3))(utf-8-validate@5.0.10)(vite@8.2.2(@types/node@25.6.0)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.46.1)(tsx@4.23.14)(yaml@2.9.0))(vitest@5.0.0) + '@vitest/mocker': 5.0.0(msw@2.15.0(@types/node@25.6.0)(typescript@6.0.3))(vite@8.2.2(@types/node@25.6.0)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.46.1)(tsx@4.23.14)(yaml@2.9.0)) playwright: 1.62.1 tinyrainbow: 3.1.1 - vitest: 5.0.0(@edge-runtime/vm@5.0.0)(@opentelemetry/api@1.9.0)(@types/node@25.6.0)(@vitest/browser-playwright@5.0.0)(@vitest/coverage-v8@5.0.0)(@vitest/ui@5.0.0)(happy-dom@20.10.2(bufferutil@4.1.0)(utf-8-validate@5.0.10))(jsdom@27.0.0(bufferutil@4.1.0)(utf-8-validate@5.0.10))(msw@2.15.0(@types/node@25.6.0)(typescript@6.0.3))(vite@8.2.2(@types/node@25.6.0)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.46.1)(tsx@4.20.6)(yaml@2.9.0)) + vitest: 5.0.0(@edge-runtime/vm@5.0.0)(@opentelemetry/api@1.9.0)(@types/node@25.6.0)(@vitest/browser-playwright@5.0.0)(@vitest/coverage-v8@5.0.0)(@vitest/ui@5.0.0)(happy-dom@20.10.2(bufferutil@4.1.0)(utf-8-validate@5.0.10))(jsdom@27.0.0(bufferutil@4.1.0)(utf-8-validate@5.0.10))(msw@2.15.0(@types/node@25.6.0)(typescript@6.0.3))(vite@8.2.2(@types/node@25.6.0)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.46.1)(tsx@4.23.14)(yaml@2.9.0)) transitivePeerDependencies: - bufferutil - msw @@ -22002,17 +21871,17 @@ snapshots: - vite optional: true - '@vitest/browser@5.0.0(bufferutil@4.1.0)(msw@2.15.0(@types/node@22.20.1)(typescript@6.0.3))(utf-8-validate@5.0.10)(vite@8.2.2(@types/node@22.20.1)(esbuild@0.27.7)(jiti@2.7.0)(terser@5.46.1)(tsx@4.20.6)(yaml@2.9.0))(vitest@5.0.0)': + '@vitest/browser@5.0.0(bufferutil@4.1.0)(msw@2.15.0(@types/node@22.20.1)(typescript@6.0.3))(utf-8-validate@5.0.10)(vite@8.2.2(@types/node@22.20.1)(esbuild@0.27.7)(jiti@2.7.0)(terser@5.46.1)(tsx@4.23.14)(yaml@2.9.0))(vitest@5.0.0)': dependencies: '@blazediff/core': 1.10.0 - '@vitest/mocker': 5.0.0(msw@2.15.0(@types/node@22.20.1)(typescript@6.0.3))(vite@8.2.2(@types/node@22.20.1)(esbuild@0.27.7)(jiti@2.7.0)(terser@5.46.1)(tsx@4.20.6)(yaml@2.9.0)) + '@vitest/mocker': 5.0.0(msw@2.15.0(@types/node@22.20.1)(typescript@6.0.3))(vite@8.2.2(@types/node@22.20.1)(esbuild@0.27.7)(jiti@2.7.0)(terser@5.46.1)(tsx@4.23.14)(yaml@2.9.0)) '@vitest/ui': 5.0.0(vitest@5.0.0) '@vitest/utils': 5.0.0 magic-string: 1.2.3 pngjs: 7.0.0 sirv: 3.0.2 tinyrainbow: 3.1.1 - vitest: 5.0.0(@edge-runtime/vm@5.0.0)(@opentelemetry/api@1.9.0)(@types/node@22.20.1)(@vitest/browser-playwright@5.0.0)(@vitest/coverage-v8@5.0.0)(@vitest/ui@5.0.0)(happy-dom@20.10.2(bufferutil@4.1.0)(utf-8-validate@5.0.10))(jsdom@27.0.0(bufferutil@4.1.0)(utf-8-validate@5.0.10))(msw@2.15.0(@types/node@22.20.1)(typescript@6.0.3))(vite@8.2.2(@types/node@22.20.1)(esbuild@0.27.7)(jiti@2.7.0)(terser@5.46.1)(tsx@4.20.6)(yaml@2.9.0)) + vitest: 5.0.0(@edge-runtime/vm@5.0.0)(@opentelemetry/api@1.9.0)(@types/node@22.20.1)(@vitest/browser-playwright@5.0.0)(@vitest/coverage-v8@5.0.0)(@vitest/ui@5.0.0)(happy-dom@20.10.2(bufferutil@4.1.0)(utf-8-validate@5.0.10))(jsdom@27.0.0(bufferutil@4.1.0)(utf-8-validate@5.0.10))(msw@2.15.0(@types/node@22.20.1)(typescript@6.0.3))(vite@8.2.2(@types/node@22.20.1)(esbuild@0.27.7)(jiti@2.7.0)(terser@5.46.1)(tsx@4.23.14)(yaml@2.9.0)) ws: 8.21.3(bufferutil@4.1.0)(utf-8-validate@5.0.10) transitivePeerDependencies: - bufferutil @@ -22020,17 +21889,17 @@ snapshots: - utf-8-validate - vite - '@vitest/browser@5.0.0(bufferutil@4.1.0)(msw@2.15.0(@types/node@22.20.1)(typescript@6.0.3))(utf-8-validate@5.0.10)(vite@8.2.2(@types/node@22.20.1)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.46.1)(tsx@4.20.6)(yaml@2.9.0))(vitest@5.0.0)': + '@vitest/browser@5.0.0(bufferutil@4.1.0)(msw@2.15.0(@types/node@22.20.1)(typescript@6.0.3))(utf-8-validate@5.0.10)(vite@8.2.2(@types/node@22.20.1)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.46.1)(tsx@4.23.14)(yaml@2.9.0))(vitest@5.0.0)': dependencies: '@blazediff/core': 1.10.0 - '@vitest/mocker': 5.0.0(msw@2.15.0(@types/node@22.20.1)(typescript@6.0.3))(vite@8.2.2(@types/node@22.20.1)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.46.1)(tsx@4.20.6)(yaml@2.9.0)) + '@vitest/mocker': 5.0.0(msw@2.15.0(@types/node@22.20.1)(typescript@6.0.3))(vite@8.2.2(@types/node@22.20.1)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.46.1)(tsx@4.23.14)(yaml@2.9.0)) '@vitest/ui': 5.0.0(vitest@5.0.0) '@vitest/utils': 5.0.0 magic-string: 1.2.3 pngjs: 7.0.0 sirv: 3.0.2 tinyrainbow: 3.1.1 - vitest: 5.0.0(@edge-runtime/vm@5.0.0)(@opentelemetry/api@1.9.0)(@types/node@22.20.1)(@vitest/browser-playwright@5.0.0)(@vitest/coverage-v8@5.0.0)(@vitest/ui@5.0.0)(happy-dom@20.10.2(bufferutil@4.1.0)(utf-8-validate@5.0.10))(jsdom@27.0.0(bufferutil@4.1.0)(utf-8-validate@5.0.10))(msw@2.15.0(@types/node@22.20.1)(typescript@6.0.3))(vite@8.2.2(@types/node@22.20.1)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.46.1)(tsx@4.20.6)(yaml@2.9.0)) + vitest: 5.0.0(@edge-runtime/vm@5.0.0)(@opentelemetry/api@1.9.0)(@types/node@22.20.1)(@vitest/browser-playwright@5.0.0)(@vitest/coverage-v8@5.0.0)(@vitest/ui@5.0.0)(happy-dom@20.10.2(bufferutil@4.1.0)(utf-8-validate@5.0.10))(jsdom@27.0.0(bufferutil@4.1.0)(utf-8-validate@5.0.10))(msw@2.15.0(@types/node@22.20.1)(typescript@6.0.3))(vite@8.2.2(@types/node@22.20.1)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.46.1)(tsx@4.23.14)(yaml@2.9.0)) ws: 8.21.3(bufferutil@4.1.0)(utf-8-validate@5.0.10) transitivePeerDependencies: - bufferutil @@ -22039,17 +21908,17 @@ snapshots: - vite optional: true - '@vitest/browser@5.0.0(bufferutil@4.1.0)(msw@2.15.0(@types/node@25.6.0)(typescript@6.0.3))(utf-8-validate@5.0.10)(vite@8.2.2(@types/node@25.6.0)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.46.1)(tsx@4.20.6)(yaml@2.9.0))(vitest@5.0.0)': + '@vitest/browser@5.0.0(bufferutil@4.1.0)(msw@2.15.0(@types/node@25.6.0)(typescript@6.0.3))(utf-8-validate@5.0.10)(vite@8.2.2(@types/node@25.6.0)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.46.1)(tsx@4.23.14)(yaml@2.9.0))(vitest@5.0.0)': dependencies: '@blazediff/core': 1.10.0 - '@vitest/mocker': 5.0.0(msw@2.15.0(@types/node@25.6.0)(typescript@6.0.3))(vite@8.2.2(@types/node@25.6.0)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.46.1)(tsx@4.20.6)(yaml@2.9.0)) + '@vitest/mocker': 5.0.0(msw@2.15.0(@types/node@25.6.0)(typescript@6.0.3))(vite@8.2.2(@types/node@25.6.0)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.46.1)(tsx@4.23.14)(yaml@2.9.0)) '@vitest/ui': 5.0.0(vitest@5.0.0) '@vitest/utils': 5.0.0 magic-string: 1.2.3 pngjs: 7.0.0 sirv: 3.0.2 tinyrainbow: 3.1.1 - vitest: 5.0.0(@edge-runtime/vm@5.0.0)(@opentelemetry/api@1.9.0)(@types/node@25.6.0)(@vitest/browser-playwright@5.0.0)(@vitest/coverage-v8@5.0.0)(@vitest/ui@5.0.0)(happy-dom@20.10.2(bufferutil@4.1.0)(utf-8-validate@5.0.10))(jsdom@27.0.0(bufferutil@4.1.0)(utf-8-validate@5.0.10))(msw@2.15.0(@types/node@25.6.0)(typescript@6.0.3))(vite@8.2.2(@types/node@25.6.0)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.46.1)(tsx@4.20.6)(yaml@2.9.0)) + vitest: 5.0.0(@edge-runtime/vm@5.0.0)(@opentelemetry/api@1.9.0)(@types/node@25.6.0)(@vitest/browser-playwright@5.0.0)(@vitest/coverage-v8@5.0.0)(@vitest/ui@5.0.0)(happy-dom@20.10.2(bufferutil@4.1.0)(utf-8-validate@5.0.10))(jsdom@27.0.0(bufferutil@4.1.0)(utf-8-validate@5.0.10))(msw@2.15.0(@types/node@25.6.0)(typescript@6.0.3))(vite@8.2.2(@types/node@25.6.0)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.46.1)(tsx@4.23.14)(yaml@2.9.0)) ws: 8.21.3(bufferutil@4.1.0)(utf-8-validate@5.0.10) transitivePeerDependencies: - bufferutil @@ -22068,9 +21937,18 @@ snapshots: obug: 2.1.4 std-env: 4.2.0 tinyrainbow: 3.1.1 - vitest: 5.0.0(@edge-runtime/vm@5.0.0)(@opentelemetry/api@1.9.0)(@types/node@22.20.1)(@vitest/browser-playwright@5.0.0)(@vitest/coverage-v8@5.0.0)(@vitest/ui@5.0.0)(happy-dom@20.10.2(bufferutil@4.1.0)(utf-8-validate@5.0.10))(jsdom@27.0.0(bufferutil@4.1.0)(utf-8-validate@5.0.10))(msw@2.15.0(@types/node@22.20.1)(typescript@6.0.3))(vite@8.2.2(@types/node@22.20.1)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.46.1)(tsx@4.20.6)(yaml@2.9.0)) + vitest: 5.0.0(@edge-runtime/vm@5.0.0)(@opentelemetry/api@1.9.0)(@types/node@22.20.1)(@vitest/browser-playwright@5.0.0)(@vitest/coverage-v8@5.0.0)(@vitest/ui@5.0.0)(happy-dom@20.10.2(bufferutil@4.1.0)(utf-8-validate@5.0.10))(jsdom@27.0.0(bufferutil@4.1.0)(utf-8-validate@5.0.10))(msw@2.15.0(@types/node@22.20.1)(typescript@6.0.3))(vite@8.2.2(@types/node@22.20.1)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.46.1)(tsx@4.23.14)(yaml@2.9.0)) optionalDependencies: - '@vitest/browser': 5.0.0(bufferutil@4.1.0)(msw@2.15.0(@types/node@22.20.1)(typescript@6.0.3))(utf-8-validate@5.0.10)(vite@8.2.2(@types/node@22.20.1)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.46.1)(tsx@4.20.6)(yaml@2.9.0))(vitest@5.0.0) + '@vitest/browser': 5.0.0(bufferutil@4.1.0)(msw@2.15.0(@types/node@22.20.1)(typescript@6.0.3))(utf-8-validate@5.0.10)(vite@8.2.2(@types/node@22.20.1)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.46.1)(tsx@4.23.14)(yaml@2.9.0))(vitest@5.0.0) + + '@vitest/expect@5.0.2': + dependencies: + '@standard-schema/spec': 1.1.0 + '@types/chai': 5.2.3 + '@vitest/spy': 5.0.2 + '@vitest/utils': 5.0.2 + chai: 6.2.2 + tinyrainbow: 3.1.1 '@vitest/istanbul-lib-coverage@1.0.1': {} @@ -22078,7 +21956,7 @@ snapshots: dependencies: '@vitest/istanbul-lib-coverage': 1.0.1 - '@vitest/mocker@5.0.0(msw@2.15.0(@types/node@22.20.1)(typescript@6.0.3))(vite@8.2.2(@types/node@22.20.1)(esbuild@0.27.7)(jiti@2.7.0)(terser@5.46.1)(tsx@4.20.6)(yaml@2.9.0))': + '@vitest/mocker@5.0.0(msw@2.15.0(@types/node@22.20.1)(typescript@6.0.3))(vite@8.2.2(@types/node@22.20.1)(esbuild@0.27.7)(jiti@2.7.0)(terser@5.46.1)(tsx@4.23.14)(yaml@2.9.0))': dependencies: '@jridgewell/trace-mapping': 0.3.31 '@vitest/spy': 5.0.0 @@ -22086,9 +21964,9 @@ snapshots: magic-string: 1.2.3 optionalDependencies: msw: 2.15.0(@types/node@22.20.1)(typescript@6.0.3) - vite: 8.2.2(@types/node@22.20.1)(esbuild@0.27.7)(jiti@2.7.0)(terser@5.46.1)(tsx@4.20.6)(yaml@2.9.0) + vite: 8.2.2(@types/node@22.20.1)(esbuild@0.27.7)(jiti@2.7.0)(terser@5.46.1)(tsx@4.23.14)(yaml@2.9.0) - '@vitest/mocker@5.0.0(msw@2.15.0(@types/node@22.20.1)(typescript@6.0.3))(vite@8.2.2(@types/node@22.20.1)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.46.1)(tsx@4.20.6)(yaml@2.9.0))': + '@vitest/mocker@5.0.0(msw@2.15.0(@types/node@22.20.1)(typescript@6.0.3))(vite@8.2.2(@types/node@22.20.1)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.46.1)(tsx@4.23.14)(yaml@2.9.0))': dependencies: '@jridgewell/trace-mapping': 0.3.31 '@vitest/spy': 5.0.0 @@ -22096,9 +21974,9 @@ snapshots: magic-string: 1.2.3 optionalDependencies: msw: 2.15.0(@types/node@22.20.1)(typescript@6.0.3) - vite: 8.2.2(@types/node@22.20.1)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.46.1)(tsx@4.20.6)(yaml@2.9.0) + vite: 8.2.2(@types/node@22.20.1)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.46.1)(tsx@4.23.14)(yaml@2.9.0) - '@vitest/mocker@5.0.0(msw@2.15.0(@types/node@25.6.0)(typescript@6.0.3))(vite@8.2.2(@types/node@25.6.0)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.46.1)(tsx@4.20.6)(yaml@2.9.0))': + '@vitest/mocker@5.0.0(msw@2.15.0(@types/node@25.6.0)(typescript@6.0.3))(vite@8.2.2(@types/node@25.6.0)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.46.1)(tsx@4.23.14)(yaml@2.9.0))': dependencies: '@jridgewell/trace-mapping': 0.3.31 '@vitest/spy': 5.0.0 @@ -22106,14 +21984,20 @@ snapshots: magic-string: 1.2.3 optionalDependencies: msw: 2.15.0(@types/node@25.6.0)(typescript@6.0.3) - vite: 8.2.2(@types/node@25.6.0)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.46.1)(tsx@4.20.6)(yaml@2.9.0) + vite: 8.2.2(@types/node@25.6.0)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.46.1)(tsx@4.23.14)(yaml@2.9.0) '@vitest/pretty-format@5.0.0': dependencies: tinyrainbow: 3.1.1 + '@vitest/pretty-format@5.0.2': + dependencies: + tinyrainbow: 3.1.1 + '@vitest/spy@5.0.0': {} + '@vitest/spy@5.0.2': {} + '@vitest/ui@5.0.0(vitest@5.0.0)': dependencies: '@vitest/utils': 5.0.0 @@ -22122,7 +22006,7 @@ snapshots: pathe: 2.0.3 sirv: 3.0.2 tinyrainbow: 3.1.1 - vitest: 5.0.0(@edge-runtime/vm@5.0.0)(@opentelemetry/api@1.9.0)(@types/node@22.20.1)(@vitest/browser-playwright@5.0.0)(@vitest/coverage-v8@5.0.0)(@vitest/ui@5.0.0)(happy-dom@20.10.2(bufferutil@4.1.0)(utf-8-validate@5.0.10))(jsdom@27.0.0(bufferutil@4.1.0)(utf-8-validate@5.0.10))(msw@2.15.0(@types/node@22.20.1)(typescript@6.0.3))(vite@8.2.2(@types/node@22.20.1)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.46.1)(tsx@4.20.6)(yaml@2.9.0)) + vitest: 5.0.0(@edge-runtime/vm@5.0.0)(@opentelemetry/api@1.9.0)(@types/node@22.20.1)(@vitest/browser-playwright@5.0.0)(@vitest/coverage-v8@5.0.0)(@vitest/ui@5.0.0)(happy-dom@20.10.2(bufferutil@4.1.0)(utf-8-validate@5.0.10))(jsdom@27.0.0(bufferutil@4.1.0)(utf-8-validate@5.0.10))(msw@2.15.0(@types/node@22.20.1)(typescript@6.0.3))(vite@8.2.2(@types/node@22.20.1)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.46.1)(tsx@4.23.14)(yaml@2.9.0)) '@vitest/utils@5.0.0': dependencies: @@ -22130,6 +22014,12 @@ snapshots: convert-source-map: 2.0.0 tinyrainbow: 3.1.1 + '@vitest/utils@5.0.2': + dependencies: + '@vitest/pretty-format': 5.0.2 + convert-source-map: 2.0.0 + tinyrainbow: 3.1.1 + '@volar/language-core@2.4.27': dependencies: '@volar/source-map': 2.4.27 @@ -22162,7 +22052,7 @@ snapshots: dependencies: defu: 6.1.7 - '@vue.ts/tsx-auto-props@1.0.0-beta.13(@nuxt/kit@4.5.2(magic-string@1.2.3)(magicast@0.5.4)(rolldown@1.1.0)(unplugin@3.3.0(@rspack/core@2.0.6)(esbuild@0.28.1)(rolldown@1.1.0)(rollup@4.61.0)(vite@8.2.2(@types/node@25.6.0)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.46.1)(tsx@4.20.6)(yaml@2.9.0))(webpack@5.102.1(esbuild@0.28.1))))(typescript@6.0.3)(vue@3.5.33(typescript@6.0.3))': + '@vue.ts/tsx-auto-props@1.0.0-beta.13(@nuxt/kit@4.5.2(magic-string@1.2.3)(magicast@0.5.4)(rolldown@1.1.0)(unplugin@3.3.0(@rspack/core@2.0.6)(esbuild@0.28.1)(rolldown@1.1.0)(rollup@4.61.0)(vite@8.2.2(@types/node@25.6.0)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.46.1)(tsx@4.23.14)(yaml@2.9.0))(webpack@5.102.1(esbuild@0.28.1))))(typescript@6.0.3)(vue@3.5.33(typescript@6.0.3))': dependencies: '@vue.ts/language': 1.0.0-beta.13 '@vue.ts/shared': 1.0.0-beta.13 @@ -22171,7 +22061,7 @@ snapshots: unplugin: 2.3.11 vue: 3.5.33(typescript@6.0.3) optionalDependencies: - '@nuxt/kit': 4.5.2(magic-string@1.2.3)(magicast@0.5.4)(rolldown@1.1.0)(unplugin@3.3.0(@rspack/core@2.0.6)(esbuild@0.28.1)(rolldown@1.1.0)(rollup@4.61.0)(vite@8.2.2(@types/node@25.6.0)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.46.1)(tsx@4.20.6)(yaml@2.9.0))(webpack@5.102.1(esbuild@0.28.1))) + '@nuxt/kit': 4.5.2(magic-string@1.2.3)(magicast@0.5.4)(rolldown@1.1.0)(unplugin@3.3.0(@rspack/core@2.0.6)(esbuild@0.28.1)(rolldown@1.1.0)(rollup@4.61.0)(vite@8.2.2(@types/node@25.6.0)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.46.1)(tsx@4.23.14)(yaml@2.9.0))(webpack@5.102.1(esbuild@0.28.1))) '@vue/babel-helper-vue-transform-on@2.0.1': {} @@ -22527,6 +22417,8 @@ snapshots: agent-base@7.1.4: {} + agent-device@0.21.18: {} + agent-install@0.0.5: dependencies: '@iarna/toml': 2.2.5 @@ -22829,14 +22721,14 @@ snapshots: astring@1.9.0: {} - astro@7.2.9(@emnapi/core@1.11.1)(@emnapi/runtime@1.11.3)(@types/node@25.6.0)(db0@0.3.4)(idb-keyval@6.2.1)(ioredis@5.11.0)(jiti@2.7.0)(terser@5.46.1)(tsx@4.20.6)(yaml@2.9.0): + astro@7.2.9(@emnapi/core@1.11.1)(@emnapi/runtime@1.11.3)(@types/node@25.6.0)(db0@0.3.4)(idb-keyval@6.2.1)(ioredis@5.11.0)(jiti@2.7.0)(terser@5.46.1)(tsx@4.23.14)(yaml@2.9.0): dependencies: '@astrojs/compiler-rs': 0.4.0(@emnapi/core@1.11.1)(@emnapi/runtime@1.11.3) '@astrojs/internal-helpers': 0.10.4 '@astrojs/markdown-satteri': 0.3.8 '@astrojs/telemetry': 3.3.3 '@capsizecss/unpack': 4.0.0 - '@clack/prompts': 1.7.0 + '@clack/prompts': 1.8.1 '@oslojs/encoding': 1.1.0 am-i-vibing: 0.4.0 aria-query: 5.3.2 @@ -22879,8 +22771,8 @@ snapshots: ultrahtml: 1.7.0 unifont: 0.7.5 unstorage: 1.17.5(db0@0.3.4)(idb-keyval@6.2.1)(ioredis@5.11.0) - vite: 8.2.2(@types/node@25.6.0)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.46.1)(tsx@4.20.6)(yaml@2.9.0) - vitefu: 1.1.3(vite@8.2.2(@types/node@25.6.0)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.46.1)(tsx@4.20.6)(yaml@2.9.0)) + vite: 8.2.2(@types/node@25.6.0)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.46.1)(tsx@4.23.14)(yaml@2.9.0) + vitefu: 1.1.3(vite@8.2.2(@types/node@25.6.0)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.46.1)(tsx@4.23.14)(yaml@2.9.0)) xxhash-wasm: 1.1.0 yargs-parser: 22.0.0 zod: 4.6.5 @@ -23666,6 +23558,8 @@ snapshots: commander@14.0.3: {} + commander@15.0.0: {} + commander@2.20.3: {} commander@4.1.1: {} @@ -24382,6 +24276,21 @@ snapshots: duplexer@0.1.2: {} + e2e@0.15.1(@cfworker/json-schema@4.1.1): + dependencies: + '@ai-sdk/provider': 4.0.18 + '@clack/prompts': 1.8.1 + '@modelcontextprotocol/sdk': 1.30.1(@cfworker/json-schema@4.1.1)(zod@4.6.1) + '@vitest/expect': 5.0.2 + commander: 15.0.0 + picocolors: 1.1.1 + pngjs: 7.0.0 + tsx: 4.23.14 + zod: 4.6.1 + transitivePeerDependencies: + - '@cfworker/json-schema' + - supports-color + eastasianwidth@0.2.0: {} ecc-jsbn@0.1.2: @@ -24661,36 +24570,6 @@ snapshots: esbuild-plugin-file-path-extensions@2.1.4: {} - esbuild@0.25.12: - optionalDependencies: - '@esbuild/aix-ppc64': 0.25.12 - '@esbuild/android-arm': 0.25.12 - '@esbuild/android-arm64': 0.25.12 - '@esbuild/android-x64': 0.25.12 - '@esbuild/darwin-arm64': 0.25.12 - '@esbuild/darwin-x64': 0.25.12 - '@esbuild/freebsd-arm64': 0.25.12 - '@esbuild/freebsd-x64': 0.25.12 - '@esbuild/linux-arm': 0.25.12 - '@esbuild/linux-arm64': 0.25.12 - '@esbuild/linux-ia32': 0.25.12 - '@esbuild/linux-loong64': 0.25.12 - '@esbuild/linux-mips64el': 0.25.12 - '@esbuild/linux-ppc64': 0.25.12 - '@esbuild/linux-riscv64': 0.25.12 - '@esbuild/linux-s390x': 0.25.12 - '@esbuild/linux-x64': 0.25.12 - '@esbuild/netbsd-arm64': 0.25.12 - '@esbuild/netbsd-x64': 0.25.12 - '@esbuild/openbsd-arm64': 0.25.12 - '@esbuild/openbsd-x64': 0.25.12 - '@esbuild/openharmony-arm64': 0.25.12 - '@esbuild/sunos-x64': 0.25.12 - '@esbuild/win32-arm64': 0.25.12 - '@esbuild/win32-ia32': 0.25.12 - '@esbuild/win32-x64': 0.25.12 - optional: true - esbuild@0.27.7: optionalDependencies: '@esbuild/aix-ppc64': 0.27.7 @@ -26394,12 +26273,12 @@ snapshots: import-without-cache@0.4.0: {} - impound@1.2.0(@rspack/core@2.0.6)(esbuild@0.28.1)(rolldown@1.1.0)(rollup@4.61.0)(vite@8.2.2(@types/node@25.6.0)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.46.1)(tsx@4.20.6)(yaml@2.9.0))(webpack@5.102.1(esbuild@0.28.1)): + impound@1.2.0(@rspack/core@2.0.6)(esbuild@0.28.1)(rolldown@1.1.0)(rollup@4.61.0)(vite@8.2.2(@types/node@25.6.0)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.46.1)(tsx@4.23.14)(yaml@2.9.0))(webpack@5.102.1(esbuild@0.28.1)): dependencies: '@jridgewell/trace-mapping': 0.3.31 es-module-lexer: 2.3.2 pathe: 2.0.3 - unplugin: 3.3.0(@rspack/core@2.0.6)(esbuild@0.28.1)(rolldown@1.1.0)(rollup@4.61.0)(vite@8.2.2(@types/node@25.6.0)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.46.1)(tsx@4.20.6)(yaml@2.9.0))(webpack@5.102.1(esbuild@0.28.1)) + unplugin: 3.3.0(@rspack/core@2.0.6)(esbuild@0.28.1)(rolldown@1.1.0)(rollup@4.61.0)(vite@8.2.2(@types/node@25.6.0)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.46.1)(tsx@4.23.14)(yaml@2.9.0))(webpack@5.102.1(esbuild@0.28.1)) unplugin-utils: 0.3.2 transitivePeerDependencies: - '@farmfe/core' @@ -28528,7 +28407,7 @@ snapshots: nice-try@1.0.5: {} - nitropack@2.13.4(@rspack/core@2.0.6)(idb-keyval@6.2.1)(rolldown@1.1.0)(vite@8.2.2(@types/node@25.6.0)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.46.1)(tsx@4.20.6)(yaml@2.9.0))(webpack@5.102.1(esbuild@0.28.1)): + nitropack@2.13.4(@rspack/core@2.0.6)(idb-keyval@6.2.1)(rolldown@1.1.0)(vite@8.2.2(@types/node@25.6.0)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.46.1)(tsx@4.23.14)(yaml@2.9.0))(webpack@5.102.1(esbuild@0.28.1)): dependencies: '@cloudflare/kv-asset-handler': 0.4.2 '@rollup/plugin-alias': 6.0.0(rollup@4.61.0) @@ -28593,7 +28472,7 @@ snapshots: uncrypto: 0.1.3 unctx: 2.5.0 unenv: 2.0.0-rc.24 - unimport: 6.4.0(@rspack/core@2.0.6)(esbuild@0.28.1)(rolldown@1.1.0)(rollup@4.61.0)(vite@8.2.2(@types/node@25.6.0)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.46.1)(tsx@4.20.6)(yaml@2.9.0))(webpack@5.102.1(esbuild@0.28.1)) + unimport: 6.4.0(@rspack/core@2.0.6)(esbuild@0.28.1)(rolldown@1.1.0)(rollup@4.61.0)(vite@8.2.2(@types/node@25.6.0)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.46.1)(tsx@4.23.14)(yaml@2.9.0))(webpack@5.102.1(esbuild@0.28.1)) unplugin-utils: 0.3.2 unstorage: 1.17.5(db0@0.3.4)(idb-keyval@6.2.1)(ioredis@5.11.0) untyped: 2.0.0 @@ -28764,17 +28643,17 @@ snapshots: nullthrows@1.1.1: {} - nuxt@4.5.2(@babel/plugin-proposal-decorators@7.28.0(@babel/core@7.29.7))(@babel/plugin-syntax-jsx@7.29.7(@babel/core@7.29.7))(@babel/plugin-syntax-typescript@7.29.7(@babel/core@7.29.7))(@oxc-project/types@0.134.0)(@parcel/watcher@2.5.6)(@rspack/core@2.0.6)(@types/node@25.6.0)(@vue/compiler-sfc@3.5.42)(bufferutil@4.1.0)(cac@6.7.14)(commander@14.0.3)(db0@0.3.4)(esbuild@0.28.1)(eslint@9.31.0(jiti@2.7.0))(idb-keyval@6.2.1)(ioredis@5.11.0)(lightningcss@1.33.0)(magicast@0.5.4)(meow@13.2.0)(optionator@0.9.4)(rolldown@1.1.0)(rollup-plugin-visualizer@7.0.1(rolldown@1.1.0)(rollup@4.61.0))(rollup@4.61.0)(terser@5.46.1)(tsx@4.20.6)(typescript@6.0.3)(utf-8-validate@5.0.10)(vite@8.2.2(@types/node@25.6.0)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.46.1)(tsx@4.20.6)(yaml@2.9.0))(vue-tsc@3.2.4(typescript@6.0.3))(webpack@5.102.1(esbuild@0.28.1))(yaml@2.9.0): + nuxt@4.5.2(@babel/plugin-proposal-decorators@7.28.0(@babel/core@7.29.7))(@babel/plugin-syntax-jsx@7.29.7(@babel/core@7.29.7))(@babel/plugin-syntax-typescript@7.29.7(@babel/core@7.29.7))(@oxc-project/types@0.134.0)(@parcel/watcher@2.5.6)(@rspack/core@2.0.6)(@types/node@25.6.0)(@vue/compiler-sfc@3.5.42)(bufferutil@4.1.0)(cac@6.7.14)(commander@15.0.0)(db0@0.3.4)(esbuild@0.28.1)(eslint@9.31.0(jiti@2.7.0))(idb-keyval@6.2.1)(ioredis@5.11.0)(lightningcss@1.33.0)(magicast@0.5.4)(meow@13.2.0)(optionator@0.9.4)(rolldown@1.1.0)(rollup-plugin-visualizer@7.0.1(rolldown@1.1.0)(rollup@4.61.0))(rollup@4.61.0)(terser@5.46.1)(tsx@4.23.14)(typescript@6.0.3)(utf-8-validate@5.0.10)(vite@8.2.2(@types/node@25.6.0)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.46.1)(tsx@4.23.14)(yaml@2.9.0))(vue-tsc@3.2.4(typescript@6.0.3))(webpack@5.102.1(esbuild@0.28.1))(yaml@2.9.0): dependencies: - '@dxup/nuxt': 0.5.10(@rspack/core@2.0.6)(esbuild@0.28.1)(magicast@0.5.4)(rolldown@1.1.0)(rollup@4.61.0)(vite@8.2.2(@types/node@25.6.0)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.46.1)(tsx@4.20.6)(yaml@2.9.0))(webpack@5.102.1(esbuild@0.28.1)) - '@nuxt/cli': 3.37.0(@nuxt/schema@4.5.2)(cac@6.7.14)(commander@14.0.3)(magicast@0.5.4) - '@nuxt/devtools': 3.4.2(bufferutil@4.1.0)(db0@0.3.4)(idb-keyval@6.2.1)(ioredis@5.11.0)(magic-string@1.2.3)(rolldown@1.1.0)(unplugin@3.3.0(@rspack/core@2.0.6)(esbuild@0.28.1)(rolldown@1.1.0)(rollup@4.61.0)(vite@8.2.2(@types/node@25.6.0)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.46.1)(tsx@4.20.6)(yaml@2.9.0))(webpack@5.102.1(esbuild@0.28.1)))(utf-8-validate@5.0.10)(vite@8.2.2(@types/node@25.6.0)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.46.1)(tsx@4.20.6)(yaml@2.9.0))(vue@3.5.42(typescript@6.0.3)) - '@nuxt/kit': 4.5.2(magic-string@1.2.3)(magicast@0.5.4)(rolldown@1.1.0)(unplugin@3.3.0(@rspack/core@2.0.6)(esbuild@0.28.1)(rolldown@1.1.0)(rollup@4.61.0)(vite@8.2.2(@types/node@25.6.0)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.46.1)(tsx@4.20.6)(yaml@2.9.0))(webpack@5.102.1(esbuild@0.28.1))) - '@nuxt/nitro-server': 4.5.2(879ff76bb2e0ee98f31f9b2805059646) + '@dxup/nuxt': 0.5.10(@rspack/core@2.0.6)(esbuild@0.28.1)(magicast@0.5.4)(rolldown@1.1.0)(rollup@4.61.0)(vite@8.2.2(@types/node@25.6.0)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.46.1)(tsx@4.23.14)(yaml@2.9.0))(webpack@5.102.1(esbuild@0.28.1)) + '@nuxt/cli': 3.37.0(@nuxt/schema@4.5.2)(cac@6.7.14)(commander@15.0.0)(magicast@0.5.4) + '@nuxt/devtools': 3.4.2(bufferutil@4.1.0)(db0@0.3.4)(idb-keyval@6.2.1)(ioredis@5.11.0)(magic-string@1.2.3)(rolldown@1.1.0)(unplugin@3.3.0(@rspack/core@2.0.6)(esbuild@0.28.1)(rolldown@1.1.0)(rollup@4.61.0)(vite@8.2.2(@types/node@25.6.0)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.46.1)(tsx@4.23.14)(yaml@2.9.0))(webpack@5.102.1(esbuild@0.28.1)))(utf-8-validate@5.0.10)(vite@8.2.2(@types/node@25.6.0)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.46.1)(tsx@4.23.14)(yaml@2.9.0))(vue@3.5.42(typescript@6.0.3)) + '@nuxt/kit': 4.5.2(magic-string@1.2.3)(magicast@0.5.4)(rolldown@1.1.0)(unplugin@3.3.0(@rspack/core@2.0.6)(esbuild@0.28.1)(rolldown@1.1.0)(rollup@4.61.0)(vite@8.2.2(@types/node@25.6.0)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.46.1)(tsx@4.23.14)(yaml@2.9.0))(webpack@5.102.1(esbuild@0.28.1))) + '@nuxt/nitro-server': 4.5.2(5d71b80bb60d18d09b48b3f6ca65979c) '@nuxt/schema': 4.5.2 - '@nuxt/telemetry': 2.8.0(@nuxt/kit@4.5.2(magic-string@1.2.3)(magicast@0.5.4)(rolldown@1.1.0)(unplugin@3.3.0(@rspack/core@2.0.6)(esbuild@0.28.1)(rolldown@1.1.0)(rollup@4.61.0)(vite@8.2.2(@types/node@25.6.0)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.46.1)(tsx@4.20.6)(yaml@2.9.0))(webpack@5.102.1(esbuild@0.28.1)))) - '@nuxt/vite-builder': 4.5.2(200211434b3910e3f7a6f479cdd8d4fb) - '@unhead/vue': 3.4.0(@oxc-project/types@0.134.0)(@rspack/core@2.0.6)(esbuild@0.28.1)(lightningcss@1.33.0)(rolldown@1.1.0)(rollup@4.61.0)(vite@8.2.2(@types/node@25.6.0)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.46.1)(tsx@4.20.6)(yaml@2.9.0))(vue@3.5.42(typescript@6.0.3))(webpack@5.102.1(esbuild@0.28.1)) + '@nuxt/telemetry': 2.8.0(@nuxt/kit@4.5.2(magic-string@1.2.3)(magicast@0.5.4)(rolldown@1.1.0)(unplugin@3.3.0(@rspack/core@2.0.6)(esbuild@0.28.1)(rolldown@1.1.0)(rollup@4.61.0)(vite@8.2.2(@types/node@25.6.0)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.46.1)(tsx@4.23.14)(yaml@2.9.0))(webpack@5.102.1(esbuild@0.28.1)))) + '@nuxt/vite-builder': 4.5.2(29f1a007dbea6b2d37230221b704cc42) + '@unhead/vue': 3.4.0(@oxc-project/types@0.134.0)(@rspack/core@2.0.6)(esbuild@0.28.1)(lightningcss@1.33.0)(rolldown@1.1.0)(rollup@4.61.0)(vite@8.2.2(@types/node@25.6.0)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.46.1)(tsx@4.23.14)(yaml@2.9.0))(vue@3.5.42(typescript@6.0.3))(webpack@5.102.1(esbuild@0.28.1)) '@vue/shared': 3.5.42 chokidar: 5.0.0 compatx: 0.2.0 @@ -28788,7 +28667,7 @@ snapshots: fnv1a-64: 0.1.2 hookable: 6.1.1 ignore: 7.0.6 - impound: 1.2.0(@rspack/core@2.0.6)(esbuild@0.28.1)(rolldown@1.1.0)(rollup@4.61.0)(vite@8.2.2(@types/node@25.6.0)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.46.1)(tsx@4.20.6)(yaml@2.9.0))(webpack@5.102.1(esbuild@0.28.1)) + impound: 1.2.0(@rspack/core@2.0.6)(esbuild@0.28.1)(rolldown@1.1.0)(rollup@4.61.0)(vite@8.2.2(@types/node@25.6.0)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.46.1)(tsx@4.23.14)(yaml@2.9.0))(webpack@5.102.1(esbuild@0.28.1)) jiti: 2.7.0 klona: 2.0.6 knitwork: 1.3.0 @@ -28815,17 +28694,17 @@ snapshots: ufo: 1.6.4 ultrahtml: 1.7.0 uncrypto: 0.1.3 - unctx: 3.0.1(magic-string@1.2.3)(rolldown@1.1.0)(unplugin@3.3.0(@rspack/core@2.0.6)(esbuild@0.28.1)(rolldown@1.1.0)(rollup@4.61.0)(vite@8.2.2(@types/node@25.6.0)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.46.1)(tsx@4.20.6)(yaml@2.9.0))(webpack@5.102.1(esbuild@0.28.1))) + unctx: 3.0.1(magic-string@1.2.3)(rolldown@1.1.0)(unplugin@3.3.0(@rspack/core@2.0.6)(esbuild@0.28.1)(rolldown@1.1.0)(rollup@4.61.0)(vite@8.2.2(@types/node@25.6.0)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.46.1)(tsx@4.23.14)(yaml@2.9.0))(webpack@5.102.1(esbuild@0.28.1))) undici: 8.10.0 - unhead: 3.4.0(@rspack/core@2.0.6)(esbuild@0.28.1)(rolldown@1.1.0)(rollup@4.61.0)(vite@8.2.2(@types/node@25.6.0)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.46.1)(tsx@4.20.6)(yaml@2.9.0))(webpack@5.102.1(esbuild@0.28.1)) - unimport: 6.4.0(@rspack/core@2.0.6)(esbuild@0.28.1)(rolldown@1.1.0)(rollup@4.61.0)(vite@8.2.2(@types/node@25.6.0)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.46.1)(tsx@4.20.6)(yaml@2.9.0))(webpack@5.102.1(esbuild@0.28.1)) - unplugin: 3.3.0(@rspack/core@2.0.6)(esbuild@0.28.1)(rolldown@1.1.0)(rollup@4.61.0)(vite@8.2.2(@types/node@25.6.0)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.46.1)(tsx@4.20.6)(yaml@2.9.0))(webpack@5.102.1(esbuild@0.28.1)) + unhead: 3.4.0(@rspack/core@2.0.6)(esbuild@0.28.1)(rolldown@1.1.0)(rollup@4.61.0)(vite@8.2.2(@types/node@25.6.0)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.46.1)(tsx@4.23.14)(yaml@2.9.0))(webpack@5.102.1(esbuild@0.28.1)) + unimport: 6.4.0(@rspack/core@2.0.6)(esbuild@0.28.1)(rolldown@1.1.0)(rollup@4.61.0)(vite@8.2.2(@types/node@25.6.0)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.46.1)(tsx@4.23.14)(yaml@2.9.0))(webpack@5.102.1(esbuild@0.28.1)) + unplugin: 3.3.0(@rspack/core@2.0.6)(esbuild@0.28.1)(rolldown@1.1.0)(rollup@4.61.0)(vite@8.2.2(@types/node@25.6.0)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.46.1)(tsx@4.23.14)(yaml@2.9.0))(webpack@5.102.1(esbuild@0.28.1)) unrouting: 0.2.3 untyped: 2.0.0 verkit: 0.3.2 vue: 3.5.42(typescript@6.0.3) vue-component-type-helpers: 3.3.11 - vue-router: 5.3.0(@rspack/core@2.0.6)(@vue/compiler-sfc@3.5.42)(esbuild@0.28.1)(rolldown@1.1.0)(rollup@4.61.0)(vite@8.2.2(@types/node@25.6.0)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.46.1)(tsx@4.20.6)(yaml@2.9.0))(vue@3.5.42(typescript@6.0.3))(webpack@5.102.1(esbuild@0.28.1)) + vue-router: 5.3.0(@rspack/core@2.0.6)(@vue/compiler-sfc@3.5.42)(esbuild@0.28.1)(rolldown@1.1.0)(rollup@4.61.0)(vite@8.2.2(@types/node@25.6.0)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.46.1)(tsx@4.23.14)(yaml@2.9.0))(vue@3.5.42(typescript@6.0.3))(webpack@5.102.1(esbuild@0.28.1)) optionalDependencies: '@parcel/watcher': 2.5.6 '@types/node': 25.6.0 @@ -29490,13 +29369,13 @@ snapshots: dependencies: postcss: 8.5.26 - postcss-load-config@6.0.1(jiti@2.7.0)(postcss@8.5.26)(tsx@4.20.6)(yaml@2.9.0): + postcss-load-config@6.0.1(jiti@2.7.0)(postcss@8.5.26)(tsx@4.23.14)(yaml@2.9.0): dependencies: lilconfig: 3.1.3 optionalDependencies: jiti: 2.7.0 postcss: 8.5.26 - tsx: 4.20.6 + tsx: 4.23.14 yaml: 2.9.0 postcss-merge-longhand@8.0.4(postcss@8.5.26): @@ -30632,7 +30511,7 @@ snapshots: '@babel/plugin-transform-typescript': 7.29.7(@babel/core@7.29.7) '@babel/preset-typescript': 7.29.7(@babel/core@7.29.7) '@dotenvx/dotenvx': 1.71.0 - '@modelcontextprotocol/sdk': 1.26.0(@cfworker/json-schema@4.1.1)(zod@3.25.76) + '@modelcontextprotocol/sdk': 1.30.1(@cfworker/json-schema@4.1.1)(zod@3.25.76) '@types/validate-npm-package-name': 4.0.2 browserslist: 4.28.8 commander: 14.0.3 @@ -31513,7 +31392,7 @@ snapshots: minimist: 1.2.8 strip-bom: 3.0.0 - tsdown@0.22.2(@arethetypeswrong/core@0.18.3)(publint@0.3.18)(tsx@4.20.6)(typescript@6.0.3)(unrun@0.3.1(synckit@0.11.11))(vue-tsc@3.2.4(typescript@6.0.3)): + tsdown@0.22.2(@arethetypeswrong/core@0.18.3)(publint@0.3.18)(tsx@4.23.14)(typescript@6.0.3)(unrun@0.3.1(synckit@0.11.11))(vue-tsc@3.2.4(typescript@6.0.3)): dependencies: ansis: 4.3.1 cac: 7.0.0 @@ -31533,7 +31412,7 @@ snapshots: optionalDependencies: '@arethetypeswrong/core': 0.18.3 publint: 0.3.18 - tsx: 4.20.6 + tsx: 4.23.14 typescript: 6.0.3 unrun: 0.3.1(synckit@0.11.11) transitivePeerDependencies: @@ -31544,7 +31423,7 @@ snapshots: tslib@2.8.1: {} - tsup@8.5.1(@microsoft/api-extractor@7.58.7(@types/node@22.20.1))(jiti@2.7.0)(postcss@8.5.26)(tsx@4.20.6)(typescript@6.0.3)(yaml@2.9.0): + tsup@8.5.1(@microsoft/api-extractor@7.58.7(@types/node@22.20.1))(jiti@2.7.0)(postcss@8.5.26)(tsx@4.23.14)(typescript@6.0.3)(yaml@2.9.0): dependencies: bundle-require: 5.1.0(esbuild@0.27.7) cac: 6.7.14 @@ -31555,7 +31434,7 @@ snapshots: fix-dts-default-cjs-exports: 1.0.1 joycon: 3.1.1 picocolors: 1.1.1 - postcss-load-config: 6.0.1(jiti@2.7.0)(postcss@8.5.26)(tsx@4.20.6)(yaml@2.9.0) + postcss-load-config: 6.0.1(jiti@2.7.0)(postcss@8.5.26)(tsx@4.23.14)(yaml@2.9.0) resolve-from: 5.0.0 rollup: 4.61.0 source-map: 0.7.6 @@ -31573,13 +31452,11 @@ snapshots: - tsx - yaml - tsx@4.20.6: + tsx@4.23.14: dependencies: - esbuild: 0.25.12 - get-tsconfig: 4.13.0 + esbuild: 0.28.1 optionalDependencies: fsevents: 2.3.3 - optional: true tunnel-agent@0.6.0: dependencies: @@ -31737,11 +31614,11 @@ snapshots: magic-string: 0.30.21 unplugin: 2.3.11 - unctx@3.0.1(magic-string@1.2.3)(rolldown@1.1.0)(unplugin@3.3.0(@rspack/core@2.0.6)(esbuild@0.28.1)(rolldown@1.1.0)(rollup@4.61.0)(vite@8.2.2(@types/node@25.6.0)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.46.1)(tsx@4.20.6)(yaml@2.9.0))(webpack@5.102.1(esbuild@0.28.1))): + unctx@3.0.1(magic-string@1.2.3)(rolldown@1.1.0)(unplugin@3.3.0(@rspack/core@2.0.6)(esbuild@0.28.1)(rolldown@1.1.0)(rollup@4.61.0)(vite@8.2.2(@types/node@25.6.0)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.46.1)(tsx@4.23.14)(yaml@2.9.0))(webpack@5.102.1(esbuild@0.28.1))): optionalDependencies: magic-string: 1.2.3 rolldown: 1.1.0 - unplugin: 3.3.0(@rspack/core@2.0.6)(esbuild@0.28.1)(rolldown@1.1.0)(rollup@4.61.0)(vite@8.2.2(@types/node@25.6.0)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.46.1)(tsx@4.20.6)(yaml@2.9.0))(webpack@5.102.1(esbuild@0.28.1)) + unplugin: 3.3.0(@rspack/core@2.0.6)(esbuild@0.28.1)(rolldown@1.1.0)(rollup@4.61.0)(vite@8.2.2(@types/node@25.6.0)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.46.1)(tsx@4.23.14)(yaml@2.9.0))(webpack@5.102.1(esbuild@0.28.1)) undici-types@7.19.2: optional: true @@ -31760,12 +31637,12 @@ snapshots: dependencies: pathe: 2.0.3 - unhead@3.4.0(@rspack/core@2.0.6)(esbuild@0.28.1)(rolldown@1.1.0)(rollup@4.61.0)(vite@8.2.2(@types/node@25.6.0)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.46.1)(tsx@4.20.6)(yaml@2.9.0))(webpack@5.102.1(esbuild@0.28.1)): + unhead@3.4.0(@rspack/core@2.0.6)(esbuild@0.28.1)(rolldown@1.1.0)(rollup@4.61.0)(vite@8.2.2(@types/node@25.6.0)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.46.1)(tsx@4.23.14)(yaml@2.9.0))(webpack@5.102.1(esbuild@0.28.1)): dependencies: hookable: 6.1.1 - unplugin: 3.3.0(@rspack/core@2.0.6)(esbuild@0.28.1)(rolldown@1.1.0)(rollup@4.61.0)(vite@8.2.2(@types/node@25.6.0)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.46.1)(tsx@4.20.6)(yaml@2.9.0))(webpack@5.102.1(esbuild@0.28.1)) + unplugin: 3.3.0(@rspack/core@2.0.6)(esbuild@0.28.1)(rolldown@1.1.0)(rollup@4.61.0)(vite@8.2.2(@types/node@25.6.0)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.46.1)(tsx@4.23.14)(yaml@2.9.0))(webpack@5.102.1(esbuild@0.28.1)) optionalDependencies: - vite: 8.2.2(@types/node@25.6.0)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.46.1)(tsx@4.20.6)(yaml@2.9.0) + vite: 8.2.2(@types/node@25.6.0)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.46.1)(tsx@4.23.14)(yaml@2.9.0) transitivePeerDependencies: - '@farmfe/core' - '@rspack/core' @@ -31811,7 +31688,7 @@ snapshots: ohash: 2.0.11 undici: 8.10.0 - unimport@6.4.0(@rspack/core@2.0.6)(esbuild@0.28.1)(rolldown@1.1.0)(rollup@4.61.0)(vite@8.2.2(@types/node@25.6.0)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.46.1)(tsx@4.20.6)(yaml@2.9.0))(webpack@5.102.1(esbuild@0.28.1)): + unimport@6.4.0(@rspack/core@2.0.6)(esbuild@0.28.1)(rolldown@1.1.0)(rollup@4.61.0)(vite@8.2.2(@types/node@25.6.0)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.46.1)(tsx@4.23.14)(yaml@2.9.0))(webpack@5.102.1(esbuild@0.28.1)): dependencies: acorn: 8.18.0 escape-string-regexp: 5.0.0 @@ -31825,7 +31702,7 @@ snapshots: scule: 1.3.0 strip-literal: 4.0.0 tinyglobby: 0.2.17 - unplugin: 3.3.0(@rspack/core@2.0.6)(esbuild@0.28.1)(rolldown@1.1.0)(rollup@4.61.0)(vite@8.2.2(@types/node@25.6.0)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.46.1)(tsx@4.20.6)(yaml@2.9.0))(webpack@5.102.1(esbuild@0.28.1)) + unplugin: 3.3.0(@rspack/core@2.0.6)(esbuild@0.28.1)(rolldown@1.1.0)(rollup@4.61.0)(vite@8.2.2(@types/node@25.6.0)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.46.1)(tsx@4.23.14)(yaml@2.9.0))(webpack@5.102.1(esbuild@0.28.1)) unplugin-utils: 0.3.2 optionalDependencies: rolldown: 1.1.0 @@ -31885,14 +31762,14 @@ snapshots: pathe: 2.0.3 picomatch: 4.0.7 - unplugin-vue@7.0.8(@types/node@25.6.0)(jiti@2.7.0)(lightningcss@1.33.0)(terser@5.46.1)(tsx@4.20.6)(vue@3.5.33(typescript@6.0.3))(yaml@2.9.0): + unplugin-vue@7.0.8(@types/node@25.6.0)(jiti@2.7.0)(lightningcss@1.33.0)(terser@5.46.1)(tsx@4.23.14)(vue@3.5.33(typescript@6.0.3))(yaml@2.9.0): dependencies: '@jridgewell/gen-mapping': 0.3.13 '@jridgewell/trace-mapping': 0.3.31 '@vue/reactivity': 3.5.42 obug: 2.1.4 unplugin: 2.3.11 - vite: 7.3.5(@types/node@25.6.0)(jiti@2.7.0)(lightningcss@1.33.0)(terser@5.46.1)(tsx@4.20.6)(yaml@2.9.0) + vite: 7.3.5(@types/node@25.6.0)(jiti@2.7.0)(lightningcss@1.33.0)(terser@5.46.1)(tsx@4.23.14)(yaml@2.9.0) vue: 3.5.33(typescript@6.0.3) transitivePeerDependencies: - '@types/node' @@ -31914,7 +31791,7 @@ snapshots: picomatch: 4.0.7 webpack-virtual-modules: 0.6.2 - unplugin@3.3.0(@rspack/core@2.0.6)(esbuild@0.28.1)(rolldown@1.1.0)(rollup@4.61.0)(vite@8.2.2(@types/node@25.6.0)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.46.1)(tsx@4.20.6)(yaml@2.9.0))(webpack@5.102.1(esbuild@0.28.1)): + unplugin@3.3.0(@rspack/core@2.0.6)(esbuild@0.28.1)(rolldown@1.1.0)(rollup@4.61.0)(vite@8.2.2(@types/node@25.6.0)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.46.1)(tsx@4.23.14)(yaml@2.9.0))(webpack@5.102.1(esbuild@0.28.1)): dependencies: '@jridgewell/remapping': 2.3.5 picomatch: 4.0.7 @@ -31924,7 +31801,7 @@ snapshots: esbuild: 0.28.1 rolldown: 1.1.0 rollup: 4.61.0 - vite: 8.2.2(@types/node@25.6.0)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.46.1)(tsx@4.20.6)(yaml@2.9.0) + vite: 8.2.2(@types/node@25.6.0)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.46.1)(tsx@4.23.14)(yaml@2.9.0) webpack: 5.102.1(esbuild@0.28.1) unrouting@0.2.3: @@ -32088,23 +31965,23 @@ snapshots: - utf-8-validate - zod - vite-dev-rpc@2.0.0(vite@8.2.2(@types/node@25.6.0)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.46.1)(tsx@4.20.6)(yaml@2.9.0)): + vite-dev-rpc@2.0.0(vite@8.2.2(@types/node@25.6.0)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.46.1)(tsx@4.23.14)(yaml@2.9.0)): dependencies: birpc: 4.0.0 - vite: 8.2.2(@types/node@25.6.0)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.46.1)(tsx@4.20.6)(yaml@2.9.0) - vite-hot-client: 2.2.0(vite@8.2.2(@types/node@25.6.0)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.46.1)(tsx@4.20.6)(yaml@2.9.0)) + vite: 8.2.2(@types/node@25.6.0)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.46.1)(tsx@4.23.14)(yaml@2.9.0) + vite-hot-client: 2.2.0(vite@8.2.2(@types/node@25.6.0)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.46.1)(tsx@4.23.14)(yaml@2.9.0)) - vite-hot-client@2.2.0(vite@8.2.2(@types/node@25.6.0)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.46.1)(tsx@4.20.6)(yaml@2.9.0)): + vite-hot-client@2.2.0(vite@8.2.2(@types/node@25.6.0)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.46.1)(tsx@4.23.14)(yaml@2.9.0)): dependencies: - vite: 8.2.2(@types/node@25.6.0)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.46.1)(tsx@4.20.6)(yaml@2.9.0) + vite: 8.2.2(@types/node@25.6.0)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.46.1)(tsx@4.23.14)(yaml@2.9.0) - vite-node@6.0.0(@types/node@25.6.0)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.46.1)(tsx@4.20.6)(yaml@2.9.0): + vite-node@6.0.0(@types/node@25.6.0)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.46.1)(tsx@4.23.14)(yaml@2.9.0): dependencies: cac: 7.0.0 es-module-lexer: 2.3.2 obug: 2.1.4 pathe: 2.0.3 - vite: 8.2.2(@types/node@25.6.0)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.46.1)(tsx@4.20.6)(yaml@2.9.0) + vite: 8.2.2(@types/node@25.6.0)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.46.1)(tsx@4.23.14)(yaml@2.9.0) transitivePeerDependencies: - '@types/node' - '@vitejs/devtools' @@ -32119,7 +31996,7 @@ snapshots: - tsx - yaml - vite-plugin-checker@0.14.5(eslint@9.31.0(jiti@2.7.0))(meow@13.2.0)(optionator@0.9.4)(typescript@6.0.3)(vite@8.2.2(@types/node@25.6.0)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.46.1)(tsx@4.20.6)(yaml@2.9.0))(vue-tsc@3.2.4(typescript@6.0.3)): + vite-plugin-checker@0.14.5(eslint@9.31.0(jiti@2.7.0))(meow@13.2.0)(optionator@0.9.4)(typescript@6.0.3)(vite@8.2.2(@types/node@25.6.0)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.46.1)(tsx@4.23.14)(yaml@2.9.0))(vue-tsc@3.2.4(typescript@6.0.3)): dependencies: '@babel/code-frame': 7.29.7 chokidar: 5.0.0 @@ -32128,7 +32005,7 @@ snapshots: picomatch: 4.0.7 proper-lockfile: 4.1.2 tiny-invariant: 1.3.3 - vite: 8.2.2(@types/node@25.6.0)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.46.1)(tsx@4.20.6)(yaml@2.9.0) + vite: 8.2.2(@types/node@25.6.0)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.46.1)(tsx@4.23.14)(yaml@2.9.0) optionalDependencies: eslint: 9.31.0(jiti@2.7.0) meow: 13.2.0 @@ -32136,7 +32013,7 @@ snapshots: typescript: 6.0.3 vue-tsc: 3.2.4(typescript@6.0.3) - vite-plugin-inspect@11.4.1(@nuxt/kit@4.5.2(magic-string@1.2.3)(magicast@0.5.4)(rolldown@1.1.0)(unplugin@3.3.0(@rspack/core@2.0.6)(esbuild@0.28.1)(rolldown@1.1.0)(rollup@4.61.0)(vite@8.2.2(@types/node@25.6.0)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.46.1)(tsx@4.20.6)(yaml@2.9.0))(webpack@5.102.1(esbuild@0.28.1))))(vite@8.2.2(@types/node@25.6.0)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.46.1)(tsx@4.20.6)(yaml@2.9.0)): + vite-plugin-inspect@11.4.1(@nuxt/kit@4.5.2(magic-string@1.2.3)(magicast@0.5.4)(rolldown@1.1.0)(unplugin@3.3.0(@rspack/core@2.0.6)(esbuild@0.28.1)(rolldown@1.1.0)(rollup@4.61.0)(vite@8.2.2(@types/node@25.6.0)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.46.1)(tsx@4.23.14)(yaml@2.9.0))(webpack@5.102.1(esbuild@0.28.1))))(vite@8.2.2(@types/node@25.6.0)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.46.1)(tsx@4.23.14)(yaml@2.9.0)): dependencies: ansis: 4.3.1 error-stack-parser-es: 1.0.5 @@ -32146,22 +32023,22 @@ snapshots: perfect-debounce: 2.1.0 sirv: 3.0.2 unplugin-utils: 0.3.2 - vite: 8.2.2(@types/node@25.6.0)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.46.1)(tsx@4.20.6)(yaml@2.9.0) - vite-dev-rpc: 2.0.0(vite@8.2.2(@types/node@25.6.0)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.46.1)(tsx@4.20.6)(yaml@2.9.0)) + vite: 8.2.2(@types/node@25.6.0)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.46.1)(tsx@4.23.14)(yaml@2.9.0) + vite-dev-rpc: 2.0.0(vite@8.2.2(@types/node@25.6.0)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.46.1)(tsx@4.23.14)(yaml@2.9.0)) optionalDependencies: - '@nuxt/kit': 4.5.2(magic-string@1.2.3)(magicast@0.5.4)(rolldown@1.1.0)(unplugin@3.3.0(@rspack/core@2.0.6)(esbuild@0.28.1)(rolldown@1.1.0)(rollup@4.61.0)(vite@8.2.2(@types/node@25.6.0)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.46.1)(tsx@4.20.6)(yaml@2.9.0))(webpack@5.102.1(esbuild@0.28.1))) + '@nuxt/kit': 4.5.2(magic-string@1.2.3)(magicast@0.5.4)(rolldown@1.1.0)(unplugin@3.3.0(@rspack/core@2.0.6)(esbuild@0.28.1)(rolldown@1.1.0)(rollup@4.61.0)(vite@8.2.2(@types/node@25.6.0)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.46.1)(tsx@4.23.14)(yaml@2.9.0))(webpack@5.102.1(esbuild@0.28.1))) - vite-plugin-vue-tracer@1.4.0(vite@8.2.2(@types/node@25.6.0)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.46.1)(tsx@4.20.6)(yaml@2.9.0))(vue@3.5.42(typescript@6.0.3)): + vite-plugin-vue-tracer@1.4.0(vite@8.2.2(@types/node@25.6.0)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.46.1)(tsx@4.23.14)(yaml@2.9.0))(vue@3.5.42(typescript@6.0.3)): dependencies: estree-walker: 3.0.3 exsolve: 1.1.1 magic-string: 0.30.21 pathe: 2.0.3 source-map-js: 1.2.1 - vite: 8.2.2(@types/node@25.6.0)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.46.1)(tsx@4.20.6)(yaml@2.9.0) + vite: 8.2.2(@types/node@25.6.0)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.46.1)(tsx@4.23.14)(yaml@2.9.0) vue: 3.5.42(typescript@6.0.3) - vite@7.3.5(@types/node@25.6.0)(jiti@2.7.0)(lightningcss@1.33.0)(terser@5.46.1)(tsx@4.20.6)(yaml@2.9.0): + vite@7.3.5(@types/node@25.6.0)(jiti@2.7.0)(lightningcss@1.33.0)(terser@5.46.1)(tsx@4.23.14)(yaml@2.9.0): dependencies: esbuild: 0.27.7 fdir: 6.5.0(picomatch@4.0.7) @@ -32175,10 +32052,10 @@ snapshots: jiti: 2.7.0 lightningcss: 1.33.0 terser: 5.46.1 - tsx: 4.20.6 + tsx: 4.23.14 yaml: 2.9.0 - vite@8.2.2(@types/node@22.20.1)(esbuild@0.27.7)(jiti@2.7.0)(terser@5.46.1)(tsx@4.20.6)(yaml@2.9.0): + vite@8.2.2(@types/node@22.20.1)(esbuild@0.27.7)(jiti@2.7.0)(terser@5.46.1)(tsx@4.23.14)(yaml@2.9.0): dependencies: lightningcss: 1.33.0 picomatch: 4.0.7 @@ -32191,10 +32068,10 @@ snapshots: fsevents: 2.3.3 jiti: 2.7.0 terser: 5.46.1 - tsx: 4.20.6 + tsx: 4.23.14 yaml: 2.9.0 - vite@8.2.2(@types/node@22.20.1)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.46.1)(tsx@4.20.6)(yaml@2.9.0): + vite@8.2.2(@types/node@22.20.1)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.46.1)(tsx@4.23.14)(yaml@2.9.0): dependencies: lightningcss: 1.33.0 picomatch: 4.0.7 @@ -32207,10 +32084,10 @@ snapshots: fsevents: 2.3.3 jiti: 2.7.0 terser: 5.46.1 - tsx: 4.20.6 + tsx: 4.23.14 yaml: 2.9.0 - vite@8.2.2(@types/node@25.6.0)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.46.1)(tsx@4.20.6)(yaml@2.9.0): + vite@8.2.2(@types/node@25.6.0)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.46.1)(tsx@4.23.14)(yaml@2.9.0): dependencies: lightningcss: 1.33.0 picomatch: 4.0.7 @@ -32223,12 +32100,12 @@ snapshots: fsevents: 2.3.3 jiti: 2.7.0 terser: 5.46.1 - tsx: 4.20.6 + tsx: 4.23.14 yaml: 2.9.0 - vitefu@1.1.3(vite@8.2.2(@types/node@25.6.0)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.46.1)(tsx@4.20.6)(yaml@2.9.0)): + vitefu@1.1.3(vite@8.2.2(@types/node@25.6.0)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.46.1)(tsx@4.23.14)(yaml@2.9.0)): optionalDependencies: - vite: 8.2.2(@types/node@25.6.0)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.46.1)(tsx@4.20.6)(yaml@2.9.0) + vite: 8.2.2(@types/node@25.6.0)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.46.1)(tsx@4.23.14)(yaml@2.9.0) vitest-axe@0.1.0(vitest@5.0.0): dependencies: @@ -32238,16 +32115,16 @@ snapshots: dom-accessibility-api: 0.5.16 lodash-es: 4.18.1 redent: 3.0.0 - vitest: 5.0.0(@edge-runtime/vm@5.0.0)(@opentelemetry/api@1.9.0)(@types/node@25.6.0)(@vitest/browser-playwright@5.0.0)(@vitest/coverage-v8@5.0.0)(@vitest/ui@5.0.0)(happy-dom@20.10.2(bufferutil@4.1.0)(utf-8-validate@5.0.10))(jsdom@27.0.0(bufferutil@4.1.0)(utf-8-validate@5.0.10))(msw@2.15.0(@types/node@25.6.0)(typescript@6.0.3))(vite@8.2.2(@types/node@25.6.0)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.46.1)(tsx@4.20.6)(yaml@2.9.0)) + vitest: 5.0.0(@edge-runtime/vm@5.0.0)(@opentelemetry/api@1.9.0)(@types/node@25.6.0)(@vitest/browser-playwright@5.0.0)(@vitest/coverage-v8@5.0.0)(@vitest/ui@5.0.0)(happy-dom@20.10.2(bufferutil@4.1.0)(utf-8-validate@5.0.10))(jsdom@27.0.0(bufferutil@4.1.0)(utf-8-validate@5.0.10))(msw@2.15.0(@types/node@25.6.0)(typescript@6.0.3))(vite@8.2.2(@types/node@25.6.0)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.46.1)(tsx@4.23.14)(yaml@2.9.0)) vitest-chrome@0.1.0: dependencies: '@types/chrome': 0.0.114 - vitest@5.0.0(@edge-runtime/vm@5.0.0)(@opentelemetry/api@1.9.0)(@types/node@22.20.1)(@vitest/browser-playwright@5.0.0)(@vitest/coverage-v8@5.0.0)(@vitest/ui@5.0.0)(happy-dom@20.10.2(bufferutil@4.1.0)(utf-8-validate@5.0.10))(jsdom@27.0.0(bufferutil@4.1.0)(utf-8-validate@5.0.10))(msw@2.15.0(@types/node@22.20.1)(typescript@6.0.3))(vite@8.2.2(@types/node@22.20.1)(esbuild@0.27.7)(jiti@2.7.0)(terser@5.46.1)(tsx@4.20.6)(yaml@2.9.0)): + vitest@5.0.0(@edge-runtime/vm@5.0.0)(@opentelemetry/api@1.9.0)(@types/node@22.20.1)(@vitest/browser-playwright@5.0.0)(@vitest/coverage-v8@5.0.0)(@vitest/ui@5.0.0)(happy-dom@20.10.2(bufferutil@4.1.0)(utf-8-validate@5.0.10))(jsdom@27.0.0(bufferutil@4.1.0)(utf-8-validate@5.0.10))(msw@2.15.0(@types/node@22.20.1)(typescript@6.0.3))(vite@8.2.2(@types/node@22.20.1)(esbuild@0.27.7)(jiti@2.7.0)(terser@5.46.1)(tsx@4.23.14)(yaml@2.9.0)): dependencies: '@types/chai': 5.2.3 - '@vitest/mocker': 5.0.0(msw@2.15.0(@types/node@22.20.1)(typescript@6.0.3))(vite@8.2.2(@types/node@22.20.1)(esbuild@0.27.7)(jiti@2.7.0)(terser@5.46.1)(tsx@4.20.6)(yaml@2.9.0)) + '@vitest/mocker': 5.0.0(msw@2.15.0(@types/node@22.20.1)(typescript@6.0.3))(vite@8.2.2(@types/node@22.20.1)(esbuild@0.27.7)(jiti@2.7.0)(terser@5.46.1)(tsx@4.23.14)(yaml@2.9.0)) chai: 6.2.2 es-module-lexer: 2.3.2 expect-type: 1.4.0 @@ -32258,13 +32135,13 @@ snapshots: tinybench: 6.1.4 tinyexec: 1.3.0 tinyglobby: 0.2.17 - vite: 8.2.2(@types/node@22.20.1)(esbuild@0.27.7)(jiti@2.7.0)(terser@5.46.1)(tsx@4.20.6)(yaml@2.9.0) + vite: 8.2.2(@types/node@22.20.1)(esbuild@0.27.7)(jiti@2.7.0)(terser@5.46.1)(tsx@4.23.14)(yaml@2.9.0) why-is-node-running: 2.3.0 optionalDependencies: '@edge-runtime/vm': 5.0.0 '@opentelemetry/api': 1.9.0 '@types/node': 22.20.1 - '@vitest/browser-playwright': 5.0.0(bufferutil@4.1.0)(msw@2.15.0(@types/node@22.20.1)(typescript@6.0.3))(playwright@1.62.1)(utf-8-validate@5.0.10)(vite@8.2.2(@types/node@22.20.1)(esbuild@0.27.7)(jiti@2.7.0)(terser@5.46.1)(tsx@4.20.6)(yaml@2.9.0))(vitest@5.0.0) + '@vitest/browser-playwright': 5.0.0(bufferutil@4.1.0)(msw@2.15.0(@types/node@22.20.1)(typescript@6.0.3))(playwright@1.62.1)(utf-8-validate@5.0.10)(vite@8.2.2(@types/node@22.20.1)(esbuild@0.27.7)(jiti@2.7.0)(terser@5.46.1)(tsx@4.23.14)(yaml@2.9.0))(vitest@5.0.0) '@vitest/coverage-v8': 5.0.0(@vitest/browser@5.0.0)(vitest@5.0.0) '@vitest/ui': 5.0.0(vitest@5.0.0) happy-dom: 20.10.2(bufferutil@4.1.0)(utf-8-validate@5.0.10) @@ -32272,10 +32149,10 @@ snapshots: transitivePeerDependencies: - msw - vitest@5.0.0(@edge-runtime/vm@5.0.0)(@opentelemetry/api@1.9.0)(@types/node@22.20.1)(@vitest/browser-playwright@5.0.0)(@vitest/coverage-v8@5.0.0)(@vitest/ui@5.0.0)(happy-dom@20.10.2(bufferutil@4.1.0)(utf-8-validate@5.0.10))(jsdom@27.0.0(bufferutil@4.1.0)(utf-8-validate@5.0.10))(msw@2.15.0(@types/node@22.20.1)(typescript@6.0.3))(vite@8.2.2(@types/node@22.20.1)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.46.1)(tsx@4.20.6)(yaml@2.9.0)): + vitest@5.0.0(@edge-runtime/vm@5.0.0)(@opentelemetry/api@1.9.0)(@types/node@22.20.1)(@vitest/browser-playwright@5.0.0)(@vitest/coverage-v8@5.0.0)(@vitest/ui@5.0.0)(happy-dom@20.10.2(bufferutil@4.1.0)(utf-8-validate@5.0.10))(jsdom@27.0.0(bufferutil@4.1.0)(utf-8-validate@5.0.10))(msw@2.15.0(@types/node@22.20.1)(typescript@6.0.3))(vite@8.2.2(@types/node@22.20.1)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.46.1)(tsx@4.23.14)(yaml@2.9.0)): dependencies: '@types/chai': 5.2.3 - '@vitest/mocker': 5.0.0(msw@2.15.0(@types/node@22.20.1)(typescript@6.0.3))(vite@8.2.2(@types/node@22.20.1)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.46.1)(tsx@4.20.6)(yaml@2.9.0)) + '@vitest/mocker': 5.0.0(msw@2.15.0(@types/node@22.20.1)(typescript@6.0.3))(vite@8.2.2(@types/node@22.20.1)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.46.1)(tsx@4.23.14)(yaml@2.9.0)) chai: 6.2.2 es-module-lexer: 2.3.2 expect-type: 1.4.0 @@ -32286,13 +32163,13 @@ snapshots: tinybench: 6.1.4 tinyexec: 1.3.0 tinyglobby: 0.2.17 - vite: 8.2.2(@types/node@22.20.1)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.46.1)(tsx@4.20.6)(yaml@2.9.0) + vite: 8.2.2(@types/node@22.20.1)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.46.1)(tsx@4.23.14)(yaml@2.9.0) why-is-node-running: 2.3.0 optionalDependencies: '@edge-runtime/vm': 5.0.0 '@opentelemetry/api': 1.9.0 '@types/node': 22.20.1 - '@vitest/browser-playwright': 5.0.0(bufferutil@4.1.0)(msw@2.15.0(@types/node@22.20.1)(typescript@6.0.3))(playwright@1.62.1)(utf-8-validate@5.0.10)(vite@8.2.2(@types/node@22.20.1)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.46.1)(tsx@4.20.6)(yaml@2.9.0))(vitest@5.0.0) + '@vitest/browser-playwright': 5.0.0(bufferutil@4.1.0)(msw@2.15.0(@types/node@22.20.1)(typescript@6.0.3))(playwright@1.62.1)(utf-8-validate@5.0.10)(vite@8.2.2(@types/node@22.20.1)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.46.1)(tsx@4.23.14)(yaml@2.9.0))(vitest@5.0.0) '@vitest/coverage-v8': 5.0.0(@vitest/browser@5.0.0)(vitest@5.0.0) '@vitest/ui': 5.0.0(vitest@5.0.0) happy-dom: 20.10.2(bufferutil@4.1.0)(utf-8-validate@5.0.10) @@ -32300,10 +32177,10 @@ snapshots: transitivePeerDependencies: - msw - vitest@5.0.0(@edge-runtime/vm@5.0.0)(@opentelemetry/api@1.9.0)(@types/node@25.6.0)(@vitest/browser-playwright@5.0.0)(@vitest/coverage-v8@5.0.0)(@vitest/ui@5.0.0)(happy-dom@20.10.2(bufferutil@4.1.0)(utf-8-validate@5.0.10))(jsdom@27.0.0(bufferutil@4.1.0)(utf-8-validate@5.0.10))(msw@2.15.0(@types/node@25.6.0)(typescript@6.0.3))(vite@8.2.2(@types/node@25.6.0)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.46.1)(tsx@4.20.6)(yaml@2.9.0)): + vitest@5.0.0(@edge-runtime/vm@5.0.0)(@opentelemetry/api@1.9.0)(@types/node@25.6.0)(@vitest/browser-playwright@5.0.0)(@vitest/coverage-v8@5.0.0)(@vitest/ui@5.0.0)(happy-dom@20.10.2(bufferutil@4.1.0)(utf-8-validate@5.0.10))(jsdom@27.0.0(bufferutil@4.1.0)(utf-8-validate@5.0.10))(msw@2.15.0(@types/node@25.6.0)(typescript@6.0.3))(vite@8.2.2(@types/node@25.6.0)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.46.1)(tsx@4.23.14)(yaml@2.9.0)): dependencies: '@types/chai': 5.2.3 - '@vitest/mocker': 5.0.0(msw@2.15.0(@types/node@25.6.0)(typescript@6.0.3))(vite@8.2.2(@types/node@25.6.0)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.46.1)(tsx@4.20.6)(yaml@2.9.0)) + '@vitest/mocker': 5.0.0(msw@2.15.0(@types/node@25.6.0)(typescript@6.0.3))(vite@8.2.2(@types/node@25.6.0)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.46.1)(tsx@4.23.14)(yaml@2.9.0)) chai: 6.2.2 es-module-lexer: 2.3.2 expect-type: 1.4.0 @@ -32314,13 +32191,13 @@ snapshots: tinybench: 6.1.4 tinyexec: 1.3.0 tinyglobby: 0.2.17 - vite: 8.2.2(@types/node@25.6.0)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.46.1)(tsx@4.20.6)(yaml@2.9.0) + vite: 8.2.2(@types/node@25.6.0)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.46.1)(tsx@4.23.14)(yaml@2.9.0) why-is-node-running: 2.3.0 optionalDependencies: '@edge-runtime/vm': 5.0.0 '@opentelemetry/api': 1.9.0 '@types/node': 25.6.0 - '@vitest/browser-playwright': 5.0.0(bufferutil@4.1.0)(msw@2.15.0(@types/node@25.6.0)(typescript@6.0.3))(playwright@1.62.1)(utf-8-validate@5.0.10)(vite@8.2.2(@types/node@25.6.0)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.46.1)(tsx@4.20.6)(yaml@2.9.0))(vitest@5.0.0) + '@vitest/browser-playwright': 5.0.0(bufferutil@4.1.0)(msw@2.15.0(@types/node@25.6.0)(typescript@6.0.3))(playwright@1.62.1)(utf-8-validate@5.0.10)(vite@8.2.2(@types/node@25.6.0)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.46.1)(tsx@4.23.14)(yaml@2.9.0))(vitest@5.0.0) '@vitest/coverage-v8': 5.0.0(@vitest/browser@5.0.0)(vitest@5.0.0) '@vitest/ui': 5.0.0(vitest@5.0.0) happy-dom: 20.10.2(bufferutil@4.1.0)(utf-8-validate@5.0.10) @@ -32342,7 +32219,7 @@ snapshots: vue-devtools-stub@0.1.0: {} - vue-router@5.3.0(@rspack/core@2.0.6)(@vue/compiler-sfc@3.5.42)(esbuild@0.28.1)(rolldown@1.1.0)(rollup@4.61.0)(vite@8.2.2(@types/node@25.6.0)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.46.1)(tsx@4.20.6)(yaml@2.9.0))(vue@3.5.42(typescript@6.0.3))(webpack@5.102.1(esbuild@0.28.1)): + vue-router@5.3.0(@rspack/core@2.0.6)(@vue/compiler-sfc@3.5.42)(esbuild@0.28.1)(rolldown@1.1.0)(rollup@4.61.0)(vite@8.2.2(@types/node@25.6.0)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.46.1)(tsx@4.23.14)(yaml@2.9.0))(vue@3.5.42(typescript@6.0.3))(webpack@5.102.1(esbuild@0.28.1)): dependencies: '@vue-macros/common': 3.1.4(vue@3.5.42(typescript@6.0.3)) '@vue/devtools-api': 8.2.1 @@ -32358,12 +32235,12 @@ snapshots: picomatch: 4.0.7 scule: 1.3.0 tinyglobby: 0.2.17 - unplugin: 3.3.0(@rspack/core@2.0.6)(esbuild@0.28.1)(rolldown@1.1.0)(rollup@4.61.0)(vite@8.2.2(@types/node@25.6.0)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.46.1)(tsx@4.20.6)(yaml@2.9.0))(webpack@5.102.1(esbuild@0.28.1)) + unplugin: 3.3.0(@rspack/core@2.0.6)(esbuild@0.28.1)(rolldown@1.1.0)(rollup@4.61.0)(vite@8.2.2(@types/node@25.6.0)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.46.1)(tsx@4.23.14)(yaml@2.9.0))(webpack@5.102.1(esbuild@0.28.1)) unplugin-utils: 0.3.2 vue: 3.5.42(typescript@6.0.3) optionalDependencies: '@vue/compiler-sfc': 3.5.42 - vite: 8.2.2(@types/node@25.6.0)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.46.1)(tsx@4.20.6)(yaml@2.9.0) + vite: 8.2.2(@types/node@25.6.0)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.46.1)(tsx@4.23.14)(yaml@2.9.0) transitivePeerDependencies: - '@farmfe/core' - '@rspack/core' @@ -32822,8 +32699,14 @@ snapshots: dependencies: zod: 3.25.76 + zod-to-json-schema@3.25.2(zod@4.6.1): + dependencies: + zod: 4.6.1 + zod@3.25.76: {} + zod@4.6.1: {} + zod@4.6.5: {} zustand@5.0.3(@types/react@18.3.28)(react@18.3.1)(use-sync-external-store@1.6.0(react@18.3.1)): diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index c666252d1cd..61497dac211 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -69,6 +69,9 @@ overrides: minimumReleaseAge: 2880 minimumReleaseAgeExclude: - '@clerk/*' + - '@e2e-dev/mobile@0.8.1' + - 'agent-device@0.21.18' + - 'e2e@0.15.1' - '@tanstack/react-router@1.170.41' - '@tanstack/router-core@1.171.34' - '@tanstack/router-generator@1.167.40' From 04c7888520aae61767b7451a0d8ca0092fc1c25b Mon Sep 17 00:00:00 2001 From: wobsoriano Date: Thu, 1 Oct 2026 20:02:38 -0700 Subject: [PATCH 03/31] ci(e2e): wait for the identifier field and skip temp video files on upload --- .github/workflows/expo-native-build.yml | 1 + integration/tests/expo-native/flows/subflows.ts | 7 +++---- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/expo-native-build.yml b/.github/workflows/expo-native-build.yml index 78e8dae8ab0..8a930ced030 100644 --- a/.github/workflows/expo-native-build.yml +++ b/.github/workflows/expo-native-build.yml @@ -372,6 +372,7 @@ jobs: include-hidden-files: true path: | integration/.e2e + !integration/.e2e/**/.video.* ${{ runner.temp }}/e2e-device-logs if-no-files-found: warn retention-days: 7 diff --git a/integration/tests/expo-native/flows/subflows.ts b/integration/tests/expo-native/flows/subflows.ts index a25deea5a68..112f3bfba1f 100644 --- a/integration/tests/expo-native/flows/subflows.ts +++ b/integration/tests/expo-native/flows/subflows.ts @@ -97,10 +97,9 @@ const afterPassword = export async function signInEmailPassword(fixtures: Fixtures) { const { screen } = fixtures; await expect(screen.getByText(/^Welcome! Sign in to continue\.?$/)).toBeVisible({ timeout: 25_000 }); - const identifierPlaceholder = screen.getByText(/^Enter your email( or username)?$/); - if (await identifierPlaceholder.isVisible()) { - await identifierPlaceholder.tap(); - } + const identifierLabel = screen.getByText(/^Enter your email( or username)?$/); + await expect(identifierLabel).toBeVisible({ timeout: 25_000 }); + await identifierLabel.tap(); const identifier = screen.getByDisplayValue(email); if (!(await identifier.isVisible())) { await fill(screen.getByRole('textbox'), email); From 48db6cd1c1ab3658e7dd321917c7ce09516905da Mon Sep 17 00:00:00 2001 From: wobsoriano Date: Thu, 1 Oct 2026 20:20:01 -0700 Subject: [PATCH 04/31] ci(e2e): handle overlapping screens and compose rows on the api 34 emulator --- .../flows/embedded-profile-host-back.e2e.ts | 4 +-- .../tests/expo-native/flows/subflows.ts | 25 +++++++++++++------ .../user-button-sign-out-re-sign-in.e2e.ts | 4 +-- .../flows/user-profile-custom-pages.e2e.ts | 4 +-- 4 files changed, 24 insertions(+), 13 deletions(-) diff --git a/integration/tests/expo-native/flows/embedded-profile-host-back.e2e.ts b/integration/tests/expo-native/flows/embedded-profile-host-back.e2e.ts index 775e21cbb5c..b74ba35c303 100644 --- a/integration/tests/expo-native/flows/embedded-profile-host-back.e2e.ts +++ b/integration/tests/expo-native/flows/embedded-profile-host-back.e2e.ts @@ -1,7 +1,7 @@ import { test } from '@e2e-dev/mobile'; import { expect } from 'e2e'; -import { assertSignedIn, assertSignedOut, openApp, signInEmailPassword, tapBack } from './subflows.ts'; +import { assertSignedIn, assertSignedOut, openApp, signInEmailPassword, tapBack, tapControl } from './subflows.ts'; const internalPush = { android: { root: 'Edit profile', row: 'Manage account', detail: /^(EMAIL ADDRESSES|Add email address)$/ }, @@ -17,7 +17,7 @@ test('Embedded UserProfileView host back round trip', async fixtures => { await assertSignedIn(fixtures); await screen.getByTestId('open-embedded-profile-button').tap(); await expect(screen.getByText(root)).toBeVisible({ timeout: 20_000 }); - await screen.getByText(row).tap(); + await tapControl(fixtures, screen.getByText(row)); await expect(screen.getByText(detail).first()).toBeVisible({ timeout: 15_000 }); await tapBack(fixtures); await expect(screen.getByText(root)).toBeVisible({ timeout: 15_000 }); diff --git a/integration/tests/expo-native/flows/subflows.ts b/integration/tests/expo-native/flows/subflows.ts index 112f3bfba1f..0da387a08c4 100644 --- a/integration/tests/expo-native/flows/subflows.ts +++ b/integration/tests/expo-native/flows/subflows.ts @@ -26,16 +26,27 @@ export async function assertSignedOut({ screen }: Fixtures) { await expect(screen.getByText('signed out')).toBeVisible({ timeout: 20_000 }); } -export async function tapBack({ screen }: Fixtures) { - const back = screen.getByLabel('Back'); - await expect(back).toBeVisible(); - const box = await back.boundingBox(); +async function tapCenter({ screen }: Fixtures, control: Locator) { + await expect(control).toBeVisible(); + const box = await control.boundingBox(); if (!box) { - throw new Error('Back control has no bounding box'); + throw new Error('Control has no bounding box'); } await screen.tapAt({ x: box.x + box.width / 2, y: box.y + box.height / 2 }); } +export async function tapControl(fixtures: Fixtures, control: Locator) { + if (fixtures.platform === 'android') { + await tapCenter(fixtures, control); + } else { + await control.tap(); + } +} + +export async function tapBack(fixtures: Fixtures) { + await tapCenter(fixtures, fixtures.screen.getByLabel('Back').last()); +} + async function fill(field: Locator, value: string) { await field.fill(value).catch((error: { code?: string }) => { if (error.code !== 'ENGINE_FAILURE') { @@ -62,7 +73,7 @@ async function skipPasskeyFirstFactor({ platform, screen }: Fixtures) { async function enterEmailCode({ screen }: Fixtures) { if (await screen.getByText('Check your email').isVisible()) { - await fill(screen.getByRole('textbox'), '424242'); + await screen.getByRole('textbox').last().pressSequentially('424242'); } } @@ -114,7 +125,7 @@ export async function signInEmailPassword(fixtures: Fixtures) { } await enterEmailCode(fixtures); if (await screen.getByText('Enter your password').first().isVisible()) { - await fill(screen.getByRole('textbox'), password); + await fill(screen.getByRole('textbox').last(), password); await screen.getByText('Continue').tap(); await expect(screen.getByText(afterPassword).first()).toBeVisible({ timeout: 15_000 }); } diff --git a/integration/tests/expo-native/flows/user-button-sign-out-re-sign-in.e2e.ts b/integration/tests/expo-native/flows/user-button-sign-out-re-sign-in.e2e.ts index c70176dc994..76cd19eb8ec 100644 --- a/integration/tests/expo-native/flows/user-button-sign-out-re-sign-in.e2e.ts +++ b/integration/tests/expo-native/flows/user-button-sign-out-re-sign-in.e2e.ts @@ -1,7 +1,7 @@ import { test } from '@e2e-dev/mobile'; import { expect } from 'e2e'; -import { assertSignedIn, assertSignedOut, openApp, signInEmailPassword } from './subflows.ts'; +import { assertSignedIn, assertSignedOut, openApp, signInEmailPassword, tapControl } from './subflows.ts'; test('UserButton native sign-out, then same-process re-sign-in', async fixtures => { const { screen } = fixtures; @@ -11,7 +11,7 @@ test('UserButton native sign-out, then same-process re-sign-in', async fixtures await assertSignedIn(fixtures); await screen.getByLabel(/^Open (account|user profile)$/).tap(); await expect(screen.getByText('Manage account')).toBeVisible({ timeout: 15_000 }); - await screen.getByText('Sign out').tap(); + await tapControl(fixtures, screen.getByText('Sign out')); await assertSignedOut(fixtures); await screen.getByTestId('open-auth-view-button').tap(); await signInEmailPassword(fixtures); diff --git a/integration/tests/expo-native/flows/user-profile-custom-pages.e2e.ts b/integration/tests/expo-native/flows/user-profile-custom-pages.e2e.ts index ef809547cfc..2856890bdf7 100644 --- a/integration/tests/expo-native/flows/user-profile-custom-pages.e2e.ts +++ b/integration/tests/expo-native/flows/user-profile-custom-pages.e2e.ts @@ -1,7 +1,7 @@ import { test } from '@e2e-dev/mobile'; import { expect } from 'e2e'; -import { assertSignedIn, assertSignedOut, openApp, signInEmailPassword, tapBack } from './subflows.ts'; +import { assertSignedIn, assertSignedOut, openApp, signInEmailPassword, tapBack, tapControl } from './subflows.ts'; test('UserProfileView renders a custom page', async fixtures => { const { device, platform, screen } = fixtures; @@ -11,7 +11,7 @@ test('UserProfileView renders a custom page', async fixtures => { await assertSignedIn(fixtures); await screen.getByTestId('open-embedded-profile-button').tap(); await expect(screen.getByText('E2E Custom Page')).toBeVisible({ timeout: 20_000 }); - await screen.getByText('E2E Custom Page').tap(); + await tapControl(fixtures, screen.getByText('E2E Custom Page')); await expect(screen.getByText('Rehosted RN body')).toBeVisible({ timeout: 15_000 }); if (platform === 'android') { await device.back(); From 61f7f9340498712da4441cf79bd4877c7b1f721b Mon Sep 17 00:00:00 2001 From: wobsoriano Date: Thu, 1 Oct 2026 20:38:02 -0700 Subject: [PATCH 05/31] ci(e2e): TEMP bust caches to measure a cold run --- .github/workflows/expo-native-build.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/expo-native-build.yml b/.github/workflows/expo-native-build.yml index 8a930ced030..78aa3586dcd 100644 --- a/.github/workflows/expo-native-build.yml +++ b/.github/workflows/expo-native-build.yml @@ -102,7 +102,7 @@ jobs: with: path: ${{ steps.native-build-key.outputs.artifact }} # Bump the version when native build commands change. - key: expo-native-build-v1-${{ runner.os }}-${{ matrix.expo-sdk }}-${{ matrix.platform }}-${{ matrix.run-e2e == true && 'e2e' || 'build' }}-${{ env.E2E_INSTANCE_NAME }}-${{ steps.native-build-key.outputs.hash }} + key: expo-native-build-v1cold-${{ runner.os }}-${{ matrix.expo-sdk }}-${{ matrix.platform }}-${{ matrix.run-e2e == true && 'e2e' || 'build' }}-${{ env.E2E_INSTANCE_NAME }}-${{ steps.native-build-key.outputs.hash }} - if: steps.native-build-cache.outputs.cache-hit != 'true' || matrix.run-e2e == true uses: pnpm/action-setup@b906affcce14559ad1aafd4ab0e942779e9f58b1 # v4 @@ -233,8 +233,8 @@ jobs: uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4 with: path: ~/.agent-device - key: agent-device-${{ runner.os }}-${{ hashFiles('pnpm-lock.yaml') }} - restore-keys: agent-device-${{ runner.os }}- + key: agent-device-cold-${{ runner.os }}-${{ hashFiles('pnpm-lock.yaml') }} + restore-keys: agent-device-cold-${{ runner.os }}- # Provisioned as late as possible so live credentials exist for the # shortest window. @@ -301,7 +301,7 @@ jobs: path: | ~/.android/avd/* ~/.android/adb* - key: avd-34-google_apis-x86_64-v1 + key: avd-34-google_apis-x86_64-v1cold - name: Create AVD snapshot if: matrix.platform == 'android' && steps.user.outputs.user_id != '' && steps.avd-cache.outputs.cache-hit != 'true' From 0db4c37cbe04a41343a795df8c7c7f0a81747729 Mon Sep 17 00:00:00 2001 From: wobsoriano Date: Thu, 1 Oct 2026 20:54:05 -0700 Subject: [PATCH 06/31] Revert "ci(e2e): TEMP bust caches to measure a cold run" This reverts commit 61f7f9340498712da4441cf79bd4877c7b1f721b. --- .github/workflows/expo-native-build.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/expo-native-build.yml b/.github/workflows/expo-native-build.yml index 78aa3586dcd..8a930ced030 100644 --- a/.github/workflows/expo-native-build.yml +++ b/.github/workflows/expo-native-build.yml @@ -102,7 +102,7 @@ jobs: with: path: ${{ steps.native-build-key.outputs.artifact }} # Bump the version when native build commands change. - key: expo-native-build-v1cold-${{ runner.os }}-${{ matrix.expo-sdk }}-${{ matrix.platform }}-${{ matrix.run-e2e == true && 'e2e' || 'build' }}-${{ env.E2E_INSTANCE_NAME }}-${{ steps.native-build-key.outputs.hash }} + key: expo-native-build-v1-${{ runner.os }}-${{ matrix.expo-sdk }}-${{ matrix.platform }}-${{ matrix.run-e2e == true && 'e2e' || 'build' }}-${{ env.E2E_INSTANCE_NAME }}-${{ steps.native-build-key.outputs.hash }} - if: steps.native-build-cache.outputs.cache-hit != 'true' || matrix.run-e2e == true uses: pnpm/action-setup@b906affcce14559ad1aafd4ab0e942779e9f58b1 # v4 @@ -233,8 +233,8 @@ jobs: uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4 with: path: ~/.agent-device - key: agent-device-cold-${{ runner.os }}-${{ hashFiles('pnpm-lock.yaml') }} - restore-keys: agent-device-cold-${{ runner.os }}- + key: agent-device-${{ runner.os }}-${{ hashFiles('pnpm-lock.yaml') }} + restore-keys: agent-device-${{ runner.os }}- # Provisioned as late as possible so live credentials exist for the # shortest window. @@ -301,7 +301,7 @@ jobs: path: | ~/.android/avd/* ~/.android/adb* - key: avd-34-google_apis-x86_64-v1cold + key: avd-34-google_apis-x86_64-v1 - name: Create AVD snapshot if: matrix.platform == 'android' && steps.user.outputs.user_id != '' && steps.avd-cache.outputs.cache-hit != 'true' From 0f64d1d337bc46ca8606138f0cbee7fc7e752736 Mon Sep 17 00:00:00 2001 From: wobsoriano Date: Fri, 2 Oct 2026 01:37:49 -0700 Subject: [PATCH 07/31] ci(e2e): create a user per test and retry taps dropped during ios transitions --- .../flows/authview-detach-reattach.e2e.ts | 21 +++-- .../flows/embedded-profile-host-back.e2e.ts | 18 +++-- .../tests/expo-native/flows/fixtures.ts | 38 +++++++++ .../tests/expo-native/flows/sign-in.e2e.ts | 6 +- .../tests/expo-native/flows/subflows.ts | 78 +++++++++---------- .../user-button-sign-out-re-sign-in.e2e.ts | 8 +- .../flows/user-profile-custom-pages.e2e.ts | 18 +++-- .../tests/expo-native/run-android-flows.sh | 61 --------------- integration/tests/expo-native/run-flows.sh | 22 ------ 9 files changed, 123 insertions(+), 147 deletions(-) create mode 100644 integration/tests/expo-native/flows/fixtures.ts delete mode 100755 integration/tests/expo-native/run-android-flows.sh delete mode 100755 integration/tests/expo-native/run-flows.sh diff --git a/integration/tests/expo-native/flows/authview-detach-reattach.e2e.ts b/integration/tests/expo-native/flows/authview-detach-reattach.e2e.ts index a3b7cbaa203..645ae3a75fe 100644 --- a/integration/tests/expo-native/flows/authview-detach-reattach.e2e.ts +++ b/integration/tests/expo-native/flows/authview-detach-reattach.e2e.ts @@ -1,21 +1,28 @@ -import { test } from '@e2e-dev/mobile'; import { expect } from 'e2e'; -import { assertSignedIn, assertSignedOut, openApp, signInEmailPassword } from './subflows.ts'; +import { test } from './fixtures.ts'; +import { + assertSignedIn, + assertSignedOut, + openApp, + openAuthView, + signInEmailPassword, + tapUntilVisible, +} from './subflows.ts'; test('AuthView survives detach and reattach', async fixtures => { const { device, platform, screen } = fixtures; await openApp(fixtures); - await screen.getByTestId('open-auth-view-button').tap(); - await expect(screen.getByText(/^Welcome! Sign in to continue\.?$/)).toBeVisible({ timeout: 25_000 }); + await openAuthView(fixtures); await expect(screen.getByText('E2E Custom Logo')).toBeVisible({ timeout: 10_000 }); + const openButton = screen.getByTestId('open-auth-view-button'); if (platform === 'android') { await device.back(); + await expect(openButton).toBeVisible({ timeout: 15_000 }); } else { - await screen.getByRole('button', 'Close').tap(); + await tapUntilVisible(screen.getByRole('button', 'Close'), openButton); } - await expect(screen.getByTestId('open-auth-view-button')).toBeVisible({ timeout: 15_000 }); - await screen.getByTestId('open-auth-view-button').tap(); + await openAuthView(fixtures); await expect(screen.getByText('E2E Custom Logo')).toBeVisible({ timeout: 15_000 }); await signInEmailPassword(fixtures); await assertSignedIn(fixtures); diff --git a/integration/tests/expo-native/flows/embedded-profile-host-back.e2e.ts b/integration/tests/expo-native/flows/embedded-profile-host-back.e2e.ts index b74ba35c303..e8ce5ef9650 100644 --- a/integration/tests/expo-native/flows/embedded-profile-host-back.e2e.ts +++ b/integration/tests/expo-native/flows/embedded-profile-host-back.e2e.ts @@ -1,7 +1,16 @@ -import { test } from '@e2e-dev/mobile'; import { expect } from 'e2e'; -import { assertSignedIn, assertSignedOut, openApp, signInEmailPassword, tapBack, tapControl } from './subflows.ts'; +import { test } from './fixtures.ts'; +import { + assertSignedIn, + assertSignedOut, + openApp, + openAuthView, + signInEmailPassword, + tapBack, + tapControl, + tapUntilVisible, +} from './subflows.ts'; const internalPush = { android: { root: 'Edit profile', row: 'Manage account', detail: /^(EMAIL ADDRESSES|Add email address)$/ }, @@ -12,11 +21,10 @@ test('Embedded UserProfileView host back round trip', async fixtures => { const { platform, screen } = fixtures; const { root, row, detail } = internalPush[platform as keyof typeof internalPush]; await openApp(fixtures); - await screen.getByTestId('open-auth-view-button').tap(); + await openAuthView(fixtures); await signInEmailPassword(fixtures); await assertSignedIn(fixtures); - await screen.getByTestId('open-embedded-profile-button').tap(); - await expect(screen.getByText(root)).toBeVisible({ timeout: 20_000 }); + await tapUntilVisible(screen.getByTestId('open-embedded-profile-button'), screen.getByText(root)); await tapControl(fixtures, screen.getByText(row)); await expect(screen.getByText(detail).first()).toBeVisible({ timeout: 15_000 }); await tapBack(fixtures); diff --git a/integration/tests/expo-native/flows/fixtures.ts b/integration/tests/expo-native/flows/fixtures.ts new file mode 100644 index 00000000000..aa7dd2a694b --- /dev/null +++ b/integration/tests/expo-native/flows/fixtures.ts @@ -0,0 +1,38 @@ +import { randomBytes } from 'node:crypto'; + +import type { Device } from '@e2e-dev/mobile'; +import { test as base } from '@e2e-dev/mobile'; +import type { TestFixtures } from 'e2e'; + +export type TestUser = { email: string; password: string }; + +export type DeviceFixtures = TestFixtures & { device: Device }; + +export type Fixtures = DeviceFixtures & { user: TestUser }; + +function bapi(path: string, init: RequestInit) { + return fetch(`${process.env.CLERK_API_URL ?? 'https://api.clerk.com'}/v1${path}`, { + ...init, + headers: { Authorization: `Bearer ${process.env.CLERK_SECRET_KEY}`, 'Content-Type': 'application/json' }, + }); +} + +export const test = base.extend<{ user: TestUser }>({ + user: async (_fixtures, use) => { + const suffix = randomBytes(4).toString('hex'); + const user = { + email: `${suffix}+clerk_test@example.com`, + password: `ClerkCI!${randomBytes(8).toString('hex')}Aa1`, + }; + const response = await bapi('/users', { + method: 'POST', + body: JSON.stringify({ email_address: [user.email], username: `e2e_${suffix}`, password: user.password }), + }); + if (!response.ok) { + throw new Error(`BAPI user creation failed (HTTP ${response.status}): ${await response.text()}`); + } + const { id } = (await response.json()) as { id: string }; + await use(user); + await bapi(`/users/${id}`, { method: 'DELETE' }); + }, +}); diff --git a/integration/tests/expo-native/flows/sign-in.e2e.ts b/integration/tests/expo-native/flows/sign-in.e2e.ts index bb89eb604fe..beecfbd4488 100644 --- a/integration/tests/expo-native/flows/sign-in.e2e.ts +++ b/integration/tests/expo-native/flows/sign-in.e2e.ts @@ -1,12 +1,12 @@ -import { test } from '@e2e-dev/mobile'; import { expect } from 'e2e'; -import { assertSignedIn, assertSignedOut, openApp, signInEmailPassword } from './subflows.ts'; +import { test } from './fixtures.ts'; +import { assertSignedIn, assertSignedOut, openApp, openAuthView, signInEmailPassword } from './subflows.ts'; test('Native AuthView sign-in syncs to JS and survives a restart', async fixtures => { const { app, screen } = fixtures; await openApp(fixtures); - await screen.getByTestId('open-auth-view-button').tap(); + await openAuthView(fixtures); await signInEmailPassword(fixtures); await assertSignedIn(fixtures); await app.restart(); diff --git a/integration/tests/expo-native/flows/subflows.ts b/integration/tests/expo-native/flows/subflows.ts index 0da387a08c4..ba6034cb046 100644 --- a/integration/tests/expo-native/flows/subflows.ts +++ b/integration/tests/expo-native/flows/subflows.ts @@ -1,13 +1,9 @@ -import type { Device } from '@e2e-dev/mobile'; -import type { Locator, TestFixtures } from 'e2e'; +import type { Locator } from 'e2e'; import { expect } from 'e2e'; -export type Fixtures = TestFixtures & { device: Device }; +import type { DeviceFixtures, Fixtures } from './fixtures.ts'; -const email = process.env.CLERK_TEST_EMAIL ?? ''; -const password = process.env.CLERK_TEST_PASSWORD ?? ''; - -export async function openApp({ app, device, platform, screen }: Fixtures) { +export async function openApp({ app, device, platform, screen }: DeviceFixtures) { await app.open(); if (platform === 'ios') { await device.clearKeychain(); @@ -17,16 +13,37 @@ export async function openApp({ app, device, platform, screen }: Fixtures) { await expect(screen.getByText('signed out')).toBeVisible(); } -export async function assertSignedIn({ screen }: Fixtures) { +export async function tapUntilVisible(control: Locator, outcome: Locator) { + await expect + .poll( + async () => { + if (!(await outcome.isVisible()) && (await control.isVisible())) { + await control.tap(); + } + return outcome.isVisible(); + }, + { timeout: 30_000, interval: 1000 }, + ) + .toBe(true); +} + +export async function openAuthView({ screen }: DeviceFixtures) { + await tapUntilVisible( + screen.getByTestId('open-auth-view-button'), + screen.getByText(/^Welcome! Sign in to continue\.?$/), + ); +} + +export async function assertSignedIn({ screen }: DeviceFixtures) { await expect(screen.getByText('signed in')).toBeVisible({ timeout: 30_000 }); await expect(screen.getByTestId('user-id')).toBeVisible(); } -export async function assertSignedOut({ screen }: Fixtures) { +export async function assertSignedOut({ screen }: DeviceFixtures) { await expect(screen.getByText('signed out')).toBeVisible({ timeout: 20_000 }); } -async function tapCenter({ screen }: Fixtures, control: Locator) { +async function tapCenter({ screen }: DeviceFixtures, control: Locator) { await expect(control).toBeVisible(); const box = await control.boundingBox(); if (!box) { @@ -35,7 +52,7 @@ async function tapCenter({ screen }: Fixtures, control: Locator) { await screen.tapAt({ x: box.x + box.width / 2, y: box.y + box.height / 2 }); } -export async function tapControl(fixtures: Fixtures, control: Locator) { +export async function tapControl(fixtures: DeviceFixtures, control: Locator) { if (fixtures.platform === 'android') { await tapCenter(fixtures, control); } else { @@ -43,11 +60,12 @@ export async function tapControl(fixtures: Fixtures, control: Locator) { } } -export async function tapBack(fixtures: Fixtures) { +export async function tapBack(fixtures: DeviceFixtures) { await tapCenter(fixtures, fixtures.screen.getByLabel('Back').last()); } async function fill(field: Locator, value: string) { + await field.tap(); await field.fill(value).catch((error: { code?: string }) => { if (error.code !== 'ENGINE_FAILURE') { throw error; @@ -56,28 +74,13 @@ async function fill(field: Locator, value: string) { }); } -async function skipPasskeyFirstFactor({ platform, screen }: Fixtures) { - if (platform === 'ios') { - const error = screen.getByText('Whoops, something is wrong'); - await expect(error).toBeVisible({ timeout: 10_000 }); - for (let attempt = 0; attempt < 3 && (await error.isVisible()); attempt++) { - await screen.getByRole('button', 'Close').last().tap(); - await expect(error) - .toBeHidden({ timeout: 3000 }) - .catch(() => {}); - } - } - await screen.getByText(/^Use (a different|another) method$/).tap(); - await screen.getByText('Sign in with your password').tap(); -} - -async function enterEmailCode({ screen }: Fixtures) { +async function enterEmailCode({ screen }: DeviceFixtures) { if (await screen.getByText('Check your email').isVisible()) { await screen.getByRole('textbox').last().pressSequentially('424242'); } } -async function dismissPasswordManager({ screen }: Fixtures) { +async function dismissPasswordManager({ screen }: DeviceFixtures) { if ( await screen .getByText(/Google Password Manager/) @@ -106,26 +109,21 @@ const afterPassword = /^(Check your email|signed in|Save Password|Strong Password|Use Strong Password|AutoFill Passwords)$|Google Password Manager/i; export async function signInEmailPassword(fixtures: Fixtures) { - const { screen } = fixtures; + const { screen, user } = fixtures; await expect(screen.getByText(/^Welcome! Sign in to continue\.?$/)).toBeVisible({ timeout: 25_000 }); const identifierLabel = screen.getByText(/^Enter your email( or username)?$/); await expect(identifierLabel).toBeVisible({ timeout: 25_000 }); - await identifierLabel.tap(); - const identifier = screen.getByDisplayValue(email); + await tapUntilVisible(identifierLabel, screen.getByRole('textbox')); + const identifier = screen.getByDisplayValue(user.email); if (!(await identifier.isVisible())) { - await fill(screen.getByRole('textbox'), email); + await fill(screen.getByRole('textbox'), user.email); } await expect(identifier).toBeVisible(); await screen.getByText('Continue').tap(); - const firstFactor = screen.getByText(/^(Enter your password|Check your email|Use your passkey)$/).first(); - await expect(firstFactor).toBeVisible({ timeout: 15_000 }); - if (await screen.getByText('Use your passkey').isVisible()) { - await skipPasskeyFirstFactor(fixtures); - await expect(screen.getByText('Enter your password').first()).toBeVisible({ timeout: 15_000 }); - } + await expect(screen.getByText(/^(Enter your password|Check your email)$/).first()).toBeVisible({ timeout: 15_000 }); await enterEmailCode(fixtures); if (await screen.getByText('Enter your password').first().isVisible()) { - await fill(screen.getByRole('textbox').last(), password); + await fill(screen.getByRole('textbox').last(), user.password); await screen.getByText('Continue').tap(); await expect(screen.getByText(afterPassword).first()).toBeVisible({ timeout: 15_000 }); } diff --git a/integration/tests/expo-native/flows/user-button-sign-out-re-sign-in.e2e.ts b/integration/tests/expo-native/flows/user-button-sign-out-re-sign-in.e2e.ts index 76cd19eb8ec..df7bd4aa504 100644 --- a/integration/tests/expo-native/flows/user-button-sign-out-re-sign-in.e2e.ts +++ b/integration/tests/expo-native/flows/user-button-sign-out-re-sign-in.e2e.ts @@ -1,19 +1,19 @@ -import { test } from '@e2e-dev/mobile'; import { expect } from 'e2e'; -import { assertSignedIn, assertSignedOut, openApp, signInEmailPassword, tapControl } from './subflows.ts'; +import { test } from './fixtures.ts'; +import { assertSignedIn, assertSignedOut, openApp, openAuthView, signInEmailPassword, tapControl } from './subflows.ts'; test('UserButton native sign-out, then same-process re-sign-in', async fixtures => { const { screen } = fixtures; await openApp(fixtures); - await screen.getByTestId('open-auth-view-button').tap(); + await openAuthView(fixtures); await signInEmailPassword(fixtures); await assertSignedIn(fixtures); await screen.getByLabel(/^Open (account|user profile)$/).tap(); await expect(screen.getByText('Manage account')).toBeVisible({ timeout: 15_000 }); await tapControl(fixtures, screen.getByText('Sign out')); await assertSignedOut(fixtures); - await screen.getByTestId('open-auth-view-button').tap(); + await openAuthView(fixtures); await signInEmailPassword(fixtures); await assertSignedIn(fixtures); await screen.getByTestId('sign-out-button').tap(); diff --git a/integration/tests/expo-native/flows/user-profile-custom-pages.e2e.ts b/integration/tests/expo-native/flows/user-profile-custom-pages.e2e.ts index 2856890bdf7..22c344d343c 100644 --- a/integration/tests/expo-native/flows/user-profile-custom-pages.e2e.ts +++ b/integration/tests/expo-native/flows/user-profile-custom-pages.e2e.ts @@ -1,16 +1,24 @@ -import { test } from '@e2e-dev/mobile'; import { expect } from 'e2e'; -import { assertSignedIn, assertSignedOut, openApp, signInEmailPassword, tapBack, tapControl } from './subflows.ts'; +import { test } from './fixtures.ts'; +import { + assertSignedIn, + assertSignedOut, + openApp, + openAuthView, + signInEmailPassword, + tapBack, + tapControl, + tapUntilVisible, +} from './subflows.ts'; test('UserProfileView renders a custom page', async fixtures => { const { device, platform, screen } = fixtures; await openApp(fixtures); - await screen.getByTestId('open-auth-view-button').tap(); + await openAuthView(fixtures); await signInEmailPassword(fixtures); await assertSignedIn(fixtures); - await screen.getByTestId('open-embedded-profile-button').tap(); - await expect(screen.getByText('E2E Custom Page')).toBeVisible({ timeout: 20_000 }); + await tapUntilVisible(screen.getByTestId('open-embedded-profile-button'), screen.getByText('E2E Custom Page')); await tapControl(fixtures, screen.getByText('E2E Custom Page')); await expect(screen.getByText('Rehosted RN body')).toBeVisible({ timeout: 15_000 }); if (platform === 'android') { diff --git a/integration/tests/expo-native/run-android-flows.sh b/integration/tests/expo-native/run-android-flows.sh deleted file mode 100755 index 5487e3f4de4..00000000000 --- a/integration/tests/expo-native/run-android-flows.sh +++ /dev/null @@ -1,61 +0,0 @@ -#!/usr/bin/env bash -# Usage: ./run-android-flows.sh (inside reactivecircus/android-emulator-runner) -set -euo pipefail -cd "$(dirname "${BASH_SOURCE[0]}")" - -apk_path=${1:?APK path is required} -command -v adb >/dev/null 2>&1 || { - echo 'adb is required' - exit 1 -} - -shards=${E2E_SHARDS:-1} -devices=(emulator-5554) -sdk=$(dirname "$(dirname "$(command -v adb)")") -debug=${E2E_DEVICE_LOGS:-${TMPDIR:-/tmp}/clerk-expo-native-e2e} -mkdir -p "$debug" - -for ((i = 1; i < shards; i++)); do - port=$((5554 + i * 2)) - "$sdk/emulator/emulator" -avd "${AVD_NAME:-test}" -read-only -port "$port" \ - -no-window -gpu swiftshader_indirect -noaudio -no-boot-anim -no-snapshot-save \ - > "$debug/emulator-$port.log" 2>&1 & - devices+=("emulator-$port") -done - -# adb wait-for-device never returns for an emulator that died at startup -wait_for_boot() { - local device=$1 elapsed=0 - until [ "$(adb -s "$device" shell getprop sys.boot_completed 2>/dev/null | tr -d '\r')" = 1 ]; do - if [ "$elapsed" -ge 240 ]; then - echo "::error::$device did not boot within ${elapsed}s" - [ -f "$debug/$device.log" ] && tail -n 40 "$debug/$device.log" - return 1 - fi - sleep 5 - elapsed=$((elapsed + 5)) - done - echo "$device booted" -} -for device in "${devices[@]}"; do - wait_for_boot "$device" - adb -s "$device" install -r "$apk_path" -done - -logcat_pids=() -stop_logcat() { - local pid - for pid in ${logcat_pids[@]+"${logcat_pids[@]}"}; do - kill "$pid" >/dev/null 2>&1 || true - wait "$pid" 2>/dev/null || true - done -} -trap stop_logcat EXIT - -for device in "${devices[@]}"; do - adb -s "$device" logcat -c || true - adb -s "$device" logcat -v threadtime > "$debug/$device-logcat.log" 2>&1 & - logcat_pids+=($!) -done - -PLATFORM=android CLERK_TEST_DEVICES=$(IFS=,; echo "${devices[*]}") ./run-flows.sh diff --git a/integration/tests/expo-native/run-flows.sh b/integration/tests/expo-native/run-flows.sh deleted file mode 100755 index c4a41a6c93f..00000000000 --- a/integration/tests/expo-native/run-flows.sh +++ /dev/null @@ -1,22 +0,0 @@ -#!/usr/bin/env bash -# Usage: PLATFORM= [CLERK_TEST_DEVICES=a,b] ./run-flows.sh -set -euo pipefail -cd "$(dirname "${BASH_SOURCE[0]}")/../../.." - -: "${PLATFORM:?PLATFORM (ios|android) is required}" -: "${CLERK_TEST_EMAIL:?CLERK_TEST_EMAIL is required}" -: "${CLERK_TEST_PASSWORD:?CLERK_TEST_PASSWORD is required}" - -status=0 -pnpm exec e2e run --config integration/e2e.expo-native.config.ts --target "$PLATFORM" --retries 1 --video=on-first-retry --reporter list,junit,markdown || status=$? - -if [ -n "${GITHUB_STEP_SUMMARY:-}" ] && [ -f integration/.e2e/summary.md ]; then - cat integration/.e2e/summary.md >> "$GITHUB_STEP_SUMMARY" -fi - -flaky=$(jq -r '.run.results[] | select(.status == "flaky") | .file' integration/.e2e/report.json 2>/dev/null || true) -if [ -n "$flaky" ]; then - echo "::error::Flaky flow(s), failed then passed on the retry: ${flaky//$'\n'/, }" - [ "$status" -ne 0 ] || status=1 -fi -exit "$status" From 8082fe1827fff9cecc633a59309d487b861da980 Mon Sep 17 00:00:00 2001 From: wobsoriano Date: Fri, 2 Oct 2026 01:37:51 -0700 Subject: [PATCH 08/31] ci(e2e): drop the runner scripts and the second android emulator --- .github/workflows/expo-native-build.yml | 107 +++++++----------------- 1 file changed, 29 insertions(+), 78 deletions(-) diff --git a/.github/workflows/expo-native-build.yml b/.github/workflows/expo-native-build.yml index 8a930ced030..eec3d0fbe01 100644 --- a/.github/workflows/expo-native-build.yml +++ b/.github/workflows/expo-native-build.yml @@ -27,7 +27,7 @@ env: SDK_PACK_DIR: /tmp/clerk-expo-pack E2E_INSTANCE_NAME: clerkstage-with-native-components BAPI_URL: https://api.clerkstage.dev - E2E_SHARDS: '2' + IOS_SIMULATORS: '2' E2E_TELEMETRY_DISABLED: '1' jobs: @@ -226,7 +226,7 @@ jobs: - name: Boot iOS simulators if: matrix.platform == 'ios' && matrix.run-e2e == true && steps.keys.outputs.pk != '' - run: ${{ env.E2E_DIR }}/boot-ios-simulators.sh boot "$E2E_SHARDS" + run: ${{ env.E2E_DIR }}/boot-ios-simulators.sh boot "$IOS_SIMULATORS" - name: Cache iOS automation runner if: matrix.platform == 'ios' && steps.keys.outputs.pk != '' @@ -236,58 +236,28 @@ jobs: key: agent-device-${{ runner.os }}-${{ hashFiles('pnpm-lock.yaml') }} restore-keys: agent-device-${{ runner.os }}- - # Provisioned as late as possible so live credentials exist for the - # shortest window. - - name: Provision test user via BAPI - id: user - if: steps.keys.outputs.pk != '' - continue-on-error: true - env: - CLERK_SECRET_KEY: ${{ steps.keys.outputs.sk }} - run: | - email="ci-${GITHUB_RUN_ID}-${RANDOM}+clerk_test@clerkcookie.com" - username="ci_${GITHUB_RUN_ID}_${RANDOM}" - password="ClerkCI!$(openssl rand -hex 8)Aa1" - http_code=$(curl -sS -o /tmp/bapi_response.json -w "%{http_code}" -X POST "$BAPI_URL/v1/users" \ - -H "Authorization: Bearer $CLERK_SECRET_KEY" \ - -H "Content-Type: application/json" \ - -d "{\"email_address\":[\"$email\"],\"username\":\"$username\",\"password\":\"$password\"}") - if [ "$http_code" -lt 200 ] || [ "$http_code" -ge 300 ]; then - echo "::error::BAPI user creation failed (HTTP $http_code)" - cat /tmp/bapi_response.json - exit 1 - fi - user_id=$(jq -er '.id' /tmp/bapi_response.json) - echo "::add-mask::$password" - { - echo "email=$email" - echo "password=$password" - echo "user_id=$user_id" - } >> "$GITHUB_OUTPUT" - - name: Run iOS e2e id: run_e2e_ios - if: matrix.platform == 'ios' && steps.user.outputs.user_id != '' - working-directory: ${{ env.FIXTURE_DIR }} + if: matrix.platform == 'ios' && steps.keys.outputs.sk != '' env: - CLERK_TEST_EMAIL: ${{ steps.user.outputs.email }} - CLERK_TEST_PASSWORD: ${{ steps.user.outputs.password }} + CLERK_SECRET_KEY: ${{ steps.keys.outputs.sk }} + CLERK_API_URL: ${{ env.BAPI_URL }} run: | - "$GITHUB_WORKSPACE/$E2E_DIR/boot-ios-simulators.sh" wait + "$E2E_DIR/boot-ios-simulators.sh" wait mkdir -p "$RUNNER_TEMP/e2e-device-logs" log_pids=() trap 'kill "${log_pids[@]}" 2>/dev/null || true; wait "${log_pids[@]}" 2>/dev/null || true' EXIT for udid in ${CLERK_TEST_DEVICES//,/ }; do - xcrun simctl install "$udid" ios/build/Build/Products/Release-iphonesimulator/ClerkExpoNativeBuildFixture.app + xcrun simctl install "$udid" "$FIXTURE_DIR/ios/build/Build/Products/Release-iphonesimulator/ClerkExpoNativeBuildFixture.app" xcrun simctl spawn "$udid" log stream --style compact \ --predicate 'processImagePath CONTAINS "ClerkExpoNativeBuildFixture"' \ > "$RUNNER_TEMP/e2e-device-logs/$udid-console.log" 2>&1 & log_pids+=($!) done - PLATFORM=ios "$GITHUB_WORKSPACE/$E2E_DIR/run-flows.sh" + pnpm test:integration:expo-native:ios --video=on-first-retry --reporter list,junit,markdown - name: Enable KVM - if: matrix.platform == 'android' && steps.user.outputs.user_id != '' + if: matrix.platform == 'android' && steps.keys.outputs.sk != '' run: | echo 'KERNEL=="kvm", GROUP="kvm", MODE="0666", OPTIONS+="static_node=kvm"' | sudo tee /etc/udev/rules.d/99-kvm4all.rules sudo udevadm control --reload-rules @@ -295,7 +265,7 @@ jobs: - name: AVD cache id: avd-cache - if: matrix.platform == 'android' && steps.user.outputs.user_id != '' + if: matrix.platform == 'android' && steps.keys.outputs.sk != '' uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4 with: path: | @@ -304,7 +274,7 @@ jobs: key: avd-34-google_apis-x86_64-v1 - name: Create AVD snapshot - if: matrix.platform == 'android' && steps.user.outputs.user_id != '' && steps.avd-cache.outputs.cache-hit != 'true' + if: matrix.platform == 'android' && steps.keys.outputs.sk != '' && steps.avd-cache.outputs.cache-hit != 'true' uses: reactivecircus/android-emulator-runner@a421e43855164a8197daf9d8d40fe71c6996bb0d # v2 with: api-level: 34 @@ -317,55 +287,28 @@ jobs: - name: Run Android e2e id: run_e2e_android - if: matrix.platform == 'android' && steps.user.outputs.user_id != '' + if: matrix.platform == 'android' && steps.keys.outputs.sk != '' uses: reactivecircus/android-emulator-runner@a421e43855164a8197daf9d8d40fe71c6996bb0d # v2 env: - CLERK_TEST_EMAIL: ${{ steps.user.outputs.email }} - CLERK_TEST_PASSWORD: ${{ steps.user.outputs.password }} + CLERK_SECRET_KEY: ${{ steps.keys.outputs.sk }} + CLERK_API_URL: ${{ env.BAPI_URL }} with: api-level: 34 target: google_apis arch: x86_64 force-avd-creation: false - # read-only: a writable instance holds a lock the shard emulators wait on forever - emulator-options: -read-only -no-snapshot-save -no-window -gpu swiftshader_indirect -noaudio -no-boot-anim + emulator-options: -no-snapshot-save -no-window -gpu swiftshader_indirect -noaudio -no-boot-anim disable-animations: true # The action runs each script line in a separate sh -c; the folded # scalar (>-) plus && keeps everything in one shell invocation. script: >- - cd integration/tests/expo-native && - E2E_DEVICE_LOGS="$RUNNER_TEMP/e2e-device-logs" ./run-android-flows.sh - "$GITHUB_WORKSPACE/$FIXTURE_DIR/android/app/build/outputs/apk/release/app-release.apk" - - # Runs before the artifact upload so the credentials are already dead - # by the time the debug files become downloadable. - - name: Cleanup test user - if: always() && steps.user.outputs.user_id != '' - env: - CLERK_SECRET_KEY: ${{ steps.keys.outputs.sk }} - USER_ID: ${{ steps.user.outputs.user_id }} - run: | - curl -fsS -X DELETE "$BAPI_URL/v1/users/$USER_ID" \ - -H "Authorization: Bearer $CLERK_SECRET_KEY" || true - - # Test reports record flow env (and typed input) in plaintext; - # add-mask only covers step logs, not artifact contents. Must run whenever - # the upload does, or a passing run uploads the password. - - name: Scrub test credentials from e2e output - id: scrub - if: always() && steps.user.outputs.user_id != '' - env: - CLERK_TEST_PASSWORD: ${{ steps.user.outputs.password }} - run: | - [ -n "$CLERK_TEST_PASSWORD" ] || exit 0 - mkdir -p integration/.e2e "$RUNNER_TEMP/e2e-device-logs" - # shellcheck disable=SC2016 - find integration/.e2e "$RUNNER_TEMP/e2e-device-logs" -type f \ - \( -name '*.json' -o -name '*.log' -o -name '*.md' -o -name '*.txt' -o -name '*.xml' \) \ - -exec perl -pi -e 's/\Q$ENV{CLERK_TEST_PASSWORD}\E/[REDACTED]/g' {} + + mkdir -p "$RUNNER_TEMP/e2e-device-logs" && + adb install -r "$FIXTURE_DIR/android/app/build/outputs/apk/release/app-release.apk" && + (adb logcat -v threadtime > "$RUNNER_TEMP/e2e-device-logs/logcat.log" 2>&1 &) && + pnpm test:integration:expo-native:android --video=on-first-retry --reporter list,junit,markdown - name: Upload e2e artifacts - if: always() && steps.scrub.outcome == 'success' + if: always() && steps.keys.outputs.sk != '' uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4 with: name: e2e-${{ matrix.platform }} @@ -378,7 +321,7 @@ jobs: retention-days: 7 - name: Report e2e outcome - if: always() && steps.user.outputs.user_id != '' + if: always() && steps.keys.outputs.sk != '' env: IOS_OUTCOME: ${{ steps.run_e2e_ios.outcome }} ANDROID_OUTCOME: ${{ steps.run_e2e_android.outcome }} @@ -386,6 +329,14 @@ jobs: outcome="$IOS_OUTCOME" [ "$outcome" = "skipped" ] && outcome="$ANDROID_OUTCOME" echo "## Native e2e (${{ matrix.platform }}): $outcome" >> "$GITHUB_STEP_SUMMARY" + if [ -f integration/.e2e/summary.md ]; then + cat integration/.e2e/summary.md >> "$GITHUB_STEP_SUMMARY" + fi if [ "$outcome" = "failure" ]; then echo "::error::Native e2e failed. See the e2e-${{ matrix.platform }} artifact." fi + flaky=$(jq -r '[.run.results[] | select(.status == "flaky") | .file] | join(", ")' integration/.e2e/report.json 2>/dev/null || true) + if [ -n "$flaky" ]; then + echo "::error::Flaky flow(s), failed then passed on the retry: $flaky" + exit 1 + fi From 878dfa5fdfa64358a879c753248ef9d841e36804 Mon Sep 17 00:00:00 2001 From: wobsoriano Date: Fri, 2 Oct 2026 01:54:10 -0700 Subject: [PATCH 09/31] ci(e2e): retype the email code when the screen does not advance --- integration/tests/expo-native/flows/subflows.ts | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/integration/tests/expo-native/flows/subflows.ts b/integration/tests/expo-native/flows/subflows.ts index ba6034cb046..ef40cd577d1 100644 --- a/integration/tests/expo-native/flows/subflows.ts +++ b/integration/tests/expo-native/flows/subflows.ts @@ -75,9 +75,22 @@ async function fill(field: Locator, value: string) { } async function enterEmailCode({ screen }: DeviceFixtures) { - if (await screen.getByText('Check your email').isVisible()) { - await screen.getByRole('textbox').last().pressSequentially('424242'); + const heading = screen.getByText('Check your email'); + if (!(await heading.isVisible())) { + return; } + await expect + .poll( + async () => { + const code = screen.getByRole('textbox').last(); + await code.clear(); + await code.pressSequentially('424242'); + await expect(heading).toBeHidden({ timeout: 5000 }); + return true; + }, + { timeout: 30_000 }, + ) + .toBe(true); } async function dismissPasswordManager({ screen }: DeviceFixtures) { From 0eac98cad0c63fbc6a923b6f60936f814658463f Mon Sep 17 00:00:00 2001 From: wobsoriano Date: Fri, 2 Oct 2026 02:14:02 -0700 Subject: [PATCH 10/31] ci(e2e): type the email code once again --- integration/tests/expo-native/flows/subflows.ts | 17 ++--------------- 1 file changed, 2 insertions(+), 15 deletions(-) diff --git a/integration/tests/expo-native/flows/subflows.ts b/integration/tests/expo-native/flows/subflows.ts index ef40cd577d1..ba6034cb046 100644 --- a/integration/tests/expo-native/flows/subflows.ts +++ b/integration/tests/expo-native/flows/subflows.ts @@ -75,22 +75,9 @@ async function fill(field: Locator, value: string) { } async function enterEmailCode({ screen }: DeviceFixtures) { - const heading = screen.getByText('Check your email'); - if (!(await heading.isVisible())) { - return; + if (await screen.getByText('Check your email').isVisible()) { + await screen.getByRole('textbox').last().pressSequentially('424242'); } - await expect - .poll( - async () => { - const code = screen.getByRole('textbox').last(); - await code.clear(); - await code.pressSequentially('424242'); - await expect(heading).toBeHidden({ timeout: 5000 }); - return true; - }, - { timeout: 30_000 }, - ) - .toBe(true); } async function dismissPasswordManager({ screen }: DeviceFixtures) { From 091c2a0b1c1084994244c9df298939268766b7e2 Mon Sep 17 00:00:00 2001 From: wobsoriano Date: Fri, 2 Oct 2026 07:03:35 -0700 Subject: [PATCH 11/31] ci(e2e): split the expo native helpers into page objects --- .../tests/expo-native/{flows => }/fixtures.ts | 22 +-- .../flows/authview-detach-reattach.e2e.ts | 34 ++--- .../flows/embedded-profile-host-back.e2e.ts | 37 ++--- .../google-sign-in-missing-credentials.e2e.ts | 8 +- .../tests/expo-native/flows/sign-in.e2e.ts | 22 ++- .../tests/expo-native/flows/subflows.ts | 132 ------------------ .../user-button-sign-out-re-sign-in.e2e.ts | 32 ++--- .../flows/user-profile-custom-pages.e2e.ts | 40 ++---- .../tests/expo-native/page-objects/app.ts | 29 ++++ .../expo-native/page-objects/authView.ts | 88 ++++++++++++ .../expo-native/page-objects/gestures.ts | 45 ++++++ .../tests/expo-native/page-objects/index.ts | 16 +++ .../expo-native/page-objects/userButton.ts | 18 +++ .../expo-native/page-objects/userProfile.ts | 27 ++++ integration/tests/expo-native/types.ts | 6 + 15 files changed, 299 insertions(+), 257 deletions(-) rename integration/tests/expo-native/{flows => }/fixtures.ts (69%) delete mode 100644 integration/tests/expo-native/flows/subflows.ts create mode 100644 integration/tests/expo-native/page-objects/app.ts create mode 100644 integration/tests/expo-native/page-objects/authView.ts create mode 100644 integration/tests/expo-native/page-objects/gestures.ts create mode 100644 integration/tests/expo-native/page-objects/index.ts create mode 100644 integration/tests/expo-native/page-objects/userButton.ts create mode 100644 integration/tests/expo-native/page-objects/userProfile.ts create mode 100644 integration/tests/expo-native/types.ts diff --git a/integration/tests/expo-native/flows/fixtures.ts b/integration/tests/expo-native/fixtures.ts similarity index 69% rename from integration/tests/expo-native/flows/fixtures.ts rename to integration/tests/expo-native/fixtures.ts index aa7dd2a694b..dc96713d584 100644 --- a/integration/tests/expo-native/flows/fixtures.ts +++ b/integration/tests/expo-native/fixtures.ts @@ -1,14 +1,10 @@ import { randomBytes } from 'node:crypto'; -import type { Device } from '@e2e-dev/mobile'; import { test as base } from '@e2e-dev/mobile'; -import type { TestFixtures } from 'e2e'; -export type TestUser = { email: string; password: string }; - -export type DeviceFixtures = TestFixtures & { device: Device }; - -export type Fixtures = DeviceFixtures & { user: TestUser }; +import type { PageObjects } from './page-objects/index.ts'; +import { createPageObjects } from './page-objects/index.ts'; +import type { TestUser } from './types.ts'; function bapi(path: string, init: RequestInit) { return fetch(`${process.env.CLERK_API_URL ?? 'https://api.clerk.com'}/v1${path}`, { @@ -17,8 +13,14 @@ function bapi(path: string, init: RequestInit) { }); } -export const test = base.extend<{ user: TestUser }>({ - user: async (_fixtures, use) => { +export const test = base.extend<{ po: PageObjects }>({ + po: async (fixtures, provide) => { + await provide(createPageObjects(fixtures)); + }, +}); + +export const testWithUser = test.extend<{ user: TestUser }>({ + user: async (_fixtures, provide) => { const suffix = randomBytes(4).toString('hex'); const user = { email: `${suffix}+clerk_test@example.com`, @@ -32,7 +34,7 @@ export const test = base.extend<{ user: TestUser }>({ throw new Error(`BAPI user creation failed (HTTP ${response.status}): ${await response.text()}`); } const { id } = (await response.json()) as { id: string }; - await use(user); + await provide(user); await bapi(`/users/${id}`, { method: 'DELETE' }); }, }); diff --git a/integration/tests/expo-native/flows/authview-detach-reattach.e2e.ts b/integration/tests/expo-native/flows/authview-detach-reattach.e2e.ts index 645ae3a75fe..5906ab6e33a 100644 --- a/integration/tests/expo-native/flows/authview-detach-reattach.e2e.ts +++ b/integration/tests/expo-native/flows/authview-detach-reattach.e2e.ts @@ -1,31 +1,15 @@ import { expect } from 'e2e'; -import { test } from './fixtures.ts'; -import { - assertSignedIn, - assertSignedOut, - openApp, - openAuthView, - signInEmailPassword, - tapUntilVisible, -} from './subflows.ts'; +import { testWithUser as test } from '../fixtures.ts'; -test('AuthView survives detach and reattach', async fixtures => { - const { device, platform, screen } = fixtures; - await openApp(fixtures); - await openAuthView(fixtures); +test('AuthView survives detach and reattach', async ({ po, screen, user }) => { + await po.app.reset(); + await po.authView.open(); await expect(screen.getByText('E2E Custom Logo')).toBeVisible({ timeout: 10_000 }); - const openButton = screen.getByTestId('open-auth-view-button'); - if (platform === 'android') { - await device.back(); - await expect(openButton).toBeVisible({ timeout: 15_000 }); - } else { - await tapUntilVisible(screen.getByRole('button', 'Close'), openButton); - } - await openAuthView(fixtures); + await po.authView.dismiss(); + await po.authView.open(); await expect(screen.getByText('E2E Custom Logo')).toBeVisible({ timeout: 15_000 }); - await signInEmailPassword(fixtures); - await assertSignedIn(fixtures); - await screen.getByTestId('sign-out-button').tap(); - await assertSignedOut(fixtures); + await po.authView.signIn(user); + await po.app.expectSignedIn(); + await po.app.signOut(); }); diff --git a/integration/tests/expo-native/flows/embedded-profile-host-back.e2e.ts b/integration/tests/expo-native/flows/embedded-profile-host-back.e2e.ts index e8ce5ef9650..1eb2c3f8158 100644 --- a/integration/tests/expo-native/flows/embedded-profile-host-back.e2e.ts +++ b/integration/tests/expo-native/flows/embedded-profile-host-back.e2e.ts @@ -1,36 +1,25 @@ import { expect } from 'e2e'; -import { test } from './fixtures.ts'; -import { - assertSignedIn, - assertSignedOut, - openApp, - openAuthView, - signInEmailPassword, - tapBack, - tapControl, - tapUntilVisible, -} from './subflows.ts'; +import { testWithUser as test } from '../fixtures.ts'; const internalPush = { android: { root: 'Edit profile', row: 'Manage account', detail: /^(EMAIL ADDRESSES|Add email address)$/ }, ios: { root: 'Security', row: 'Security', detail: /^(Password|Passkeys|Two-step verification|Active devices)$/i }, }; -test('Embedded UserProfileView host back round trip', async fixtures => { - const { platform, screen } = fixtures; +test('Embedded UserProfileView host back round trip', async ({ platform, po, screen, user }) => { const { root, row, detail } = internalPush[platform as keyof typeof internalPush]; - await openApp(fixtures); - await openAuthView(fixtures); - await signInEmailPassword(fixtures); - await assertSignedIn(fixtures); - await tapUntilVisible(screen.getByTestId('open-embedded-profile-button'), screen.getByText(root)); - await tapControl(fixtures, screen.getByText(row)); + await po.app.reset(); + await po.authView.open(); + await po.authView.signIn(user); + await po.app.expectSignedIn(); + await po.userProfile.open(); + await expect(screen.getByText(root)).toBeVisible({ timeout: 20_000 }); + await po.userProfile.openRow(row); await expect(screen.getByText(detail).first()).toBeVisible({ timeout: 15_000 }); - await tapBack(fixtures); + await po.userProfile.back(); await expect(screen.getByText(root)).toBeVisible({ timeout: 15_000 }); - await tapBack(fixtures); - await expect(screen.getByTestId('open-embedded-profile-button')).toBeVisible({ timeout: 15_000 }); - await screen.getByTestId('sign-out-button').tap(); - await assertSignedOut(fixtures); + await po.userProfile.back(); + await po.userProfile.expectClosed(); + await po.app.signOut(); }); diff --git a/integration/tests/expo-native/flows/google-sign-in-missing-credentials.e2e.ts b/integration/tests/expo-native/flows/google-sign-in-missing-credentials.e2e.ts index a8db92316af..60f5c75664d 100644 --- a/integration/tests/expo-native/flows/google-sign-in-missing-credentials.e2e.ts +++ b/integration/tests/expo-native/flows/google-sign-in-missing-credentials.e2e.ts @@ -1,11 +1,9 @@ -import { test } from '@e2e-dev/mobile'; import { expect } from 'e2e'; -import { openApp } from './subflows.ts'; +import { test } from '../fixtures.ts'; -test('useSignInWithGoogle surfaces the missing-credentials error', async fixtures => { - const { screen } = fixtures; - await openApp(fixtures); +test('useSignInWithGoogle surfaces the missing-credentials error', async ({ po, screen }) => { + await po.app.reset(); await screen.getByTestId('google-sign-in-button').tap(); await expect(screen.getByText(/Google Sign-In credentials not found/)).toBeVisible({ timeout: 15_000 }); }); diff --git a/integration/tests/expo-native/flows/sign-in.e2e.ts b/integration/tests/expo-native/flows/sign-in.e2e.ts index beecfbd4488..31e6e218f53 100644 --- a/integration/tests/expo-native/flows/sign-in.e2e.ts +++ b/integration/tests/expo-native/flows/sign-in.e2e.ts @@ -1,17 +1,11 @@ -import { expect } from 'e2e'; +import { testWithUser as test } from '../fixtures.ts'; -import { test } from './fixtures.ts'; -import { assertSignedIn, assertSignedOut, openApp, openAuthView, signInEmailPassword } from './subflows.ts'; - -test('Native AuthView sign-in syncs to JS and survives a restart', async fixtures => { - const { app, screen } = fixtures; - await openApp(fixtures); - await openAuthView(fixtures); - await signInEmailPassword(fixtures); - await assertSignedIn(fixtures); +test('Native AuthView sign-in syncs to JS and survives a restart', async ({ app, po, user }) => { + await po.app.reset(); + await po.authView.open(); + await po.authView.signIn(user); + await po.app.expectSignedIn(); await app.restart(); - await expect(screen.getByText('signed in')).toBeVisible({ timeout: 45_000 }); - await expect(screen.getByTestId('user-id')).toBeVisible(); - await screen.getByTestId('sign-out-button').tap(); - await assertSignedOut(fixtures); + await po.app.expectSignedIn(); + await po.app.signOut(); }); diff --git a/integration/tests/expo-native/flows/subflows.ts b/integration/tests/expo-native/flows/subflows.ts deleted file mode 100644 index ba6034cb046..00000000000 --- a/integration/tests/expo-native/flows/subflows.ts +++ /dev/null @@ -1,132 +0,0 @@ -import type { Locator } from 'e2e'; -import { expect } from 'e2e'; - -import type { DeviceFixtures, Fixtures } from './fixtures.ts'; - -export async function openApp({ app, device, platform, screen }: DeviceFixtures) { - await app.open(); - if (platform === 'ios') { - await device.clearKeychain(); - } - await app.clearState(); - await expect(screen.getByText(/^signed (in|out)$/)).toBeVisible({ timeout: 45_000 }); - await expect(screen.getByText('signed out')).toBeVisible(); -} - -export async function tapUntilVisible(control: Locator, outcome: Locator) { - await expect - .poll( - async () => { - if (!(await outcome.isVisible()) && (await control.isVisible())) { - await control.tap(); - } - return outcome.isVisible(); - }, - { timeout: 30_000, interval: 1000 }, - ) - .toBe(true); -} - -export async function openAuthView({ screen }: DeviceFixtures) { - await tapUntilVisible( - screen.getByTestId('open-auth-view-button'), - screen.getByText(/^Welcome! Sign in to continue\.?$/), - ); -} - -export async function assertSignedIn({ screen }: DeviceFixtures) { - await expect(screen.getByText('signed in')).toBeVisible({ timeout: 30_000 }); - await expect(screen.getByTestId('user-id')).toBeVisible(); -} - -export async function assertSignedOut({ screen }: DeviceFixtures) { - await expect(screen.getByText('signed out')).toBeVisible({ timeout: 20_000 }); -} - -async function tapCenter({ screen }: DeviceFixtures, control: Locator) { - await expect(control).toBeVisible(); - const box = await control.boundingBox(); - if (!box) { - throw new Error('Control has no bounding box'); - } - await screen.tapAt({ x: box.x + box.width / 2, y: box.y + box.height / 2 }); -} - -export async function tapControl(fixtures: DeviceFixtures, control: Locator) { - if (fixtures.platform === 'android') { - await tapCenter(fixtures, control); - } else { - await control.tap(); - } -} - -export async function tapBack(fixtures: DeviceFixtures) { - await tapCenter(fixtures, fixtures.screen.getByLabel('Back').last()); -} - -async function fill(field: Locator, value: string) { - await field.tap(); - await field.fill(value).catch((error: { code?: string }) => { - if (error.code !== 'ENGINE_FAILURE') { - throw error; - } - return field.fill(value); - }); -} - -async function enterEmailCode({ screen }: DeviceFixtures) { - if (await screen.getByText('Check your email').isVisible()) { - await screen.getByRole('textbox').last().pressSequentially('424242'); - } -} - -async function dismissPasswordManager({ screen }: DeviceFixtures) { - if ( - await screen - .getByText(/Google Password Manager/) - .first() - .isVisible() - ) { - await screen - .getByText(/^(Not now|Never)$/i) - .first() - .tap(); - } - if ( - await screen - .getByText(/^(Save Password|Strong Password|Use Strong Password|AutoFill Passwords)$/i) - .first() - .isVisible() - ) { - const dismiss = screen.getByText(/^(Not Now|Never for This Website|Don.t Save)$/i).first(); - if (await dismiss.isVisible()) { - await dismiss.tap(); - } - } -} - -const afterPassword = - /^(Check your email|signed in|Save Password|Strong Password|Use Strong Password|AutoFill Passwords)$|Google Password Manager/i; - -export async function signInEmailPassword(fixtures: Fixtures) { - const { screen, user } = fixtures; - await expect(screen.getByText(/^Welcome! Sign in to continue\.?$/)).toBeVisible({ timeout: 25_000 }); - const identifierLabel = screen.getByText(/^Enter your email( or username)?$/); - await expect(identifierLabel).toBeVisible({ timeout: 25_000 }); - await tapUntilVisible(identifierLabel, screen.getByRole('textbox')); - const identifier = screen.getByDisplayValue(user.email); - if (!(await identifier.isVisible())) { - await fill(screen.getByRole('textbox'), user.email); - } - await expect(identifier).toBeVisible(); - await screen.getByText('Continue').tap(); - await expect(screen.getByText(/^(Enter your password|Check your email)$/).first()).toBeVisible({ timeout: 15_000 }); - await enterEmailCode(fixtures); - if (await screen.getByText('Enter your password').first().isVisible()) { - await fill(screen.getByRole('textbox').last(), user.password); - await screen.getByText('Continue').tap(); - await expect(screen.getByText(afterPassword).first()).toBeVisible({ timeout: 15_000 }); - } - await enterEmailCode(fixtures); - await dismissPasswordManager(fixtures); -} diff --git a/integration/tests/expo-native/flows/user-button-sign-out-re-sign-in.e2e.ts b/integration/tests/expo-native/flows/user-button-sign-out-re-sign-in.e2e.ts index df7bd4aa504..8223a4df2a3 100644 --- a/integration/tests/expo-native/flows/user-button-sign-out-re-sign-in.e2e.ts +++ b/integration/tests/expo-native/flows/user-button-sign-out-re-sign-in.e2e.ts @@ -1,21 +1,15 @@ -import { expect } from 'e2e'; +import { testWithUser as test } from '../fixtures.ts'; -import { test } from './fixtures.ts'; -import { assertSignedIn, assertSignedOut, openApp, openAuthView, signInEmailPassword, tapControl } from './subflows.ts'; - -test('UserButton native sign-out, then same-process re-sign-in', async fixtures => { - const { screen } = fixtures; - await openApp(fixtures); - await openAuthView(fixtures); - await signInEmailPassword(fixtures); - await assertSignedIn(fixtures); - await screen.getByLabel(/^Open (account|user profile)$/).tap(); - await expect(screen.getByText('Manage account')).toBeVisible({ timeout: 15_000 }); - await tapControl(fixtures, screen.getByText('Sign out')); - await assertSignedOut(fixtures); - await openAuthView(fixtures); - await signInEmailPassword(fixtures); - await assertSignedIn(fixtures); - await screen.getByTestId('sign-out-button').tap(); - await assertSignedOut(fixtures); +test('UserButton native sign-out, then same-process re-sign-in', async ({ po, user }) => { + await po.app.reset(); + await po.authView.open(); + await po.authView.signIn(user); + await po.app.expectSignedIn(); + await po.userButton.open(); + await po.userButton.signOut(); + await po.app.expectSignedOut(); + await po.authView.open(); + await po.authView.signIn(user); + await po.app.expectSignedIn(); + await po.app.signOut(); }); diff --git a/integration/tests/expo-native/flows/user-profile-custom-pages.e2e.ts b/integration/tests/expo-native/flows/user-profile-custom-pages.e2e.ts index 22c344d343c..23bd9e345e1 100644 --- a/integration/tests/expo-native/flows/user-profile-custom-pages.e2e.ts +++ b/integration/tests/expo-native/flows/user-profile-custom-pages.e2e.ts @@ -1,34 +1,18 @@ import { expect } from 'e2e'; -import { test } from './fixtures.ts'; -import { - assertSignedIn, - assertSignedOut, - openApp, - openAuthView, - signInEmailPassword, - tapBack, - tapControl, - tapUntilVisible, -} from './subflows.ts'; +import { testWithUser as test } from '../fixtures.ts'; -test('UserProfileView renders a custom page', async fixtures => { - const { device, platform, screen } = fixtures; - await openApp(fixtures); - await openAuthView(fixtures); - await signInEmailPassword(fixtures); - await assertSignedIn(fixtures); - await tapUntilVisible(screen.getByTestId('open-embedded-profile-button'), screen.getByText('E2E Custom Page')); - await tapControl(fixtures, screen.getByText('E2E Custom Page')); +test('UserProfileView renders a custom page', async ({ po, screen, user }) => { + await po.app.reset(); + await po.authView.open(); + await po.authView.signIn(user); + await po.app.expectSignedIn(); + await po.userProfile.open(); + await po.userProfile.openRow('E2E Custom Page'); await expect(screen.getByText('Rehosted RN body')).toBeVisible({ timeout: 15_000 }); - if (platform === 'android') { - await device.back(); - } else { - await tapBack(fixtures); - } + await po.userProfile.leaveCustomPage(); await expect(screen.getByText('E2E Custom Page')).toBeVisible({ timeout: 15_000 }); - await tapBack(fixtures); - await expect(screen.getByTestId('open-embedded-profile-button')).toBeVisible({ timeout: 15_000 }); - await screen.getByTestId('sign-out-button').tap(); - await assertSignedOut(fixtures); + await po.userProfile.back(); + await po.userProfile.expectClosed(); + await po.app.signOut(); }); diff --git a/integration/tests/expo-native/page-objects/app.ts b/integration/tests/expo-native/page-objects/app.ts new file mode 100644 index 00000000000..e2e53549e79 --- /dev/null +++ b/integration/tests/expo-native/page-objects/app.ts @@ -0,0 +1,29 @@ +import { expect } from 'e2e'; + +import type { DeviceFixtures } from '../types.ts'; + +export const createAppPageObject = ({ app, device, platform, screen }: DeviceFixtures) => { + const self = { + reset: async () => { + await app.open(); + if (platform === 'ios') { + await device.clearKeychain(); + } + await app.clearState(); + await expect(screen.getByText(/^signed (in|out)$/)).toBeVisible({ timeout: 45_000 }); + await self.expectSignedOut(); + }, + expectSignedIn: async () => { + await expect(screen.getByText('signed in')).toBeVisible({ timeout: 45_000 }); + await expect(screen.getByTestId('user-id')).toBeVisible(); + }, + expectSignedOut: () => { + return expect(screen.getByText('signed out')).toBeVisible({ timeout: 20_000 }); + }, + signOut: async () => { + await screen.getByTestId('sign-out-button').tap(); + await self.expectSignedOut(); + }, + }; + return self; +}; diff --git a/integration/tests/expo-native/page-objects/authView.ts b/integration/tests/expo-native/page-objects/authView.ts new file mode 100644 index 00000000000..729b207eaa2 --- /dev/null +++ b/integration/tests/expo-native/page-objects/authView.ts @@ -0,0 +1,88 @@ +import { expect } from 'e2e'; + +import type { DeviceFixtures, TestUser } from '../types.ts'; +import { fill, tapUntilVisible } from './gestures.ts'; + +const welcome = /^Welcome! Sign in to continue\.?$/; +const iosPasswordPrompt = /^(Save Password|Strong Password|Use Strong Password|AutoFill Passwords)$/i; +const androidPasswordPrompt = /Google Password Manager/; +const afterPassword = new RegExp( + `^(Check your email|signed in)$|${iosPasswordPrompt.source}|${androidPasswordPrompt.source}`, + 'i', +); + +export const createAuthViewPageObject = ({ device, platform, screen }: DeviceFixtures) => { + const openButton = screen.getByTestId('open-auth-view-button'); + + const dismissAndroidPasswordPrompt = async () => { + if (await screen.getByText(androidPasswordPrompt).first().isVisible()) { + await screen + .getByText(/^(Not now|Never)$/i) + .first() + .tap(); + } + }; + + const dismissIosPasswordPrompt = async () => { + const dismiss = screen.getByText(/^(Not Now|Never for This Website|Don.t Save)$/i).first(); + if ((await screen.getByText(iosPasswordPrompt).first().isVisible()) && (await dismiss.isVisible())) { + await dismiss.tap(); + } + }; + + const self = { + open: () => { + return tapUntilVisible(openButton, screen.getByText(welcome)); + }, + dismiss: async () => { + if (platform === 'android') { + await device.back(); + await expect(openButton).toBeVisible({ timeout: 15_000 }); + } else { + await tapUntilVisible(screen.getByRole('button', 'Close'), openButton); + } + }, + setIdentifier: async (identifier: string) => { + const label = screen.getByText(/^Enter your email( or username)?$/); + await expect(label).toBeVisible({ timeout: 25_000 }); + await tapUntilVisible(label, screen.getByRole('textbox')); + const value = screen.getByDisplayValue(identifier); + if (!(await value.isVisible())) { + await fill(screen.getByRole('textbox'), identifier); + } + await expect(value).toBeVisible(); + }, + setPassword: (password: string) => { + return fill(screen.getByRole('textbox').last(), password); + }, + continue: () => { + return screen.getByText('Continue').tap(); + }, + enterEmailCode: async () => { + if (await screen.getByText('Check your email').isVisible()) { + await screen.getByRole('textbox').last().pressSequentially('424242'); + } + }, + dismissPasswordPrompt: async () => { + await dismissAndroidPasswordPrompt(); + await dismissIosPasswordPrompt(); + }, + signIn: async ({ email, password }: TestUser) => { + await expect(screen.getByText(welcome)).toBeVisible({ timeout: 25_000 }); + await self.setIdentifier(email); + await self.continue(); + await expect(screen.getByText(/^(Enter your password|Check your email)$/).first()).toBeVisible({ + timeout: 15_000, + }); + await self.enterEmailCode(); + if (await screen.getByText('Enter your password').first().isVisible()) { + await self.setPassword(password); + await self.continue(); + await expect(screen.getByText(afterPassword).first()).toBeVisible({ timeout: 15_000 }); + } + await self.enterEmailCode(); + await self.dismissPasswordPrompt(); + }, + }; + return self; +}; diff --git a/integration/tests/expo-native/page-objects/gestures.ts b/integration/tests/expo-native/page-objects/gestures.ts new file mode 100644 index 00000000000..67d67eef48a --- /dev/null +++ b/integration/tests/expo-native/page-objects/gestures.ts @@ -0,0 +1,45 @@ +import type { Locator } from 'e2e'; +import { expect } from 'e2e'; + +import type { DeviceFixtures } from '../types.ts'; + +export async function tapUntilVisible(control: Locator, outcome: Locator) { + await expect + .poll( + async () => { + if (!(await outcome.isVisible()) && (await control.isVisible())) { + await control.tap(); + } + return outcome.isVisible(); + }, + { timeout: 30_000, interval: 1000 }, + ) + .toBe(true); +} + +export async function tapCenter({ screen }: DeviceFixtures, control: Locator) { + await expect(control).toBeVisible(); + const box = await control.boundingBox(); + if (!box) { + throw new Error('Control has no bounding box'); + } + await screen.tapAt({ x: box.x + box.width / 2, y: box.y + box.height / 2 }); +} + +export async function tapControl(fixtures: DeviceFixtures, control: Locator) { + if (fixtures.platform === 'android') { + await tapCenter(fixtures, control); + } else { + await control.tap(); + } +} + +export async function fill(field: Locator, value: string) { + await field.tap(); + await field.fill(value).catch((error: { code?: string }) => { + if (error.code !== 'ENGINE_FAILURE') { + throw error; + } + return field.fill(value); + }); +} diff --git a/integration/tests/expo-native/page-objects/index.ts b/integration/tests/expo-native/page-objects/index.ts new file mode 100644 index 00000000000..e2174890569 --- /dev/null +++ b/integration/tests/expo-native/page-objects/index.ts @@ -0,0 +1,16 @@ +import type { DeviceFixtures } from '../types.ts'; +import { createAppPageObject } from './app.ts'; +import { createAuthViewPageObject } from './authView.ts'; +import { createUserButtonPageObject } from './userButton.ts'; +import { createUserProfilePageObject } from './userProfile.ts'; + +export const createPageObjects = (fixtures: DeviceFixtures) => { + return { + app: createAppPageObject(fixtures), + authView: createAuthViewPageObject(fixtures), + userButton: createUserButtonPageObject(fixtures), + userProfile: createUserProfilePageObject(fixtures), + }; +}; + +export type PageObjects = ReturnType; diff --git a/integration/tests/expo-native/page-objects/userButton.ts b/integration/tests/expo-native/page-objects/userButton.ts new file mode 100644 index 00000000000..d41c073c197 --- /dev/null +++ b/integration/tests/expo-native/page-objects/userButton.ts @@ -0,0 +1,18 @@ +import { expect } from 'e2e'; + +import type { DeviceFixtures } from '../types.ts'; +import { tapControl } from './gestures.ts'; + +export const createUserButtonPageObject = (fixtures: DeviceFixtures) => { + const { screen } = fixtures; + const self = { + open: async () => { + await screen.getByLabel(/^Open (account|user profile)$/).tap(); + await expect(screen.getByText('Manage account')).toBeVisible({ timeout: 15_000 }); + }, + signOut: () => { + return tapControl(fixtures, screen.getByText('Sign out')); + }, + }; + return self; +}; diff --git a/integration/tests/expo-native/page-objects/userProfile.ts b/integration/tests/expo-native/page-objects/userProfile.ts new file mode 100644 index 00000000000..6025cb71304 --- /dev/null +++ b/integration/tests/expo-native/page-objects/userProfile.ts @@ -0,0 +1,27 @@ +import { expect } from 'e2e'; + +import type { DeviceFixtures } from '../types.ts'; +import { tapCenter, tapControl, tapUntilVisible } from './gestures.ts'; + +export const createUserProfilePageObject = (fixtures: DeviceFixtures) => { + const { screen } = fixtures; + const openButton = screen.getByTestId('open-embedded-profile-button'); + const self = { + open: () => { + return tapUntilVisible(openButton, screen.getByText('E2E Custom Page')); + }, + openRow: (name: string) => { + return tapControl(fixtures, screen.getByText(name)); + }, + back: () => { + return tapCenter(fixtures, screen.getByLabel('Back').last()); + }, + leaveCustomPage: () => { + return fixtures.platform === 'android' ? fixtures.device.back() : self.back(); + }, + expectClosed: () => { + return expect(openButton).toBeVisible({ timeout: 15_000 }); + }, + }; + return self; +}; diff --git a/integration/tests/expo-native/types.ts b/integration/tests/expo-native/types.ts new file mode 100644 index 00000000000..78f5eda528c --- /dev/null +++ b/integration/tests/expo-native/types.ts @@ -0,0 +1,6 @@ +import type { Device } from '@e2e-dev/mobile'; +import type { TestFixtures } from 'e2e'; + +export type DeviceFixtures = TestFixtures & { device: Device }; + +export type TestUser = { email: string; password: string }; From e24d05a72f46846ed6e51dba8e0aede43efc9ce1 Mon Sep 17 00:00:00 2001 From: wobsoriano Date: Fri, 2 Oct 2026 07:16:27 -0700 Subject: [PATCH 12/31] ci(e2e): flatten the expo native test folder and split out user creation --- integration/e2e.expo-native.config.ts | 2 +- integration/tests/expo-native/.gitignore | 1 - .../authview-detach-reattach.e2e.ts | 2 +- .../embedded-profile-host-back.e2e.ts | 2 +- integration/tests/expo-native/fixtures.ts | 28 +++--------------- .../google-sign-in-missing-credentials.e2e.ts | 2 +- .../expo-native/page-objects/authView.ts | 3 +- .../expo-native/{flows => }/sign-in.e2e.ts | 2 +- integration/tests/expo-native/types.ts | 2 -- .../user-button-sign-out-re-sign-in.e2e.ts | 2 +- .../user-profile-custom-pages.e2e.ts | 2 +- integration/tests/expo-native/users.ts | 29 +++++++++++++++++++ 12 files changed, 42 insertions(+), 35 deletions(-) delete mode 100644 integration/tests/expo-native/.gitignore rename integration/tests/expo-native/{flows => }/authview-detach-reattach.e2e.ts (89%) rename integration/tests/expo-native/{flows => }/embedded-profile-host-back.e2e.ts (94%) rename integration/tests/expo-native/{flows => }/google-sign-in-missing-credentials.e2e.ts (89%) rename integration/tests/expo-native/{flows => }/sign-in.e2e.ts (84%) rename integration/tests/expo-native/{flows => }/user-button-sign-out-re-sign-in.e2e.ts (88%) rename integration/tests/expo-native/{flows => }/user-profile-custom-pages.e2e.ts (91%) create mode 100644 integration/tests/expo-native/users.ts diff --git a/integration/e2e.expo-native.config.ts b/integration/e2e.expo-native.config.ts index 74a31d821f0..88c47c58e57 100644 --- a/integration/e2e.expo-native.config.ts +++ b/integration/e2e.expo-native.config.ts @@ -5,7 +5,7 @@ const app = { bundleId: 'com.clerk.exponativebuildfixture' }; const devices = process.env.CLERK_TEST_DEVICES?.split(','); export default { - tests: 'tests/expo-native/flows/*.e2e.ts', + tests: 'tests/expo-native/*.e2e.ts', targets: [ { name: 'ios', engine: mobile({ platform: 'ios', device: devices }), app }, { name: 'android', engine: mobile({ platform: 'android', device: devices }), app }, diff --git a/integration/tests/expo-native/.gitignore b/integration/tests/expo-native/.gitignore deleted file mode 100644 index e33609d251c..00000000000 --- a/integration/tests/expo-native/.gitignore +++ /dev/null @@ -1 +0,0 @@ -*.png diff --git a/integration/tests/expo-native/flows/authview-detach-reattach.e2e.ts b/integration/tests/expo-native/authview-detach-reattach.e2e.ts similarity index 89% rename from integration/tests/expo-native/flows/authview-detach-reattach.e2e.ts rename to integration/tests/expo-native/authview-detach-reattach.e2e.ts index 5906ab6e33a..30e05632fe2 100644 --- a/integration/tests/expo-native/flows/authview-detach-reattach.e2e.ts +++ b/integration/tests/expo-native/authview-detach-reattach.e2e.ts @@ -1,6 +1,6 @@ import { expect } from 'e2e'; -import { testWithUser as test } from '../fixtures.ts'; +import { testWithUser as test } from './fixtures.ts'; test('AuthView survives detach and reattach', async ({ po, screen, user }) => { await po.app.reset(); diff --git a/integration/tests/expo-native/flows/embedded-profile-host-back.e2e.ts b/integration/tests/expo-native/embedded-profile-host-back.e2e.ts similarity index 94% rename from integration/tests/expo-native/flows/embedded-profile-host-back.e2e.ts rename to integration/tests/expo-native/embedded-profile-host-back.e2e.ts index 1eb2c3f8158..06c2338cb0a 100644 --- a/integration/tests/expo-native/flows/embedded-profile-host-back.e2e.ts +++ b/integration/tests/expo-native/embedded-profile-host-back.e2e.ts @@ -1,6 +1,6 @@ import { expect } from 'e2e'; -import { testWithUser as test } from '../fixtures.ts'; +import { testWithUser as test } from './fixtures.ts'; const internalPush = { android: { root: 'Edit profile', row: 'Manage account', detail: /^(EMAIL ADDRESSES|Add email address)$/ }, diff --git a/integration/tests/expo-native/fixtures.ts b/integration/tests/expo-native/fixtures.ts index dc96713d584..159a29b050a 100644 --- a/integration/tests/expo-native/fixtures.ts +++ b/integration/tests/expo-native/fixtures.ts @@ -1,17 +1,9 @@ -import { randomBytes } from 'node:crypto'; - import { test as base } from '@e2e-dev/mobile'; import type { PageObjects } from './page-objects/index.ts'; import { createPageObjects } from './page-objects/index.ts'; -import type { TestUser } from './types.ts'; - -function bapi(path: string, init: RequestInit) { - return fetch(`${process.env.CLERK_API_URL ?? 'https://api.clerk.com'}/v1${path}`, { - ...init, - headers: { Authorization: `Bearer ${process.env.CLERK_SECRET_KEY}`, 'Content-Type': 'application/json' }, - }); -} +import type { TestUser } from './users.ts'; +import { createTestUser, deleteTestUser } from './users.ts'; export const test = base.extend<{ po: PageObjects }>({ po: async (fixtures, provide) => { @@ -21,20 +13,8 @@ export const test = base.extend<{ po: PageObjects }>({ export const testWithUser = test.extend<{ user: TestUser }>({ user: async (_fixtures, provide) => { - const suffix = randomBytes(4).toString('hex'); - const user = { - email: `${suffix}+clerk_test@example.com`, - password: `ClerkCI!${randomBytes(8).toString('hex')}Aa1`, - }; - const response = await bapi('/users', { - method: 'POST', - body: JSON.stringify({ email_address: [user.email], username: `e2e_${suffix}`, password: user.password }), - }); - if (!response.ok) { - throw new Error(`BAPI user creation failed (HTTP ${response.status}): ${await response.text()}`); - } - const { id } = (await response.json()) as { id: string }; + const user = await createTestUser(); await provide(user); - await bapi(`/users/${id}`, { method: 'DELETE' }); + await deleteTestUser(user); }, }); diff --git a/integration/tests/expo-native/flows/google-sign-in-missing-credentials.e2e.ts b/integration/tests/expo-native/google-sign-in-missing-credentials.e2e.ts similarity index 89% rename from integration/tests/expo-native/flows/google-sign-in-missing-credentials.e2e.ts rename to integration/tests/expo-native/google-sign-in-missing-credentials.e2e.ts index 60f5c75664d..2141911247b 100644 --- a/integration/tests/expo-native/flows/google-sign-in-missing-credentials.e2e.ts +++ b/integration/tests/expo-native/google-sign-in-missing-credentials.e2e.ts @@ -1,6 +1,6 @@ import { expect } from 'e2e'; -import { test } from '../fixtures.ts'; +import { test } from './fixtures.ts'; test('useSignInWithGoogle surfaces the missing-credentials error', async ({ po, screen }) => { await po.app.reset(); diff --git a/integration/tests/expo-native/page-objects/authView.ts b/integration/tests/expo-native/page-objects/authView.ts index 729b207eaa2..924eb417d90 100644 --- a/integration/tests/expo-native/page-objects/authView.ts +++ b/integration/tests/expo-native/page-objects/authView.ts @@ -1,6 +1,7 @@ import { expect } from 'e2e'; -import type { DeviceFixtures, TestUser } from '../types.ts'; +import type { DeviceFixtures } from '../types.ts'; +import type { TestUser } from '../users.ts'; import { fill, tapUntilVisible } from './gestures.ts'; const welcome = /^Welcome! Sign in to continue\.?$/; diff --git a/integration/tests/expo-native/flows/sign-in.e2e.ts b/integration/tests/expo-native/sign-in.e2e.ts similarity index 84% rename from integration/tests/expo-native/flows/sign-in.e2e.ts rename to integration/tests/expo-native/sign-in.e2e.ts index 31e6e218f53..858037a2224 100644 --- a/integration/tests/expo-native/flows/sign-in.e2e.ts +++ b/integration/tests/expo-native/sign-in.e2e.ts @@ -1,4 +1,4 @@ -import { testWithUser as test } from '../fixtures.ts'; +import { testWithUser as test } from './fixtures.ts'; test('Native AuthView sign-in syncs to JS and survives a restart', async ({ app, po, user }) => { await po.app.reset(); diff --git a/integration/tests/expo-native/types.ts b/integration/tests/expo-native/types.ts index 78f5eda528c..4eee9dc425b 100644 --- a/integration/tests/expo-native/types.ts +++ b/integration/tests/expo-native/types.ts @@ -2,5 +2,3 @@ import type { Device } from '@e2e-dev/mobile'; import type { TestFixtures } from 'e2e'; export type DeviceFixtures = TestFixtures & { device: Device }; - -export type TestUser = { email: string; password: string }; diff --git a/integration/tests/expo-native/flows/user-button-sign-out-re-sign-in.e2e.ts b/integration/tests/expo-native/user-button-sign-out-re-sign-in.e2e.ts similarity index 88% rename from integration/tests/expo-native/flows/user-button-sign-out-re-sign-in.e2e.ts rename to integration/tests/expo-native/user-button-sign-out-re-sign-in.e2e.ts index 8223a4df2a3..ec3322a19a0 100644 --- a/integration/tests/expo-native/flows/user-button-sign-out-re-sign-in.e2e.ts +++ b/integration/tests/expo-native/user-button-sign-out-re-sign-in.e2e.ts @@ -1,4 +1,4 @@ -import { testWithUser as test } from '../fixtures.ts'; +import { testWithUser as test } from './fixtures.ts'; test('UserButton native sign-out, then same-process re-sign-in', async ({ po, user }) => { await po.app.reset(); diff --git a/integration/tests/expo-native/flows/user-profile-custom-pages.e2e.ts b/integration/tests/expo-native/user-profile-custom-pages.e2e.ts similarity index 91% rename from integration/tests/expo-native/flows/user-profile-custom-pages.e2e.ts rename to integration/tests/expo-native/user-profile-custom-pages.e2e.ts index 23bd9e345e1..7d49ae77459 100644 --- a/integration/tests/expo-native/flows/user-profile-custom-pages.e2e.ts +++ b/integration/tests/expo-native/user-profile-custom-pages.e2e.ts @@ -1,6 +1,6 @@ import { expect } from 'e2e'; -import { testWithUser as test } from '../fixtures.ts'; +import { testWithUser as test } from './fixtures.ts'; test('UserProfileView renders a custom page', async ({ po, screen, user }) => { await po.app.reset(); diff --git a/integration/tests/expo-native/users.ts b/integration/tests/expo-native/users.ts new file mode 100644 index 00000000000..8128df1fc19 --- /dev/null +++ b/integration/tests/expo-native/users.ts @@ -0,0 +1,29 @@ +import { randomBytes } from 'node:crypto'; + +export type TestUser = { id: string; email: string; password: string }; + +function bapi(path: string, init: RequestInit) { + return fetch(`${process.env.CLERK_API_URL ?? 'https://api.clerk.com'}/v1${path}`, { + ...init, + headers: { Authorization: `Bearer ${process.env.CLERK_SECRET_KEY}`, 'Content-Type': 'application/json' }, + }); +} + +export async function createTestUser(): Promise { + const suffix = randomBytes(4).toString('hex'); + const email = `${suffix}+clerk_test@example.com`; + const password = `ClerkCI!${randomBytes(8).toString('hex')}Aa1`; + const response = await bapi('/users', { + method: 'POST', + body: JSON.stringify({ email_address: [email], username: `e2e_${suffix}`, password }), + }); + if (!response.ok) { + throw new Error(`BAPI user creation failed (HTTP ${response.status}): ${await response.text()}`); + } + const { id } = (await response.json()) as { id: string }; + return { id, email, password }; +} + +export async function deleteTestUser({ id }: TestUser) { + await bapi(`/users/${id}`, { method: 'DELETE' }); +} From 43fe8becdf2b340d194202b61a71324a0c66137a Mon Sep 17 00:00:00 2001 From: wobsoriano Date: Fri, 2 Oct 2026 07:24:19 -0700 Subject: [PATCH 13/31] ci(e2e): group the expo native tests by component --- .../tests/expo-native/auth-view.e2e.ts | 27 +++++++++++++ .../authview-detach-reattach.e2e.ts | 15 ------- .../embedded-profile-host-back.e2e.ts | 25 ------------ ...edentials.e2e.ts => google-sign-in.e2e.ts} | 0 integration/tests/expo-native/sign-in.e2e.ts | 11 ----- .../user-button-sign-out-re-sign-in.e2e.ts | 15 ------- .../tests/expo-native/user-button.e2e.ts | 18 +++++++++ .../user-profile-custom-pages.e2e.ts | 18 --------- .../tests/expo-native/user-profile.e2e.ts | 40 +++++++++++++++++++ 9 files changed, 85 insertions(+), 84 deletions(-) create mode 100644 integration/tests/expo-native/auth-view.e2e.ts delete mode 100644 integration/tests/expo-native/authview-detach-reattach.e2e.ts delete mode 100644 integration/tests/expo-native/embedded-profile-host-back.e2e.ts rename integration/tests/expo-native/{google-sign-in-missing-credentials.e2e.ts => google-sign-in.e2e.ts} (100%) delete mode 100644 integration/tests/expo-native/sign-in.e2e.ts delete mode 100644 integration/tests/expo-native/user-button-sign-out-re-sign-in.e2e.ts create mode 100644 integration/tests/expo-native/user-button.e2e.ts delete mode 100644 integration/tests/expo-native/user-profile-custom-pages.e2e.ts create mode 100644 integration/tests/expo-native/user-profile.e2e.ts diff --git a/integration/tests/expo-native/auth-view.e2e.ts b/integration/tests/expo-native/auth-view.e2e.ts new file mode 100644 index 00000000000..d7a819cf0b2 --- /dev/null +++ b/integration/tests/expo-native/auth-view.e2e.ts @@ -0,0 +1,27 @@ +import { expect } from 'e2e'; + +import { testWithUser as test } from './fixtures.ts'; + +test.describe('AuthView', () => { + test.beforeEach(({ po }) => po.app.reset()); + + test('native sign-in syncs to JS and survives a restart', async ({ app, po, user }) => { + await po.authView.open(); + await po.authView.signIn(user); + await po.app.expectSignedIn(); + await app.restart(); + await po.app.expectSignedIn(); + await po.app.signOut(); + }); + + test('survives detach and reattach', async ({ po, screen, user }) => { + await po.authView.open(); + await expect(screen.getByText('E2E Custom Logo')).toBeVisible({ timeout: 10_000 }); + await po.authView.dismiss(); + await po.authView.open(); + await expect(screen.getByText('E2E Custom Logo')).toBeVisible({ timeout: 15_000 }); + await po.authView.signIn(user); + await po.app.expectSignedIn(); + await po.app.signOut(); + }); +}); diff --git a/integration/tests/expo-native/authview-detach-reattach.e2e.ts b/integration/tests/expo-native/authview-detach-reattach.e2e.ts deleted file mode 100644 index 30e05632fe2..00000000000 --- a/integration/tests/expo-native/authview-detach-reattach.e2e.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { expect } from 'e2e'; - -import { testWithUser as test } from './fixtures.ts'; - -test('AuthView survives detach and reattach', async ({ po, screen, user }) => { - await po.app.reset(); - await po.authView.open(); - await expect(screen.getByText('E2E Custom Logo')).toBeVisible({ timeout: 10_000 }); - await po.authView.dismiss(); - await po.authView.open(); - await expect(screen.getByText('E2E Custom Logo')).toBeVisible({ timeout: 15_000 }); - await po.authView.signIn(user); - await po.app.expectSignedIn(); - await po.app.signOut(); -}); diff --git a/integration/tests/expo-native/embedded-profile-host-back.e2e.ts b/integration/tests/expo-native/embedded-profile-host-back.e2e.ts deleted file mode 100644 index 06c2338cb0a..00000000000 --- a/integration/tests/expo-native/embedded-profile-host-back.e2e.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { expect } from 'e2e'; - -import { testWithUser as test } from './fixtures.ts'; - -const internalPush = { - android: { root: 'Edit profile', row: 'Manage account', detail: /^(EMAIL ADDRESSES|Add email address)$/ }, - ios: { root: 'Security', row: 'Security', detail: /^(Password|Passkeys|Two-step verification|Active devices)$/i }, -}; - -test('Embedded UserProfileView host back round trip', async ({ platform, po, screen, user }) => { - const { root, row, detail } = internalPush[platform as keyof typeof internalPush]; - await po.app.reset(); - await po.authView.open(); - await po.authView.signIn(user); - await po.app.expectSignedIn(); - await po.userProfile.open(); - await expect(screen.getByText(root)).toBeVisible({ timeout: 20_000 }); - await po.userProfile.openRow(row); - await expect(screen.getByText(detail).first()).toBeVisible({ timeout: 15_000 }); - await po.userProfile.back(); - await expect(screen.getByText(root)).toBeVisible({ timeout: 15_000 }); - await po.userProfile.back(); - await po.userProfile.expectClosed(); - await po.app.signOut(); -}); diff --git a/integration/tests/expo-native/google-sign-in-missing-credentials.e2e.ts b/integration/tests/expo-native/google-sign-in.e2e.ts similarity index 100% rename from integration/tests/expo-native/google-sign-in-missing-credentials.e2e.ts rename to integration/tests/expo-native/google-sign-in.e2e.ts diff --git a/integration/tests/expo-native/sign-in.e2e.ts b/integration/tests/expo-native/sign-in.e2e.ts deleted file mode 100644 index 858037a2224..00000000000 --- a/integration/tests/expo-native/sign-in.e2e.ts +++ /dev/null @@ -1,11 +0,0 @@ -import { testWithUser as test } from './fixtures.ts'; - -test('Native AuthView sign-in syncs to JS and survives a restart', async ({ app, po, user }) => { - await po.app.reset(); - await po.authView.open(); - await po.authView.signIn(user); - await po.app.expectSignedIn(); - await app.restart(); - await po.app.expectSignedIn(); - await po.app.signOut(); -}); diff --git a/integration/tests/expo-native/user-button-sign-out-re-sign-in.e2e.ts b/integration/tests/expo-native/user-button-sign-out-re-sign-in.e2e.ts deleted file mode 100644 index ec3322a19a0..00000000000 --- a/integration/tests/expo-native/user-button-sign-out-re-sign-in.e2e.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { testWithUser as test } from './fixtures.ts'; - -test('UserButton native sign-out, then same-process re-sign-in', async ({ po, user }) => { - await po.app.reset(); - await po.authView.open(); - await po.authView.signIn(user); - await po.app.expectSignedIn(); - await po.userButton.open(); - await po.userButton.signOut(); - await po.app.expectSignedOut(); - await po.authView.open(); - await po.authView.signIn(user); - await po.app.expectSignedIn(); - await po.app.signOut(); -}); diff --git a/integration/tests/expo-native/user-button.e2e.ts b/integration/tests/expo-native/user-button.e2e.ts new file mode 100644 index 00000000000..65fcdb4e032 --- /dev/null +++ b/integration/tests/expo-native/user-button.e2e.ts @@ -0,0 +1,18 @@ +import { testWithUser as test } from './fixtures.ts'; + +test.describe('UserButton', () => { + test.beforeEach(({ po }) => po.app.reset()); + + test('native sign-out, then same-process re-sign-in', async ({ po, user }) => { + await po.authView.open(); + await po.authView.signIn(user); + await po.app.expectSignedIn(); + await po.userButton.open(); + await po.userButton.signOut(); + await po.app.expectSignedOut(); + await po.authView.open(); + await po.authView.signIn(user); + await po.app.expectSignedIn(); + await po.app.signOut(); + }); +}); diff --git a/integration/tests/expo-native/user-profile-custom-pages.e2e.ts b/integration/tests/expo-native/user-profile-custom-pages.e2e.ts deleted file mode 100644 index 7d49ae77459..00000000000 --- a/integration/tests/expo-native/user-profile-custom-pages.e2e.ts +++ /dev/null @@ -1,18 +0,0 @@ -import { expect } from 'e2e'; - -import { testWithUser as test } from './fixtures.ts'; - -test('UserProfileView renders a custom page', async ({ po, screen, user }) => { - await po.app.reset(); - await po.authView.open(); - await po.authView.signIn(user); - await po.app.expectSignedIn(); - await po.userProfile.open(); - await po.userProfile.openRow('E2E Custom Page'); - await expect(screen.getByText('Rehosted RN body')).toBeVisible({ timeout: 15_000 }); - await po.userProfile.leaveCustomPage(); - await expect(screen.getByText('E2E Custom Page')).toBeVisible({ timeout: 15_000 }); - await po.userProfile.back(); - await po.userProfile.expectClosed(); - await po.app.signOut(); -}); diff --git a/integration/tests/expo-native/user-profile.e2e.ts b/integration/tests/expo-native/user-profile.e2e.ts new file mode 100644 index 00000000000..2a8f44cf2cf --- /dev/null +++ b/integration/tests/expo-native/user-profile.e2e.ts @@ -0,0 +1,40 @@ +import { expect } from 'e2e'; + +import { testWithUser as test } from './fixtures.ts'; + +const internalPush = { + android: { root: 'Edit profile', row: 'Manage account', detail: /^(EMAIL ADDRESSES|Add email address)$/ }, + ios: { root: 'Security', row: 'Security', detail: /^(Password|Passkeys|Two-step verification|Active devices)$/i }, +}; + +test.describe('UserProfileView', () => { + test.beforeEach(async ({ po, user }) => { + await po.app.reset(); + await po.authView.open(); + await po.authView.signIn(user); + await po.app.expectSignedIn(); + await po.userProfile.open(); + }); + + test('embedded host back round trip', async ({ platform, po, screen }) => { + const { root, row, detail } = internalPush[platform as keyof typeof internalPush]; + await expect(screen.getByText(root)).toBeVisible({ timeout: 20_000 }); + await po.userProfile.openRow(row); + await expect(screen.getByText(detail).first()).toBeVisible({ timeout: 15_000 }); + await po.userProfile.back(); + await expect(screen.getByText(root)).toBeVisible({ timeout: 15_000 }); + await po.userProfile.back(); + await po.userProfile.expectClosed(); + await po.app.signOut(); + }); + + test('renders a custom page', async ({ po, screen }) => { + await po.userProfile.openRow('E2E Custom Page'); + await expect(screen.getByText('Rehosted RN body')).toBeVisible({ timeout: 15_000 }); + await po.userProfile.leaveCustomPage(); + await expect(screen.getByText('E2E Custom Page')).toBeVisible({ timeout: 15_000 }); + await po.userProfile.back(); + await po.userProfile.expectClosed(); + await po.app.signOut(); + }); +}); From 85ff9d283ebed27546b521f51f52ba529c5e9185 Mon Sep 17 00:00:00 2001 From: wobsoriano Date: Fri, 2 Oct 2026 07:24:20 -0700 Subject: [PATCH 14/31] ci(e2e): TEMP bust caches to measure a cold run --- .github/workflows/expo-native-build.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/expo-native-build.yml b/.github/workflows/expo-native-build.yml index eec3d0fbe01..faa39ebac2d 100644 --- a/.github/workflows/expo-native-build.yml +++ b/.github/workflows/expo-native-build.yml @@ -102,7 +102,7 @@ jobs: with: path: ${{ steps.native-build-key.outputs.artifact }} # Bump the version when native build commands change. - key: expo-native-build-v1-${{ runner.os }}-${{ matrix.expo-sdk }}-${{ matrix.platform }}-${{ matrix.run-e2e == true && 'e2e' || 'build' }}-${{ env.E2E_INSTANCE_NAME }}-${{ steps.native-build-key.outputs.hash }} + key: expo-native-build-v1cold2-${{ runner.os }}-${{ matrix.expo-sdk }}-${{ matrix.platform }}-${{ matrix.run-e2e == true && 'e2e' || 'build' }}-${{ env.E2E_INSTANCE_NAME }}-${{ steps.native-build-key.outputs.hash }} - if: steps.native-build-cache.outputs.cache-hit != 'true' || matrix.run-e2e == true uses: pnpm/action-setup@b906affcce14559ad1aafd4ab0e942779e9f58b1 # v4 @@ -233,8 +233,8 @@ jobs: uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4 with: path: ~/.agent-device - key: agent-device-${{ runner.os }}-${{ hashFiles('pnpm-lock.yaml') }} - restore-keys: agent-device-${{ runner.os }}- + key: agent-device-cold2-${{ runner.os }}-${{ hashFiles('pnpm-lock.yaml') }} + restore-keys: agent-device-cold2-${{ runner.os }}- - name: Run iOS e2e id: run_e2e_ios @@ -271,7 +271,7 @@ jobs: path: | ~/.android/avd/* ~/.android/adb* - key: avd-34-google_apis-x86_64-v1 + key: avd-34-google_apis-x86_64-v1cold2 - name: Create AVD snapshot if: matrix.platform == 'android' && steps.keys.outputs.sk != '' && steps.avd-cache.outputs.cache-hit != 'true' From 1d8224178ed6d99428c66ff2be9de83a08fc8943 Mon Sep 17 00:00:00 2001 From: wobsoriano Date: Fri, 2 Oct 2026 08:27:53 -0700 Subject: [PATCH 15/31] Revert "ci(e2e): TEMP bust caches to measure a cold run" This reverts commit 85ff9d283ebed27546b521f51f52ba529c5e9185. --- .github/workflows/expo-native-build.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/expo-native-build.yml b/.github/workflows/expo-native-build.yml index faa39ebac2d..eec3d0fbe01 100644 --- a/.github/workflows/expo-native-build.yml +++ b/.github/workflows/expo-native-build.yml @@ -102,7 +102,7 @@ jobs: with: path: ${{ steps.native-build-key.outputs.artifact }} # Bump the version when native build commands change. - key: expo-native-build-v1cold2-${{ runner.os }}-${{ matrix.expo-sdk }}-${{ matrix.platform }}-${{ matrix.run-e2e == true && 'e2e' || 'build' }}-${{ env.E2E_INSTANCE_NAME }}-${{ steps.native-build-key.outputs.hash }} + key: expo-native-build-v1-${{ runner.os }}-${{ matrix.expo-sdk }}-${{ matrix.platform }}-${{ matrix.run-e2e == true && 'e2e' || 'build' }}-${{ env.E2E_INSTANCE_NAME }}-${{ steps.native-build-key.outputs.hash }} - if: steps.native-build-cache.outputs.cache-hit != 'true' || matrix.run-e2e == true uses: pnpm/action-setup@b906affcce14559ad1aafd4ab0e942779e9f58b1 # v4 @@ -233,8 +233,8 @@ jobs: uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4 with: path: ~/.agent-device - key: agent-device-cold2-${{ runner.os }}-${{ hashFiles('pnpm-lock.yaml') }} - restore-keys: agent-device-cold2-${{ runner.os }}- + key: agent-device-${{ runner.os }}-${{ hashFiles('pnpm-lock.yaml') }} + restore-keys: agent-device-${{ runner.os }}- - name: Run iOS e2e id: run_e2e_ios @@ -271,7 +271,7 @@ jobs: path: | ~/.android/avd/* ~/.android/adb* - key: avd-34-google_apis-x86_64-v1cold2 + key: avd-34-google_apis-x86_64-v1 - name: Create AVD snapshot if: matrix.platform == 'android' && steps.keys.outputs.sk != '' && steps.avd-cache.outputs.cache-hit != 'true' From 9815c29f2612dc5f3bfdde07f7b4648d11efabe9 Mon Sep 17 00:00:00 2001 From: wobsoriano Date: Fri, 2 Oct 2026 08:29:16 -0700 Subject: [PATCH 16/31] ci(e2e): port the biometric availability flow --- .../flows/biometric-availability.yaml | 9 --------- .../tests/expo-native/google-sign-in.e2e.ts | 9 --------- .../tests/expo-native/native-modules.e2e.ts | 17 +++++++++++++++++ 3 files changed, 17 insertions(+), 18 deletions(-) delete mode 100644 integration/tests/expo-native/flows/biometric-availability.yaml delete mode 100644 integration/tests/expo-native/google-sign-in.e2e.ts create mode 100644 integration/tests/expo-native/native-modules.e2e.ts diff --git a/integration/tests/expo-native/flows/biometric-availability.yaml b/integration/tests/expo-native/flows/biometric-availability.yaml deleted file mode 100644 index 10fb9ce88aa..00000000000 --- a/integration/tests/expo-native/flows/biometric-availability.yaml +++ /dev/null @@ -1,9 +0,0 @@ -appId: com.clerk.exponativebuildfixture -name: useBiometricCredentials reaches the expo-biometrics native module ---- -- runFlow: subflows/open-app.yaml -- tapOn: - id: 'biometric-availability-button' -- extendedWaitUntil: - visible: 'biometric availability: .*' - timeout: 15000 diff --git a/integration/tests/expo-native/google-sign-in.e2e.ts b/integration/tests/expo-native/google-sign-in.e2e.ts deleted file mode 100644 index 2141911247b..00000000000 --- a/integration/tests/expo-native/google-sign-in.e2e.ts +++ /dev/null @@ -1,9 +0,0 @@ -import { expect } from 'e2e'; - -import { test } from './fixtures.ts'; - -test('useSignInWithGoogle surfaces the missing-credentials error', async ({ po, screen }) => { - await po.app.reset(); - await screen.getByTestId('google-sign-in-button').tap(); - await expect(screen.getByText(/Google Sign-In credentials not found/)).toBeVisible({ timeout: 15_000 }); -}); diff --git a/integration/tests/expo-native/native-modules.e2e.ts b/integration/tests/expo-native/native-modules.e2e.ts new file mode 100644 index 00000000000..ff609114bff --- /dev/null +++ b/integration/tests/expo-native/native-modules.e2e.ts @@ -0,0 +1,17 @@ +import { expect } from 'e2e'; + +import { test } from './fixtures.ts'; + +test.describe('native modules', () => { + test.beforeEach(({ po }) => po.app.reset()); + + test('useSignInWithGoogle surfaces the missing-credentials error', async ({ screen }) => { + await screen.getByTestId('google-sign-in-button').tap(); + await expect(screen.getByText(/Google Sign-In credentials not found/)).toBeVisible({ timeout: 15_000 }); + }); + + test('useBiometricCredentials reaches the expo-biometrics native module', async ({ screen }) => { + await screen.getByTestId('biometric-availability-button').tap(); + await expect(screen.getByText(/^biometric availability: /)).toBeVisible({ timeout: 15_000 }); + }); +}); From 784727f07fbf26050d74ff73d6d8a1b0f30fa877 Mon Sep 17 00:00:00 2001 From: wobsoriano Date: Fri, 2 Oct 2026 08:31:20 -0700 Subject: [PATCH 17/31] ci(e2e): name the expo native tests after the bridge behaviour they cover --- .../tests/expo-native/auth-view.e2e.ts | 17 ++++------- .../tests/expo-native/native-modules.e2e.ts | 2 +- .../tests/expo-native/session-sync.e2e.ts | 30 +++++++++++++++++++ .../tests/expo-native/user-button.e2e.ts | 18 ----------- .../tests/expo-native/user-profile.e2e.ts | 6 ++-- 5 files changed, 40 insertions(+), 33 deletions(-) create mode 100644 integration/tests/expo-native/session-sync.e2e.ts delete mode 100644 integration/tests/expo-native/user-button.e2e.ts diff --git a/integration/tests/expo-native/auth-view.e2e.ts b/integration/tests/expo-native/auth-view.e2e.ts index d7a819cf0b2..7f9718a7c9c 100644 --- a/integration/tests/expo-native/auth-view.e2e.ts +++ b/integration/tests/expo-native/auth-view.e2e.ts @@ -2,19 +2,14 @@ import { expect } from 'e2e'; import { testWithUser as test } from './fixtures.ts'; -test.describe('AuthView', () => { +test.describe('@clerk/expo ', () => { test.beforeEach(({ po }) => po.app.reset()); - test('native sign-in syncs to JS and survives a restart', async ({ app, po, user }) => { - await po.authView.open(); - await po.authView.signIn(user); - await po.app.expectSignedIn(); - await app.restart(); - await po.app.expectSignedIn(); - await po.app.signOut(); - }); - - test('survives detach and reattach', async ({ po, screen, user }) => { + test('rehosts the React logo and still signs in after the host view is detached and reattached', async ({ + po, + screen, + user, + }) => { await po.authView.open(); await expect(screen.getByText('E2E Custom Logo')).toBeVisible({ timeout: 10_000 }); await po.authView.dismiss(); diff --git a/integration/tests/expo-native/native-modules.e2e.ts b/integration/tests/expo-native/native-modules.e2e.ts index ff609114bff..52d344989be 100644 --- a/integration/tests/expo-native/native-modules.e2e.ts +++ b/integration/tests/expo-native/native-modules.e2e.ts @@ -2,7 +2,7 @@ import { expect } from 'e2e'; import { test } from './fixtures.ts'; -test.describe('native modules', () => { +test.describe('@clerk/expo native modules', () => { test.beforeEach(({ po }) => po.app.reset()); test('useSignInWithGoogle surfaces the missing-credentials error', async ({ screen }) => { diff --git a/integration/tests/expo-native/session-sync.e2e.ts b/integration/tests/expo-native/session-sync.e2e.ts new file mode 100644 index 00000000000..45ecedfc3f2 --- /dev/null +++ b/integration/tests/expo-native/session-sync.e2e.ts @@ -0,0 +1,30 @@ +import { testWithUser as test } from './fixtures.ts'; + +test.describe('@clerk/expo native session sync', () => { + test.beforeEach(({ po }) => po.app.reset()); + + test('a native sign-in reaches the JS SDK and survives an app restart', async ({ app, po, user }) => { + await po.authView.open(); + await po.authView.signIn(user); + await po.app.expectSignedIn(); + await app.restart(); + await po.app.expectSignedIn(); + await po.app.signOut(); + }); + + test('a native sign-out reaches the JS SDK, and so does a second sign-in in the same process', async ({ + po, + user, + }) => { + await po.authView.open(); + await po.authView.signIn(user); + await po.app.expectSignedIn(); + await po.userButton.open(); + await po.userButton.signOut(); + await po.app.expectSignedOut(); + await po.authView.open(); + await po.authView.signIn(user); + await po.app.expectSignedIn(); + await po.app.signOut(); + }); +}); diff --git a/integration/tests/expo-native/user-button.e2e.ts b/integration/tests/expo-native/user-button.e2e.ts deleted file mode 100644 index 65fcdb4e032..00000000000 --- a/integration/tests/expo-native/user-button.e2e.ts +++ /dev/null @@ -1,18 +0,0 @@ -import { testWithUser as test } from './fixtures.ts'; - -test.describe('UserButton', () => { - test.beforeEach(({ po }) => po.app.reset()); - - test('native sign-out, then same-process re-sign-in', async ({ po, user }) => { - await po.authView.open(); - await po.authView.signIn(user); - await po.app.expectSignedIn(); - await po.userButton.open(); - await po.userButton.signOut(); - await po.app.expectSignedOut(); - await po.authView.open(); - await po.authView.signIn(user); - await po.app.expectSignedIn(); - await po.app.signOut(); - }); -}); diff --git a/integration/tests/expo-native/user-profile.e2e.ts b/integration/tests/expo-native/user-profile.e2e.ts index 2a8f44cf2cf..3fef2a7c810 100644 --- a/integration/tests/expo-native/user-profile.e2e.ts +++ b/integration/tests/expo-native/user-profile.e2e.ts @@ -7,7 +7,7 @@ const internalPush = { ios: { root: 'Security', row: 'Security', detail: /^(Password|Passkeys|Two-step verification|Active devices)$/i }, }; -test.describe('UserProfileView', () => { +test.describe('@clerk/expo ', () => { test.beforeEach(async ({ po, user }) => { await po.app.reset(); await po.authView.open(); @@ -16,7 +16,7 @@ test.describe('UserProfileView', () => { await po.userProfile.open(); }); - test('embedded host back round trip', async ({ platform, po, screen }) => { + test('onHostBack closes the embedded profile from JS after native navigation', async ({ platform, po, screen }) => { const { root, row, detail } = internalPush[platform as keyof typeof internalPush]; await expect(screen.getByText(root)).toBeVisible({ timeout: 20_000 }); await po.userProfile.openRow(row); @@ -28,7 +28,7 @@ test.describe('UserProfileView', () => { await po.app.signOut(); }); - test('renders a custom page', async ({ po, screen }) => { + test('a custom page renders React Native content inside the native profile', async ({ po, screen }) => { await po.userProfile.openRow('E2E Custom Page'); await expect(screen.getByText('Rehosted RN body')).toBeVisible({ timeout: 15_000 }); await po.userProfile.leaveCustomPage(); From 20a74ddb2e4e27c9f625d0482bdcead2c4395183 Mon Sep 17 00:00:00 2001 From: wobsoriano Date: Fri, 2 Oct 2026 08:48:51 -0700 Subject: [PATCH 18/31] ci(e2e): TEMP bust caches to measure a cold run --- .github/workflows/expo-native-build.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/expo-native-build.yml b/.github/workflows/expo-native-build.yml index 42dd6657710..d55633b7a58 100644 --- a/.github/workflows/expo-native-build.yml +++ b/.github/workflows/expo-native-build.yml @@ -104,7 +104,7 @@ jobs: with: path: ${{ steps.native-build-key.outputs.artifact }} # Bump the version when native build commands change. - key: expo-native-build-v1-${{ runner.os }}-${{ matrix.expo-sdk }}-${{ matrix.platform }}-${{ matrix.run-e2e == true && 'e2e' || 'build' }}-${{ env.E2E_INSTANCE_NAME }}-${{ steps.native-build-key.outputs.hash }} + key: expo-native-build-v1cold3-${{ runner.os }}-${{ matrix.expo-sdk }}-${{ matrix.platform }}-${{ matrix.run-e2e == true && 'e2e' || 'build' }}-${{ env.E2E_INSTANCE_NAME }}-${{ steps.native-build-key.outputs.hash }} - if: steps.native-build-cache.outputs.cache-hit != 'true' || matrix.run-e2e == true uses: pnpm/action-setup@b906affcce14559ad1aafd4ab0e942779e9f58b1 # v4 @@ -246,8 +246,8 @@ jobs: uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4 with: path: ~/.agent-device - key: agent-device-${{ runner.os }}-${{ hashFiles('pnpm-lock.yaml') }} - restore-keys: agent-device-${{ runner.os }}- + key: agent-device-cold3-${{ runner.os }}-${{ hashFiles('pnpm-lock.yaml') }} + restore-keys: agent-device-cold3-${{ runner.os }}- - name: Run iOS e2e id: run_e2e_ios @@ -284,7 +284,7 @@ jobs: path: | ~/.android/avd/* ~/.android/adb* - key: avd-34-google_apis-x86_64-v1 + key: avd-34-google_apis-x86_64-v1cold3 - name: Create AVD snapshot if: matrix.platform == 'android' && steps.keys.outputs.sk != '' && steps.avd-cache.outputs.cache-hit != 'true' From 9d8c1029ef235dd20cfcee35e802f16975df4a3d Mon Sep 17 00:00:00 2001 From: wobsoriano Date: Fri, 2 Oct 2026 09:01:08 -0700 Subject: [PATCH 19/31] Revert "ci(e2e): TEMP bust caches to measure a cold run" This reverts commit 20a74ddb2e4e27c9f625d0482bdcead2c4395183. --- .github/workflows/expo-native-build.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/expo-native-build.yml b/.github/workflows/expo-native-build.yml index d55633b7a58..42dd6657710 100644 --- a/.github/workflows/expo-native-build.yml +++ b/.github/workflows/expo-native-build.yml @@ -104,7 +104,7 @@ jobs: with: path: ${{ steps.native-build-key.outputs.artifact }} # Bump the version when native build commands change. - key: expo-native-build-v1cold3-${{ runner.os }}-${{ matrix.expo-sdk }}-${{ matrix.platform }}-${{ matrix.run-e2e == true && 'e2e' || 'build' }}-${{ env.E2E_INSTANCE_NAME }}-${{ steps.native-build-key.outputs.hash }} + key: expo-native-build-v1-${{ runner.os }}-${{ matrix.expo-sdk }}-${{ matrix.platform }}-${{ matrix.run-e2e == true && 'e2e' || 'build' }}-${{ env.E2E_INSTANCE_NAME }}-${{ steps.native-build-key.outputs.hash }} - if: steps.native-build-cache.outputs.cache-hit != 'true' || matrix.run-e2e == true uses: pnpm/action-setup@b906affcce14559ad1aafd4ab0e942779e9f58b1 # v4 @@ -246,8 +246,8 @@ jobs: uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4 with: path: ~/.agent-device - key: agent-device-cold3-${{ runner.os }}-${{ hashFiles('pnpm-lock.yaml') }} - restore-keys: agent-device-cold3-${{ runner.os }}- + key: agent-device-${{ runner.os }}-${{ hashFiles('pnpm-lock.yaml') }} + restore-keys: agent-device-${{ runner.os }}- - name: Run iOS e2e id: run_e2e_ios @@ -284,7 +284,7 @@ jobs: path: | ~/.android/avd/* ~/.android/adb* - key: avd-34-google_apis-x86_64-v1cold3 + key: avd-34-google_apis-x86_64-v1 - name: Create AVD snapshot if: matrix.platform == 'android' && steps.keys.outputs.sk != '' && steps.avd-cache.outputs.cache-hit != 'true' From 07467aeccecdc78d739107724540473b729f312f Mon Sep 17 00:00:00 2001 From: wobsoriano Date: Fri, 2 Oct 2026 09:20:27 -0700 Subject: [PATCH 20/31] ci(e2e): create test users that skip the new-device email code --- integration/tests/expo-native/users.ts | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/integration/tests/expo-native/users.ts b/integration/tests/expo-native/users.ts index 8128df1fc19..8b793aa52ee 100644 --- a/integration/tests/expo-native/users.ts +++ b/integration/tests/expo-native/users.ts @@ -15,7 +15,12 @@ export async function createTestUser(): Promise { const password = `ClerkCI!${randomBytes(8).toString('hex')}Aa1`; const response = await bapi('/users', { method: 'POST', - body: JSON.stringify({ email_address: [email], username: `e2e_${suffix}`, password }), + body: JSON.stringify({ + email_address: [email], + username: `e2e_${suffix}`, + password, + bypass_client_trust: true, + }), }); if (!response.ok) { throw new Error(`BAPI user creation failed (HTTP ${response.status}): ${await response.text()}`); From 334076ba70b3d39c655162a00a2c20a6955e6b9b Mon Sep 17 00:00:00 2001 From: wobsoriano Date: Fri, 2 Oct 2026 09:32:51 -0700 Subject: [PATCH 21/31] ci(e2e): drop the email code step from the native sign-in helper --- .../expo-native/page-objects/authView.ts | 24 ++++--------------- 1 file changed, 5 insertions(+), 19 deletions(-) diff --git a/integration/tests/expo-native/page-objects/authView.ts b/integration/tests/expo-native/page-objects/authView.ts index 924eb417d90..b50bf701d36 100644 --- a/integration/tests/expo-native/page-objects/authView.ts +++ b/integration/tests/expo-native/page-objects/authView.ts @@ -7,10 +7,7 @@ import { fill, tapUntilVisible } from './gestures.ts'; const welcome = /^Welcome! Sign in to continue\.?$/; const iosPasswordPrompt = /^(Save Password|Strong Password|Use Strong Password|AutoFill Passwords)$/i; const androidPasswordPrompt = /Google Password Manager/; -const afterPassword = new RegExp( - `^(Check your email|signed in)$|${iosPasswordPrompt.source}|${androidPasswordPrompt.source}`, - 'i', -); +const afterPassword = new RegExp(`^signed in$|${iosPasswordPrompt.source}|${androidPasswordPrompt.source}`, 'i'); export const createAuthViewPageObject = ({ device, platform, screen }: DeviceFixtures) => { const openButton = screen.getByTestId('open-auth-view-button'); @@ -59,11 +56,6 @@ export const createAuthViewPageObject = ({ device, platform, screen }: DeviceFix continue: () => { return screen.getByText('Continue').tap(); }, - enterEmailCode: async () => { - if (await screen.getByText('Check your email').isVisible()) { - await screen.getByRole('textbox').last().pressSequentially('424242'); - } - }, dismissPasswordPrompt: async () => { await dismissAndroidPasswordPrompt(); await dismissIosPasswordPrompt(); @@ -72,16 +64,10 @@ export const createAuthViewPageObject = ({ device, platform, screen }: DeviceFix await expect(screen.getByText(welcome)).toBeVisible({ timeout: 25_000 }); await self.setIdentifier(email); await self.continue(); - await expect(screen.getByText(/^(Enter your password|Check your email)$/).first()).toBeVisible({ - timeout: 15_000, - }); - await self.enterEmailCode(); - if (await screen.getByText('Enter your password').first().isVisible()) { - await self.setPassword(password); - await self.continue(); - await expect(screen.getByText(afterPassword).first()).toBeVisible({ timeout: 15_000 }); - } - await self.enterEmailCode(); + await expect(screen.getByText('Enter your password').first()).toBeVisible({ timeout: 15_000 }); + await self.setPassword(password); + await self.continue(); + await expect(screen.getByText(afterPassword).first()).toBeVisible({ timeout: 15_000 }); await self.dismissPasswordPrompt(); }, }; From d4a4ab3f32d3196263832ed9cab31033a6a54f1c Mon Sep 17 00:00:00 2001 From: wobsoriano Date: Fri, 2 Oct 2026 09:32:52 -0700 Subject: [PATCH 22/31] ci(e2e): TEMP bust caches to measure a cold run --- .github/workflows/expo-native-build.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/expo-native-build.yml b/.github/workflows/expo-native-build.yml index 42dd6657710..a83bdd4da27 100644 --- a/.github/workflows/expo-native-build.yml +++ b/.github/workflows/expo-native-build.yml @@ -104,7 +104,7 @@ jobs: with: path: ${{ steps.native-build-key.outputs.artifact }} # Bump the version when native build commands change. - key: expo-native-build-v1-${{ runner.os }}-${{ matrix.expo-sdk }}-${{ matrix.platform }}-${{ matrix.run-e2e == true && 'e2e' || 'build' }}-${{ env.E2E_INSTANCE_NAME }}-${{ steps.native-build-key.outputs.hash }} + key: expo-native-build-v1cold4-${{ runner.os }}-${{ matrix.expo-sdk }}-${{ matrix.platform }}-${{ matrix.run-e2e == true && 'e2e' || 'build' }}-${{ env.E2E_INSTANCE_NAME }}-${{ steps.native-build-key.outputs.hash }} - if: steps.native-build-cache.outputs.cache-hit != 'true' || matrix.run-e2e == true uses: pnpm/action-setup@b906affcce14559ad1aafd4ab0e942779e9f58b1 # v4 @@ -246,8 +246,8 @@ jobs: uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4 with: path: ~/.agent-device - key: agent-device-${{ runner.os }}-${{ hashFiles('pnpm-lock.yaml') }} - restore-keys: agent-device-${{ runner.os }}- + key: agent-device-cold4-${{ runner.os }}-${{ hashFiles('pnpm-lock.yaml') }} + restore-keys: agent-device-cold4-${{ runner.os }}- - name: Run iOS e2e id: run_e2e_ios @@ -284,7 +284,7 @@ jobs: path: | ~/.android/avd/* ~/.android/adb* - key: avd-34-google_apis-x86_64-v1 + key: avd-34-google_apis-x86_64-v1cold4 - name: Create AVD snapshot if: matrix.platform == 'android' && steps.keys.outputs.sk != '' && steps.avd-cache.outputs.cache-hit != 'true' From ae628466415a2b3b067fd14122ebf2984b76058d Mon Sep 17 00:00:00 2001 From: wobsoriano Date: Fri, 2 Oct 2026 09:44:05 -0700 Subject: [PATCH 23/31] Revert "ci(e2e): TEMP bust caches to measure a cold run" This reverts commit d4a4ab3f32d3196263832ed9cab31033a6a54f1c. --- .github/workflows/expo-native-build.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/expo-native-build.yml b/.github/workflows/expo-native-build.yml index a83bdd4da27..42dd6657710 100644 --- a/.github/workflows/expo-native-build.yml +++ b/.github/workflows/expo-native-build.yml @@ -104,7 +104,7 @@ jobs: with: path: ${{ steps.native-build-key.outputs.artifact }} # Bump the version when native build commands change. - key: expo-native-build-v1cold4-${{ runner.os }}-${{ matrix.expo-sdk }}-${{ matrix.platform }}-${{ matrix.run-e2e == true && 'e2e' || 'build' }}-${{ env.E2E_INSTANCE_NAME }}-${{ steps.native-build-key.outputs.hash }} + key: expo-native-build-v1-${{ runner.os }}-${{ matrix.expo-sdk }}-${{ matrix.platform }}-${{ matrix.run-e2e == true && 'e2e' || 'build' }}-${{ env.E2E_INSTANCE_NAME }}-${{ steps.native-build-key.outputs.hash }} - if: steps.native-build-cache.outputs.cache-hit != 'true' || matrix.run-e2e == true uses: pnpm/action-setup@b906affcce14559ad1aafd4ab0e942779e9f58b1 # v4 @@ -246,8 +246,8 @@ jobs: uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4 with: path: ~/.agent-device - key: agent-device-cold4-${{ runner.os }}-${{ hashFiles('pnpm-lock.yaml') }} - restore-keys: agent-device-cold4-${{ runner.os }}- + key: agent-device-${{ runner.os }}-${{ hashFiles('pnpm-lock.yaml') }} + restore-keys: agent-device-${{ runner.os }}- - name: Run iOS e2e id: run_e2e_ios @@ -284,7 +284,7 @@ jobs: path: | ~/.android/avd/* ~/.android/adb* - key: avd-34-google_apis-x86_64-v1cold4 + key: avd-34-google_apis-x86_64-v1 - name: Create AVD snapshot if: matrix.platform == 'android' && steps.keys.outputs.sk != '' && steps.avd-cache.outputs.cache-hit != 'true' From 16dee055ff35c6207f6bdb003e081207c7bf9ff8 Mon Sep 17 00:00:00 2001 From: wobsoriano Date: Fri, 2 Oct 2026 10:08:30 -0700 Subject: [PATCH 24/31] ci(e2e): type the password with key presses and retry field focus on engine failures --- .../tests/expo-native/page-objects/authView.ts | 8 +++++--- .../tests/expo-native/page-objects/gestures.ts | 16 ++++++++++++---- 2 files changed, 17 insertions(+), 7 deletions(-) diff --git a/integration/tests/expo-native/page-objects/authView.ts b/integration/tests/expo-native/page-objects/authView.ts index b50bf701d36..6b11acccb36 100644 --- a/integration/tests/expo-native/page-objects/authView.ts +++ b/integration/tests/expo-native/page-objects/authView.ts @@ -2,7 +2,7 @@ import { expect } from 'e2e'; import type { DeviceFixtures } from '../types.ts'; import type { TestUser } from '../users.ts'; -import { fill, tapUntilVisible } from './gestures.ts'; +import { fill, focus, tapUntilVisible } from './gestures.ts'; const welcome = /^Welcome! Sign in to continue\.?$/; const iosPasswordPrompt = /^(Save Password|Strong Password|Use Strong Password|AutoFill Passwords)$/i; @@ -50,8 +50,10 @@ export const createAuthViewPageObject = ({ device, platform, screen }: DeviceFix } await expect(value).toBeVisible(); }, - setPassword: (password: string) => { - return fill(screen.getByRole('textbox').last(), password); + setPassword: async (password: string) => { + const field = screen.getByRole('textbox').last(); + await focus(field); + await field.pressSequentially(password); }, continue: () => { return screen.getByText('Continue').tap(); diff --git a/integration/tests/expo-native/page-objects/gestures.ts b/integration/tests/expo-native/page-objects/gestures.ts index 67d67eef48a..5528b3e99d1 100644 --- a/integration/tests/expo-native/page-objects/gestures.ts +++ b/integration/tests/expo-native/page-objects/gestures.ts @@ -34,12 +34,20 @@ export async function tapControl(fixtures: DeviceFixtures, control: Locator) { } } -export async function fill(field: Locator, value: string) { - await field.tap(); - await field.fill(value).catch((error: { code?: string }) => { +function retryEngineFailure(action: () => Promise) { + return action().catch((error: { code?: string }) => { if (error.code !== 'ENGINE_FAILURE') { throw error; } - return field.fill(value); + return action(); }); } + +export function focus(field: Locator) { + return retryEngineFailure(() => field.tap()); +} + +export async function fill(field: Locator, value: string) { + await focus(field); + await retryEngineFailure(() => field.fill(value)); +} From 50af268f1660ef4eca18bfe155cbb30a5d5b5ae4 Mon Sep 17 00:00:00 2001 From: wobsoriano Date: Fri, 2 Oct 2026 10:08:31 -0700 Subject: [PATCH 25/31] ci(e2e): TEMP bust caches to measure a cold run --- .github/workflows/expo-native-build.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/expo-native-build.yml b/.github/workflows/expo-native-build.yml index 42dd6657710..6d51fe64928 100644 --- a/.github/workflows/expo-native-build.yml +++ b/.github/workflows/expo-native-build.yml @@ -104,7 +104,7 @@ jobs: with: path: ${{ steps.native-build-key.outputs.artifact }} # Bump the version when native build commands change. - key: expo-native-build-v1-${{ runner.os }}-${{ matrix.expo-sdk }}-${{ matrix.platform }}-${{ matrix.run-e2e == true && 'e2e' || 'build' }}-${{ env.E2E_INSTANCE_NAME }}-${{ steps.native-build-key.outputs.hash }} + key: expo-native-build-v1cold5-${{ runner.os }}-${{ matrix.expo-sdk }}-${{ matrix.platform }}-${{ matrix.run-e2e == true && 'e2e' || 'build' }}-${{ env.E2E_INSTANCE_NAME }}-${{ steps.native-build-key.outputs.hash }} - if: steps.native-build-cache.outputs.cache-hit != 'true' || matrix.run-e2e == true uses: pnpm/action-setup@b906affcce14559ad1aafd4ab0e942779e9f58b1 # v4 @@ -246,8 +246,8 @@ jobs: uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4 with: path: ~/.agent-device - key: agent-device-${{ runner.os }}-${{ hashFiles('pnpm-lock.yaml') }} - restore-keys: agent-device-${{ runner.os }}- + key: agent-device-cold5-${{ runner.os }}-${{ hashFiles('pnpm-lock.yaml') }} + restore-keys: agent-device-cold5-${{ runner.os }}- - name: Run iOS e2e id: run_e2e_ios @@ -284,7 +284,7 @@ jobs: path: | ~/.android/avd/* ~/.android/adb* - key: avd-34-google_apis-x86_64-v1 + key: avd-34-google_apis-x86_64-v1cold5 - name: Create AVD snapshot if: matrix.platform == 'android' && steps.keys.outputs.sk != '' && steps.avd-cache.outputs.cache-hit != 'true' From f6b7e6e1d8eedc6d091cf13bb62c973ae431471f Mon Sep 17 00:00:00 2001 From: wobsoriano Date: Fri, 2 Oct 2026 10:19:59 -0700 Subject: [PATCH 26/31] Revert "ci(e2e): TEMP bust caches to measure a cold run" This reverts commit 50af268f1660ef4eca18bfe155cbb30a5d5b5ae4. --- .github/workflows/expo-native-build.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/expo-native-build.yml b/.github/workflows/expo-native-build.yml index 6d51fe64928..42dd6657710 100644 --- a/.github/workflows/expo-native-build.yml +++ b/.github/workflows/expo-native-build.yml @@ -104,7 +104,7 @@ jobs: with: path: ${{ steps.native-build-key.outputs.artifact }} # Bump the version when native build commands change. - key: expo-native-build-v1cold5-${{ runner.os }}-${{ matrix.expo-sdk }}-${{ matrix.platform }}-${{ matrix.run-e2e == true && 'e2e' || 'build' }}-${{ env.E2E_INSTANCE_NAME }}-${{ steps.native-build-key.outputs.hash }} + key: expo-native-build-v1-${{ runner.os }}-${{ matrix.expo-sdk }}-${{ matrix.platform }}-${{ matrix.run-e2e == true && 'e2e' || 'build' }}-${{ env.E2E_INSTANCE_NAME }}-${{ steps.native-build-key.outputs.hash }} - if: steps.native-build-cache.outputs.cache-hit != 'true' || matrix.run-e2e == true uses: pnpm/action-setup@b906affcce14559ad1aafd4ab0e942779e9f58b1 # v4 @@ -246,8 +246,8 @@ jobs: uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4 with: path: ~/.agent-device - key: agent-device-cold5-${{ runner.os }}-${{ hashFiles('pnpm-lock.yaml') }} - restore-keys: agent-device-cold5-${{ runner.os }}- + key: agent-device-${{ runner.os }}-${{ hashFiles('pnpm-lock.yaml') }} + restore-keys: agent-device-${{ runner.os }}- - name: Run iOS e2e id: run_e2e_ios @@ -284,7 +284,7 @@ jobs: path: | ~/.android/avd/* ~/.android/adb* - key: avd-34-google_apis-x86_64-v1cold5 + key: avd-34-google_apis-x86_64-v1 - name: Create AVD snapshot if: matrix.platform == 'android' && steps.keys.outputs.sk != '' && steps.avd-cache.outputs.cache-hit != 'true' From 309c972a81a33cd0ef07de58e36da002da5725a5 Mon Sep 17 00:00:00 2001 From: wobsoriano Date: Fri, 2 Oct 2026 10:46:40 -0700 Subject: [PATCH 27/31] ci(e2e): give the native sign-in 45 seconds to reach the JS SDK --- integration/tests/expo-native/page-objects/authView.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/integration/tests/expo-native/page-objects/authView.ts b/integration/tests/expo-native/page-objects/authView.ts index 6b11acccb36..4abad335dd0 100644 --- a/integration/tests/expo-native/page-objects/authView.ts +++ b/integration/tests/expo-native/page-objects/authView.ts @@ -69,7 +69,7 @@ export const createAuthViewPageObject = ({ device, platform, screen }: DeviceFix await expect(screen.getByText('Enter your password').first()).toBeVisible({ timeout: 15_000 }); await self.setPassword(password); await self.continue(); - await expect(screen.getByText(afterPassword).first()).toBeVisible({ timeout: 15_000 }); + await expect(screen.getByText(afterPassword).first()).toBeVisible({ timeout: 45_000 }); await self.dismissPasswordPrompt(); }, }; From fb9643c617ac04d72f3eb5a4c7e1aabcf899bfbb Mon Sep 17 00:00:00 2001 From: wobsoriano Date: Fri, 2 Oct 2026 13:21:00 -0700 Subject: [PATCH 28/31] ci(e2e): address review on test user cleanup, path filter and the detach check --- .github/workflows/expo-native-build.yml | 14 ++++++++++++++ .../tests/expo-native/page-objects/authView.ts | 1 + integration/tests/expo-native/users.ts | 6 +++--- 3 files changed, 18 insertions(+), 3 deletions(-) diff --git a/.github/workflows/expo-native-build.yml b/.github/workflows/expo-native-build.yml index 42dd6657710..d047c8c96e1 100644 --- a/.github/workflows/expo-native-build.yml +++ b/.github/workflows/expo-native-build.yml @@ -7,6 +7,7 @@ on: - main paths: - '.github/workflows/expo-native-build.yml' + - 'integration/e2e.expo-native.config.ts' - 'integration/templates/expo-native/**' - 'integration/tests/expo-native/**' - 'packages/expo/**' @@ -37,6 +38,8 @@ jobs: name: Native ${{ matrix.run-e2e == true && 'E2E' || 'Build' }} (${{ matrix.platform }}, sdk ${{ matrix.expo-sdk }}) runs-on: ${{ matrix.runner }} timeout-minutes: ${{ matrix.run-e2e == true && 60 || 45 }} + env: + CLERK_TEST_USERNAME_PREFIX: e2e_${{ github.run_id }}_${{ matrix.platform }}_ strategy: fail-fast: false matrix: @@ -320,6 +323,17 @@ jobs: (adb logcat -v threadtime > "$RUNNER_TEMP/e2e-device-logs/logcat.log" 2>&1 &) && pnpm test:integration:expo-native:android --video=on-first-retry --reporter list,junit,markdown + - name: Delete leftover test users + if: always() && steps.keys.outputs.sk != '' + env: + CLERK_SECRET_KEY: ${{ steps.keys.outputs.sk }} + run: | + curl -fsS "$BAPI_URL/v1/users?limit=100&query=$CLERK_TEST_USERNAME_PREFIX" -H "Authorization: Bearer $CLERK_SECRET_KEY" | + jq -r '.[].id' | + while read -r user_id; do + curl -fsS -o /dev/null -X DELETE "$BAPI_URL/v1/users/$user_id" -H "Authorization: Bearer $CLERK_SECRET_KEY" || true + done + - name: Upload e2e artifacts if: always() && steps.keys.outputs.sk != '' uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4 diff --git a/integration/tests/expo-native/page-objects/authView.ts b/integration/tests/expo-native/page-objects/authView.ts index 4abad335dd0..0debc89a922 100644 --- a/integration/tests/expo-native/page-objects/authView.ts +++ b/integration/tests/expo-native/page-objects/authView.ts @@ -39,6 +39,7 @@ export const createAuthViewPageObject = ({ device, platform, screen }: DeviceFix } else { await tapUntilVisible(screen.getByRole('button', 'Close'), openButton); } + await expect(screen.getByText(welcome)).toBeHidden({ timeout: 15_000 }); }, setIdentifier: async (identifier: string) => { const label = screen.getByText(/^Enter your email( or username)?$/); diff --git a/integration/tests/expo-native/users.ts b/integration/tests/expo-native/users.ts index 8b793aa52ee..1728ffae53c 100644 --- a/integration/tests/expo-native/users.ts +++ b/integration/tests/expo-native/users.ts @@ -10,14 +10,14 @@ function bapi(path: string, init: RequestInit) { } export async function createTestUser(): Promise { - const suffix = randomBytes(4).toString('hex'); - const email = `${suffix}+clerk_test@example.com`; + const suffix = randomBytes(2).toString('hex'); + const email = `${suffix}+clerk_test@clerkcookie.com`; const password = `ClerkCI!${randomBytes(8).toString('hex')}Aa1`; const response = await bapi('/users', { method: 'POST', body: JSON.stringify({ email_address: [email], - username: `e2e_${suffix}`, + username: `${process.env.CLERK_TEST_USERNAME_PREFIX ?? 'e2e_local_'}${suffix}`, password, bypass_client_trust: true, }), From d505001ba2c1a216f33b8eb01554b189eea69d61 Mon Sep 17 00:00:00 2001 From: wobsoriano Date: Sat, 3 Oct 2026 07:18:43 -0700 Subject: [PATCH 29/31] ci(e2e): only delete leftover users by username prefix and report failed deletions --- .github/workflows/expo-native-build.yml | 4 ++-- integration/tests/expo-native/users.ts | 5 ++++- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/.github/workflows/expo-native-build.yml b/.github/workflows/expo-native-build.yml index d047c8c96e1..d805683ccbb 100644 --- a/.github/workflows/expo-native-build.yml +++ b/.github/workflows/expo-native-build.yml @@ -328,8 +328,8 @@ jobs: env: CLERK_SECRET_KEY: ${{ steps.keys.outputs.sk }} run: | - curl -fsS "$BAPI_URL/v1/users?limit=100&query=$CLERK_TEST_USERNAME_PREFIX" -H "Authorization: Bearer $CLERK_SECRET_KEY" | - jq -r '.[].id' | + curl -fsS -G "$BAPI_URL/v1/users" --data-urlencode "limit=100" --data-urlencode "query=$CLERK_TEST_USERNAME_PREFIX" -H "Authorization: Bearer $CLERK_SECRET_KEY" | + jq -r --arg p "$CLERK_TEST_USERNAME_PREFIX" '.[] | select((.username // "") | startswith($p)) | .id' | while read -r user_id; do curl -fsS -o /dev/null -X DELETE "$BAPI_URL/v1/users/$user_id" -H "Authorization: Bearer $CLERK_SECRET_KEY" || true done diff --git a/integration/tests/expo-native/users.ts b/integration/tests/expo-native/users.ts index 1728ffae53c..2a22e74b419 100644 --- a/integration/tests/expo-native/users.ts +++ b/integration/tests/expo-native/users.ts @@ -30,5 +30,8 @@ export async function createTestUser(): Promise { } export async function deleteTestUser({ id }: TestUser) { - await bapi(`/users/${id}`, { method: 'DELETE' }); + const response = await bapi(`/users/${id}`, { method: 'DELETE' }); + if (!response.ok && response.status !== 404) { + console.warn(`BAPI user deletion failed for ${id} (HTTP ${response.status}): ${await response.text()}`); + } } From 0e92cc2e3c37d11f7e9fb5830d61724819e4f9de Mon Sep 17 00:00:00 2001 From: wobsoriano Date: Mon, 5 Oct 2026 12:47:14 -0700 Subject: [PATCH 30/31] ci(e2e): retry leftover user deletion and warn when it fails --- .github/workflows/expo-native-build.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/expo-native-build.yml b/.github/workflows/expo-native-build.yml index d805683ccbb..e0cd977ceae 100644 --- a/.github/workflows/expo-native-build.yml +++ b/.github/workflows/expo-native-build.yml @@ -331,7 +331,8 @@ jobs: curl -fsS -G "$BAPI_URL/v1/users" --data-urlencode "limit=100" --data-urlencode "query=$CLERK_TEST_USERNAME_PREFIX" -H "Authorization: Bearer $CLERK_SECRET_KEY" | jq -r --arg p "$CLERK_TEST_USERNAME_PREFIX" '.[] | select((.username // "") | startswith($p)) | .id' | while read -r user_id; do - curl -fsS -o /dev/null -X DELETE "$BAPI_URL/v1/users/$user_id" -H "Authorization: Bearer $CLERK_SECRET_KEY" || true + curl -fsS --retry 3 --retry-delay 1 -o /dev/null -X DELETE "$BAPI_URL/v1/users/$user_id" -H "Authorization: Bearer $CLERK_SECRET_KEY" || + echo "::warning::Could not delete leftover test user $user_id" done - name: Upload e2e artifacts From db7c31b34d372a5d4b1ed5956830bf1b8c1ea37f Mon Sep 17 00:00:00 2001 From: wobsoriano Date: Mon, 5 Oct 2026 14:02:43 -0700 Subject: [PATCH 31/31] ci(e2e): stop recording retry videos in the expo native e2e --- .github/workflows/expo-native-build.yml | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/.github/workflows/expo-native-build.yml b/.github/workflows/expo-native-build.yml index e0cd977ceae..7fe76c6d0dd 100644 --- a/.github/workflows/expo-native-build.yml +++ b/.github/workflows/expo-native-build.yml @@ -270,7 +270,7 @@ jobs: > "$RUNNER_TEMP/e2e-device-logs/$udid-console.log" 2>&1 & log_pids+=($!) done - pnpm test:integration:expo-native:ios --video=on-first-retry --reporter list,junit,markdown + pnpm test:integration:expo-native:ios --reporter list,junit,markdown - name: Enable KVM if: matrix.platform == 'android' && steps.keys.outputs.sk != '' @@ -321,7 +321,7 @@ jobs: mkdir -p "$RUNNER_TEMP/e2e-device-logs" && adb install -r "$FIXTURE_DIR/android/app/build/outputs/apk/release/app-release.apk" && (adb logcat -v threadtime > "$RUNNER_TEMP/e2e-device-logs/logcat.log" 2>&1 &) && - pnpm test:integration:expo-native:android --video=on-first-retry --reporter list,junit,markdown + pnpm test:integration:expo-native:android --reporter list,junit,markdown - name: Delete leftover test users if: always() && steps.keys.outputs.sk != '' @@ -343,7 +343,6 @@ jobs: include-hidden-files: true path: | integration/.e2e - !integration/.e2e/**/.video.* ${{ runner.temp }}/e2e-device-logs if-no-files-found: warn retention-days: 7